diff --git a/src/bonsai/bonsai/bim/__init__.py b/src/bonsai/bonsai/bim/__init__.py index 7d0672e55d..6b1bc27457 100644 --- a/src/bonsai/bonsai/bim/__init__.py +++ b/src/bonsai/bonsai/bim/__init__.py @@ -215,7 +215,6 @@ classes = [ ui.BIM_PT_section_with_cappings, ui.BIM_PT_decorators_overlay, ui.BIM_PT_snappping, - ] for mod in modules.values(): @@ -238,6 +237,7 @@ def on_register(scene): bpy.app.handlers.depsgraph_update_post.remove(on_register) is_registering = False + def register_panel_visibility_properties(): for panel_list in ui.TAB_PANELS.values(): for panel in panel_list: @@ -404,4 +404,4 @@ def unregister(): del bpy.types.Scene.active_tab_name del bpy.types.Scene.tab_panels del bpy.types.Scene.active_tab_panel_index - unregister_panel_visibility_properties() \ No newline at end of file + unregister_panel_visibility_properties() diff --git a/src/bonsai/bonsai/bim/operator.py b/src/bonsai/bonsai/bim/operator.py index f497f241a4..2d6f7b9340 100644 --- a/src/bonsai/bonsai/bim/operator.py +++ b/src/bonsai/bonsai/bim/operator.py @@ -1627,8 +1627,10 @@ class BIM_UL_tab_panels(bpy.types.UIList): icon="SOLO_ON" if item.get("bookmarked", False) else "SOLO_OFF", ).action = f"BOOKMARK_{item.name}" + class BIM_OT_toggle_panel_visibility(bpy.types.Operator): """Toggle Panel Visibility""" + bl_idname = "bim.toggle_panel_visibility" bl_label = "Toggle Panel Visibility" bl_options = {"REGISTER", "UNDO"} @@ -1657,8 +1659,10 @@ class BIM_OT_toggle_panel_visibility(bpy.types.Operator): self.report({"INFO"}, f"Toggled visibility for {panel_name}.") return {"FINISHED"} + class BIM_OT_bookmark_panel(bpy.types.Operator): """Bookmark Panel""" + bl_idname = "bim.bookmark_panel" bl_label = "Bookmark Panel" bl_options = {"REGISTER", "UNDO"} @@ -1675,7 +1679,9 @@ class BIM_OT_bookmark_panel(bpy.types.Operator): prop_name = f"bookmark_{panel_name.lower()}" if hasattr(context.scene, prop_name): setattr(context.scene, prop_name, item["bookmarked"]) - print(f"Toggled bookmark for panel: {panel_name} to {'bookmarked' if item['bookmarked'] else 'Not bookmarked'}") + print( + f"Toggled bookmark for panel: {panel_name} to {'bookmarked' if item['bookmarked'] else 'Not bookmarked'}" + ) else: print(f"Property '{prop_name}' not found on Scene.") @@ -1701,10 +1707,11 @@ class BIM_OT_bookmark_panel(bpy.types.Operator): self.report({"INFO"}, f"Toggled bookmark for {panel_name}.") return {"FINISHED"} - + class BIM_OT_manage_tab_panels(bpy.types.Operator): """Manage Tab Panels""" + bl_idname = "bim.manage_tab_panels" bl_label = "Manage Tab Panels" bl_options = {"REGISTER", "UNDO"} @@ -1716,8 +1723,8 @@ class BIM_OT_manage_tab_panels(bpy.types.Operator): context.scene.tab_panels.clear() for panel_data in TAB_PANELS.get(self.tab_name, []): - panel_name = panel_data.get("bl_idname","") - panel_label = panel_data.get("bl_label","") + panel_name = panel_data.get("bl_idname", "") + panel_label = panel_data.get("bl_label", "") if not panel_name or not panel_label: continue item = context.scene.tab_panels.add() @@ -1752,8 +1759,10 @@ class BIM_OT_manage_tab_panels(bpy.types.Operator): self.report({"INFO"}, f"Panels for {self.tab_name} managed successfully.") return {"FINISHED"} + class BIM_OT_manage_tab_visibility(bpy.types.Operator): """Manage Tab Visibility""" + bl_idname = "bim.manage_tab_visibility" bl_label = "Manage Tab Visibility" bl_options = {"REGISTER", "UNDO"} @@ -1762,15 +1771,15 @@ class BIM_OT_manage_tab_visibility(bpy.types.Operator): layout = self.layout row = layout.row() row = self.layout.row(align=True) - row.alignment = 'RIGHT' + row.alignment = "RIGHT" row.operator("bim.reset_ui_layout", icon="FILE_REFRESH", text="") row.operator("bim.load_json_layout", icon="IMPORT", text="") row.operator("bim.save_json_layout", icon="EXPORT", text="") row = layout.row() row = self.layout.row(align=True) - row.alignment = 'CENTER' - + row.alignment = "CENTER" + for tab_name, is_visible in TAB_VISIBILITY.items(): row = layout.row() row.label(text=tab_name) @@ -1784,8 +1793,10 @@ class BIM_OT_manage_tab_visibility(bpy.types.Operator): def invoke(self, context, event): return context.window_manager.invoke_popup(self) + class BIM_OT_toggle_tab_visibility(bpy.types.Operator): """Toggle Tab Visibility""" + bl_idname = "bim.toggle_tab_visibility" bl_label = "Toggle Tab Visibility" bl_options = {"REGISTER", "UNDO"} @@ -1795,7 +1806,7 @@ class BIM_OT_toggle_tab_visibility(bpy.types.Operator): def execute(self, context): if self.tab_name in TAB_VISIBILITY: TAB_VISIBILITY[self.tab_name] = not TAB_VISIBILITY[self.tab_name] - + for area in bpy.context.window.screen.areas: if area.type == "PROPERTIES": area.tag_redraw() @@ -1803,11 +1814,14 @@ class BIM_OT_toggle_tab_visibility(bpy.types.Operator): self.report({"INFO"}, f"Toggled visibility for {self.tab_name}.") return {"FINISHED"} + import json import bpy + class BIM_OT_load_json_layout(bpy.types.Operator): """Load JSON Layout""" + bl_idname = "bim.load_json_layout" bl_label = "Load UI Layout" bl_options = {"REGISTER", "UNDO"} @@ -1844,7 +1858,7 @@ class BIM_OT_load_json_layout(bpy.types.Operator): return {"FINISHED"} def invoke(self, context, event): - ifc_file_path = bpy.context.scene.BIMProperties['ifc_file'] + ifc_file_path = bpy.context.scene.BIMProperties["ifc_file"] if not ifc_file_path: self.report({"ERROR"}, "No IFC file is associated with the project.") return {"CANCELLED"} @@ -1853,8 +1867,10 @@ class BIM_OT_load_json_layout(bpy.types.Operator): context.window_manager.fileselect_add(self) return {"RUNNING_MODAL"} + class BIM_OT_save_json_layout(bpy.types.Operator): """Save JSON Layout""" + bl_idname = "bim.save_json_layout" bl_label = "Save UI Layout" bl_options = {"REGISTER", "UNDO"} @@ -1863,7 +1879,7 @@ class BIM_OT_save_json_layout(bpy.types.Operator): def execute(self, context): try: - ifc_file_path = bpy.context.scene.BIMProperties['ifc_file'] + ifc_file_path = bpy.context.scene.BIMProperties["ifc_file"] if not ifc_file_path: self.report({"ERROR"}, "No IFC file is associated with the project.") return {"CANCELLED"} @@ -1883,7 +1899,9 @@ class BIM_OT_save_json_layout(bpy.types.Operator): show_prop_name = f"show_{panel_name.lower()}" bookmark_prop_name = f"bookmark_{panel_name.lower()}" layout_data["scene_properties"][show_prop_name] = getattr(context.scene, show_prop_name, True) - layout_data["scene_properties"][bookmark_prop_name] = getattr(context.scene, bookmark_prop_name, False) + layout_data["scene_properties"][bookmark_prop_name] = getattr( + context.scene, bookmark_prop_name, False + ) with open(self.filepath, "w") as file: json.dump(layout_data, file, indent=4) @@ -1895,7 +1913,7 @@ class BIM_OT_save_json_layout(bpy.types.Operator): return {"FINISHED"} def invoke(self, context, event): - ifc_file_path = bpy.context.scene.BIMProperties['ifc_file'] + ifc_file_path = bpy.context.scene.BIMProperties["ifc_file"] if not ifc_file_path: self.report({"ERROR"}, "No IFC file is associated with the project.") return {"CANCELLED"} @@ -1904,8 +1922,10 @@ class BIM_OT_save_json_layout(bpy.types.Operator): context.window_manager.fileselect_add(self) return {"RUNNING_MODAL"} + class BIM_OT_reset_ui_layout(bpy.types.Operator): """Reset UI Layout to Default""" + bl_idname = "bim.reset_ui_layout" bl_label = "Reset UI Layout" bl_options = {"REGISTER", "UNDO"} @@ -1937,4 +1957,4 @@ class BIM_OT_reset_ui_layout(bpy.types.Operator): area.tag_redraw() self.report({"INFO"}, "UI layout reset to default.") - return {"FINISHED"} \ No newline at end of file + return {"FINISHED"} diff --git a/src/bonsai/bonsai/bim/ui.py b/src/bonsai/bonsai/bim/ui.py index 1aa2c737b5..f89c64c45d 100644 --- a/src/bonsai/bonsai/bim/ui.py +++ b/src/bonsai/bonsai/bim/ui.py @@ -64,67 +64,59 @@ if TYPE_CHECKING: TAB_PANELS = { "PROJECT": [ -# "BIM_PT_tab_new_project_wizard", - {"bl_idname":"BIM_PT_tab_project_info", "bl_label":"Project Info"}, - {"bl_idname":"BIM_PT_tab_spatial", "bl_label":"Spatial"}, - {"bl_idname":"BIM_PT_tab_project_setup", "bl_label":"Project Setup"}, - {"bl_idname":"BIM_PT_tab_geometry", "bl_label":"Geometry"}, - {"bl_idname":"BIM_PT_tab_stakeholders", "bl_label":"Stakeholders"}, - {"bl_idname":"BIM_PT_tab_grouping_and_filtering", "bl_label":"Grouping and Filtering"}, + # "BIM_PT_tab_new_project_wizard", + {"bl_idname": "BIM_PT_tab_project_info", "bl_label": "Project Info"}, + {"bl_idname": "BIM_PT_tab_spatial", "bl_label": "Spatial"}, + {"bl_idname": "BIM_PT_tab_project_setup", "bl_label": "Project Setup"}, + {"bl_idname": "BIM_PT_tab_geometry", "bl_label": "Geometry"}, + {"bl_idname": "BIM_PT_tab_stakeholders", "bl_label": "Stakeholders"}, + {"bl_idname": "BIM_PT_tab_grouping_and_filtering", "bl_label": "Grouping and Filtering"}, ], "OBJECT": [ - {"bl_idname":"BIM_PT_tab_object_metadata", "bl_label":"Object Metadata"}, - {"bl_idname":"BIM_PT_tab_misc", "bl_label":"Misc"}, - + {"bl_idname": "BIM_PT_tab_object_metadata", "bl_label": "Object Metadata"}, + {"bl_idname": "BIM_PT_tab_misc", "bl_label": "Misc"}, ], "GEOMETRY": [ - {"bl_idname":"BIM_PT_tab_placement", "bl_label":"Placement"}, - {"bl_idname":"BIM_PT_tab_representations", "bl_label":"Representations"}, - {"bl_idname":"BIM_PT_tab_geometric_relationships", "bl_label":"Geometric Relationships"}, - {"bl_idname":"BIM_PT_tab_parametric_geometry", "bl_label":"Parametric Geometry"}, - {"bl_idname":"BIM_PT_tab_object_materials", "bl_label":"Object Materials"}, - {"bl_idname":"BIM_PT_tab_materials", "bl_label":"Materials"}, - {"bl_idname":"BIM_PT_tab_styles", "bl_label":"Styles"}, - {"bl_idname":"BIM_PT_tab_profiles", "bl_label":"Profiles"}, - + {"bl_idname": "BIM_PT_tab_placement", "bl_label": "Placement"}, + {"bl_idname": "BIM_PT_tab_representations", "bl_label": "Representations"}, + {"bl_idname": "BIM_PT_tab_geometric_relationships", "bl_label": "Geometric Relationships"}, + {"bl_idname": "BIM_PT_tab_parametric_geometry", "bl_label": "Parametric Geometry"}, + {"bl_idname": "BIM_PT_tab_object_materials", "bl_label": "Object Materials"}, + {"bl_idname": "BIM_PT_tab_materials", "bl_label": "Materials"}, + {"bl_idname": "BIM_PT_tab_styles", "bl_label": "Styles"}, + {"bl_idname": "BIM_PT_tab_profiles", "bl_label": "Profiles"}, ], "DRAWINGS": [ - {"bl_idname":"BIM_PT_tab_sheets", "bl_label":"Sheets"}, - {"bl_idname":"BIM_PT_tab_drawings", "bl_label":"Drawings"}, - {"bl_idname":"BIM_PT_tab_schedules", "bl_label":"Schedules"}, - {"bl_idname":"BIM_PT_tab_references", "bl_label":"References"}, - + {"bl_idname": "BIM_PT_tab_sheets", "bl_label": "Sheets"}, + {"bl_idname": "BIM_PT_tab_drawings", "bl_label": "Drawings"}, + {"bl_idname": "BIM_PT_tab_schedules", "bl_label": "Schedules"}, + {"bl_idname": "BIM_PT_tab_references", "bl_label": "References"}, ], "SERVICES": [ - {"bl_idname":"BIM_PT_tab_services", "bl_label":"Services"}, - {"bl_idname":"BIM_PT_tab_zones", "bl_label":"Zones"}, - {"bl_idname":"BIM_PT_tab_solar_analysis", "bl_label":"Solar Analysis"}, - {"bl_idname":"BIM_PT_tab_lighting", "bl_label":"Lighting"}, - + {"bl_idname": "BIM_PT_tab_services", "bl_label": "Services"}, + {"bl_idname": "BIM_PT_tab_zones", "bl_label": "Zones"}, + {"bl_idname": "BIM_PT_tab_solar_analysis", "bl_label": "Solar Analysis"}, + {"bl_idname": "BIM_PT_tab_lighting", "bl_label": "Lighting"}, ], "STRUCTURE": [ - {"bl_idname":"BIM_PT_tab_structural", "bl_label":"Structural"}, - + {"bl_idname": "BIM_PT_tab_structural", "bl_label": "Structural"}, ], "SCHEDULING": [ - {"bl_idname":"BIM_PT_tab_status", "bl_label":"Status"}, - {"bl_idname":"BIM_PT_tab_qto", "bl_label":"Quantity Take-off"}, - {"bl_idname":"BIM_PT_tab_resources", "bl_label":"Resources"}, - {"bl_idname":"BIM_PT_tab_cost", "bl_label":"Cost"}, - {"bl_idname":"BIM_PT_tab_sequence", "bl_label":"Construction Scheduling"}, - + {"bl_idname": "BIM_PT_tab_status", "bl_label": "Status"}, + {"bl_idname": "BIM_PT_tab_qto", "bl_label": "Quantity Take-off"}, + {"bl_idname": "BIM_PT_tab_resources", "bl_label": "Resources"}, + {"bl_idname": "BIM_PT_tab_cost", "bl_label": "Cost"}, + {"bl_idname": "BIM_PT_tab_sequence", "bl_label": "Construction Scheduling"}, ], "FM": [ - {"bl_idname":"BIM_PT_tab_handover", "bl_label":"Handover"}, - {"bl_idname":"BIM_PT_tab_operations", "bl_label":"Operations"}, - + {"bl_idname": "BIM_PT_tab_handover", "bl_label": "Handover"}, + {"bl_idname": "BIM_PT_tab_operations", "bl_label": "Operations"}, ], "QUALITY": [ - {"bl_idname":"BIM_PT_tab_quality_control", "bl_label":"Quality Control"}, - {"bl_idname":"BIM_PT_tab_clash_detection", "bl_label":"Clash Detection"}, - {"bl_idname":"BIM_PT_tab_collaboration", "bl_label":"Collaboration"}, - {"bl_idname":"BIM_PT_tab_sandbox", "bl_label":"Sandbox"}, - + {"bl_idname": "BIM_PT_tab_quality_control", "bl_label": "Quality Control"}, + {"bl_idname": "BIM_PT_tab_clash_detection", "bl_label": "Clash Detection"}, + {"bl_idname": "BIM_PT_tab_collaboration", "bl_label": "Collaboration"}, + {"bl_idname": "BIM_PT_tab_sandbox", "bl_label": "Sandbox"}, ], "BOOKMARK": [ {}, @@ -147,10 +139,22 @@ TAB_VISIBILITY = { def get_tab_name(bl_idname): - return next((k for k, v in reversed(list(TAB_PANELS.items())) if any(d.get("bl_idname") == bl_idname for d in v)), "BOOKMARK") + return next( + (k for k, v in reversed(list(TAB_PANELS.items())) if any(d.get("bl_idname") == bl_idname for d in v)), + "BOOKMARK", + ) + def get_bl_label(bl_idname): - return next((panel["bl_label"] for panels in TAB_PANELS.values() for panel in panels if isinstance(panel, dict) and panel.get("bl_idname") == bl_idname), "NO LABEL") + return next( + ( + panel["bl_label"] + for panels in TAB_PANELS.values() + for panel in panels + if isinstance(panel, dict) and panel.get("bl_idname") == bl_idname + ), + "NO LABEL", + ) class IFCFileSelector: @@ -1053,7 +1057,7 @@ class BIM_PT_tabs(Panel): ).tab = "PROJECT" if TAB_VISIBILITY["OBJECT"]: self.draw_tab_entry(row_left, "FILE_3D", "OBJECT", is_ifc_project, aprops.tab == "OBJECT") - if TAB_VISIBILITY["GEOMETRY"]: + if TAB_VISIBILITY["GEOMETRY"]: self.draw_tab_entry(row_left, "MATERIAL", "GEOMETRY", is_ifc_project, aprops.tab == "GEOMETRY") if TAB_VISIBILITY["DRAWINGS"]: self.draw_tab_entry(row_left, "DOCUMENTS", "DRAWINGS", is_ifc_project, aprops.tab == "DRAWINGS") @@ -1082,20 +1086,14 @@ class BIM_PT_tabs(Panel): row_left.prop(aprops, "active_tab", text="", icon="BLANK1") else: row_left.prop(aprops, "inactive_tab", text="", icon="BLANK1", emboss=False) - row_left.prop(aprops, "inactive_tab", text="", icon="BLANK1", emboss=False) #space for Switch - + row_left.prop(aprops, "inactive_tab", text="", icon="BLANK1", emboss=False) # space for Switch col_right = split.column(align=True) row_right = col_right.row(align=True) - row_right.alignment = 'RIGHT' + row_right.alignment = "RIGHT" row_right.operator("bim.manage_tab_visibility", icon="PREFERENCES", text="") - - - - - row = self.layout.row(align=True) row.prop(aprops, "tab", text="") @@ -1105,8 +1103,6 @@ class BIM_PT_tabs(Panel): if aprops.tab == tab: row.operator("bim.manage_tab_panels", text="", icon="PREFERENCES").tab_name = tab - - if bonsai.REINSTALLED_BBIM_VERSION: box = self.layout.box() box.alert = True @@ -1218,8 +1214,8 @@ class BIM_PT_tab_project_info(Panel): return False if getattr(context.scene, prop_bookmark, False): return tool.Blender.is_tab(context, "BOOKMARK") - if not tool.Blender.is_tab(context, get_tab_name(cls.bl_idname)): - + if not tool.Blender.is_tab(context, get_tab_name(cls.bl_idname)): + return False bim_props = tool.Blender.get_bim_props() pprops = tool.Project.get_project_props() @@ -1738,7 +1734,7 @@ class BIM_PT_tab_placement(Panel): return False if getattr(context.scene, prop_bookmark, False): return tool.Blender.is_tab(context, "BOOKMARK") - + return ( tool.Blender.is_tab(context, get_tab_name(cls.bl_idname)) and tool.Ifc.get()