From 1bcc7199f633af1136cb9d40e1b651e314382f6d Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 29 Sep 2024 21:20:17 +1000 Subject: [PATCH] Redesign BIM tool to have mutually exclusive add/edit modes. --- src/bonsai/bonsai/bim/module/model/product.py | 15 ++--- .../bonsai/bim/module/model/workspace.py | 66 ++++++++++--------- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/bonsai/bonsai/bim/module/model/product.py b/src/bonsai/bonsai/bim/module/model/product.py index 84647e7816..92fce0bccf 100644 --- a/src/bonsai/bonsai/bim/module/model/product.py +++ b/src/bonsai/bonsai/bim/module/model/product.py @@ -142,8 +142,10 @@ class AddOccurrence(bpy.types.Operator, PolylineOperator): if result: self.report({"WARNING"}, result) + # TODO: when this workflow matures a bit, recode it so it doesn't rely on selection and cursor # Select snapped object so we can insert doors and windows detected_snaps = tool.Snap.detect_snapping_points(context, event, self.objs_2d_bbox, self.tool_state) + snap_obj = None for snap in detected_snaps: if snap_obj := snap.get("Object", None): try: @@ -153,6 +155,7 @@ class AddOccurrence(bpy.types.Operator, PolylineOperator): snap_obj = bpy.data.objects.get(snap_obj[0].name) snap_obj.name tool.Blender.select_and_activate_single_object(context, snap_obj) + break except: pass @@ -162,6 +165,9 @@ class AddOccurrence(bpy.types.Operator, PolylineOperator): bpy.ops.bim.add_constr_type_instance("INVOKE_DEFAULT") + if snap_obj: + snap_obj.select_set(False) + def modal(self, context, event): if not self.relating_type: self.report({"WARNING"}, "You need to select a wall type.") @@ -181,11 +187,7 @@ class AddOccurrence(bpy.types.Operator, PolylineOperator): self.choose_axis(event) self.handle_snap_selection(context, event) - if ( - not self.tool_state.is_input_on - and event.value == "RELEASE" - and event.type in {"RIGHTMOUSE"} - ): + if not self.tool_state.is_input_on and event.value == "RELEASE" and event.type in {"RIGHTMOUSE"}: context.workspace.status_text_set(text=None) PolylineDecorator.uninstall() context.scene.BIMPolylineProperties.product_preview.clear() @@ -454,10 +456,7 @@ class AddConstrTypeInstance(bpy.types.Operator, tool.Ifc.Operator): @staticmethod def generate_layered_element(ifc_class: str, relating_type: ifcopenshell.entity_instance) -> bool: - layer_set_direction = None - usage = tool.Model.get_usage_type(relating_type) - print('usage', usage) obj = None if usage == "LAYER3": diff --git a/src/bonsai/bonsai/bim/module/model/workspace.py b/src/bonsai/bonsai/bim/module/model/workspace.py index f34c75bb3b..7178585172 100644 --- a/src/bonsai/bonsai/bim/module/model/workspace.py +++ b/src/bonsai/bonsai/bim/module/model/workspace.py @@ -110,10 +110,10 @@ class BimTool(WorkSpaceTool): # Unlike operators, Blender doesn't treat workspace tools as a class, so we'll create our own. if context.scene.BIMGeometryProperties.mode == "ITEM": EditItemUI.draw(context, layout) + elif context.active_object and context.selected_objects: + EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) else: CreateObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) - if context.active_object and context.selected_objects: - EditObjectUI.draw(context, layout, ifc_element_type=cls.ifc_element_type) class WallTool(BimTool): @@ -340,8 +340,9 @@ class CreateObjectUI: cls.layout.label(text=tool_name, icon="TOOL_SETTINGS") cls.draw_type_manager_launcher(context) - cls.draw_thumbnail() if context.region.type != "TOOL_HEADER" else cls cls.draw_add_object(context) + cls.draw_thumbnail() if context.region.type != "TOOL_HEADER" else cls + cls.draw_add_object_parameters(context) @classmethod def draw_container_info(cls, context): @@ -353,7 +354,6 @@ class CreateObjectUI: @classmethod def draw_type_manager_launcher(cls, context): - ui_context = str(context.region.type) row = cls.layout.row(align=True) if not AuthoringData.data["ifc_classes"]: if AuthoringData.data["ifc_element_type"]: @@ -372,6 +372,36 @@ class CreateObjectUI: @classmethod def draw_add_object(cls, context): + ui_context = str(context.region.type) + if AuthoringData.data["ifc_classes"]: + if not AuthoringData.data["ifc_element_type"]: + row = cls.layout.row(align=True) + prop_with_search(row, cls.props, "ifc_class", text="Type Class" if ui_context != "TOOL_HEADER" else "") + if AuthoringData.data["relating_type_id"]: + row = cls.layout.row(align=True) + box = row.box() + # This trick creates a fake dropdown + row2 = box.row(align=True) + row2.operator( + "bim.launch_type_manager", + icon="FILE_3D", + text=AuthoringData.data["relating_type_name"], + emboss=False, + ) + row2.operator( + "bim.launch_type_manager", + icon="DOWNARROW_HLT", + text="", + emboss=False, + ) + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row + op = row.operator("bim.hotkey", text="Add", icon_value=custom_icon_previews["ADD"].icon_id) + op.hotkey = "S_A" + else: + row.label(text="No Construction Type", icon="FILE_3D") + + @classmethod + def draw_add_object_parameters(cls, context): ui_context = str(context.region.type) row = cls.layout.row(align=True) if not AuthoringData.data["relating_type_id"]: @@ -424,28 +454,6 @@ class CreateObjectUI: row = cls.layout.row(align=True) row.prop(data=cls.props, property="rl_mode", text="RL Mode" if ui_context != "TOOL_HEADER" else "RL") - if AuthoringData.data["ifc_classes"]: - if not AuthoringData.data["ifc_element_type"]: - row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - prop_with_search(row, cls.props, "ifc_class", text="Type Class" if ui_context != "TOOL_HEADER" else "") - if AuthoringData.data["relating_type_id"]: - row = cls.layout.row(align=True) - row.operator( - "bim.launch_type_manager", - icon=tool.Blender.TYPE_MANAGER_ICON, - text="Type: " + AuthoringData.data["relating_type_name"], - ) - row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - add_layout_hotkey_operator(row, "Add", "S_A", bpy.ops.bim.add_constr_type_instance.__doc__, ui_context) - row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - ( - add_layout_hotkey_operator(row, "Draw", "S_P", bpy.ops.bim.draw_polyline_wall.__doc__, ui_context) - if cls.props.ifc_class == "IfcWallType" - else row - ) - else: - row.label(text="No Construction Type", icon="FILE_3D") - @classmethod def draw_thumbnail(cls): if AuthoringData.data["ifc_classes"]: @@ -1090,12 +1098,6 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): self.props.y = self.y self.props.z = self.z - def hotkey_S_P(self): - mode = bpy.context.mode - current_tool = bpy.context.workspace.tools.from_space_view3d_mode(mode) - if current_tool.idname == "bim.wall_tool": - bpy.ops.bim.draw_polyline_wall("INVOKE_DEFAULT") - def hotkey_S_L(self): if AuthoringData.data["active_class"] in ("IfcOpeningElement",): if len(bpy.context.selected_objects) == 2: