diff --git a/src/bonsai/bonsai/bim/module/covering/workspace.py b/src/bonsai/bonsai/bim/module/covering/workspace.py index 383a2322d9..c24f478408 100644 --- a/src/bonsai/bonsai/bim/module/covering/workspace.py +++ b/src/bonsai/bonsai/bim/module/covering/workspace.py @@ -136,8 +136,8 @@ class CoveringToolUI: if AuthoringData.data["ifc_classes"]: if cls.props.ifc_class: box = cls.layout.box() - if AuthoringData.data["type_thumbnail"]: - box.template_icon(icon_value=AuthoringData.data["type_thumbnail"], scale=5) + if thumbnail := AuthoringData.data["relating_type_data"].get("thumbnail"): + box.template_icon(icon_value=thumbnail, scale=5) else: op = box.operator("bim.load_type_thumbnails", text="Load Thumbnails", icon="FILE_REFRESH") op.ifc_class = cls.props.ifc_class @@ -175,14 +175,14 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): element = tool.Ifc.get_entity(active_obj) container = tool.Root.get_default_container() - if AuthoringData.data["predefined_type"] == "FLOORING": + if AuthoringData.data["relating_type_data"].get("predefined_type") == "FLOORING": if element and bpy.context.selected_objects and element.is_a("IfcWall"): bpy.ops.bim.add_instance_flooring_coverings_from_walls() elif container: bpy.ops.bim.add_instance_flooring_covering_from_cursor() else: bpy.ops.bim.add_constr_type_instance() - elif AuthoringData.data["predefined_type"] == "CEILING": + elif AuthoringData.data["relating_type_data"].get("predefined_type") == "CEILING": if element and bpy.context.selected_objects and element.is_a("IfcWall"): bpy.ops.bim.add_instance_ceiling_coverings_from_walls() elif container: diff --git a/src/bonsai/bonsai/bim/module/model/data.py b/src/bonsai/bonsai/bim/module/model/data.py index 5cc0f64699..937c586343 100644 --- a/src/bonsai/bonsai/bim/module/model/data.py +++ b/src/bonsai/bonsai/bim/module/model/data.py @@ -26,7 +26,7 @@ from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc import bonsai.tool as tool from math import degrees from natsort import natsorted -from typing import Union, Optional +from typing import Union, Optional, Any def refresh(): @@ -43,7 +43,7 @@ def refresh(): class AuthoringData: data = {} - type_thumbnails = {} + type_thumbnails: dict[int, int] = {} types_per_page = 9 is_loaded = False @@ -58,13 +58,10 @@ class AuthoringData: # Make sure .ifc_classes() was run before next lines cls.data["type_elements"] = cls.type_elements() cls.data["type_elements_filtered"] = cls.type_elements_filtered() + # After .type_elements(). cls.data["relating_type_id"] = cls.relating_type_id() # Make sure .relating_type_id() was run before next lines - cls.data["relating_type_id_current"] = cls.relating_type_id_current() - cls.data["relating_type_name"] = cls.relating_type_name() - cls.data["relating_type_description"] = cls.relating_type_description() - cls.data["relating_type_material_usage"] = cls.relating_type_material_usage() - cls.data["predefined_type"] = cls.predefined_type() + cls.data["relating_type_data"] = cls.relating_type_data() # Make sure .type_elements_filtered() was run before next lines cls.data["total_types"] = cls.total_types() cls.data["total_pages"] = cls.total_pages() # Only after .total_types() @@ -72,7 +69,6 @@ class AuthoringData: cls.data["prev_page"] = cls.prev_page() cls.data["paginated_relating_types"] = cls.paginated_relating_types() - cls.data["type_thumbnail"] = cls.type_thumbnail() # Only after .relating_type_id_current() cls.data["materials"] = cls.materials() cls.data["is_voidable_element"] = cls.is_voidable_element() cls.data["has_visible_openings"] = cls.has_visible_openings() @@ -109,10 +105,6 @@ class AuthoringData: version = tool.Ifc.get_schema() return [(c, c, get_entity_doc(version, c).get("description", "")) for c in sorted(names)] - @classmethod - def type_thumbnail(cls): - return cls.type_thumbnails.get(int(cls.data["relating_type_id_current"] or 0), 0) - @classmethod def materials(cls): results = [("0", "None", "No material")] @@ -150,7 +142,7 @@ class AuthoringData: def type_elements_filtered(cls): search_query = cls.props.search_name.lower() - def filter_element(element): + def filter_element(element: ifcopenshell.entity_instance) -> bool: if search_query in (element.Name or "Unnamed").lower(): return True if search_query in (element.Description or "").lower(): @@ -170,21 +162,24 @@ class AuthoringData: elements = cls.data["type_elements_filtered"] elements = elements[(cls.props.type_page - 1) * cls.types_per_page : cls.props.type_page * cls.types_per_page] for element in elements: - predefined_type = ifcopenshell.util.element.get_predefined_type(element) - if predefined_type == "NOTDEFINED": - predefined_type = None - results.append( - { - "id": element.id(), - "ifc_class": element.is_a(), - "name": element.Name or "Unnamed", - "description": element.Description or "No Description", - "predefined_type": predefined_type, - "icon_id": cls.type_thumbnails.get(element.id(), None) or 0, - } - ) + results.append(cls.get_type_data(element)) return results + @classmethod + def get_type_data(cls, element: ifcopenshell.entity_instance) -> dict[str, Any]: + predefined_type = ifcopenshell.util.element.get_predefined_type(element) + if predefined_type == "NOTDEFINED": + predefined_type = None + data = { + "id": element.id(), + "ifc_class": element.is_a(), + "name": element.Name or "Unnamed", + "description": element.Description or "No Description", + "predefined_type": predefined_type, + "icon_id": cls.type_thumbnails.get(element.id(), 0), + } + return data + @classmethod def is_voidable_element(cls): if active_object := tool.Blender.get_active_object(): @@ -313,38 +308,16 @@ class AuthoringData: return [(str(e.id()), e.Name or "Unnamed", e.Description or "") for e in elements] @classmethod - def relating_type_id_current(cls): + def relating_type_data(cls) -> dict[str, Any]: relating_type_id = tool.Blender.get_enum_safe(cls.props, "relating_type_id") relating_type_id_data = cls.data["relating_type_id"] - if not relating_type_id and relating_type_id_data: - relating_type_id = relating_type_id_data[0][0] - return relating_type_id - - @classmethod - def relating_type_name(cls): - if relating_type_id := cls.data["relating_type_id_current"]: - return tool.Ifc.get().by_id(int(relating_type_id)).Name or "Unnamed" - - @classmethod - def relating_type_description(cls): - if relating_type_id := cls.data["relating_type_id_current"]: - return tool.Ifc.get().by_id(int(relating_type_id)).Description or "No description" - - @classmethod - def relating_type_material_usage(cls): - if relating_type_id := cls.data["relating_type_id_current"]: - return tool.Model.get_usage_type(tool.Ifc.get().by_id(int(relating_type_id))) - - @classmethod - def predefined_type(cls): - relating_type_id = tool.Blender.get_enum_safe(cls.props, "relating_type_id") if relating_type_id is None: - return - relating_type = tool.Ifc.get().by_id(int(relating_type_id)) - if not hasattr(relating_type, "PredefinedType"): - return - predefined_type = relating_type.PredefinedType - return predefined_type + if not relating_type_id_data: + return {} + relating_type_id = relating_type_id_data[0][0] + ifc_file = tool.Ifc.get() + relating_type = ifc_file.by_id(int(relating_type_id)) + return cls.get_type_data(relating_type) @classmethod def selected_material_usages(cls): diff --git a/src/bonsai/bonsai/bim/module/model/product.py b/src/bonsai/bonsai/bim/module/model/product.py index 4e4ebd731d..c8b9e2548f 100644 --- a/src/bonsai/bonsai/bim/module/model/product.py +++ b/src/bonsai/bonsai/bim/module/model/product.py @@ -646,8 +646,8 @@ class LoadTypeThumbnails(bpy.types.Operator): queue = queue[offset : offset + 9] # The active type may be in another page than the active one : - if relating_type_id_current := AuthoringData.data["relating_type_id_current"]: - active_element = tool.Ifc.get_entity_by_id(int(relating_type_id_current)) + if relating_type_id_current := AuthoringData.data["relating_type_data"].get("id"): + active_element = tool.Ifc.get_entity_by_id(relating_type_id_current) if active_element and active_element not in queue: queue.append(active_element) diff --git a/src/bonsai/bonsai/bim/module/model/prop.py b/src/bonsai/bonsai/bim/module/model/prop.py index c8eca8963f..4a93620693 100644 --- a/src/bonsai/bonsai/bim/module/model/prop.py +++ b/src/bonsai/bonsai/bim/module/model/prop.py @@ -60,7 +60,7 @@ def update_ifc_class(self, context): AuthoringData.data["ifc_class_current"] = self.ifc_class AuthoringData.data["type_elements"] = AuthoringData.type_elements() AuthoringData.data["relating_type_id"] = AuthoringData.relating_type_id() - AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail() + AuthoringData.data["relating_type_data"] = AuthoringData.relating_type_data() if tool.Blender.get_enum_safe(self, "relating_type_id") is None: self["relating_type_id"] = 0 @@ -73,9 +73,7 @@ def update_ifc_class(self, context): def update_relating_type_id(self, context): AuthoringData.data["relating_type_id"] = AuthoringData.relating_type_id() - AuthoringData.data["relating_type_name"] = AuthoringData.relating_type_name() - AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail() - AuthoringData.data["predefined_type"] = AuthoringData.predefined_type() + AuthoringData.data["relating_type_data"] = AuthoringData.relating_type_data() self.type_page = [e[0] for e in AuthoringData.data["relating_type_id"]].index(self.relating_type_id) // 9 + 1 diff --git a/src/bonsai/bonsai/bim/module/model/ui.py b/src/bonsai/bonsai/bim/module/model/ui.py index 297ce5a2d7..3374b0695d 100644 --- a/src/bonsai/bonsai/bim/module/model/ui.py +++ b/src/bonsai/bonsai/bim/module/model/ui.py @@ -166,9 +166,7 @@ class LaunchTypeManager(bpy.types.Operator): row2.operator("bim.set_active_type", text="", emboss=False).relating_type = relating_type["id"] row2.operator("bim.set_active_type", text="", emboss=False).relating_type = relating_type["id"] row2.operator("bim.set_active_type", text="", emboss=False).relating_type = relating_type["id"] - is_current_relating_type = str(relating_type["id"]) == str( - AuthoringData.data["relating_type_id_current"] - ) + is_current_relating_type = relating_type["id"] == AuthoringData.data["relating_type_data"].get("id") if is_current_relating_type: active_row = row2.row() active_row.alignment = "CENTER" diff --git a/src/bonsai/bonsai/bim/module/model/workspace.py b/src/bonsai/bonsai/bim/module/model/workspace.py index 014ebd013b..b35af2b5c9 100644 --- a/src/bonsai/bonsai/bim/module/model/workspace.py +++ b/src/bonsai/bonsai/bim/module/model/workspace.py @@ -674,12 +674,13 @@ class CreateObjectUI: if not (ifc_class := AuthoringData.data["ifc_class_current"]): return + relating_type_data = AuthoringData.data["relating_type_data"] box = cls.layout.box() row = box.row(align=True) - thumbnail: int = AuthoringData.data["type_thumbnail"] + thumbnail: int = relating_type_data["icon_id"] row.template_icon(icon_value=thumbnail) - row.operator("bim.launch_type_manager", text=AuthoringData.data["relating_type_name"], emboss=False) + row.operator("bim.launch_type_manager", text=relating_type_data["name"], emboss=False) row.operator( "bim.launch_type_manager", icon=tool.Blender.TYPE_MANAGER_ICON, @@ -693,7 +694,7 @@ class CreateObjectUI: row.alignment = "CENTER" row.operator( "bim.launch_type_manager", - text=AuthoringData.data["relating_type_description"], + text=relating_type_data["description"], emboss=False, ) @@ -718,7 +719,7 @@ class CreateObjectUI: row.alignment = "CENTER" row.operator( "bim.launch_type_manager", - text=AuthoringData.data["predefined_type"], + text=AuthoringData.data["relating_type_data"].get("predefined_type"), emboss=False, ) @@ -870,7 +871,7 @@ class EditObjectUI: ) 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) - if AuthoringData.data["relating_type_material_usage"] == "LAYER3": + if AuthoringData.data["relating_type_data"].get("usage") == "LAYER3": row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row add_layout_hotkey_operator( row, @@ -884,7 +885,7 @@ class EditObjectUI: if "LAYER2" in AuthoringData.data["selected_material_usages"]: row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row add_layout_hotkey_operator(cls.layout, "Extend Wall To Slab", "S_E", "", ui_context) - if AuthoringData.data["relating_type_material_usage"] == "LAYER2": + if AuthoringData.data["relating_type_data"].get("usage") == "LAYER2": row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row add_layout_hotkey_operator( row,