From 618bed38890c3a172ebd0a591763bd3dfd1ac2c1 Mon Sep 17 00:00:00 2001 From: carlos Date: Sun, 10 Jul 2022 07:46:30 +0200 Subject: [PATCH] Improved version with optional cascading --- .../blenderbim/bim/module/model/__init__.py | 4 +- .../blenderbim/bim/module/model/data.py | 66 +++-- .../blenderbim/bim/module/model/product.py | 253 +++++++++++++++--- .../blenderbim/bim/module/model/prop.py | 42 ++- .../blenderbim/bim/module/model/ui.py | 41 +-- .../blenderbim/bim/module/model/workspace.py | 53 +++- 6 files changed, 349 insertions(+), 110 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/model/__init__.py b/src/blenderbim/blenderbim/bim/module/model/__init__.py index 5a43a63b56..3aecc33fc7 100644 --- a/src/blenderbim/blenderbim/bim/module/model/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/model/__init__.py @@ -23,7 +23,8 @@ classes = ( product.AddEmptyType, product.AddTypeInstance, product.DisplayIFCTypes, - product.AddIFCTypeInstance, + product.SelectTypeInstance, + product.TypeInstanceHelp, product.AlignProduct, product.DynamicallyVoidProduct, workspace.Hotkey, @@ -36,7 +37,6 @@ classes = ( prop.BIMModelProperties, prop.IfcTypeInfo, ui.BIM_PT_authoring, - ui.BIM_PT_authoring_architectural, grid.BIM_OT_add_object, stair.BIM_OT_add_object, opening.BIM_OT_add_object, diff --git a/src/blenderbim/blenderbim/bim/module/model/data.py b/src/blenderbim/blenderbim/bim/module/model/data.py index 3048360ab6..13dd02d98b 100644 --- a/src/blenderbim/blenderbim/bim/module/model/data.py +++ b/src/blenderbim/blenderbim/bim/module/model/data.py @@ -31,6 +31,7 @@ def refresh(): class AuthoringData: data = {} is_loaded = False + updating = False @classmethod def load(cls): @@ -85,22 +86,33 @@ class AuthoringData: def relating_types(cls, ifc_class=None): return [(str(e.id()), e.Name, e.Description or "") for e in cls.ifc_class_entities(ifc_class=ifc_class)] + @staticmethod + def new_ifc_type_info(ifc_class): + ifc_type_info = bpy.context.scene.IfcTypeInfo.add() + ifc_type_info.name = ifc_class + return ifc_type_info + @classmethod - def assetize_relating_type_from_selection(cls): - props = bpy.context.scene.BIMModelProperties - ifc_class = props.ifc_class - relating_type_id = props.relating_type - ifc_class_occurrences = cls.ifc_class_entities(ifc_class=ifc_class) - ifc_class_occurrences = [entity for entity in ifc_class_occurrences if entity.id() == int(relating_type_id)] - if len(ifc_class_occurrences) == 0: - return - ifc_class_entity = ifc_class_occurrences[0] - obj = tool.Ifc.get_object(ifc_class_entity) + def assetize_ifc_class(cls, ifc_class=None): + if ifc_class is None: + props = bpy.context.scene.BIMModelProperties + ifc_class = props.ifc_class + ifc_type_info = cls.ifc_type_info(ifc_class) + _ = cls.new_ifc_type_info(ifc_class) if ifc_type_info is None else ifc_type_info + ifc_class_occurrences = cls.ifc_class_entities(ifc_class) + for ifc_class_entity in ifc_class_occurrences: + obj = tool.Ifc.get_object(ifc_class_entity) + cls.assetize_object(obj, ifc_class, ifc_class_entity) + ifc_type_info = cls.ifc_type_info(ifc_class) + ifc_type_info.fully_loaded = True + + @classmethod + def assetize_object(cls, obj, ifc_class, ifc_class_entity, from_selection=False): relating_type = ifc_class_entity.Name to_be_deleted = False if obj.type == 'EMPTY': - bpy.ops.bim.add_type_instance() - new_obj = bpy.context.selected_objects[-1] + kwargs = {} if from_selection else {'ifc_class': ifc_class, 'relating_type_id': ifc_class_entity.id()} + new_obj = cls.new_ifc_type_instance(**kwargs) if new_obj is not None: to_be_deleted = True obj = new_obj @@ -114,17 +126,37 @@ class AuthoringData: for col in obj.users_collection: col.objects.unlink(obj) + @classmethod + def assetize_relating_type_from_selection(cls): + props = bpy.context.scene.BIMModelProperties + ifc_class = props.ifc_class + relating_type_id = props.relating_type + ifc_class_occurrences = cls.ifc_class_entities(ifc_class=ifc_class) + ifc_class_occurrences = [entity for entity in ifc_class_occurrences if entity.id() == int(relating_type_id)] + if len(ifc_class_occurrences) == 0: + return False + ifc_class_entity = ifc_class_occurrences[0] + obj = tool.Ifc.get_object(ifc_class_entity) + if obj is None: + return False + cls.assetize_object(obj, ifc_class, ifc_class_entity, from_selection=True) + return True + @staticmethod def ifc_type_info(ifc_class): - ifc_type_infos = [element for element in bpy.context.scene.IfcTypeInfo if element.ifc_class == ifc_class] + ifc_type_infos = [element for element in bpy.context.scene.IfcTypeInfo if element.name == ifc_class] return None if len(ifc_type_infos) == 0 else ifc_type_infos[0] @classmethod - def new_ifc_type_instance(cls, ifc_class, relating_type_id): - props = bpy.context.scene.BIMModelProperties - props.ifc_class = ifc_class - props.relating_type = str(relating_type_id) + def new_ifc_type_instance(cls, ifc_class=None, relating_type_id=None): + if ifc_class is not None: + cls.updating = True + props = bpy.context.scene.BIMModelProperties + props.ifc_class = ifc_class + props.relating_type = str(relating_type_id) + cls.updating = False bpy.ops.bim.add_type_instance() + return bpy.context.selected_objects[-1] @staticmethod def relating_type_name_by_id(ifc_class, relating_type_id): diff --git a/src/blenderbim/blenderbim/bim/module/model/product.py b/src/blenderbim/blenderbim/bim/module/model/product.py index 34a5f665c6..3e8e5c5dd1 100644 --- a/src/blenderbim/blenderbim/bim/module/model/product.py +++ b/src/blenderbim/blenderbim/bim/module/model/product.py @@ -17,6 +17,7 @@ # along with BlenderBIM Add-on. If not, see . import bpy +import math import mathutils import ifcopenshell import ifcopenshell.api @@ -30,9 +31,11 @@ import blenderbim.core.geometry from . import wall, slab, profile, mep from blenderbim.bim.ifc import IfcStore from blenderbim.bim.module.model.data import AuthoringData +from blenderbim.bim.helper import prop_with_search from ifcopenshell.api.pset.data import Data as PsetData from mathutils import Vector, Matrix from bpy_extras.object_utils import AddObjectHelper +from . import prop class AddEmptyType(bpy.types.Operator, AddObjectHelper): @@ -54,13 +57,26 @@ def add_empty_type_button(self, context): self.layout.operator(AddEmptyType.bl_idname, icon="FILE_3D") +def close_operator_panel(event): + x, y = event.mouse_x, event.mouse_y + bpy.context.window.cursor_warp(10, 10) + move_back = lambda: bpy.context.window.cursor_warp(x, y) + bpy.app.timers.register(move_back, first_interval=0.001) + + class AddTypeInstance(bpy.types.Operator): bl_idname = "bim.add_type_instance" - bl_label = "Add Type Instance" + bl_label = "Add" bl_options = {"REGISTER", "UNDO"} - bl_description = "Add the selected Type Instance to the model" + bl_description = "Add Type Instance to the model" ifc_class: bpy.props.StringProperty() relating_type: bpy.props.IntProperty() + from_invoke: bpy.props.BoolProperty(default=False) + + def invoke(self, context, event): + if self.from_invoke: + close_operator_panel(event) + return self.execute(context) def execute(self, context): return IfcStore.execute_ifc_operator(self, context) @@ -176,7 +192,7 @@ class AddTypeInstance(bpy.types.Operator): class DisplayIFCTypes(bpy.types.Operator): bl_idname = "bim.display_ifc_types" - bl_label = "Browse IFC Types" + bl_label = "Browse IFC Construction Types" bl_options = {"REGISTER", "UNDO"} bl_description = "Display all possible IFC types for new instances" @@ -188,67 +204,232 @@ class DisplayIFCTypes(bpy.types.Operator): if not AuthoringData.is_loaded: AuthoringData.load() props = context.scene.BIMModelProperties - props.relating_type = props.relating_type + if props.unfold_relating_type: + ifc_class = props.ifc_class + ifc_type_info = AuthoringData.ifc_type_info(ifc_class) + if ifc_type_info is None or not ifc_type_info.fully_loaded: + AuthoringData.assetize_ifc_class(ifc_class) + else: + prop.update_relating_type(props, context) min_width = 250 - width = max([min_width, int(context.region.width / 7)]) + width_scaling = 6. ** -1 + width = max([min_width, int(width_scaling * context.region.width)]) return context.window_manager.invoke_popup(self, width=width) def draw(self, context): - layout = self.layout props = context.scene.BIMModelProperties + if props.unfold_relating_type: + self.draw_by_class(props) + else: + self.draw_by_class_and_relating_type(props) + + def draw_header(self, props): + layout = self.layout split = layout.split(align=True, factor=0.6) - col = split.column(align=True) - row = col.row() - row.label(text="Select IFC Type to add:") - col.row().separator(factor=2) + col1 = split.column(align=True) + row = col1.row() + row.prop(data=props, property="unfold_relating_type", text="Preview All Relating Types") + col1.row().separator(factor=0.5) + row = col1.row() + row.label(text="Select IFC Construction Type:") + col1.row().separator(factor=2) enabled = True if AuthoringData.data["ifc_classes"]: - row = col.row() - row.prop(data=props, property="ifc_class", text="", icon="FILE_VOLUME") - col.row().separator() + row = col1.row() + row.label(text="", icon="FILE_VOLUME") + prop_with_search(row, props, "ifc_class", text="") + col1.row().separator() else: enabled = False + col2 = split.column(align=True) + subsplit = col2.split(factor=0.9) + subcol = [subsplit.column() for _ in range(2)][-1] + subcol.operator("bim.type_instance_help", text="", icon="QUESTION") + col2.row().separator(factor=1) + return {"enabled": enabled, "layout": layout, "col1": col1, "col2": col2} + + def draw_by_class(self, props): + header_data = self.draw_header(props) + enabled, layout = [header_data[key] for key in ["enabled", "layout"]] + ifc_class = props.ifc_class + num_cols = 3 + layout.row().separator(factor=0.25) + flow = layout.grid_flow(row_major=True, columns=num_cols, even_columns=True, even_rows=True, align=True) + relating_types = AuthoringData.relating_types() + num_types = len(relating_types) + for idx, (rt_id, name, desc) in enumerate(relating_types): + outer_col = flow.column() + box = outer_col.box() + row = box.row() + row.label(text=name, icon="FILE_3D") + row.alignment = "CENTER" + row = box.row() + if enabled: + preview_ifc_types = AuthoringData.data["preview_ifc_types"] + if ifc_class in preview_ifc_types: + preview_ifc_class = preview_ifc_types[ifc_class] + if name in preview_ifc_class: + icon_id = preview_ifc_class[name]["icon_id"] + row.template_icon(icon_value=icon_id, scale=6.) + outer_col.row().separator(factor=0.5) + row = outer_col.row() + split = row.split(factor=0.5) + col = split.column() + op = col.operator("bim.select_type_instance", icon="RIGHTARROW_THIN") + op.ifc_class = ifc_class + op.relating_type_id = rt_id + col = split.column() + op = col.operator("bim.add_type_instance", icon="ADD") + op.from_invoke = True + op.ifc_class = ifc_class + if rt_id.isnumeric(): + op.relating_type = int(rt_id) + factor = 2 if idx + 1 < math.ceil(num_types / num_cols) else 0.5 + outer_col.row().separator(factor=factor) + 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_class_and_relating_type(self, props): + header_data = self.draw_header(props) + enabled, col1, col2 = [header_data[key] for key in ["enabled", "col1", "col2"]] + ifc_class = props.ifc_class if AuthoringData.data["relating_types"]: - row = col.row() - row.prop(data=props, property="relating_type", text="", icon="FILE_3D") - col.row().separator() + row = col1.row() + row.label(text="", icon="FILE_3D") + prop_with_search(row, props, "relating_type", text="") + col1.row().separator() else: enabled = False - col.row().separator(factor=4) - row = col.row() - op = row.operator("bim.add_ifc_type_instance", icon="ADD") + col1.row().separator(factor=4.75) + row = col1.row() row.enabled = enabled - op.ifc_class = props.ifc_class + op = row.operator("bim.select_type_instance", icon="RIGHTARROW_THIN") + op.ifc_class = ifc_class op.relating_type_id = props.relating_type - col = split.column() - box = col.box() + op = row.operator("bim.add_type_instance", icon="ADD") + op.from_invoke = True + op.ifc_class = ifc_class + relating_type = props.relating_type + if relating_type.isnumeric(): + op.relating_type = int(relating_type) + box = col2.box() if enabled: box.template_icon(icon_value=props.icon_id, scale=6.) -class AddIFCTypeInstance(bpy.types.Operator): - bl_idname = "bim.add_ifc_type_instance" - bl_label = "Add" +class SelectTypeInstance(bpy.types.Operator): + bl_idname = "bim.select_type_instance" + bl_label = "Select" bl_options = {"REGISTER", "UNDO"} - bl_description = "Add an instance of this IFC type" + bl_description = "Pick Type Instance as selection for subsequent operations" ifc_class: bpy.props.StringProperty() relating_type_id: bpy.props.StringProperty() - def close_panel(self, event): - x, y = event.mouse_x, event.mouse_y - bpy.context.window.cursor_warp(10, 10) - move_back = lambda: bpy.context.window.cursor_warp(x, y) - bpy.app.timers.register(move_back, first_interval=0.001) - def invoke(self, context, event): - self.close_panel(event) + close_operator_panel(event) return self.execute(context) def execute(self, context): props = context.scene.BIMModelProperties - props.ifc_class, props.relating_type = self.ifc_class, self.relating_type_id - bpy.ops.bim.add_type_instance() - return {'FINISHED'} + if self.ifc_class != "": + props.ifc_class = self.ifc_class + if self.relating_type_id != "": + props.relating_type = self.relating_type_id + return {"FINISHED"} + + +class TypeInstanceHelp(bpy.types.Operator): + bl_idname = "bim.type_instance_help" + bl_label = "IFC Construction Type Help" + bl_options = {"REGISTER", "UNDO"} + bl_description = "Click to read some contextual help" + + def execute(self, context): + return {"FINISHED"} + + def invoke(self, context, event): + return context.window_manager.invoke_popup(self, width=525) + + def draw(self, context): + layout = self.layout + layout.row().separator(factor=0.5) + row = layout.row() + row.alignment = "CENTER" + row.label(text="BlenderBIM Help", icon="BLENDER") + row = layout.row() + row.alignment = "CENTER" + row.label(text="[IFC Construction Type Browser]") + layout.row().separator(factor=0.5) + row = self.col_with_margins(layout.row()).row() + row.label(text="When to use:", icon="KEYTYPE_MOVING_HOLD_VEC") + self.draw_lines(layout, self.message_purpose) + layout.row().separator() + row = self.col_with_margins(layout.row()).row() + row.label(text="Overall workflow:", icon="KEYTYPE_MOVING_HOLD_VEC") + self.draw_lines(layout, self.message_overall) + layout.row().separator() + row = self.col_with_margins(layout.row()).row() + row.label(text="UI panel hints:", icon="KEYTYPE_MOVING_HOLD_VEC") + self.draw_lines(layout, self.message_ui) + layout.row().separator(factor=1.5) + row = self.col_with_margins(layout.row()).row() + row.label(text="Further help:", icon="KEYTYPE_MOVING_HOLD_VEC") + layout.row().separator(factor=0.5) + row = self.col_with_margins(layout).row() + op = row.operator("bim.open_upstream", text="Homepage", icon="HOME") + op.page = "home" + op = row.operator("bim.open_upstream", text="Docs", icon="DOCUMENTS") + op.page = "docs" + op = row.operator("bim.open_upstream", text="Wiki", icon="CURRENT_FILE") + op.page = "wiki" + op = row.operator("bim.open_upstream", text="Community", icon="COMMUNITY") + op.page = "community" + layout.row().separator() + + @staticmethod + def col_with_margins(layout, margin_left=0.025, margin_right=None): + margin_right = margin_left if margin_right is None else margin_right + split = layout.split(factor=margin_left, align=True) + col = [split.column() for _ in range(2)][-1] + subsplit = col.split(factor=(1. - margin_right), align=True) + subcol = subsplit.column() + subsplit.column().label(text="") + return subcol + + def draw_lines(self, layout, lines): + box = self.col_with_margins(layout).box() + for line in lines: + row = box.row() + row.label(text="", icon="RIGHTARROW_THIN") + row.label(text=line) + + @property + def message_purpose(self): + return [ + 'Available IFC Construction Types can be previewed and added through the button', + '"Browse IFC Construction Types", which appears when an IFC Project Library,', + 'containing in turn definitions of construction types, is loaded. In order to ', + 'manage loaded IFC Project Libraries, navigate to [Scene Properties] -> [IFC', + 'Project Setup] -> [IFC Project Library] under the Properties panel.' + ] + + @property + def message_overall(self): + return [ + 'Choose an IFC Construction Type by picking 1) an IFC Class and 2) a Relating Type. ', + 'Then, click on the "Add" button to directly add one instance of the chosen type to', + 'the model, or alternatively click on the "Select" button to be able to later add ', + 'several instances with SHIFT + A.' + ] + + @property + def message_ui(self): + return [ + 'If "Preview All Relating Types" is marked, a preview for every Relating Type will', + 'be shown at once. Not advisable on large projects with dozens of types per class.' + ] class AlignProduct(bpy.types.Operator): diff --git a/src/blenderbim/blenderbim/bim/module/model/prop.py b/src/blenderbim/blenderbim/bim/module/model/prop.py index 5da1e67535..0276c6e13e 100644 --- a/src/blenderbim/blenderbim/bim/module/model/prop.py +++ b/src/blenderbim/blenderbim/bim/module/model/prop.py @@ -44,16 +44,25 @@ def update_icon_id(self, context): if ((ifc_class not in AuthoringData.data["preview_ifc_types"] or relating_type not in AuthoringData.data["preview_ifc_types"][ifc_class]) and relating_type is not None): - AuthoringData.assetize_relating_type_from_selection() + if not AuthoringData.assetize_relating_type_from_selection(): + return props = bpy.context.scene.BIMModelProperties props.icon_id = AuthoringData.data["preview_ifc_types"][ifc_class][relating_type]["icon_id"] def update_ifc_class(self, context): - AuthoringData.load_ifc_classes() - AuthoringData.load_relating_types() - self.relating_type = AuthoringData.data["relating_types"][0][0] - update_icon_id(self, context) + if not AuthoringData.updating: + AuthoringData.load_ifc_classes() + AuthoringData.load_relating_types() + props = context.scene.BIMModelProperties + if props.unfold_relating_type: + ifc_class = props.ifc_class + ifc_type_info = AuthoringData.ifc_type_info(ifc_class) + if ifc_type_info is None or not ifc_type_info.fully_loaded: + AuthoringData.assetize_ifc_class(ifc_class) + else: + self.relating_type = AuthoringData.data["relating_types"][0][0] + update_icon_id(self, context) def update_relating_type(self, context): @@ -61,26 +70,45 @@ def update_relating_type(self, context): update_icon_id(self, context) +def update_unfold_relating_type(self, context): + update_ifc_class(self, context) + + # if self.unfold_relating_type: + # props = context.scene.BIMModelProperties + # ifc_class = props.ifc_class + # ifc_type_info = AuthoringData.ifc_type_info(ifc_class) + # if ifc_type_info is None or not ifc_type_info.fully_loaded: + # AuthoringData.assetize_ifc_class(ifc_class) + # else: + # update_ifc_class(self, context) + + class BIMModelProperties(PropertyGroup): ifc_class: bpy.props.EnumProperty(items=get_ifc_class, name="IFC Class", update=update_ifc_class) relating_type: bpy.props.EnumProperty(items=get_relating_type, name="Relating Type", update=update_relating_type) icon_id: bpy.props.IntProperty() + unfold_relating_type: bpy.props.BoolProperty(update=update_unfold_relating_type) occurrence_name_style: bpy.props.EnumProperty( items=[("CLASS", "By Class", ""), ("TYPE", "By Type", ""), ("CUSTOM", "Custom", "")], name="Occurrence Name Style", ) occurrence_name_function: bpy.props.StringProperty(name="Occurrence Name Function") + getter_enum = { + "ifc_class": get_ifc_class, + "relating_type": get_relating_type + } def get_ifc_type_info_relating_types(self, context): - ifc_class = self.ifc_class + ifc_class = self.name return AuthoringData.relating_types(ifc_class=ifc_class) class IfcTypeInfo(PropertyGroup): - ifc_class: bpy.props.StringProperty(name="IFC class", description="IFC class") + name: bpy.props.StringProperty(name="IFC class", description="IFC class") relating_type: bpy.props.EnumProperty( name="Relating type", description="Relating type", items=get_ifc_type_info_relating_types ) + fully_loaded: bpy.props.BoolProperty(default=False) diff --git a/src/blenderbim/blenderbim/bim/module/model/ui.py b/src/blenderbim/blenderbim/bim/module/model/ui.py index 8a198ce7a1..dcdcf6655d 100644 --- a/src/blenderbim/blenderbim/bim/module/model/ui.py +++ b/src/blenderbim/blenderbim/bim/module/model/ui.py @@ -16,54 +16,15 @@ # You should have received a copy of the GNU General Public License # along with BlenderBIM Add-on. If not, see . -import blenderbim.bim.module.type.prop as type_prop from bpy.types import Panel -from blenderbim.bim.ifc import IfcStore -from blenderbim.bim.module.model.data import AuthoringData class BIM_PT_authoring(Panel): - bl_idname = "BIM_PT_authoring" - bl_label = "Authoring" - bl_space_type = "VIEW_3D" - bl_region_type = "UI" - bl_category = "BlenderBIM" - - @classmethod - def poll(cls, context): - return IfcStore.get_file() - - def draw(self, context): - if not AuthoringData.is_loaded: - AuthoringData.load() - - props = context.scene.BIMModelProperties - col = self.layout.column(align=True) - enabled = True - - if AuthoringData.data["ifc_classes"]: - col.prop(props, "ifc_class", text="", icon="FILE_VOLUME") - else: - col.label(text="No IFC Class", icon="FILE_VOLUME") - enabled = False - if AuthoringData.data["relating_types"]: - col.prop(props, "relating_type", text="", icon="FILE_3D") - else: - col.label(text="No Relating Type", icon="FILE_3D") - enabled = False - row = col.row() - row.operator("bim.add_type_instance", icon="ADD") - row.enabled = enabled - - -class BIM_PT_authoring_architectural(Panel): bl_label = "Architectural" - bl_idname = "BIM_PT_authoring_architectural" - bl_options = {"DEFAULT_CLOSED"} + bl_idname = "BIM_PT_authoring" bl_space_type = "VIEW_3D" bl_region_type = "UI" bl_category = "BlenderBIM" - bl_parent_id = "BIM_PT_authoring" def draw(self, context): row = self.layout.row(align=True) diff --git a/src/blenderbim/blenderbim/bim/module/model/workspace.py b/src/blenderbim/blenderbim/bim/module/model/workspace.py index 1f65486c12..003ea26aa3 100644 --- a/src/blenderbim/blenderbim/bim/module/model/workspace.py +++ b/src/blenderbim/blenderbim/bim/module/model/workspace.py @@ -37,6 +37,7 @@ class BimTool(WorkSpaceTool): bl_keymap = ( # ("bim.wall_tool_op", {"type": 'MOUSEMOVE', "value": 'ANY'}, {"properties": []}), # ("mesh.add_wall", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": []}), + ("bim.hotkey", {"type": "A", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_A")]}), ("bim.hotkey", {"type": "E", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_E")]}), ("bim.join_wall", {"type": "T", "value": "PRESS", "shift": True}, {"properties": [("join_type", "L")]}), ("bim.join_wall", {"type": "Y", "value": "PRESS", "shift": True}, {"properties": [("join_type", "V")]}), @@ -54,19 +55,52 @@ class BimTool(WorkSpaceTool): if not AuthoringData.is_loaded and IfcStore.get_file(): AuthoringData.load() + props = context.scene.BIMModelProperties + is_tool_header = context.region.type == "TOOL_HEADER" + ifc_classes = AuthoringData.data["ifc_classes"] + relating_types = AuthoringData.data["relating_types"] + row = layout.row(align=True) if not IfcStore.get_file(): row.label(text="No IFC Project", icon="ERROR") return - props = context.scene.BIMModelProperties - if AuthoringData.data["ifc_classes"]: - row.operator("bim.display_ifc_types", icon="COLLAPSEMENU") - else: - row.label(text="No IFC Class") - if not AuthoringData.data["relating_types"]: - row.label(text="No Relating Type") - row.label(text="", icon="BLANK1") + if is_tool_header: + row.operator("bim.type_instance_help", text="", icon="QUESTION") + + if ifc_classes and is_tool_header: + row.label(text="", icon="BLANK1") + row.operator("bim.display_ifc_types", icon="COLLAPSEMENU") + + ifc_class = props.ifc_class + relating_type = AuthoringData.relating_type_name_by_id(ifc_class, props.relating_type) + + if is_tool_header: + row.label(text="", icon="BLANK1") + row = layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="", icon="EVENT_A") + if ifc_classes: + row.label(text=f" Add") + row.label(text="", icon="FILE_VOLUME") + row.label(text=ifc_class) + row.label(text="", icon="FILE_3D") + row.label(text=f"{relating_type} ") + else: + row.label(text=f" Add instance") + else: + txt_ifc_class = ifc_class if ifc_classes else "No IFC Class" + txt_relating_type = relating_type if relating_types else "No Relating Type" + row = layout.row(align=True) + row.label(text="Selected IFC 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") + row = layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") + row.label(text="", icon="EVENT_A") + row.label(text=f" Add Type Instance") if AuthoringData.data["ifc_classes"]: if props.ifc_class == "IfcWallType": @@ -148,6 +182,9 @@ class Hotkey(bpy.types.Operator): getattr(self, f"hotkey_{self.hotkey}")() return {"FINISHED"} + def hotkey_S_A(self): + bpy.ops.bim.add_type_instance() + def hotkey_S_C(self): if self.has_ifc_class and self.props.ifc_class == "IfcWallType": bpy.ops.bim.align_wall(align_type="CENTERLINE")