diff --git a/src/bonsai/bonsai/bim/module/model/data.py b/src/bonsai/bonsai/bim/module/model/data.py index bfe7c729e2..9a37bc55fa 100644 --- a/src/bonsai/bonsai/bim/module/model/data.py +++ b/src/bonsai/bonsai/bim/module/model/data.py @@ -57,20 +57,22 @@ class AuthoringData: cls.data["ifc_element_type"] = cls.ifc_element_type cls.data["ifc_classes"] = cls.ifc_classes() cls.data["ifc_class_current"] = cls.ifc_class_current() - cls.data["relating_type_id"] = cls.relating_type_id() # only after .ifc_classes() - cls.data["relating_type_id_current"] = cls.relating_type_id_current() # only after .ifc_classes() - cls.data["relating_type_name"] = cls.relating_type_name() # only after .relating_type_id() - cls.data["relating_type_description"] = cls.relating_type_description() # only after .relating_type_id() - cls.data["predefined_type"] = cls.predefined_type() # only after .relating_type_id() - - # Only after .ifc_classes() + # Make sure .ifc_classes() was run before next lines + cls.data["filtered_type_elements"] = cls.filtered_type_elements() + # Make sure .filtered_type_elements() was run before next lines + 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["predefined_type"] = cls.predefined_type() cls.data["total_types"] = cls.total_types() - cls.data["total_pages"] = cls.total_pages() + cls.data["total_pages"] = cls.total_pages() # Only after .total_types() cls.data["next_page"] = cls.next_page() 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() + cls.data["type_thumbnail"] = cls.type_thumbnail() cls.data["is_voidable_element"] = cls.is_voidable_element() cls.data["has_visible_openings"] = cls.has_visible_openings() cls.data["has_visible_boundaries"] = cls.has_visible_boundaries() @@ -114,13 +116,11 @@ class AuthoringData: @classmethod def total_types(cls): - ifc_class = cls.data["ifc_class_current"] - return len(tool.Ifc.get().by_type(ifc_class)) if ifc_class else 0 + return len(cls.data["filtered_type_elements"]) @classmethod def total_pages(cls): - ifc_class = cls.data["ifc_class_current"] - total_types = len(tool.Ifc.get().by_type(ifc_class)) if ifc_class else 0 + total_types = cls.data["total_types"] return math.ceil(total_types / cls.types_per_page) @classmethod @@ -134,12 +134,19 @@ class AuthoringData: return cls.props.type_page - 1 @classmethod - def paginated_relating_types(cls): + def filtered_type_elements(cls): ifc_class = cls.data["ifc_class_current"] if not ifc_class: return [] + elements = list(tool.Ifc.get().by_type(ifc_class)) + if cls.props.search_name: + elements = [e for e in elements if cls.props.search_name.lower() in (e.Name or "Unnamed").lower()] + return natsorted(elements, key=lambda s: (s.Name or "Unnamed").lower()) + + @classmethod + def paginated_relating_types(cls): results = [] - elements = natsorted(tool.Ifc.get().by_type(ifc_class), key=lambda e: e.Name or "Unnamed") + elements = cls.data["filtered_type_elements"] 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) @@ -266,13 +273,8 @@ class AuthoringData: @classmethod def relating_type_id(cls): - results = [] - ifc_class = cls.data["ifc_class_current"] - if ifc_class: - elements = natsorted(tool.Ifc.get().by_type(ifc_class), key=lambda s: (s.Name or "Unnamed").lower()) - results.extend(elements) - return [(str(e.id()), e.Name or "Unnamed", e.Description or "") for e in results] - return [] + elements = cls.data["filtered_type_elements"] + return [(str(e.id()), e.Name or "Unnamed", e.Description or "") for e in elements] @classmethod def relating_type_id_current(cls): diff --git a/src/bonsai/bonsai/bim/module/model/product.py b/src/bonsai/bonsai/bim/module/model/product.py index 93fc8761c6..9e9bafcaba 100644 --- a/src/bonsai/bonsai/bim/module/model/product.py +++ b/src/bonsai/bonsai/bim/module/model/product.py @@ -566,7 +566,9 @@ class LoadTypeThumbnails(bpy.types.Operator, tool.Ifc.Operator): processing = set() # Only process at most one paginated class at a time. # Large projects have hundreds of types which can lead to unnecessary lag. - queue = sorted(tool.Ifc.get().by_type(self.ifc_class), key=lambda e: e.Name or "Unnamed") + if not AuthoringData.is_loaded: + AuthoringData.load() + queue = AuthoringData.data["filtered_type_elements"] if self.limit: queue = queue[self.offset : self.offset + self.limit] else: diff --git a/src/bonsai/bonsai/bim/module/model/prop.py b/src/bonsai/bonsai/bim/module/model/prop.py index 27aa3151a4..c9f1de899c 100644 --- a/src/bonsai/bonsai/bim/module/model/prop.py +++ b/src/bonsai/bonsai/bim/module/model/prop.py @@ -97,11 +97,26 @@ def update_slab_direction_decorator(self, context): SlabDirectionDecorator.uninstall() +def update_search_name(self, context): + AuthoringData.load() + # Total number of pages may decrease when using the search bar : + if self.type_page > AuthoringData.data["total_pages"]: + self.type_page = AuthoringData.data["total_pages"] + bpy.ops.bim.load_type_thumbnails(ifc_class=self.ifc_class) + + class BIMModelProperties(PropertyGroup): ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class) relating_type_id: bpy.props.EnumProperty( items=get_relating_type_id, name="Relating Type", update=update_relating_type_id ) + search_name: bpy.props.StringProperty( + name="Search Name", + default="", + description="Use this property to filter the list of available types", + update=update_search_name, + options={"SKIP_SAVE", "TEXTEDIT_UPDATE"}, + ) menu_relating_type_id: bpy.props.IntProperty() icon_id: bpy.props.IntProperty() updating: bpy.props.BoolProperty(default=False) diff --git a/src/bonsai/bonsai/bim/module/model/ui.py b/src/bonsai/bonsai/bim/module/model/ui.py index 286fa41794..08fc46cb6f 100644 --- a/src/bonsai/bonsai/bim/module/model/ui.py +++ b/src/bonsai/bonsai/bim/module/model/ui.py @@ -108,12 +108,10 @@ class LaunchTypeManager(bpy.types.Operator): def draw(self, context): props = context.scene.BIMModelProperties row = self.layout.row(align=True) + text = f"{AuthoringData.data['total_types']} {AuthoringData.data['ifc_element_type']}" if AuthoringData.data["total_types"] > 1: - text = f"{AuthoringData.data['total_types']} {AuthoringData.data['ifc_element_type']}s" - else: - text = f"{AuthoringData.data['total_types']} {AuthoringData.data['ifc_element_type']}" + text += "s" row.label(text=text, icon="FILE_VOLUME") - # prop_with_search(row, props, "ifc_class", text="", should_click_ok_to_validate=True) row.menu("BIM_MT_type_manager_menu", text="", icon="PREFERENCES") row = self.layout.row(align=True) row.operator("bim.launch_add_element", text=f"Create New {AuthoringData.data['ifc_element_type']}", icon="ADD") @@ -121,9 +119,6 @@ class LaunchTypeManager(bpy.types.Operator): columns = self.layout.column_flow(columns=3) row = columns.row(align=True) row.alignment = "CENTER" - ### In case you want something here in the future - - ### row = columns.row(align=True) row.alignment = "RIGHT" @@ -136,6 +131,8 @@ class LaunchTypeManager(bpy.types.Operator): op = row.operator("bim.change_type_page", icon="TRIA_RIGHT", text="") op.page = AuthoringData.data["next_page"] + self.layout.prop(props, "search_name", icon="VIEWZOOM", text="") + flow = self.layout.grid_flow(row_major=True, columns=3, even_columns=True, even_rows=True, align=True) for relating_type in AuthoringData.data["paginated_relating_types"]: