Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f2efbf57bb | |||
| 74347fe5e0 | |||
| a7c6969a4a | |||
| 423c145984 | |||
| c6ecf55f59 | |||
| c402a388d8 | |||
| bc3d4d26d2 | |||
| 9397774e24 | |||
| ddbcb7ee39 | |||
| 105bb00304 | |||
| ffd4da1ed9 | |||
| 26ba5c921b | |||
| a3aaf4471c | |||
| 4995f02351 |
@@ -6,7 +6,7 @@ orbs:
|
||||
jobs:
|
||||
package-connector:
|
||||
docker:
|
||||
- image: cimg/python:3.11.0
|
||||
- image: cimg/python:3.11.12
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
|
||||
build-connector-zip:
|
||||
docker:
|
||||
- image: cimg/python:3.11.0
|
||||
- image: cimg/python:3.11.12
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ./
|
||||
@@ -44,10 +44,10 @@ jobs:
|
||||
root: ./
|
||||
paths:
|
||||
- bpy_speckle.zip
|
||||
|
||||
|
||||
get-ci-tools: # Clones our ci tools and persists them to the workspace
|
||||
docker:
|
||||
- image: cimg/base:2021.01
|
||||
- image: cimg/base:2025.04
|
||||
steps:
|
||||
- add_ssh_keys:
|
||||
fingerprints:
|
||||
@@ -104,7 +104,7 @@ jobs:
|
||||
- run:
|
||||
name: Sync Certs
|
||||
command: |
|
||||
& $env:SSM\smksp_cert_sync.exe
|
||||
& $env:SSM\smctl.exe windows certsync
|
||||
- run:
|
||||
name: Build Installer
|
||||
command: speckle-sharp-ci-tools\InnoSetup\ISCC.exe speckle-sharp-ci-tools\blender.iss /Sbyparam=$p /DSIGN_INSTALLER /DCODE_SIGNING_CERT_FINGERPRINT=%SM_CODE_SIGNING_CERT_SHA1_HASH%
|
||||
@@ -166,7 +166,7 @@ jobs:
|
||||
|
||||
build-installer-manual:
|
||||
docker:
|
||||
- image: cimg/base:2021.01
|
||||
- image: cimg/base:2025.04
|
||||
parameters:
|
||||
slug:
|
||||
type: string
|
||||
@@ -228,7 +228,7 @@ workflows:
|
||||
filters: &build_filters
|
||||
tags:
|
||||
only: /([0-9]+)\.([0-9]+)\.([0-9]+)(?:-\w+)?(?:\.[0-9]+)?/
|
||||
|
||||
|
||||
- build-connector-zip:
|
||||
requires:
|
||||
- package-connector
|
||||
|
||||
@@ -13,13 +13,13 @@ from bpy_speckle.properties import *
|
||||
from bpy_speckle.ui import *
|
||||
|
||||
bl_info = {
|
||||
"name": "SpeckleBlender 2.0",
|
||||
"name": "SpeckleBlender 2.0 (Legacy)",
|
||||
"author": "Speckle Systems",
|
||||
"version": (0, 2, 0),
|
||||
"blender": (2, 92, 0),
|
||||
"location": "3d viewport toolbar (N), under the Speckle tab.",
|
||||
"description": "The Speckle Connector using specklepy 2.0!",
|
||||
"warning": "This add-on is WIP and should be used with caution",
|
||||
"description": "(Legacy) Speckle Connector using specklepy 2.0!",
|
||||
"warning": "This is a legacy add-on. Download the new connector from https://app.speckle.systems/connectors",
|
||||
"wiki_url": "https://github.com/specklesystems/speckle-blender",
|
||||
"category": "Scene",
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ from attrs import define
|
||||
from bpy.types import ID, Collection, Object
|
||||
from specklepy.objects.base import Base
|
||||
from specklepy.objects.graph_traversal.commit_object_builder import (
|
||||
ROOT, CommitObjectBuilder)
|
||||
ROOT,
|
||||
CommitObjectBuilder,
|
||||
)
|
||||
from specklepy.objects.other import Collection as SCollection
|
||||
|
||||
from bpy_speckle.functions import _report
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
Permanent handle on all user clients
|
||||
"""
|
||||
|
||||
from specklepy.core.api.client import SpeckleClient
|
||||
|
||||
speckle_clients: list[SpeckleClient] = []
|
||||
|
||||
@@ -9,26 +9,43 @@ from mathutils import Matrix as MMatrix
|
||||
from mathutils import Quaternion as MQuaternion
|
||||
from mathutils import Vector as MVector
|
||||
from specklepy.objects.base import Base
|
||||
from specklepy.objects.geometry import (Arc, Circle, Curve, Ellipse, Line,
|
||||
Mesh, Plane, Polycurve, Polyline)
|
||||
from specklepy.objects.geometry import (
|
||||
Arc,
|
||||
Circle,
|
||||
Curve,
|
||||
Ellipse,
|
||||
Line,
|
||||
Mesh,
|
||||
Plane,
|
||||
Polycurve,
|
||||
Polyline,
|
||||
)
|
||||
from specklepy.objects.other import BlockDefinition
|
||||
from specklepy.objects.other import Collection as SCollection
|
||||
from specklepy.objects.other import Instance, Transform
|
||||
|
||||
from bpy_speckle.convert.constants import (DISPLAY_VALUE_PROPERTY_ALIASES,
|
||||
ELEMENTS_PROPERTY_ALIASES,
|
||||
OBJECT_NAME_MAX_LENGTH,
|
||||
OBJECT_NAME_NUMERAL_SEPARATOR,
|
||||
OBJECT_NAME_SPECKLE_SEPARATOR,
|
||||
SPECKLE_ID_LENGTH)
|
||||
from bpy_speckle.convert.constants import (
|
||||
DISPLAY_VALUE_PROPERTY_ALIASES,
|
||||
ELEMENTS_PROPERTY_ALIASES,
|
||||
OBJECT_NAME_MAX_LENGTH,
|
||||
OBJECT_NAME_NUMERAL_SEPARATOR,
|
||||
OBJECT_NAME_SPECKLE_SEPARATOR,
|
||||
SPECKLE_ID_LENGTH,
|
||||
)
|
||||
from bpy_speckle.convert.util import ConversionSkippedException
|
||||
from bpy_speckle.functions import (_report, get_default_traversal_func,
|
||||
get_scale_length)
|
||||
from bpy_speckle.functions import _report, get_default_traversal_func, get_scale_length
|
||||
|
||||
from .util import (add_colors, add_custom_properties, add_faces,
|
||||
add_to_hierarchy, add_uv_coords, add_vertices,
|
||||
get_render_material, get_vertex_color_material,
|
||||
render_material_to_native)
|
||||
from .util import (
|
||||
add_colors,
|
||||
add_custom_properties,
|
||||
add_faces,
|
||||
add_to_hierarchy,
|
||||
add_uv_coords,
|
||||
add_vertices,
|
||||
get_render_material,
|
||||
get_vertex_color_material,
|
||||
render_material_to_native,
|
||||
)
|
||||
|
||||
SUPPORTED_CURVES = (Line, Polyline, Curve, Arc, Polycurve, Ellipse, Circle)
|
||||
CAN_CONVERT_TO_NATIVE = (
|
||||
@@ -59,7 +76,9 @@ def can_convert_to_native(speckle_object: Base) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
convert_instances_as: str = "" # HACK: This is hacky, we need a better way to pass settings down to the converter
|
||||
convert_instances_as: str = (
|
||||
"" # HACK: This is hacky, we need a better way to pass settings down to the converter
|
||||
)
|
||||
|
||||
|
||||
def set_convert_instances_as(value: str):
|
||||
@@ -682,9 +701,9 @@ def instance_to_native_object(instance: Instance, scale: float) -> Object:
|
||||
native_instance = create_new_object(None, name)
|
||||
native_instance.empty_display_size = 0
|
||||
|
||||
converted_objects[
|
||||
"__ROOT"
|
||||
] = native_instance # we create a dummy root to avoid id conflicts, since revit definitions have displayValues, they are convertible
|
||||
converted_objects["__ROOT"] = (
|
||||
native_instance # we create a dummy root to avoid id conflicts, since revit definitions have displayValues, they are convertible
|
||||
)
|
||||
traversal_root = Base(elements=definition, id="__ROOT")
|
||||
|
||||
# Convert definition + "elements" on definition
|
||||
@@ -758,9 +777,9 @@ def _instance_definition_to_native(
|
||||
native_def["applicationId"] = definition.applicationId
|
||||
|
||||
converted_objects = {}
|
||||
converted_objects[
|
||||
"__ROOT"
|
||||
] = native_def # we create a dummy root to avoid id conflicts, since revit definitions have displayValues, they are convertible
|
||||
converted_objects["__ROOT"] = (
|
||||
native_def # we create a dummy root to avoid id conflicts, since revit definitions have displayValues, they are convertible
|
||||
)
|
||||
dummyRoot = Base(elements=definition, id="__ROOT")
|
||||
|
||||
_deep_conversion(dummyRoot, converted_objects, True)
|
||||
|
||||
@@ -11,22 +11,40 @@ from mathutils import Matrix as MMatrix
|
||||
from mathutils import Vector as MVector
|
||||
from mathutils.geometry import interpolate_bezier
|
||||
from specklepy.objects import Base
|
||||
from specklepy.objects.geometry import (Box, Curve, Interval, Mesh, Point,
|
||||
Polyline, Vector)
|
||||
from specklepy.objects.other import (BlockDefinition, BlockInstance,
|
||||
RenderMaterial, Transform)
|
||||
from specklepy.objects.geometry import (
|
||||
Box,
|
||||
Curve,
|
||||
Interval,
|
||||
Mesh,
|
||||
Point,
|
||||
Polyline,
|
||||
Vector,
|
||||
)
|
||||
from specklepy.objects.other import (
|
||||
BlockDefinition,
|
||||
BlockInstance,
|
||||
RenderMaterial,
|
||||
Transform,
|
||||
)
|
||||
|
||||
from bpy_speckle.blender_commit_object_builder import \
|
||||
BlenderCommitObjectBuilder
|
||||
from bpy_speckle.convert.constants import (OBJECT_NAME_SPECKLE_SEPARATOR,
|
||||
SPECKLE_ID_LENGTH)
|
||||
from bpy_speckle.convert.util import (ConversionSkippedException,
|
||||
get_blender_custom_properties,
|
||||
make_knots, nurb_make_curve, to_argb_int)
|
||||
from bpy_speckle.blender_commit_object_builder import BlenderCommitObjectBuilder
|
||||
from bpy_speckle.convert.constants import (
|
||||
OBJECT_NAME_SPECKLE_SEPARATOR,
|
||||
SPECKLE_ID_LENGTH,
|
||||
)
|
||||
from bpy_speckle.convert.util import (
|
||||
ConversionSkippedException,
|
||||
get_blender_custom_properties,
|
||||
make_knots,
|
||||
nurb_make_curve,
|
||||
to_argb_int,
|
||||
)
|
||||
from bpy_speckle.functions import _report
|
||||
|
||||
Units: str = "m" # The desired final units to send
|
||||
UnitsScale: float = 1 # The scale factor conversions need to apply to position data to get to the desired units
|
||||
UnitsScale: float = (
|
||||
1 # The scale factor conversions need to apply to position data to get to the desired units
|
||||
)
|
||||
|
||||
CAN_CONVERT_TO_SPECKLE = ("MESH", "CURVE", "EMPTY", "CAMERA", "FONT", "SURFACE", "META")
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
from typing import Callable
|
||||
|
||||
from specklepy.objects.base import Base
|
||||
from specklepy.objects.graph_traversal.traversal import (GraphTraversal,
|
||||
TraversalRule)
|
||||
from specklepy.objects.units import (get_scale_factor_to_meters,
|
||||
get_units_from_string)
|
||||
from specklepy.objects.graph_traversal.traversal import GraphTraversal, TraversalRule
|
||||
from specklepy.objects.units import get_scale_factor_to_meters, get_units_from_string
|
||||
|
||||
from bpy_speckle.convert.constants import ELEMENTS_PROPERTY_ALIASES
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
Provides uniform and consistent path helpers for `specklepy`
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from importlib import import_module, invalidate_caches
|
||||
@@ -167,6 +168,7 @@ def install_requirements(host_application: str) -> None:
|
||||
"--prefer-binary",
|
||||
"--ignore-installed",
|
||||
"--no-compile",
|
||||
"--no-deps",
|
||||
"-t",
|
||||
str(path),
|
||||
"-r",
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
from .commit import DeleteCommit
|
||||
from .misc import OpenSpeckleForum, OpenSpeckleGuide, OpenSpeckleTutorials
|
||||
from .object import (DeleteObject, ResetObject, SelectIfHasCustomProperty,
|
||||
SelectIfSameCustomProperty, UpdateObject,
|
||||
UploadNgonsAsPolylines)
|
||||
from .streams import (AddStreamFromURL, CopyBranchName, CopyCommitId,
|
||||
CopyModelId, CopyStreamId, CreateStream, DeleteStream,
|
||||
ReceiveStreamObjects, SelectOrphanObjects,
|
||||
SendStreamObjects, ViewStreamDataApi)
|
||||
from .streams import (
|
||||
AddStreamFromURL,
|
||||
CopyCommitId,
|
||||
CopyModelId,
|
||||
CopyStreamId,
|
||||
CreateStream,
|
||||
ReceiveStreamObjects,
|
||||
SendStreamObjects,
|
||||
ViewStreamDataApi,
|
||||
)
|
||||
from .users import LoadUsers, LoadUserStreams, ResetUsers
|
||||
|
||||
operator_classes = [
|
||||
@@ -17,28 +20,14 @@ operator_classes = [
|
||||
LoadUserStreams,
|
||||
CopyStreamId,
|
||||
CopyCommitId,
|
||||
CopyBranchName,
|
||||
CopyModelId,
|
||||
]
|
||||
|
||||
operator_classes.extend([DeleteCommit])
|
||||
|
||||
operator_classes.extend(
|
||||
[
|
||||
UpdateObject,
|
||||
ResetObject,
|
||||
DeleteObject,
|
||||
UploadNgonsAsPolylines,
|
||||
SelectIfSameCustomProperty,
|
||||
SelectIfHasCustomProperty,
|
||||
]
|
||||
)
|
||||
|
||||
operator_classes.extend(
|
||||
[
|
||||
ViewStreamDataApi,
|
||||
DeleteStream,
|
||||
SelectOrphanObjects,
|
||||
AddStreamFromURL,
|
||||
CreateStream,
|
||||
OpenSpeckleGuide,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
Commit operators
|
||||
"""
|
||||
|
||||
import bpy
|
||||
from bpy.props import BoolProperty
|
||||
from specklepy.logging import metrics
|
||||
|
||||
@@ -1,346 +0,0 @@
|
||||
"""
|
||||
Object operators
|
||||
"""
|
||||
|
||||
import bpy
|
||||
from bpy.props import BoolProperty, EnumProperty
|
||||
from deprecated import deprecated
|
||||
from specklepy.logging import metrics
|
||||
|
||||
from bpy_speckle.clients import speckle_clients
|
||||
from bpy_speckle.convert.to_speckle import (convert_to_speckle,
|
||||
ngons_to_speckle_polylines)
|
||||
from bpy_speckle.functions import _report, get_scale_length
|
||||
|
||||
|
||||
@deprecated
|
||||
class UpdateObject(bpy.types.Operator):
|
||||
"""
|
||||
Update local (receive) or remote (send) object depending on
|
||||
the update direction. If sending, updates the object on the
|
||||
server in-place.
|
||||
"""
|
||||
|
||||
bl_idname = "speckle.update_object"
|
||||
bl_label = "Update Object (DEPRECATED)"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
client = None
|
||||
|
||||
def execute(self, context):
|
||||
client = speckle_clients[int(context.scene.speckle.active_user)]
|
||||
|
||||
active = context.active_object
|
||||
_report(active)
|
||||
|
||||
if active is not None and active.speckle.enabled:
|
||||
if active.speckle.send_or_receive == "send" and active.speckle.stream_id:
|
||||
sstream = client.streams.get(active.speckle.stream_id)
|
||||
# res = client.StreamGetAsync(active.speckle.stream_id)['resource']
|
||||
# res = client.streams.get(active.speckle.stream_id)
|
||||
|
||||
if sstream is None:
|
||||
_report("Getting stream failed.")
|
||||
return {"CANCELLED"}
|
||||
|
||||
stream_units = "Meters"
|
||||
if sstream.baseProperties:
|
||||
stream_units = sstream.baseProperties.units
|
||||
|
||||
scale = context.scene.unit_settings.scale_length / get_scale_length(
|
||||
stream_units
|
||||
)
|
||||
|
||||
sm = convert_to_speckle(active, scale)
|
||||
|
||||
_report("Updating object {}".format(sm["_id"]))
|
||||
client.objects.update(active.speckle.object_id, sm)
|
||||
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
None,
|
||||
custom_props={"name": "UpdateObject"},
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
return {"CANCELLED"}
|
||||
return {"CANCELLED"}
|
||||
|
||||
|
||||
@deprecated
|
||||
class ResetObject(bpy.types.Operator):
|
||||
"""
|
||||
Reset Speckle object settings
|
||||
"""
|
||||
|
||||
bl_idname = "speckle.reset_object"
|
||||
bl_label = "Reset Object (DEPRECATED)"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
context.object.speckle.send_or_receive = "send"
|
||||
context.object.speckle.stream_id = ""
|
||||
context.object.speckle.object_id = ""
|
||||
context.object.speckle.enabled = False
|
||||
context.view_layer.update()
|
||||
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
None,
|
||||
custom_props={"name": "ResetObject"},
|
||||
)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@deprecated
|
||||
class DeleteObject(bpy.types.Operator):
|
||||
"""
|
||||
Delete object from the server and update relevant stream
|
||||
"""
|
||||
|
||||
bl_idname = "speckle.delete_object"
|
||||
bl_label = "Delete Object (DEPRECATED)"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
client = speckle_clients[int(context.scene.speckle.active_user)]
|
||||
active = context.object
|
||||
if active.speckle.enabled:
|
||||
res = client.StreamGetAsync(active.speckle.stream_id)
|
||||
existing = [
|
||||
x
|
||||
for x in res["resource"]["objects"]
|
||||
if x["_id"] == active.speckle.object_id
|
||||
]
|
||||
if existing is None:
|
||||
return {"CANCELLED"}
|
||||
new_objects = [
|
||||
x
|
||||
for x in res["resource"]["objects"]
|
||||
if x["_id"] != active.speckle.object_id
|
||||
]
|
||||
|
||||
res = client.GetLayers(active.speckle.stream_id)
|
||||
new_layers = res["resource"]["layers"]
|
||||
new_layers[-1]["objectCount"] = new_layers[-1]["objectCount"] - 1
|
||||
new_layers[-1]["topology"] = "0-%s" % new_layers[-1]["objectCount"]
|
||||
|
||||
res = client.StreamUpdateAsync(
|
||||
{"objects": new_objects, "layers": new_layers}, active.speckle.stream_id
|
||||
)
|
||||
res = client.ObjectDeleteAsync(active.speckle.object_id)
|
||||
|
||||
active.speckle.send_or_receive = "send"
|
||||
active.speckle.stream_id = ""
|
||||
active.speckle.object_id = ""
|
||||
active.speckle.enabled = False
|
||||
context.view_layer.update()
|
||||
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
None,
|
||||
custom_props={"name": "DeleteObject"},
|
||||
)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@deprecated
|
||||
class UploadNgonsAsPolylines(bpy.types.Operator):
|
||||
"""
|
||||
Upload mesh ngon faces as polyline outlines
|
||||
TODO: move to another category of specialized operators and fix to work with API 2.0
|
||||
"""
|
||||
|
||||
bl_idname = "speckle.upload_ngons_as_polylines"
|
||||
bl_label = "Upload Ngons As Polylines (DEPRECATED)"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
clear_stream: BoolProperty(
|
||||
name="Clear stream",
|
||||
default=False,
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
active = context.active_object
|
||||
if active is not None and active.type == "MESH":
|
||||
user = context.scene.speckle.users[int(context.scene.speckle.active_user)]
|
||||
client = speckle_clients[int(context.scene.speckle.active_user)]
|
||||
stream = user.streams[user.active_stream]
|
||||
|
||||
# scale = context.scene.unit_settings.scale_length / get_scale_length(
|
||||
# stream.units
|
||||
# )
|
||||
scale = 1.0
|
||||
|
||||
sp = ngons_to_speckle_polylines(active, scale)
|
||||
|
||||
if sp is None:
|
||||
return {"CANCELLED"}
|
||||
|
||||
placeholders = []
|
||||
for polyline in sp:
|
||||
res = client.objects.create([polyline])
|
||||
|
||||
if res is None:
|
||||
_report(client.me)
|
||||
continue
|
||||
placeholders.extend(res)
|
||||
|
||||
if not placeholders:
|
||||
return {"CANCELLED"}
|
||||
|
||||
# Get list of existing objects in stream and append new object to list
|
||||
_report("Fetching stream...")
|
||||
sstream = client.streams.get(stream.id)
|
||||
|
||||
if self.clear_stream:
|
||||
_report("Clearing stream...")
|
||||
sstream.objects = placeholders
|
||||
N = 0
|
||||
else:
|
||||
sstream.objects.extend(placeholders)
|
||||
|
||||
N = sstream.layers[-1].objectCount
|
||||
if self.clear_stream:
|
||||
N = 0
|
||||
sstream.layers[-1].objectCount = N + len(placeholders)
|
||||
sstream.layers[-1].topology = "0-%s" % (N + len(placeholders))
|
||||
|
||||
res = client.streams.update(sstream.id, sstream)
|
||||
|
||||
# Update view layer
|
||||
context.view_layer.update()
|
||||
_report("Done.")
|
||||
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
None,
|
||||
custom_props={"name": "UploadNgonsAsPolylines"},
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "clear_stream")
|
||||
|
||||
|
||||
def get_custom_speckle_props(self, context):
|
||||
active = context.active_object
|
||||
if not active:
|
||||
return []
|
||||
|
||||
return [(x, "{}".format(x), "") for x in active.keys()]
|
||||
|
||||
|
||||
@deprecated
|
||||
class SelectIfSameCustomProperty(bpy.types.Operator):
|
||||
"""
|
||||
Select scene objects if they have the same custom property
|
||||
value as the active object
|
||||
"""
|
||||
|
||||
bl_idname = "speckle.select_if_same_custom_props"
|
||||
bl_label = "Select Identical Custom Props (DEPRECATED)"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
custom_prop: EnumProperty(
|
||||
name="Custom properties",
|
||||
description="Available streams associated with user.",
|
||||
items=get_custom_speckle_props,
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
col = layout.column()
|
||||
col.prop(self, "custom_prop")
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def execute(self, context):
|
||||
active = context.active_object
|
||||
if not active:
|
||||
return {"CANCELLED"}
|
||||
|
||||
if self.custom_prop not in active.keys():
|
||||
return {"CANCELLED"}
|
||||
|
||||
value = active[self.custom_prop]
|
||||
|
||||
_report(
|
||||
"Looking for '{}' property with a value of '{}'.".format(
|
||||
self.custom_prop, value
|
||||
)
|
||||
)
|
||||
|
||||
for obj in bpy.data.objects:
|
||||
if self.custom_prop in obj.keys() and obj[self.custom_prop] == value:
|
||||
obj.select_set(True)
|
||||
else:
|
||||
obj.select_set(False)
|
||||
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
None,
|
||||
custom_props={"name": "SelectIfSameCustomProperty"},
|
||||
)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@deprecated
|
||||
class SelectIfHasCustomProperty(bpy.types.Operator):
|
||||
"""
|
||||
Select scene objects if they have the same custom property
|
||||
as the active object, regardless of the value
|
||||
"""
|
||||
|
||||
bl_idname = "speckle.select_if_has_custom_props"
|
||||
bl_label = "Select Same Custom Prop (DEPRECATED)"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
custom_prop: EnumProperty(
|
||||
name="Custom properties",
|
||||
description="Custom properties yo",
|
||||
items=get_custom_speckle_props,
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
col = layout.column()
|
||||
col.prop(self, "custom_prop")
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def execute(self, context):
|
||||
active = context.active_object
|
||||
if not active:
|
||||
return {"CANCELLED"}
|
||||
|
||||
if self.custom_prop not in active.keys():
|
||||
return {"CANCELLED"}
|
||||
|
||||
_report("Looking for '{}' property.".format(self.custom_prop))
|
||||
|
||||
for obj in bpy.data.objects:
|
||||
if self.custom_prop in obj.keys():
|
||||
obj.select_set(True)
|
||||
else:
|
||||
obj.select_set(False)
|
||||
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
None,
|
||||
custom_props={"name": "SelectIfHasCustomProperty"},
|
||||
)
|
||||
|
||||
return {"FINISHED"}
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
Stream operators
|
||||
"""
|
||||
|
||||
import webbrowser
|
||||
from math import radians
|
||||
from typing import Callable, Dict, Optional, Tuple, Union, cast
|
||||
@@ -19,23 +20,25 @@ from specklepy.objects import Base
|
||||
from specklepy.objects.other import Collection as SCollection
|
||||
from specklepy.transports.server import ServerTransport
|
||||
|
||||
from bpy_speckle.blender_commit_object_builder import \
|
||||
BlenderCommitObjectBuilder
|
||||
from bpy_speckle.blender_commit_object_builder import BlenderCommitObjectBuilder
|
||||
from bpy_speckle.clients import speckle_clients
|
||||
from bpy_speckle.convert.to_native import (can_convert_to_native,
|
||||
collection_to_native,
|
||||
convert_to_native,
|
||||
set_convert_instances_as)
|
||||
from bpy_speckle.convert.to_native import (
|
||||
can_convert_to_native,
|
||||
collection_to_native,
|
||||
convert_to_native,
|
||||
set_convert_instances_as,
|
||||
)
|
||||
from bpy_speckle.convert.to_speckle import convert_to_speckle
|
||||
from bpy_speckle.convert.util import (ConversionSkippedException,
|
||||
add_to_hierarchy)
|
||||
from bpy_speckle.functions import (_report, get_default_traversal_func,
|
||||
get_scale_length)
|
||||
from bpy_speckle.convert.util import ConversionSkippedException, add_to_hierarchy
|
||||
from bpy_speckle.functions import _report, get_default_traversal_func, get_scale_length
|
||||
from bpy_speckle.operators.users import LoadUserStreams, add_user_stream
|
||||
from bpy_speckle.properties.scene import (SpeckleSceneSettings,
|
||||
SpeckleStreamObject,
|
||||
SpeckleUserObject, get_speckle,
|
||||
selection_state)
|
||||
from bpy_speckle.properties.scene import (
|
||||
SpeckleSceneSettings,
|
||||
SpeckleStreamObject,
|
||||
SpeckleUserObject,
|
||||
get_speckle,
|
||||
selection_state,
|
||||
)
|
||||
|
||||
ObjectCallback = Optional[Callable[[bpy.types.Context, Object, Base], Object]]
|
||||
ReceiveCompleteCallback = Optional[
|
||||
@@ -45,9 +48,17 @@ ReceiveCompleteCallback = Optional[
|
||||
|
||||
def get_project_workspace_id(client: SpeckleClient, project_id: str) -> Optional[str]:
|
||||
workspace_id = None
|
||||
server_version = client.project.server_version or client.server.verison()
|
||||
maj = server_version[0]
|
||||
min = server_version[1]
|
||||
server_version = client.project.server_version or client.server.version()
|
||||
|
||||
# Local yarn builds of server will report a server version if "dev"
|
||||
# We'll assume that local builds are up-to-date with the latest features
|
||||
if server_version[0] == "dev":
|
||||
maj = 999
|
||||
min = 999
|
||||
else:
|
||||
maj = server_version[0]
|
||||
min = server_version[1]
|
||||
|
||||
if maj > 2 or (maj == 2 and min > 20):
|
||||
workspace_id = client.project.get(project_id).workspaceId
|
||||
return workspace_id
|
||||
@@ -181,7 +192,7 @@ class ReceiveStreamObjects(bpy.types.Operator):
|
||||
).slug,
|
||||
"sourceHostAppVersion": commit.source_application,
|
||||
"isMultiplayer": commit.author_id != user.id,
|
||||
"workspace_id": get_project_workspace_id(client, stream.id)
|
||||
"workspace_id": get_project_workspace_id(client, stream.id),
|
||||
# "connector_version": "unknown", #TODO
|
||||
},
|
||||
)
|
||||
@@ -647,109 +658,6 @@ class CreateStream(bpy.types.Operator):
|
||||
)
|
||||
|
||||
|
||||
@deprecated
|
||||
class DeleteStream(bpy.types.Operator):
|
||||
"""
|
||||
Permanently delete the selected project
|
||||
"""
|
||||
|
||||
bl_idname = "speckle.delete_stream"
|
||||
bl_label = "Delete Project"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Permanently delete the selected project"
|
||||
|
||||
are_you_sure: BoolProperty(
|
||||
name="Confirm",
|
||||
description="⚠ This action will delete your entire stream permanently ⚠",
|
||||
default=False,
|
||||
) # type: ignore
|
||||
|
||||
delete_collection: BoolProperty(name="Delete collection", default=False) # type: ignore
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
col = layout.column()
|
||||
col.prop(self, "are_you_sure")
|
||||
col.prop(self, "delete_collection")
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
speckle = get_speckle(context)
|
||||
if len(speckle.users) > 0:
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
return {"CANCELLED"}
|
||||
|
||||
def execute(self, context):
|
||||
if not self.are_you_sure:
|
||||
_report(f"Cancelled by user - are_you_sure was {self.are_you_sure}")
|
||||
return {"CANCELLED"}
|
||||
self.are_you_sure = False
|
||||
|
||||
self.delete_stream(context, self.delete_collection)
|
||||
return {"FINISHED"}
|
||||
|
||||
@staticmethod
|
||||
def delete_stream(context: Context, delete_collection: bool) -> None:
|
||||
speckle = get_speckle(context)
|
||||
(_, stream) = speckle.validate_stream_selection()
|
||||
|
||||
client = speckle_clients[int(speckle.active_user)]
|
||||
|
||||
client.stream.delete(id=stream.id)
|
||||
|
||||
if delete_collection:
|
||||
# This may not work anymore since we changed the collection naming...
|
||||
col_name = "SpeckleStream_{}_{}".format(stream.name, stream.id)
|
||||
if col_name in bpy.data.collections:
|
||||
collection = bpy.data.collections[col_name]
|
||||
bpy.data.collections.remove(collection)
|
||||
|
||||
bpy.ops.speckle.load_user_streams()
|
||||
context.view_layer.update()
|
||||
|
||||
if context.area:
|
||||
context.area.tag_redraw()
|
||||
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
client.account,
|
||||
custom_props={"name": "delete_stream"},
|
||||
)
|
||||
|
||||
|
||||
@deprecated
|
||||
class SelectOrphanObjects(bpy.types.Operator):
|
||||
"""
|
||||
Select Speckle objects that don't belong to any stream
|
||||
"""
|
||||
|
||||
bl_idname = "speckle.select_orphans"
|
||||
bl_label = "Select Orphaned Objects (DEPRECATED)"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Select Speckle objects that don't belong to any stream"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
def execute(self, context):
|
||||
for o in context.scene.objects:
|
||||
if (
|
||||
o.speckle.stream_id
|
||||
and o.speckle.stream_id not in context.scene["speckle_streams"]
|
||||
):
|
||||
o.select = True
|
||||
else:
|
||||
o.select = False
|
||||
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
custom_props={"name": "SelectOrphanObjects"},
|
||||
)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CopyStreamId(bpy.types.Operator):
|
||||
"""
|
||||
Copy the selected project id to clipboard
|
||||
@@ -827,63 +735,3 @@ class CopyModelId(bpy.types.Operator):
|
||||
"Connector Action",
|
||||
custom_props={"name": "copy_branch_id"},
|
||||
)
|
||||
|
||||
|
||||
@deprecated
|
||||
class CopyBranchName(bpy.types.Operator):
|
||||
"""
|
||||
Copy branch name to clipboard
|
||||
"""
|
||||
|
||||
bl_idname = "speckle.branch_copy_name"
|
||||
bl_label = "Copy branch name"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Copy branch name to clipboard"
|
||||
|
||||
def execute(self, context):
|
||||
self.copy_branch_id(context)
|
||||
return {"FINISHED"}
|
||||
|
||||
def copy_branch_id(self, context) -> None:
|
||||
speckle = get_speckle(context)
|
||||
|
||||
(_, _, branch) = speckle.validate_branch_selection()
|
||||
|
||||
bpy.context.window_manager.clipboard = branch.name
|
||||
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
custom_props={"name": "copy_branch_id"},
|
||||
)
|
||||
|
||||
|
||||
@deprecated
|
||||
class SelectOrphanObjects(bpy.types.Operator):
|
||||
"""
|
||||
Select Speckle objects that don't belong to any stream
|
||||
"""
|
||||
|
||||
bl_idname = "speckle.select_orphans"
|
||||
bl_label = "Select orphaned objects"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Select Speckle objects that don't belong to any stream"
|
||||
|
||||
def draw(self, context):
|
||||
pass
|
||||
|
||||
def execute(self, context):
|
||||
for o in context.scene.objects:
|
||||
if (
|
||||
o.speckle.stream_id
|
||||
and o.speckle.stream_id not in context.scene["speckle_streams"]
|
||||
):
|
||||
o.select = True
|
||||
else:
|
||||
o.select = False
|
||||
|
||||
metrics.track(
|
||||
"Connector Action",
|
||||
custom_props={"name": "SelectOrphanObjects"},
|
||||
)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
User account operators
|
||||
"""
|
||||
|
||||
from typing import cast
|
||||
|
||||
import bpy
|
||||
@@ -12,10 +13,13 @@ from specklepy.logging import metrics
|
||||
|
||||
from bpy_speckle.clients import speckle_clients
|
||||
from bpy_speckle.functions import _report
|
||||
from bpy_speckle.properties.scene import (SpeckleSceneSettings,
|
||||
SpeckleStreamObject,
|
||||
SpeckleUserObject, get_speckle,
|
||||
restore_selection_state)
|
||||
from bpy_speckle.properties.scene import (
|
||||
SpeckleSceneSettings,
|
||||
SpeckleStreamObject,
|
||||
SpeckleUserObject,
|
||||
get_speckle,
|
||||
restore_selection_state,
|
||||
)
|
||||
|
||||
|
||||
class ResetUsers(bpy.types.Operator):
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
from .addon import SpeckleAddonPreferences
|
||||
from .collection import SpeckleCollectionSettings
|
||||
from .object import SpeckleObjectSettings
|
||||
from .scene import (SpeckleBranchObject, SpeckleCommitObject,
|
||||
SpeckleSceneObject, SpeckleSceneSettings,
|
||||
SpeckleStreamObject, SpeckleUserObject)
|
||||
from .scene import (
|
||||
SpeckleBranchObject,
|
||||
SpeckleCommitObject,
|
||||
SpeckleSceneObject,
|
||||
SpeckleSceneSettings,
|
||||
SpeckleStreamObject,
|
||||
SpeckleUserObject,
|
||||
)
|
||||
|
||||
property_classes = [
|
||||
SpeckleSceneObject,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
Addon properties
|
||||
"""
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
Collection properties
|
||||
"""
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
Object properties
|
||||
"""
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
"""
|
||||
Scene properties
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterable, Optional, Tuple, Union, cast
|
||||
|
||||
import bpy
|
||||
from bpy.props import (CollectionProperty, EnumProperty, FloatProperty,
|
||||
IntProperty, StringProperty)
|
||||
from bpy.props import (
|
||||
CollectionProperty,
|
||||
EnumProperty,
|
||||
FloatProperty,
|
||||
IntProperty,
|
||||
StringProperty,
|
||||
)
|
||||
from specklepy.core.api.models import Stream
|
||||
|
||||
from bpy_speckle.clients import speckle_clients
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
from .object import OBJECT_PT_speckle
|
||||
from .view3d import (VIEW3D_PT_SpeckleActiveStream, VIEW3D_PT_SpeckleHelp,
|
||||
VIEW3D_PT_SpeckleStreams, VIEW3D_PT_SpeckleUser,
|
||||
VIEW3D_UL_SpeckleStreams, VIEW3D_UL_SpeckleUsers)
|
||||
from .view3d import (
|
||||
VIEW3D_PT_SpeckleActiveStream,
|
||||
VIEW3D_PT_SpeckleHelp,
|
||||
VIEW3D_PT_SpeckleStreams,
|
||||
VIEW3D_PT_SpeckleUser,
|
||||
VIEW3D_UL_SpeckleStreams,
|
||||
VIEW3D_UL_SpeckleUsers,
|
||||
)
|
||||
|
||||
ui_classes = [
|
||||
VIEW3D_PT_SpeckleUser,
|
||||
|
||||
@@ -12,7 +12,7 @@ class OBJECT_PT_speckle(bpy.types.Panel):
|
||||
# bl_idname = 'OBJECT_PT_speckle'
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "object"
|
||||
bl_label = "Speckle"
|
||||
bl_label = "Speckle (Legacy)"
|
||||
|
||||
def draw_header(self, context):
|
||||
self.layout.prop(context.object.speckle, "enabled", text="")
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
Speckle UI elements for the 3d viewport
|
||||
"""
|
||||
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import bpy
|
||||
@@ -94,7 +93,7 @@ class VIEW3D_PT_SpeckleUser(bpy.types.Panel):
|
||||
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = Region
|
||||
bl_category = "Speckle"
|
||||
bl_category = "Speckle (Legacy)"
|
||||
bl_context = "objectmode"
|
||||
bl_label = "User Account"
|
||||
|
||||
@@ -102,6 +101,13 @@ class VIEW3D_PT_SpeckleUser(bpy.types.Panel):
|
||||
speckle = get_speckle(context)
|
||||
|
||||
layout = self.layout
|
||||
# Draw a box with the text "Warning: This is a legacy add-on. Download the new connector from https://app.speckle.systems/connectors"
|
||||
box = layout.box()
|
||||
box.label(text="Warning: This is a legacy add-on.", icon="ERROR")
|
||||
box.label(text="Download the new connector from")
|
||||
box.label(text="https://app.speckle.systems/connectors")
|
||||
layout.separator()
|
||||
|
||||
col = layout.column()
|
||||
|
||||
if len(speckle.users) < 1:
|
||||
@@ -122,7 +128,7 @@ class VIEW3D_PT_SpeckleStreams(bpy.types.Panel):
|
||||
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = Region
|
||||
bl_category = "Speckle"
|
||||
bl_category = "Speckle (Legacy)"
|
||||
bl_context = "objectmode"
|
||||
bl_label = "Projects"
|
||||
|
||||
@@ -150,7 +156,7 @@ class VIEW3D_PT_SpeckleActiveStream(bpy.types.Panel):
|
||||
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = Region
|
||||
bl_category = "Speckle"
|
||||
bl_category = "Speckle (Legacy)"
|
||||
bl_context = "objectmode"
|
||||
bl_label = "Active Project"
|
||||
|
||||
@@ -246,7 +252,7 @@ class VIEW3D_PT_SpeckleHelp(bpy.types.Panel):
|
||||
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = Region
|
||||
bl_category = "Speckle"
|
||||
bl_category = "Speckle (Legacy)"
|
||||
bl_context = "objectmode"
|
||||
bl_label = "Help"
|
||||
|
||||
|
||||
Generated
+853
-783
File diff suppressed because it is too large
Load Diff
+33
-7
@@ -4,21 +4,47 @@ version = "2.0.0"
|
||||
description = "the Speckle 2.0 connector for Blender!"
|
||||
authors = ["izzy lyseggen <izzy.lyseggen@gmail.com>", "Gergő Jedlicska <gergo@jedlicska.com>"]
|
||||
license = "Apache-2.0"
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.requires-plugins]
|
||||
poetry-plugin-export = ">=1.8"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.8, <4.0.0"
|
||||
specklepy = "^2.20.1"
|
||||
attrs = "^23.1.0"
|
||||
python = ">=3.9.0, <4.0.0"
|
||||
specklepy = "^2.23.0"
|
||||
|
||||
# [tool.poetry.group.local_specklepy.dependencies]
|
||||
# specklepy = {path = "../specklepy", develop = true}
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
fake-bpy-module-latest = "^20240524"
|
||||
black = "24.3.0"
|
||||
pylint = "^2.15.7"
|
||||
ruff = "^0.4.4"
|
||||
fake-bpy-module-latest = "^20241010"
|
||||
black = "24.10.0"
|
||||
isort = "^5.13.2"
|
||||
pylint = "^3.3.2"
|
||||
ruff = "^0.8.2"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.black]
|
||||
exclude = '''
|
||||
/(
|
||||
\.eggs
|
||||
| \.git
|
||||
| \.hg
|
||||
| \.mypy_cache
|
||||
| \.tox
|
||||
| \.venv
|
||||
| _build
|
||||
| buck-out
|
||||
| build
|
||||
| dist
|
||||
)/
|
||||
'''
|
||||
include = '\.pyi?$'
|
||||
line-length = 88
|
||||
target-version = ["py39", "py310", "py311", "py312", "py313"]
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
Reference in New Issue
Block a user