Add search bar with simple filter function to the type manager

This commit is contained in:
Gorgious56
2025-01-10 09:44:12 +01:00
parent a6e953a550
commit aafb6fc426
4 changed files with 46 additions and 30 deletions
+24 -22
View File
@@ -57,20 +57,22 @@ class AuthoringData:
cls.data["ifc_element_type"] = cls.ifc_element_type cls.data["ifc_element_type"] = cls.ifc_element_type
cls.data["ifc_classes"] = cls.ifc_classes() cls.data["ifc_classes"] = cls.ifc_classes()
cls.data["ifc_class_current"] = cls.ifc_class_current() cls.data["ifc_class_current"] = cls.ifc_class_current()
cls.data["relating_type_id"] = cls.relating_type_id() # only after .ifc_classes() # Make sure .ifc_classes() was run before next lines
cls.data["relating_type_id_current"] = cls.relating_type_id_current() # only after .ifc_classes() cls.data["filtered_type_elements"] = cls.filtered_type_elements()
cls.data["relating_type_name"] = cls.relating_type_name() # only after .relating_type_id() # Make sure .filtered_type_elements() was run before next lines
cls.data["relating_type_description"] = cls.relating_type_description() # only after .relating_type_id() cls.data["relating_type_id"] = cls.relating_type_id()
cls.data["predefined_type"] = cls.predefined_type() # only after .relating_type_id() # Make sure .relating_type_id() was run before next lines
cls.data["relating_type_id_current"] = cls.relating_type_id_current()
# Only after .ifc_classes() 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_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["next_page"] = cls.next_page()
cls.data["prev_page"] = cls.prev_page() cls.data["prev_page"] = cls.prev_page()
cls.data["paginated_relating_types"] = cls.paginated_relating_types() 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["is_voidable_element"] = cls.is_voidable_element()
cls.data["has_visible_openings"] = cls.has_visible_openings() cls.data["has_visible_openings"] = cls.has_visible_openings()
cls.data["has_visible_boundaries"] = cls.has_visible_boundaries() cls.data["has_visible_boundaries"] = cls.has_visible_boundaries()
@@ -114,13 +116,11 @@ class AuthoringData:
@classmethod @classmethod
def total_types(cls): def total_types(cls):
ifc_class = cls.data["ifc_class_current"] return len(cls.data["filtered_type_elements"])
return len(tool.Ifc.get().by_type(ifc_class)) if ifc_class else 0
@classmethod @classmethod
def total_pages(cls): def total_pages(cls):
ifc_class = cls.data["ifc_class_current"] total_types = cls.data["total_types"]
total_types = len(tool.Ifc.get().by_type(ifc_class)) if ifc_class else 0
return math.ceil(total_types / cls.types_per_page) return math.ceil(total_types / cls.types_per_page)
@classmethod @classmethod
@@ -134,12 +134,19 @@ class AuthoringData:
return cls.props.type_page - 1 return cls.props.type_page - 1
@classmethod @classmethod
def paginated_relating_types(cls): def filtered_type_elements(cls):
ifc_class = cls.data["ifc_class_current"] ifc_class = cls.data["ifc_class_current"]
if not ifc_class: if not ifc_class:
return [] 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 = [] 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] elements = elements[(cls.props.type_page - 1) * cls.types_per_page : cls.props.type_page * cls.types_per_page]
for element in elements: for element in elements:
predefined_type = ifcopenshell.util.element.get_predefined_type(element) predefined_type = ifcopenshell.util.element.get_predefined_type(element)
@@ -266,13 +273,8 @@ class AuthoringData:
@classmethod @classmethod
def relating_type_id(cls): def relating_type_id(cls):
results = [] elements = cls.data["filtered_type_elements"]
ifc_class = cls.data["ifc_class_current"] return [(str(e.id()), e.Name or "Unnamed", e.Description or "") for e in elements]
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 []
@classmethod @classmethod
def relating_type_id_current(cls): def relating_type_id_current(cls):
@@ -566,7 +566,9 @@ class LoadTypeThumbnails(bpy.types.Operator, tool.Ifc.Operator):
processing = set() processing = set()
# Only process at most one paginated class at a time. # Only process at most one paginated class at a time.
# Large projects have hundreds of types which can lead to unnecessary lag. # 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: if self.limit:
queue = queue[self.offset : self.offset + self.limit] queue = queue[self.offset : self.offset + self.limit]
else: else:
@@ -97,11 +97,26 @@ def update_slab_direction_decorator(self, context):
SlabDirectionDecorator.uninstall() 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): class BIMModelProperties(PropertyGroup):
ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class) ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class)
relating_type_id: bpy.props.EnumProperty( relating_type_id: bpy.props.EnumProperty(
items=get_relating_type_id, name="Relating Type", update=update_relating_type_id 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() menu_relating_type_id: bpy.props.IntProperty()
icon_id: bpy.props.IntProperty() icon_id: bpy.props.IntProperty()
updating: bpy.props.BoolProperty(default=False) updating: bpy.props.BoolProperty(default=False)
+4 -7
View File
@@ -108,12 +108,10 @@ class LaunchTypeManager(bpy.types.Operator):
def draw(self, context): def draw(self, context):
props = context.scene.BIMModelProperties props = context.scene.BIMModelProperties
row = self.layout.row(align=True) row = self.layout.row(align=True)
text = f"{AuthoringData.data['total_types']} {AuthoringData.data['ifc_element_type']}"
if AuthoringData.data["total_types"] > 1: if AuthoringData.data["total_types"] > 1:
text = f"{AuthoringData.data['total_types']} {AuthoringData.data['ifc_element_type']}s" text += "s"
else:
text = f"{AuthoringData.data['total_types']} {AuthoringData.data['ifc_element_type']}"
row.label(text=text, icon="FILE_VOLUME") 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.menu("BIM_MT_type_manager_menu", text="", icon="PREFERENCES")
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.operator("bim.launch_add_element", text=f"Create New {AuthoringData.data['ifc_element_type']}", icon="ADD") 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) columns = self.layout.column_flow(columns=3)
row = columns.row(align=True) row = columns.row(align=True)
row.alignment = "CENTER" row.alignment = "CENTER"
### In case you want something here in the future
###
row = columns.row(align=True) row = columns.row(align=True)
row.alignment = "RIGHT" row.alignment = "RIGHT"
@@ -136,6 +131,8 @@ class LaunchTypeManager(bpy.types.Operator):
op = row.operator("bim.change_type_page", icon="TRIA_RIGHT", text="") op = row.operator("bim.change_type_page", icon="TRIA_RIGHT", text="")
op.page = AuthoringData.data["next_page"] 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) 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"]: for relating_type in AuthoringData.data["paginated_relating_types"]: