Another attempt.

Went back to previous toolbar : icon + type name + dot grid icon which all launch the type manager.
    Validating the type manager popup now only closes it. Functionally is the same thing as clicking Cancel. Don't really know what to do to fix it. Does cancel make sense in the type manager ? Do we want to be able to undo what is possible to be done from within the type manager ?
    You can change the active type either with the dropdown in the popup and in the grid flow. I changed it so that changing the type in the dropdown jumps to the corresponding page. BTW first time using github copilot to figure out the maths and it worked magically :) . I'm not against removing the dropdown but I feel like it's nice to see a plain list to choose from.
    You can input a specific page number or scrub the page number field. Might be usefull if user has dozens of pages to flip through.
    Right now the search is very simple, it does not implement fuzzy search or anything fancy with *
This commit is contained in:
Gorgious56
2025-01-10 14:24:33 +01:00
parent aafb6fc426
commit 4f4c557f61
5 changed files with 48 additions and 37 deletions
+14 -8
View File
@@ -58,14 +58,15 @@ class AuthoringData:
cls.data["ifc_classes"] = cls.ifc_classes()
cls.data["ifc_class_current"] = cls.ifc_class_current()
# 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["type_elements"] = cls.type_elements()
cls.data["type_elements_filtered"] = cls.type_elements_filtered()
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()
# 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()
cls.data["next_page"] = cls.next_page()
@@ -116,7 +117,7 @@ class AuthoringData:
@classmethod
def total_types(cls):
return len(cls.data["filtered_type_elements"])
return len(cls.data["type_elements_filtered"])
@classmethod
def total_pages(cls):
@@ -134,19 +135,24 @@ class AuthoringData:
return cls.props.type_page - 1
@classmethod
def filtered_type_elements(cls):
def 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 type_elements_filtered(cls):
elements = cls.data["type_elements"]
if cls.props.search_name:
return [e for e in elements if cls.props.search_name.lower() in (e.Name or "Unnamed").lower()]
return elements
@classmethod
def paginated_relating_types(cls):
results = []
elements = cls.data["filtered_type_elements"]
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)
@@ -273,7 +279,7 @@ class AuthoringData:
@classmethod
def relating_type_id(cls):
elements = cls.data["filtered_type_elements"]
elements = cls.data["type_elements"]
return [(str(e.id()), e.Name or "Unnamed", e.Description or "") for e in elements]
@classmethod
@@ -568,7 +568,7 @@ class LoadTypeThumbnails(bpy.types.Operator, tool.Ifc.Operator):
# Large projects have hundreds of types which can lead to unnecessary lag.
if not AuthoringData.is_loaded:
AuthoringData.load()
queue = AuthoringData.data["filtered_type_elements"]
queue = AuthoringData.data["type_elements_filtered"]
if self.limit:
queue = queue[self.offset : self.offset + self.limit]
else:
+6 -2
View File
@@ -65,10 +65,14 @@ def update_relating_type_id(self, context):
AuthoringData.data["relating_type_name"] = AuthoringData.relating_type_name()
AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail()
AuthoringData.data["predefined_type"] = AuthoringData.predefined_type()
self.type_page = [e[0] for e in AuthoringData.data["relating_type_id"]].index(self.relating_type_id) // 9 + 1
def update_type_page(self, context):
AuthoringData.data["paginated_relating_types"] = AuthoringData.paginated_relating_types()
bpy.ops.bim.load_type_thumbnails(ifc_class=self.ifc_class, offset=9 * (self.type_page - 1), limit=9)
self["type_page"] = min(self["type_page"], AuthoringData.data["total_pages"])
self["type_page"] = max(self["type_page"], 1)
def update_relating_array_from_object(self, context):
@@ -101,7 +105,7 @@ 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"]
self.type_page = max(1, AuthoringData.data["total_pages"])
bpy.ops.bim.load_type_thumbnails(ifc_class=self.ifc_class)
@@ -177,7 +181,7 @@ class BIMModelProperties(PropertyGroup):
# Used for plan calculation points such as in room generation
rl3: bpy.props.FloatProperty(name="RL", default=1, subtype="DISTANCE", description="Z offset for space calculation")
x_angle: bpy.props.FloatProperty(name="X Angle", default=0, subtype="ANGLE", min=-pi / 180 * 89, max=pi / 180 * 89)
type_page: bpy.props.IntProperty(name="Type Page", default=1, update=update_type_page)
type_page: bpy.props.IntProperty(name="Type Page", default=1, min=1,update=update_type_page)
type_name: bpy.props.StringProperty(name="Name", default="TYPEX")
boundary_class: bpy.props.EnumProperty(items=get_boundary_class, name="Boundary Class")
direction_sense: bpy.props.EnumProperty(
+24 -19
View File
@@ -87,7 +87,6 @@ class LaunchTypeManager(bpy.types.Operator):
bl_description = "Display all available Construction Types to add new occurrences"
def execute(self, context):
bpy.ops.bim.hotkey("INVOKE_DEFAULT", hotkey="S_A")
return {"FINISHED"}
def invoke(self, context, event):
@@ -101,9 +100,7 @@ class LaunchTypeManager(bpy.types.Operator):
# will be None if project has no types
if ifc_class is not None:
bpy.ops.bim.load_type_thumbnails(ifc_class=ifc_class, offset=0, limit=9)
return context.window_manager.invoke_props_dialog(
self, width=550, title="Type Manager", confirm_text="Add Occurrence"
)
return context.window_manager.invoke_props_dialog(self, width=550, title="Type Manager", confirm_text="Close")
def draw(self, context):
props = context.scene.BIMModelProperties
@@ -113,25 +110,33 @@ class LaunchTypeManager(bpy.types.Operator):
text += "s"
row.label(text=text, icon="FILE_VOLUME")
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")
row = self.layout.row(align=True)
row.prop(props, "relating_type_id", text="")
# prop_with_search(row, props, "relating_type_id", text="", should_click_ok_to_validate=True)
row.prop(props, "search_name", icon="FILTER", text="")
columns = self.layout.column_flow(columns=3)
row = columns.row(align=True)
row.alignment = "CENTER"
if AuthoringData.data["total_pages"] > 0:
row = columns.row(align=True)
row.alignment = "RIGHT"
row2 = row.row(align=True)
row2.label(text="Page")
row2.prop(props, "type_page", text="", emboss=False)
row2.label(text=f"/{AuthoringData.data['total_pages']} ")
row = columns.row(align=True)
row.alignment = "RIGHT"
if AuthoringData.data["total_pages"] > 1:
row.label(text=f"Page {props.type_page}/{AuthoringData.data['total_pages']} ")
if AuthoringData.data["prev_page"]:
op = row.operator("bim.change_type_page", icon="TRIA_LEFT", text="")
op.page = AuthoringData.data["prev_page"]
if AuthoringData.data["next_page"]:
op = row.operator("bim.change_type_page", icon="TRIA_RIGHT", text="")
op.page = AuthoringData.data["next_page"]
prev_page_op = row.row(align=True)
op = prev_page_op.operator("bim.change_type_page", icon="TRIA_LEFT", text="")
op.page = AuthoringData.data["prev_page"] or 0
prev_page_op.enabled = op.page > 0
self.layout.prop(props, "search_name", icon="VIEWZOOM", text="")
next_page_op = row.row(align=True)
op = next_page_op.operator("bim.change_type_page", icon="TRIA_RIGHT", text="")
op.page = AuthoringData.data["next_page"] or 0
next_page_op.enabled = op.page > 0
flow = self.layout.grid_flow(row_major=True, columns=3, even_columns=True, even_rows=True, align=True)
@@ -139,11 +144,11 @@ class LaunchTypeManager(bpy.types.Operator):
outer_col = flow.column()
box = outer_col.box()
row = box.row(align=True)
row = box.row()
op = row.operator("bim.set_active_type", text=relating_type["name"], icon="BLANK1", emboss=False)
op.relating_type = relating_type["id"]
op = row.operator("bim.launch_type_menu", icon="PREFERENCES", text="", emboss=False)
op = row.operator("bim.launch_type_menu", icon="PREFERENCES", text="", emboss=True)
op.relating_type_id = relating_type["id"]
row = box.row()
@@ -509,13 +509,9 @@ class CreateObjectUI:
if ifc_class:
box = cls.layout.box()
row = box.row(align=True)
prop_with_search(row, cls.props, "relating_type_id", text="")
if AuthoringData.data["type_thumbnail"] and ui_context == "TOOL_HEADER":
row.template_icon(icon_value=AuthoringData.data["type_thumbnail"])
row.operator("bim.launch_type_manager", text="Type Manager", emboss=False)
else:
row.operator("bim.launch_type_manager", icon="BLANK1", text="Type Manager", emboss=False)
if ui_context == "TOOL_HEADER":
row.template_icon(icon_value=AuthoringData.data.get("type_thumbnail", 0))
row.operator("bim.launch_type_manager", text=AuthoringData.data["relating_type_name"], emboss=False)
row.operator(
"bim.launch_type_manager",
icon=tool.Blender.TYPE_MANAGER_ICON,