diff --git a/src/bonsai/bonsai/bim/module/style/__init__.py b/src/bonsai/bonsai/bim/module/style/__init__.py index 7a343e7460..ba44a727b1 100644 --- a/src/bonsai/bonsai/bim/module/style/__init__.py +++ b/src/bonsai/bonsai/bim/module/style/__init__.py @@ -43,6 +43,7 @@ classes = ( operator.SaveUVToStyle, operator.SelectByStyle, operator.SelectStyleInStylesUI, + operator.SetAssetMaterialToExternalStyle, operator.UnlinkStyle, operator.UpdateCurrentStyle, operator.UpdateStyleColours, @@ -61,8 +62,10 @@ classes = ( def register(): bpy.types.Scene.BIMStylesProperties = bpy.props.PointerProperty(type=prop.BIMStylesProperties) bpy.types.Material.BIMStyleProperties = bpy.props.PointerProperty(type=prop.BIMStyleProperties) + bpy.types.ASSETBROWSER_MT_context_menu.append(ui.draw_asset_browser_context_menu_append) def unregister(): del bpy.types.Scene.BIMStylesProperties del bpy.types.Material.BIMStyleProperties + bpy.types.ASSETBROWSER_MT_context_menu.remove(ui.draw_asset_browser_context_menu_append) diff --git a/src/bonsai/bonsai/bim/module/style/operator.py b/src/bonsai/bonsai/bim/module/style/operator.py index 05f94f813a..b1b63ebca2 100644 --- a/src/bonsai/bonsai/bim/module/style/operator.py +++ b/src/bonsai/bonsai/bim/module/style/operator.py @@ -80,6 +80,7 @@ class RemoveStyle(bpy.types.Operator, tool.Ifc.Operator): style: bpy.props.IntProperty() def _execute(self, context): + core.disable_editing_style(tool.Style) # So we don't end up soft-locking style edition core.remove_style(tool.Ifc, tool.Style, style=tool.Ifc.get().by_id(self.style), reload_styles_ui=True) @@ -236,6 +237,35 @@ class UpdateCurrentStyle(bpy.types.Operator): return {"FINISHED"} +class SetAssetMaterialToExternalStyle(bpy.types.Operator): + bl_idname = "bim.set_asset_material_to_external_style" + bl_label = "Set To External Style" + bl_options = {"REGISTER", "UNDO"} + + def execute_delayed(self, name, filepath, props): + style_id = props.active_style.ifc_definition_id + bpy.ops.bim.enable_editing_surface_style(style=style_id, ifc_class="IfcExternallyDefinedSurfaceStyle") + bpy.ops.bim.browse_external_style( + data_block_type="materials", + data_block=name, + filepath=filepath, + active_surface_style_id=style_id, + use_relative_path=False, + ) + bpy.ops.bim.edit_surface_style() + + def execute(self, context): + # We delay execution because for some obscure reason we can't use + # the temp override to copy material node tree `right now` + name = context.asset.name + filepath = context.asset.full_library_path + bpy.app.timers.register( + lambda: self.execute_delayed(name, filepath, context.scene.BIMStylesProperties), + first_interval=0.001, + ) + return {"FINISHED"} + + class BrowseExternalStyle(bpy.types.Operator): bl_idname = "bim.browse_external_style" bl_label = "Browse External Style" diff --git a/src/bonsai/bonsai/bim/module/style/prop.py b/src/bonsai/bonsai/bim/module/style/prop.py index b99da24fa4..1221159be0 100644 --- a/src/bonsai/bonsai/bim/module/style/prop.py +++ b/src/bonsai/bonsai/bim/module/style/prop.py @@ -261,6 +261,11 @@ class BIMStylesProperties(PropertyGroup): styles: CollectionProperty(name="Styles", type=Style) active_style_index: IntProperty(name="Active Style Index") + + @property + def active_style(self): + return self.styles[self.active_style_index] if 0 <= self.active_style_index < len(self.styles) else None + active_style_type: EnumProperty( name="Active Style Type", description="Update current blender material to match style type for all objects in the scene", diff --git a/src/bonsai/bonsai/bim/module/style/ui.py b/src/bonsai/bonsai/bim/module/style/ui.py index 605cbef697..d793e7d801 100644 --- a/src/bonsai/bonsai/bim/module/style/ui.py +++ b/src/bonsai/bonsai/bim/module/style/ui.py @@ -52,7 +52,7 @@ class BIM_PT_styles(Panel): row.operator("bim.load_styles", text="", icon="IMPORT").style_type = style_type return - active_style = bool(self.props.styles and self.props.active_style_index < len(self.props.styles)) + active_style = self.props.active_style row = self.layout.row(align=True) row.label(text="{} {}s".format(len(self.props.styles), self.props.style_type), icon="SHADING_RENDERED") row.operator("bim.disable_editing_styles", text="", icon="CANCEL") @@ -62,7 +62,7 @@ class BIM_PT_styles(Panel): if not self.props.is_adding: row.operator("bim.enable_adding_presentation_style", text="", icon="ADD") if active_style: - style = self.props.styles[self.props.active_style_index] + style = active_style row.operator("bim.duplicate_style", text="", icon="DUPLICATE").style = style.ifc_definition_id row.operator("bim.select_by_style", text="", icon="RESTRICT_SELECT_OFF").style = style.ifc_definition_id @@ -237,7 +237,7 @@ class BIM_PT_styles(Panel): def draw_externally_defined_surface_style(self): row = self.layout.row() op = row.operator("bim.browse_external_style", icon="APPEND_BLEND", text="Append From Blend File") - style = self.props.styles[self.props.active_style_index] + style = self.props.active_style op.active_surface_style_id = style.ifc_definition_id bonsai.bim.helper.draw_attributes(self.props.external_style_attributes, self.layout) @@ -327,3 +327,12 @@ class BIM_PT_style(Panel): row = self.layout.row(align=True) row.label(text="IFC Style Name:") row.label(text=BlenderMaterialStyleData.data["linked_style_name"]) + + +def draw_asset_browser_context_menu_append(self, context): + asset = context.asset + if not asset or not asset.id_type == "MATERIAL": + return + if not context.scene.BIMStylesProperties.is_editing: + return + self.layout.operator("bim.set_asset_material_to_external_style") diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index ec1665eb5c..f6cb45e08e 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -943,10 +943,10 @@ class Blender(bonsai.core.tool.Blender): bpy.ops.bim.finish_editing_door() elif cls.is_editing_window_parameters(obj): bpy.ops.bim.finish_editing_window() - else: + else: return False return True - + @classmethod def try_canceling_editing_modifier_parameters_or_path(cls, obj: bpy.types.Object) -> bool: """Tries to cancel the current BIM modifier parameters or path edition for the active object @@ -972,45 +972,45 @@ class Blender(bonsai.core.tool.Blender): return True @classmethod - def is_eligible_for_railing_modifier(cls, obj: bpy.types.Object)-> bool: + def is_eligible_for_railing_modifier(cls, obj: bpy.types.Object) -> bool: return tool.Blender.is_object_an_ifc_class(obj, ("IfcRailing", "IfcRailingType")) @classmethod - def is_eligible_for_stair_modifier(cls, obj: bpy.types.Object)-> bool: + def is_eligible_for_stair_modifier(cls, obj: bpy.types.Object) -> bool: return tool.Blender.is_object_an_ifc_class( obj, ("IfcStairFlight", "IfcStairFlightType", "IfcMember", "IfcMemberType", "IfcStair", "IfcStairType") ) @classmethod - def is_eligible_for_window_modifier(cls, obj: bpy.types.Object)-> bool: + def is_eligible_for_window_modifier(cls, obj: bpy.types.Object) -> bool: return tool.Blender.is_object_an_ifc_class(obj, ("IfcWindow", "IfcWindowType", "IfcWindowStyle")) @classmethod - def is_eligible_for_door_modifier(cls, obj: bpy.types.Object)-> bool: + def is_eligible_for_door_modifier(cls, obj: bpy.types.Object) -> bool: return tool.Blender.is_object_an_ifc_class(obj, ("IfcDoor", "IfcDoorType", "IfcDoorStyle")) @classmethod - def is_eligible_for_roof_modifier(cls, obj: bpy.types.Object)-> bool: + def is_eligible_for_roof_modifier(cls, obj: bpy.types.Object) -> bool: return tool.Blender.is_object_an_ifc_class(obj, ("IfcRoof", "IfcRoofType")) @classmethod - def is_railing(cls, element: entity_instance)-> bool: + def is_railing(cls, element: entity_instance) -> bool: return tool.Pset.get_element_pset(element, "BBIM_Railing") @classmethod - def is_roof(cls, element: entity_instance)-> bool: + def is_roof(cls, element: entity_instance) -> bool: return tool.Pset.get_element_pset(element, "BBIM_Roof") @classmethod - def is_window(cls, element: entity_instance)-> bool: + def is_window(cls, element: entity_instance) -> bool: return tool.Pset.get_element_pset(element, "BBIM_Window") @classmethod - def is_door(cls, element: entity_instance)-> bool: + def is_door(cls, element: entity_instance) -> bool: return tool.Pset.get_element_pset(element, "BBIM_Door") @classmethod - def is_stair(cls, element: entity_instance)-> bool: + def is_stair(cls, element: entity_instance) -> bool: return tool.Pset.get_element_pset(element, "BBIM_Stair") @classmethod @@ -1018,31 +1018,31 @@ class Blender(bonsai.core.tool.Blender): return obj.BIMRailingProperties.is_editing_path @classmethod - def is_editing_roof_path(cls, obj: bpy.types.Object)-> bool: + def is_editing_roof_path(cls, obj: bpy.types.Object) -> bool: return obj.BIMRoofProperties.is_editing_path @classmethod - def is_editing_railing_parameters(cls, obj: bpy.types.Object)-> bool: + def is_editing_railing_parameters(cls, obj: bpy.types.Object) -> bool: return obj.BIMRailingProperties.is_editing @classmethod - def is_editing_roof_parameters(cls, obj: bpy.types.Object)-> bool: + def is_editing_roof_parameters(cls, obj: bpy.types.Object) -> bool: return obj.BIMRoofProperties.is_editing @classmethod - def is_editing_window_parameters(cls, obj: bpy.types.Object)-> bool: + def is_editing_window_parameters(cls, obj: bpy.types.Object) -> bool: return obj.BIMWindowProperties.is_editing @classmethod - def is_editing_door_parameters(cls, obj: bpy.types.Object)-> bool: + def is_editing_door_parameters(cls, obj: bpy.types.Object) -> bool: return obj.BIMDoorProperties.is_editing @classmethod - def is_editing_stair_parameters(cls, obj: bpy.types.Object)-> bool: + def is_editing_stair_parameters(cls, obj: bpy.types.Object) -> bool: return obj.BIMStairProperties.is_editing @classmethod - def is_modifier_with_non_editable_path(cls, element: entity_instance)-> bool: + def is_modifier_with_non_editable_path(cls, element: entity_instance) -> bool: return cls.is_stair(element) or cls.is_door(element) or cls.is_window(element) class Array: diff --git a/src/bonsai/bonsai/tool/style.py b/src/bonsai/bonsai/tool/style.py index c4dff46fb1..359386b25a 100644 --- a/src/bonsai/bonsai/tool/style.py +++ b/src/bonsai/bonsai/tool/style.py @@ -116,9 +116,7 @@ class Style(bonsai.core.tool.Style): @classmethod def get_active_style_in_ui(cls) -> Union[bpy.types.PropertyGroup, None]: props = bpy.context.scene.BIMStylesProperties - if len(props.styles) > props.active_style_index >= 0: - return props.styles[props.active_style_index] - return None + return props.active_style @classmethod def get_active_style_type(cls) -> str: