diff --git a/src/blenderbim/blenderbim/bim/module/model/data.py b/src/blenderbim/blenderbim/bim/module/model/data.py index 139ec6dd24..93066affbd 100644 --- a/src/blenderbim/blenderbim/bim/module/model/data.py +++ b/src/blenderbim/blenderbim/bim/module/model/data.py @@ -42,6 +42,7 @@ class AuthoringData: cls.props = bpy.context.scene.BIMModelProperties cls.load_ifc_classes() cls.load_relating_types() + cls.load_relating_types_browser() cls.load_preview_constr_types() @classmethod @@ -52,6 +53,10 @@ class AuthoringData: def load_relating_types(cls): cls.data["relating_types_ids"] = cls.relating_types() + @classmethod + def load_relating_types_browser(cls): + cls.data["relating_types_browser_ids"] = cls.relating_types_browser() + @classmethod def load_preview_constr_types(cls): cls.data["preview_constr_types"] = preview_icon_ids @@ -88,6 +93,10 @@ class AuthoringData: def relating_types(cls, ifc_class=None): return [(str(e.id()), e.Name, e.Description or "") for e in cls.constr_class_entities(ifc_class=ifc_class)] + @classmethod + def relating_types_browser(cls): + return cls.relating_types(ifc_class=cls.props.ifc_class_browser) + @staticmethod def new_relating_type_info(ifc_class): relating_type_info = bpy.context.scene.ConstrTypeInfo.add() @@ -137,9 +146,9 @@ class AuthoringData: col.objects.unlink(obj) @classmethod - def assetize_relating_type_from_selection(cls): - ifc_class= cls.props.ifc_class - relating_type_id = cls.props.relating_type_id + def assetize_relating_type_from_selection(cls, browser=False): + ifc_class = cls.props.ifc_class_browser if browser else cls.props.ifc_class + relating_type_id = cls.props.relating_type_id_browser if browser else cls.props.relating_type_id constr_class_occurrences = cls.constr_class_entities(ifc_class=ifc_class) constr_class_occurrences = [ entity for entity in constr_class_occurrences if entity.id() == int(relating_type_id) diff --git a/src/blenderbim/blenderbim/bim/module/model/product.py b/src/blenderbim/blenderbim/bim/module/model/product.py index e38bd1dc60..de701fa449 100644 --- a/src/blenderbim/blenderbim/bim/module/model/product.py +++ b/src/blenderbim/blenderbim/bim/module/model/product.py @@ -193,13 +193,10 @@ class DisplayConstrTypes(bpy.types.Operator): if not AuthoringData.is_loaded: AuthoringData.load() props = context.scene.BIMModelProperties - if props.unfold_relating_types: - ifc_class = props.ifc_class - relating_type_info = AuthoringData.relating_type_info(ifc_class) - if relating_type_info is None or not relating_type_info.fully_loaded: - AuthoringData.assetize_constr_class(ifc_class) - else: - prop.update_relating_type(props, context) + ifc_class = props.ifc_class + relating_type_info = AuthoringData.relating_type_info(ifc_class) + if relating_type_info is None or not relating_type_info.fully_loaded: + AuthoringData.assetize_constr_class(ifc_class) bpy.ops.bim.display_constr_types_ui("INVOKE_DEFAULT") return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/model/prop.py b/src/blenderbim/blenderbim/bim/module/model/prop.py index 39d92722e9..05a38e4458 100644 --- a/src/blenderbim/blenderbim/bim/module/model/prop.py +++ b/src/blenderbim/blenderbim/bim/module/model/prop.py @@ -33,16 +33,24 @@ def get_relating_type(self, context): return AuthoringData.data["relating_types_ids"] -def update_icon_id(self, context): - ifc_class = self.ifc_class - relating_type_id = self.relating_type_id +def get_relating_type_browser(self, context): + if not AuthoringData.is_loaded: + AuthoringData.load() + return AuthoringData.data["relating_types_browser_ids"] + + +def update_icon_id(self, context, browser=False): + ifc_class = self.ifc_class_browser if browser else self.ifc_class + relating_type_id = self.relating_type_id_browser if browser else self.relating_type_id relating_type = AuthoringData.relating_type_name_by_id(ifc_class, relating_type_id) if ( ifc_class not in AuthoringData.data["preview_constr_types"] or relating_type_id not in AuthoringData.data["preview_constr_types"][ifc_class] ) and relating_type is not None: - if not AuthoringData.assetize_relating_type_from_selection(): + if not AuthoringData.assetize_relating_type_from_selection(browser=browser): return + if ifc_class not in AuthoringData.data["preview_constr_types"]: + pass self.icon_id = AuthoringData.data["preview_constr_types"][ifc_class][relating_type_id]["icon_id"] @@ -51,13 +59,17 @@ def update_ifc_class(self, context): AuthoringData.load_relating_types() if self.updating: return - if self.unfold_relating_types: - ifc_class = self.ifc_class - relating_type_info = AuthoringData.relating_type_info(ifc_class) - if relating_type_info is None or not relating_type_info.fully_loaded: - AuthoringData.assetize_constr_class(ifc_class) - else: - self.relating_type_id = AuthoringData.data["relating_types_ids"][0][0] + + +def update_ifc_class_browser(self, context): + AuthoringData.load_ifc_classes() + AuthoringData.load_relating_types_browser() + if self.updating: + return + ifc_class = self.ifc_class_browser + relating_type_info = AuthoringData.relating_type_info(ifc_class) + if relating_type_info is None or not relating_type_info.fully_loaded: + AuthoringData.assetize_constr_class(ifc_class) def update_relating_type(self, context): @@ -66,6 +78,12 @@ def update_relating_type(self, context): update_icon_id(self, context) +def update_relating_type_browser(self, context): + AuthoringData.load_relating_types_browser() + if not self.updating: + update_icon_id(self, context, browser=True) + + def update_relating_type_by_name(self, context): AuthoringData.load_relating_types() relating_type_id = AuthoringData.relating_type_id_by_name(self.ifc_class, self.relating_type) @@ -73,8 +91,8 @@ def update_relating_type_by_name(self, context): self.relating_type_id = relating_type_id -def update_unfold_relating_type(self, context): - if self.unfold_relating_types: +def update_preview_multiple(self, context): + if self.preview_multiple_constr_types: ifc_class = self.ifc_class relating_type_info = AuthoringData.relating_type_info(ifc_class) if relating_type_info is None or not relating_type_info.fully_loaded: @@ -85,12 +103,17 @@ def update_unfold_relating_type(self, context): class BIMModelProperties(PropertyGroup): ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", update=update_ifc_class) + ifc_class_browser: bpy.props.EnumProperty(items=get_ifc_class, name="Construction Class", + update=update_ifc_class_browser) relating_type: bpy.props.StringProperty(update=update_relating_type_by_name) relating_type_id: bpy.props.EnumProperty( items=get_relating_type, name="Construction Type", update=update_relating_type ) + relating_type_id_browser: bpy.props.EnumProperty( + items=get_relating_type_browser, name="Construction Type", update=update_relating_type_browser + ) icon_id: bpy.props.IntProperty() - unfold_relating_types: bpy.props.BoolProperty(update=update_unfold_relating_type) + preview_multiple_constr_types: bpy.props.BoolProperty(default=False, update=update_preview_multiple) updating: bpy.props.BoolProperty(default=False) occurrence_name_style: bpy.props.EnumProperty( items=[("CLASS", "By Class", ""), ("TYPE", "By Type", ""), ("CUSTOM", "Custom", "")], diff --git a/src/blenderbim/blenderbim/bim/module/model/ui.py b/src/blenderbim/blenderbim/bim/module/model/ui.py index 1b041f9c5b..374b9a051b 100644 --- a/src/blenderbim/blenderbim/bim/module/model/ui.py +++ b/src/blenderbim/blenderbim/bim/module/model/ui.py @@ -16,7 +16,6 @@ # You should have received a copy of the GNU General Public License # along with BlenderBIM Add-on. If not, see . -import math from bpy.types import Panel, Operator from blenderbim.bim.module.model.data import AuthoringData from blenderbim.bim.helper import prop_with_search, close_operator_panel @@ -54,34 +53,19 @@ class DisplayConstrTypesUI(Operator): return {"FINISHED"} def invoke(self, context, event): - return context.window_manager.invoke_popup(self) + return context.window_manager.invoke_popup(self, width=550) def draw(self, context): props = context.scene.BIMModelProperties - self.draw_header(props) - if props.unfold_relating_types: - self.draw_by_ifc_class(props) - else: - self.draw_by_ifc_class_and_type(props) - self.draw_footer(props) - - def draw_header(self, props): if AuthoringData.data["ifc_classes"]: row = self.layout.row() row.label(text="", icon="FILE_VOLUME") - prop_with_search(row, props, "ifc_class", text="") - - def draw_footer(self, props): - row = self.layout.row() - row.prop(data=props, property="unfold_relating_types", text="Show more") - row.operator("bim.help_relating_types", text="", icon="QUESTION") - - def draw_by_ifc_class(self, props): - ifc_class = props.ifc_class + prop_with_search(row, props, "ifc_class_browser", text="") + ifc_class = props.ifc_class_browser num_cols = 3 self.layout.row().separator(factor=0.25) flow = self.layout.grid_flow(row_major=True, columns=num_cols, even_columns=True, even_rows=True, align=True) - relating_types = AuthoringData.relating_types() + relating_types = AuthoringData.relating_types_browser() num_types = len(relating_types) for idx, (relating_type_id, name, desc) in enumerate(relating_types): outer_col = flow.column() @@ -102,27 +86,13 @@ class DisplayConstrTypesUI(Operator): op.ifc_class = ifc_class if relating_type_id.isnumeric(): op.relating_type_id = int(relating_type_id) - factor = 2 if idx + 1 < math.ceil(num_types / num_cols) else 1.5 last_row_cols = num_types % num_cols if last_row_cols != 0: for _ in range(num_cols - last_row_cols): flow.column() - - def draw_by_ifc_class_and_type(self, props): - ifc_class = props.ifc_class - relating_type_id = props.relating_type_id - if AuthoringData.data["relating_types_ids"]: - row = self.layout.row() - row.label(text="", icon="FILE_3D") - prop_with_search(row, props, "relating_type_id", text="") - box = self.layout.box() - box.template_icon(icon_value=props.icon_id, scale=7) row = self.layout.row() - op = row.operator("bim.add_constr_type_instance", icon="ADD") - op.from_invoke = True - op.ifc_class = ifc_class - if relating_type_id.isnumeric(): - op.relating_type_id = int(relating_type_id) + row.alignment = "RIGHT" + row.operator("bim.help_relating_types", text="", icon="QUESTION") class HelpConstrTypes(Operator): diff --git a/src/blenderbim/blenderbim/bim/module/model/workspace.py b/src/blenderbim/blenderbim/bim/module/model/workspace.py index 862b1adb6f..295701231c 100644 --- a/src/blenderbim/blenderbim/bim/module/model/workspace.py +++ b/src/blenderbim/blenderbim/bim/module/model/workspace.py @@ -23,6 +23,7 @@ from blenderbim.bim.helper import prop_with_search, close_operator_panel from bpy.types import WorkSpaceTool from blenderbim.bim.ifc import IfcStore from blenderbim.bim.module.model.data import AuthoringData +from blenderbim.bim.module.model import prop class BimTool(WorkSpaceTool): @@ -53,70 +54,80 @@ class BimTool(WorkSpaceTool): ) def draw_settings(context, layout, tool): - if not AuthoringData.is_loaded and IfcStore.get_file(): - AuthoringData.load() - props = context.scene.BIMModelProperties is_tool_header = context.region.type == "TOOL_HEADER" + is_sidebar = context.region.type == "UI" + row = layout.row(align=True) if not IfcStore.get_file(): row.label(text="No IFC Project", icon="ERROR") return - ifc_classes = AuthoringData.data["ifc_classes"] - relating_types_ids = AuthoringData.data["relating_types_ids"] + if not AuthoringData.is_loaded: + AuthoringData.load() + + ifc_classes = AuthoringData.data[ + "ifc_classes"] if "ifc_classes" in AuthoringData.data else False + relating_types_ids = AuthoringData.data[ + "relating_types_ids"] if "relating_types_ids" in AuthoringData.data else False + + if ifc_classes and relating_types_ids and not props.icon_id: + # hack Dion won't like to show a preview also on the first time the sidebar is shown + bpy.app.timers.register(lambda: prop.update_relating_type(props, context)) ifc_class = props.ifc_class relating_type_id = props.relating_type_id - relating_type = AuthoringData.relating_type_name_by_id(ifc_class, relating_type_id) if is_tool_header: + row = layout.row(align=True) if ifc_classes: row.label(text="", icon="FILE_VOLUME") - row.label(text=ifc_class) + row.prop(data=props, property="ifc_class", text="") + else: + row.label(text="No Construction Class", icon="FILE_VOLUME") + row = layout.row(align=True) + if relating_types_ids: row.label(text="", icon="FILE_3D") - row.label(text=f"{relating_type} ") + row.prop(data=props, property="relating_type_id", text="") + else: + row.label(text="No Construction Type", icon="FILE_3D") + if ifc_classes: + row = layout.row() row.operator("bim.display_constr_types", icon="TRIA_DOWN", text="") - row.operator("bim.display_constr_types", icon="VIEW_ORTHO", text="") row = layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_A") row.label(text=f" Add") else: - txt_ifc_class = ifc_class if ifc_classes else "No Construction Class" - txt_relating_type = relating_type if relating_types_ids else "No Construction Type" row = layout.row(align=True) - row.label(text=txt_ifc_class, icon="FILE_VOLUME") - row = layout.row(align=True) - row.label(text=txt_relating_type, icon="FILE_3D") - - if AuthoringData.data["ifc_classes"]: - row = layout.row() + if ifc_classes: row.label(text="", icon="FILE_VOLUME") prop_with_search(row, props, "ifc_class", text="") + else: + row.label(text="No Construction Class", icon="FILE_VOLUME") + row = layout.row(align=True) + if relating_types_ids: + row.label(text="", icon="FILE_3D") + prop_with_search(row, props, "relating_type_id", text="") + else: + row.label(text="No Construction Type", icon="FILE_3D") + if is_sidebar and ifc_classes and relating_types_ids: + box = layout.box() + box.template_icon(icon_value=props.icon_id, scale=8) + row = layout.row() + op = row.operator("bim.add_constr_type_instance", icon="ADD") + op.from_invoke = True + op.ifc_class = ifc_class + if relating_type_id.isnumeric(): + op.relating_type_id = int(relating_type_id) + if ifc_classes: row = layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_A") row.label(text=f" Add Type Instance") - ifc_class = props.ifc_class - relating_type_id = props.relating_type_id - if AuthoringData.data["relating_types_ids"]: - row = layout.row() - row.label(text="", icon="FILE_3D") - prop_with_search(row, props, "relating_type_id", text="") - - box = layout.box() - box.template_icon(icon_value=props.icon_id, scale=7) - row = layout.row() - op = row.operator("bim.add_constr_type_instance", icon="ADD") - op.from_invoke = True - op.ifc_class = ifc_class - if relating_type_id.isnumeric(): - op.relating_type_id = int(relating_type_id) - - if AuthoringData.data["ifc_classes"]: + if ifc_classes: if ifc_class == "IfcWallType": row = layout.row() row.label(text="Join")