diff --git a/src/bonsai/bonsai/bim/module/cad/__init__.py b/src/bonsai/bonsai/bim/module/cad/__init__.py index cf4d5297a0..601c4da1c3 100644 --- a/src/bonsai/bonsai/bim/module/cad/__init__.py +++ b/src/bonsai/bonsai/bim/module/cad/__init__.py @@ -48,4 +48,4 @@ def unregister(): bpy.utils.unregister_tool(workspace.CadTool) del bpy.types.Scene.BIMCadProperties - workspace.unload_custom_icons() \ No newline at end of file + workspace.unload_custom_icons() diff --git a/src/bonsai/bonsai/bim/module/cad/workspace.py b/src/bonsai/bonsai/bim/module/cad/workspace.py index 6b3723cf72..7fb643c9bc 100644 --- a/src/bonsai/bonsai/bim/module/cad/workspace.py +++ b/src/bonsai/bonsai/bim/module/cad/workspace.py @@ -24,10 +24,11 @@ import ifcopenshell.util.unit from bpy.types import WorkSpaceTool from bonsai.bim.module.model.data import AuthoringData, RailingData, RoofData + def check_display_mode(): global display_mode try: - theme = bpy.context.preferences.themes['Default'] + theme = bpy.context.preferences.themes["Default"] text_color = theme.user_interface.wcol_menu_item.text background_color = theme.user_interface.wcol_menu_item.outline print(f"text_color = {text_color}") @@ -44,12 +45,12 @@ def load_custom_icons(): global custom_icon_previews if display_mode is None: check_display_mode() - + icons_dir = os.path.join(os.path.dirname(__file__), "..", "..", "data", "icons") custom_icon_previews = bpy.utils.previews.new() - + prefix = f"{display_mode}_" - + for entry in os.scandir(icons_dir): if entry.name.endswith(".png") and entry.name.startswith(prefix): name = os.path.splitext(entry.name)[0].replace(prefix, "", 1) @@ -92,16 +93,36 @@ class CadTool(WorkSpaceTool): element = tool.Ifc.get_entity(obj) if element: if element.is_a("IfcProfileDef"): - add_header_apply_button(layout, "Edit Profile", "bim.edit_arbitrary_profile", "bim.disable_editing_arbitrary_profile", ui_context) + add_header_apply_button( + layout, + "Edit Profile", + "bim.edit_arbitrary_profile", + "bim.disable_editing_arbitrary_profile", + ui_context, + ) elif element.is_a("IfcRelSpaceBoundary"): - add_header_apply_button(layout, "Edit Boundary Geometry", "bim.edit_boundary_geometry", "bim.disable_editing_boundary_geometry", ui_context) + add_header_apply_button( + layout, + "Edit Boundary Geometry", + "bim.edit_boundary_geometry", + "bim.disable_editing_boundary_geometry", + ui_context, + ) else: - add_header_apply_button(layout, "Edit Profile", "bim.edit_extrusion_profile", "bim.disable_editing_extrusion_profile", ui_context) + add_header_apply_button( + layout, + "Edit Profile", + "bim.edit_extrusion_profile", + "bim.disable_editing_extrusion_profile", + ui_context, + ) - row = layout.row(align=True) + row = layout.row(align=True) add_layout_hotkey_operator(row, "Extend", "S_E", "Extends/reduces element to 3D cursor", ui_context) row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) - add_layout_hotkey_operator(row, "Join", "S_T", "Joins two non-parallel paths at their intersection", ui_context) + add_layout_hotkey_operator( + row, "Join", "S_T", "Joins two non-parallel paths at their intersection", ui_context + ) row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) add_layout_hotkey_operator(row, "Fillet", "S_V", "Fillet", ui_context) row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) @@ -117,10 +138,12 @@ class CadTool(WorkSpaceTool): elif hasattr(obj.data, "BIMMeshProperties") and obj.data.BIMMeshProperties.subshape_type == "AXIS": add_header_apply_button(layout, "Edit Axis", "bim.set_arc_index", "bim.set_arc_index", ui_context) - row = layout.row(align=True) + row = layout.row(align=True) add_layout_hotkey_operator(row, "Extend", "S_E", "Extends/reduces element to 3D cursor", ui_context) row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) - add_layout_hotkey_operator(row, "Join", "S_T", "Joins two non-parallel paths at their intersection", ui_context) + add_layout_hotkey_operator( + row, "Join", "S_T", "Joins two non-parallel paths at their intersection", ui_context + ) row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) add_layout_hotkey_operator(row, "Fillet", "S_F", "Fillet", ui_context) row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) @@ -132,21 +155,31 @@ class CadTool(WorkSpaceTool): and RailingData.data["pset_data"] and context.active_object.BIMRailingProperties.is_editing_path ): - add_header_apply_button(layout, "Edit Railing Path", "bim.finish_editing_railing_path", "bim.cancel_editing_railing_path", ui_context) + add_header_apply_button( + layout, + "Edit Railing Path", + "bim.finish_editing_railing_path", + "bim.cancel_editing_railing_path", + ui_context, + ) elif ( (RoofData.is_loaded or not RoofData.load()) and RoofData.data["pset_data"] and context.active_object.BIMRoofProperties.is_editing_path ): - add_header_apply_button(layout, "Edit Roof Path", "bim.finish_editing_roof_path", "bim.cancel_editing_roof_path", ui_context) - row = layout.row(align=True) + add_header_apply_button( + layout, "Edit Roof Path", "bim.finish_editing_roof_path", "bim.cancel_editing_roof_path", ui_context + ) + row = layout.row(align=True) add_layout_hotkey_operator(row, "Set Gable Roof Angle", "S_R", "Set Gable Roof Angle", ui_context) - - row = layout.row(align=True) + + row = layout.row(align=True) add_layout_hotkey_operator(row, "Extend", "S_E", "Extends/reduces element to 3D cursor", ui_context) row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) - add_layout_hotkey_operator(row, "Join", "S_T", "Joins two non-parallel paths at their intersection", ui_context) + add_layout_hotkey_operator( + row, "Join", "S_T", "Joins two non-parallel paths at their intersection", ui_context + ) row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) add_layout_hotkey_operator(row, "Fillet", "S_V", "Fillet", ui_context) row = row if ui_context == "TOOL_HEADER" else layout.row(align=True) @@ -284,11 +317,17 @@ def add_header_apply_button(layout, text, apply_operator, cancel_operator, ui_co row = layout.row(align=True) row.label(text=f"{text} Mode", icon_value=custom_icon) if apply_operator in ("bim.edit_arbitrary_profile", "bim.edit_extrusion_profile"): - row.operator("bim.align_view_to_profile", text="Align View" if ui_context!="TOOL_HEADER" else "", icon="AXIS_FRONT") + row.operator( + "bim.align_view_to_profile", text="Align View" if ui_context != "TOOL_HEADER" else "", icon="AXIS_FRONT" + ) row = layout.row(align=True) - row.operator(apply_operator, text="Apply" if ui_context!="TOOL_HEADER" else "", icon_value=custom_icon_previews["APPLY"].icon_id) - row.label(text="", icon="EVENT_TAB") if ui_context!="TOOL_HEADER" else row + row.operator( + apply_operator, + text="Apply" if ui_context != "TOOL_HEADER" else "", + icon_value=custom_icon_previews["APPLY"].icon_id, + ) + row.label(text="", icon="EVENT_TAB") if ui_context != "TOOL_HEADER" else row row = layout.row(align=True) row.label(text="Tools") @@ -300,7 +339,7 @@ def add_layout_hotkey_operator(layout, text, hotkey, description, ui_context="") op_text = "" if ui_context == "TOOL_HEADER" else text custom_icon = custom_icon_previews.get(text.upper().replace(" ", "_"), custom_icon_previews["IFC"]).icon_id modifier_icon, modifier_str = MODIFIERS.get(modifier, ("NONE", "")) - + row = layout if ui_context == "TOOL_HEADER" else layout.row(align=True) op = row.operator("bim.cad_hotkey", text=op_text, icon_value=custom_icon) @@ -317,9 +356,6 @@ def add_layout_hotkey_operator(layout, text, hotkey, description, ui_context="") return op - - - custom_icon_previews = None display_mode = None diff --git a/src/bonsai/bonsai/bim/module/model/workspace.py b/src/bonsai/bonsai/bim/module/model/workspace.py index 0c3a9f3f9b..1b2a113f15 100644 --- a/src/bonsai/bonsai/bim/module/model/workspace.py +++ b/src/bonsai/bonsai/bim/module/model/workspace.py @@ -311,7 +311,7 @@ def add_layout_hotkey_operator(layout, text, hotkey, description, ui_context="") def format_ifc_camel_case(string): string = string.replace("Ifc", "") - return ''.join(' ' + char if char.isupper() else char for char in string).strip() + return "".join(" " + char if char.isupper() else char for char in string).strip() class CreateObjectUI: @@ -336,13 +336,17 @@ class CreateObjectUI: AuthoringData.load(ifc_element_type) if ifc_element_type and context.region.type == "TOOL_HEADER": - tool_name = "Multi Object Tool" if ifc_element_type == "all" else format_ifc_camel_case(ifc_element_type.removesuffix('Type')) + ' Tool' + tool_name = ( + "Multi Object Tool" + if ifc_element_type == "all" + else format_ifc_camel_case(ifc_element_type.removesuffix("Type")) + " Tool" + ) 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) - + @classmethod def draw_container_info(cls, context): text = AuthoringData.data["default_container"] @@ -376,7 +380,7 @@ class CreateObjectUI: row = cls.layout.row(align=True) if not AuthoringData.data["relating_type_id"]: return - + if cls.props.ifc_class == "IfcWallType": row.prop(data=cls.props, property="rl1", text="Relative Level" if ui_context != "TOOL_HEADER" else "RL") row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row @@ -385,17 +389,19 @@ class CreateObjectUI: row.prop(data=cls.props, property="length", text="Length" if ui_context != "TOOL_HEADER" else "L") row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row row.prop(data=cls.props, property="x_angle", text="Slope") if ui_context != "TOOL_HEADER" else "A" - + elif cls.props.ifc_class in ("IfcSlabType", "IfcRampType", "IfcRoofType"): - row.prop(data=cls.props, property="x_angle", text="Slope" if ui_context != "TOOL_HEADER" else "A", icon="FILE_3D") + row.prop( + data=cls.props, property="x_angle", text="Slope" if ui_context != "TOOL_HEADER" else "A", icon="FILE_3D" + ) elif cls.props.ifc_class in ("IfcColumnType", "IfcMemberType"): row.prop(data=cls.props, property="cardinal_point", text="Axis") - row.prop(data=cls.props, property="extrusion_depth", text="Height" if ui_context !="TOOL_HEADER" else "H") - + row.prop(data=cls.props, property="extrusion_depth", text="Height" if ui_context != "TOOL_HEADER" else "H") + elif cls.props.ifc_class in ("IfcBeamType"): row.prop(data=cls.props, property="cardinal_point", text="Axis") - row.prop(data=cls.props, property="extrusion_depth", text="Length" if ui_context !="TOOL_HEADER" else "L") + row.prop(data=cls.props, property="extrusion_depth", text="Length" if ui_context != "TOOL_HEADER" else "L") elif cls.props.ifc_class in ("IfcDoorType", "IfcDoorStyle"): row.prop(data=cls.props, property="rl1", text="Relative Level" if ui_context != "TOOL_HEADER" else "RL") @@ -410,7 +416,9 @@ class CreateObjectUI: "IfcCableCarrierSegmentType", "IfcCableSegmentType", ): - row.prop(data=cls.props, property="rl2", text="Relative Level (rl2)" if ui_context != "TOOL_HEADER" else "RL") + row.prop( + data=cls.props, property="rl2", text="Relative Level (rl2)" if ui_context != "TOOL_HEADER" else "RL" + ) ### this neeeds to move elif cls.props.ifc_class in ("IfcSpaceType"): @@ -421,17 +429,23 @@ class CreateObjectUI: 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"]: + 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) if ui_context != "TOOL_HEADER" else row - prop_with_search(row, cls.props, "relating_type_id", text="Relating Type" if ui_context != "TOOL_HEADER" else "") + prop_with_search( + row, cls.props, "relating_type_id", text="Relating Type" if ui_context != "TOOL_HEADER" else "" + ) row.operator("bim.launch_type_manager", icon=tool.Blender.TYPE_MANAGER_ICON, text="") 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 + ( + 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") @@ -469,7 +483,7 @@ class EditObjectUI: elif AuthoringData.data["ifc_element_type"] != ifc_element_type: AuthoringData.load(ifc_element_type) - if context.region.type == "TOOL_HEADER": + if context.region.type == "TOOL_HEADER": text = format_ifc_camel_case(AuthoringData.data["active_class"]) layout.label(text=f"{text} Edit Tools:", icon="RESTRICT_SELECT_OFF") cls.draw_parameter_adjustments(context) @@ -479,7 +493,7 @@ class EditObjectUI: cls.draw_aggregation(context) cls.draw_qto(context) cls.draw_modes(context) - + if context.region.type in ("UI", "WINDOW"): text = format_ifc_camel_case(AuthoringData.data["active_class"]) layout.label(text=f"{text} Edit Tools:", icon="RESTRICT_SELECT_OFF") @@ -490,20 +504,20 @@ class EditObjectUI: cls.draw_aggregation(context) cls.draw_qto(context) cls.draw_modes(context) - + @classmethod def draw_parameter_adjustments(cls, context): ui_context = str(context.region.type) row = cls.layout.row(align=True) row.label(text="Parameter Adjustments") if ui_context != "TOOL_HEADER" else row row = cls.layout.row(align=True) - + if AuthoringData.data["active_material_usage"] == "LAYER2": row.prop(data=cls.props, property="extrusion_depth", text="Height" if ui_context != "TOOL_HEADER" else "H") op = row.operator("bim.change_extrusion_depth", icon="FILE_REFRESH", text="") op.depth = cls.props.extrusion_depth - row = cls.layout.row(align=True)if ui_context != "TOOL_HEADER" else row + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row row.prop(data=cls.props, property="length", text="Length" if ui_context != "TOOL_HEADER" else "L") op = row.operator("bim.change_layer_length", icon="FILE_REFRESH", text="") op.length = cls.props.length @@ -512,7 +526,7 @@ class EditObjectUI: row.prop(data=cls.props, property="x_angle", text="Slope" if ui_context != "TOOL_HEADER" else "A") op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="") op.x_angle = cls.props.x_angle - + elif AuthoringData.data["active_material_usage"] == "LAYER3": row.prop(data=cls.props, property="x_angle", text="Angle" if ui_context != "TOOL_HEADER" else "A") op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="") @@ -523,18 +537,31 @@ class EditObjectUI: op = row.operator("bim.change_cardinal_point", icon="FILE_REFRESH", text="") op.cardinal_point = int(cls.props.cardinal_point) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - label = ("Height" if AuthoringData.data["active_class"] in ("IfcColumn", "IfcColumnStandardCase") else "Length") - row.prop(data=cls.props, property="extrusion_depth", text=label if ui_context != "TOOL_HEADER" else label[0]) + label = ( + "Height" if AuthoringData.data["active_class"] in ("IfcColumn", "IfcColumnStandardCase") else "Length" + ) + row.prop( + data=cls.props, property="extrusion_depth", text=label if ui_context != "TOOL_HEADER" else label[0] + ) op = row.operator("bim.change_profile_depth", icon="FILE_REFRESH", text="") op.depth = cls.props.extrusion_depth - elif AuthoringData.data["active_class"] in ("IfcWindow","IfcWindowStandardCase","IfcDoor","IfcDoorStandardCase"): + elif AuthoringData.data["active_class"] in ( + "IfcWindow", + "IfcWindowStandardCase", + "IfcDoor", + "IfcDoorStandardCase", + ): if AuthoringData.data["active_class"] in ("IfcWindow", "IfcWindowStandardCase"): row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - row.prop(data=cls.props, property="rl2", text="Relative Level (rl2)" if ui_context != "TOOL_HEADER" else "RL") + row.prop( + data=cls.props, property="rl2", text="Relative Level (rl2)" if ui_context != "TOOL_HEADER" else "RL" + ) elif AuthoringData.data["active_class"] in ("IfcDoor", "IfcDoorStandardCase"): row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - row.prop(data=cls.props, property="rl1", text="Relative Level (rl1)" if ui_context != "TOOL_HEADER" else "RL") + row.prop( + data=cls.props, property="rl1", text="Relative Level (rl1)" if ui_context != "TOOL_HEADER" else "RL" + ) @classmethod def draw_operations(cls, context): @@ -549,19 +576,27 @@ class EditObjectUI: row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row add_layout_hotkey_operator(row, "Extend", "S_E", "Extends/reduces element to 3D cursor", ui_context) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - add_layout_hotkey_operator(row, "Butt", "S_T", "Intersects two non-parallel elements to a butt corner junction", ui_context) + add_layout_hotkey_operator( + row, "Butt", "S_T", "Intersects two non-parallel elements to a butt corner junction", ui_context + ) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - add_layout_hotkey_operator(row, "Mitre", "S_Y", "Intersects two non-parallel elements to a mitred corner junction", ui_context) + add_layout_hotkey_operator( + row, "Mitre", "S_Y", "Intersects two non-parallel elements to a mitred corner junction", ui_context + ) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row add_layout_hotkey_operator(row, "Unjoin Walls", "S_U", "", ui_context) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row add_layout_hotkey_operator(row, "Merge", "S_M", "Merge selected Elements", ui_context) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - add_layout_hotkey_operator(row, "Split", "S_K", "Split selected Element into two Elements at the cursor location", ui_context) + add_layout_hotkey_operator( + row, "Split", "S_K", "Split selected Element into two Elements at the cursor location", ui_context + ) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row add_layout_hotkey_operator(row, "Rotate 90", "S_R", "Rotate the selected Element by 90 degrees", ui_context) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - add_layout_hotkey_operator(row, "Flip", "S_F", "Flip Element about its local axes, keep the position", ui_context) + add_layout_hotkey_operator( + row, "Flip", "S_F", "Flip Element about its local axes, keep the position", ui_context + ) elif AuthoringData.data["active_material_usage"] == "LAYER3": if "LAYER2" in AuthoringData.data["selected_material_usages"]: @@ -575,35 +610,56 @@ class EditObjectUI: add_layout_hotkey_operator(row, "Flip", "S_F", bpy.ops.bim.flip_object.__doc__, ui_context) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - if AuthoringData.data["active_class"] in ("IfcCableCarrierSegment","IfcCableSegment","IfcDuctSegment","IfcPipeSegment"): + if AuthoringData.data["active_class"] in ( + "IfcCableCarrierSegment", + "IfcCableSegment", + "IfcDuctSegment", + "IfcPipeSegment", + ): add_layout_hotkey_operator(row, "Add Fitting", "S_Y", "", ui_context) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - row.operator("bim.mep_add_bend", text="Add Bend" if ui_context != "TOOL_HEADER" else "", icon_value=custom_icon_previews["ADD_BEND"].icon_id) + row.operator( + "bim.mep_add_bend", + text="Add Bend" if ui_context != "TOOL_HEADER" else "", + icon_value=custom_icon_previews["ADD_BEND"].icon_id, + ) row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row - + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - row.operator("bim.mep_add_transition", text="Add Transition" if ui_context != "TOOL_HEADER" else "", icon_value=custom_icon_previews["ADD_TRANSITION"].icon_id) + row.operator( + "bim.mep_add_transition", + text="Add Transition" if ui_context != "TOOL_HEADER" else "", + icon_value=custom_icon_previews["ADD_TRANSITION"].icon_id, + ) row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row - + row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - row.operator("bim.mep_add_obstruction", text="Add Obstruction" if ui_context != "TOOL_HEADER" else "", icon_value=custom_icon_previews["IFC"].icon_id) + row.operator( + "bim.mep_add_obstruction", + text="Add Obstruction" if ui_context != "TOOL_HEADER" else "", + icon_value=custom_icon_previews["IFC"].icon_id, + ) row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row else: - add_layout_hotkey_operator( row, "Edit Axis", "A_E", "", ui_context) + add_layout_hotkey_operator(row, "Edit Axis", "A_E", "", ui_context) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row add_layout_hotkey_operator(row, "Butt", "S_T", "", ui_context) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row add_layout_hotkey_operator(row, "Mitre", "S_Y", "", ui_context) row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row add_layout_hotkey_operator(row, "Rotate 90", "S_R", bpy.ops.bim.rotate_90.__doc__, ui_context) - + if PortData.data["total_ports"] > 0: row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - row.operator("bim.mep_connect_elements", text="Connect MEP Elements" if ui_context != "TOOL_HEADER" else "", icon_value=custom_icon_previews["CONNECT_MEP_ELEMENTS"].icon_id) + row.operator( + "bim.mep_connect_elements", + text="Connect MEP Elements" if ui_context != "TOOL_HEADER" else "", + icon_value=custom_icon_previews["CONNECT_MEP_ELEMENTS"].icon_id, + ) row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row row.label(text="", icon="BLANK1") if ui_context != "TOOL_HEADER" else row @@ -612,14 +668,19 @@ class EditObjectUI: @classmethod def draw_regen_operations(cls, row): custom_icon = custom_icon_previews.get("REGEN", custom_icon_previews["IFC"]).icon_id - + if AuthoringData.data["active_material_usage"] == "LAYER2": op = row.operator("bim.hotkey", text="", icon_value=custom_icon) description = f"{bpy.ops.bim.recalculate_wall.__doc__}\n\nHotkey: S G" op.hotkey = "S_G" op.description = description.strip() elif AuthoringData.data["active_material_usage"] == "PROFILE": - if AuthoringData.data["active_class"] in ("IfcCableCarrierSegment","IfcCableSegment","IfcDuctSegment","IfcPipeSegment"): + if AuthoringData.data["active_class"] in ( + "IfcCableCarrierSegment", + "IfcCableSegment", + "IfcDuctSegment", + "IfcPipeSegment", + ): pass else: op = row.operator("bim.hotkey", text="", icon_value=custom_icon) @@ -636,7 +697,7 @@ class EditObjectUI: @classmethod def draw_void(cls, context, row): ui_context = str(context.region.type) - + if len(context.selected_objects) > 1: op_text = "Apply Void" if ui_context != "TOOL_HEADER" else "" op_icon = custom_icon_previews["APPLY_VOID"].icon_id @@ -656,7 +717,7 @@ class EditObjectUI: row = cls.layout.row(align=True) row.operator("bim.edit_openings", icon="CHECKMARK", text="") row.operator("bim.hide_openings", icon="CANCEL", text="") - + if AuthoringData.data["active_class"] in ("IfcOpeningElement",): row = cls.layout.row(align=True) row.operator("bim.edit_openings", icon="CHECKMARK", text="") @@ -701,7 +762,9 @@ class EditObjectUI: row.separator() row.label(text="Quantity Take-off") if ui_context != "TOOL_HEADER" else row row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - add_layout_hotkey_operator(row, "Perform Quantity Take-off", "S_Q", bpy.ops.bim.perform_quantity_take_off.__doc__, ui_context) + add_layout_hotkey_operator( + row, "Perform Quantity Take-off", "S_Q", bpy.ops.bim.perform_quantity_take_off.__doc__, ui_context + ) @classmethod def draw_modes(cls, context): @@ -709,14 +772,20 @@ class EditObjectUI: row = cls.layout.row(align=True) row.separator() row.label(text="Mode") if ui_context != "TOOL_HEADER" else row - + if AuthoringData.data["active_material_usage"] == "LAYER3": if len(context.selected_objects) == 1: row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row add_layout_hotkey_operator(row, "Edit Profile", "S_E", "", ui_context) - elif (tool.Model.is_parametric_railing_active() and not context.active_object.BIMRailingProperties.is_editing_path): + elif ( + tool.Model.is_parametric_railing_active() and not context.active_object.BIMRailingProperties.is_editing_path + ): row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row - row.operator("bim.enable_editing_railing_path", text="Edit Path" if ui_context != "TOOL_HEADER" else "", icon_value=custom_icon_previews["EDIT_RAILING_PATH"].icon_id) + row.operator( + "bim.enable_editing_railing_path", + text="Edit Path" if ui_context != "TOOL_HEADER" else "", + icon_value=custom_icon_previews["EDIT_RAILING_PATH"].icon_id, + ) elif AuthoringData.data["active_material_usage"] == "PROFILE": row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row add_layout_hotkey_operator(row, "Edit Axis", "A_E", "", ui_context) @@ -1025,7 +1094,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): if AuthoringData.data["active_class"] in ("IfcOpeningElement",): if len(bpy.context.selected_objects) == 2: bpy.ops.bim.clone_opening() - + def hotkey_S_U(self): if not bpy.context.selected_objects: return diff --git a/src/bonsai/bonsai/tool/web.py b/src/bonsai/bonsai/tool/web.py index 53e7763ffd..9ba769c938 100644 --- a/src/bonsai/bonsai/tool/web.py +++ b/src/bonsai/bonsai/tool/web.py @@ -348,9 +348,9 @@ class Web(bonsai.core.tool.Web): ifc_file = tool.Ifc.get() if operator_data["type"] == "getPredefinedTypes": cls.send_webui_data( - data=ifcopenshell.util.cost.get_cost_schedule_types(ifc_file), - data_key="predefined_types", - event="predefined_types" + data=ifcopenshell.util.cost.get_cost_schedule_types(ifc_file), + data_key="predefined_types", + event="predefined_types", ) if operator_data["type"] == "addCostSchedule": bonsai.core.cost.add_cost_schedule( @@ -385,7 +385,7 @@ class Web(bonsai.core.tool.Web): if operator_data["type"] == "addCostItem": if not operator_data["costItemId"]: return - cost_item=tool.Ifc.get().by_id(operator_data["costItemId"]) + cost_item = tool.Ifc.get().by_id(operator_data["costItemId"]) tool.Ifc.run("cost.add_cost_item", cost_item=cost_item) cost_schedule = tool.Cost.get_cost_schedule(cost_item=cost_item) cls.load_cost_schedule_web_ui(cost_schedule) @@ -454,7 +454,13 @@ class Web(bonsai.core.tool.Web): prop_name = operator_data["propName"] if prop_name == "count": prop_name = "" - bonsai.core.cost.assign_cost_item_quantity(tool.Ifc, tool.Cost, cost_item=ifc_file.by_id(operator_data["costItemId"]), related_object_type="PRODUCT", prop_name=prop_name) + bonsai.core.cost.assign_cost_item_quantity( + tool.Ifc, + tool.Cost, + cost_item=ifc_file.by_id(operator_data["costItemId"]), + related_object_type="PRODUCT", + prop_name=prop_name, + ) cost_schedule = tool.Cost.get_cost_schedule(cost_item=tool.Ifc.get().by_id(operator_data["costItemId"])) cls.load_cost_schedule_web_ui(cost_schedule) if operator_data["type"] == "enableEditingQuantities": @@ -473,7 +479,11 @@ class Web(bonsai.core.tool.Web): cost_item = ifc_file.by_id(cost_item_id) cost_schedule = tool.Cost.get_cost_schedule(cost_item) physical_quantity = tool.Ifc.get().by_id(operator_data["quantityId"]) - tool.Ifc.run("cost.edit_cost_item_quantity", physical_quantity=physical_quantity, attributes=operator_data["attributes"]) + tool.Ifc.run( + "cost.edit_cost_item_quantity", + physical_quantity=physical_quantity, + attributes=operator_data["attributes"], + ) cls.load_cost_schedule_web_ui(cost_schedule) cls.load_cost_item_quantities_ui(cost_item) if operator_data["type"] == "deleteCostItemQuantity": @@ -485,7 +495,7 @@ class Web(bonsai.core.tool.Web): cls.load_cost_item_quantities_ui(cost_item) @classmethod - def load_cost_item_quantities_ui(cls, cost_item : ifcopenshell.entity_instance) -> None: + def load_cost_item_quantities_ui(cls, cost_item: ifcopenshell.entity_instance) -> None: if not cost_item: return selected_products = list(tool.Spatial.get_selected_products()) @@ -508,7 +518,7 @@ class Web(bonsai.core.tool.Web): ) @classmethod - def selection_data(cls, cost_item : ifcopenshell.entity_instance, elements : list) -> list: + def selection_data(cls, cost_item: ifcopenshell.entity_instance, elements: list) -> list: if not elements: return [] if not cost_item: @@ -554,7 +564,7 @@ class Web(bonsai.core.tool.Web): return data @classmethod - def load_cost_schedule_web_ui(cls, cost_schedule :ifcopenshell.entity_instance) -> None: + def load_cost_schedule_web_ui(cls, cost_schedule: ifcopenshell.entity_instance) -> None: ifc2json = ifc5D2json() ifc2json.file_path = tool.Ifc.get() ifc2json.cost_schedule = cost_schedule diff --git a/src/ifc5d/ifc5d/ifc2json.py b/src/ifc5d/ifc5d/ifc2json.py index be6320597a..a94927f408 100644 --- a/src/ifc5d/ifc5d/ifc2json.py +++ b/src/ifc5d/ifc5d/ifc2json.py @@ -6,6 +6,7 @@ import ifcopenshell.util.date CostItem = dict[str, Any] + class ifc5D2json: def __init__(self): self.json: str = None @@ -15,7 +16,7 @@ class ifc5D2json: self.units: dict[str, ifcopenshell.entity_instance] = {} self._cost_values = {} self.data: list[dict[str, Any]] = [] - + def convert_ifc_to_json(self): self.data = [] if not isinstance(self.file_path, str): @@ -46,8 +47,8 @@ class ifc5D2json: for cost_item in rel.RelatedObjects: self.extract_cost_item_data(cost_item, schedule_data) return schedule_data - - def extract_cost_item_data(self , cost_item: ifcopenshell.entity_instance, json_data): + + def extract_cost_item_data(self, cost_item: ifcopenshell.entity_instance, json_data): data = {} self.extract_cost_item_quantities(cost_item, data) self.populate_cost_values(cost_item, data) @@ -157,4 +158,4 @@ class ifc5D2json: .name() ) if "Count" in measure_class: - data["UnitSymbol"] = "U" \ No newline at end of file + data["UnitSymbol"] = "U"