Small UI in Blender material properties tab with unlinking #4843

Example - https://i.imgur.com/7VqIowz.png

This tab is needed only to indicate whether style is linked to some IFC element and to unlink it. Unlinking from Blender material makes much more sense as you can see from this tab what you're actually unlinking.
Unlinking for styles now works very similar to how it works for objects.
This commit is contained in:
Andrej730
2024-06-24 18:19:53 +05:00
parent c37240cf96
commit a0e5d350bd
4 changed files with 135 additions and 6 deletions
@@ -52,6 +52,7 @@ classes = (
prop.BIMStyleProperties,
ui.BIM_PT_styles,
ui.BIM_UL_styles,
ui.BIM_PT_style,
)
@@ -20,10 +20,12 @@ import bpy
import ifcopenshell
import blenderbim.tool as tool
from ifcopenshell.util.doc import get_entity_doc
from typing import Union
def refresh():
StylesData.is_loaded = False
BlenderMaterialStyleData.is_loaded = False
class StylesData:
@@ -67,3 +69,55 @@ class StylesData:
@classmethod
def total_styles(cls):
return len(tool.Ifc.get().by_type("IfcPresentationStyle"))
class BlenderMaterialStyleData:
style: Union[ifcopenshell.entity_instance, None] = None
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {
"is_linked_to_style": cls.is_linked_to_style(),
# After is_linked_to_style.
"linked_style_name": cls.linked_style_name(),
}
cls.is_loaded = True
@classmethod
def is_linked_to_style(cls) -> bool:
ifc_file = tool.Ifc.get()
if not ifc_file:
return False
context = bpy.context
cls.linked_style = None
obj = context.active_object
if not obj:
return False
material = obj.active_material
if not material:
return False
props = material.BIMMaterialProperties
style_id = props.ifc_style_id
style = tool.Ifc.get_entity_by_id(style_id)
if not style:
return False
# Double check that it's the right material
# and not material from other Blender session.
linked_material = tool.Ifc.get_object(style)
if linked_material != material:
return False
cls.style = style
return True
@classmethod
def linked_style_name(cls) -> Union[str, None]:
"""Return str if Blender Material is linked to IFC style or None if it's not.
Method will return "Unnamed" if style name is None.
"""
if cls.style:
return cls.style.Name or "Unnamed"
return None
@@ -96,11 +96,48 @@ class AddStyle(bpy.types.Operator, tool.Ifc.Operator):
class UnlinkStyle(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.unlink_style"
bl_label = "Unlink Style"
bl_description = (
"Unlink Blender material from it's linked IFC style.\n\n"
"You can either remove style the material is linked to from IFC or keep it. "
"Note that keeping the unlinked style in IFC might lead to unpredictable issues"
"and should be used only by advanced users"
)
bl_options = {"REGISTER", "UNDO"}
style: bpy.props.IntProperty(default=0)
blender_material: bpy.props.StringProperty(name="Blender Material")
should_delete: bpy.props.BoolProperty(name="Delete IFC Style", default=True)
def draw(self, context):
row = self.layout.row()
row.prop(self, "should_delete")
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self)
def _execute(self, context):
core.unlink_style(tool.Ifc, style=tool.Ifc.get().by_id(self.style))
# TODO: move to core.style
# Don't check blender_material and style_id as this operator is only called from UI.
assert isinstance(self.blender_material, str) # Type checker.
material = bpy.data.materials[self.blender_material]
style_id = material.BIMMaterialProperties.ifc_style_id
style = tool.Ifc.get_entity_by_id(style_id)
# Material is linked to a style from a different project.
if not style or tool.Ifc.get_object(style) != material:
tool.Ifc.unlink(obj=material)
return {"FINISHED"}
if self.should_delete:
# Create a copy that will be removed
# and leave user with unlinked original material.
# It's needed so we don't need to search everywhere original
# material was used and replace it with the unlinked version.
material_copy = material.copy()
tool.Ifc.unlink(element=style)
tool.Ifc.link(style, material_copy)
core.remove_style(tool.Ifc, tool.Style, style)
else:
tool.Ifc.unlink(element=style)
return {"FINISHED"}
class EnableEditingStyle(bpy.types.Operator, tool.Ifc.Operator):
@@ -21,8 +21,7 @@ import blenderbim.bim.helper
import blenderbim.tool as tool
from bpy.types import Panel, UIList
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.style.data import StylesData
from bl_ui.properties_material import MaterialButtonsPanel
from blenderbim.bim.module.style.data import StylesData, BlenderMaterialStyleData
class BIM_PT_styles(Panel):
@@ -67,8 +66,6 @@ class BIM_PT_styles(Panel):
row.operator("bim.select_by_style", text="", icon="RESTRICT_SELECT_OFF").style = style.ifc_definition_id
op = row.operator("bim.assign_style_to_selected", text="", icon="BRUSH_DATA")
op.style_id = style.ifc_definition_id
op = row.operator("bim.unlink_style", text="", icon="UNLINKED")
op.style = style.ifc_definition_id
op = row.operator("bim.enable_editing_style", text="", icon="GREASEPENCIL")
op.style = style.ifc_definition_id
row.operator("bim.remove_style", text="", icon="X").style = style.ifc_definition_id
@@ -291,3 +288,43 @@ class BIM_UL_styles(UIList):
row2.label(text="", icon="LIGHT_POINT")
elif style.name == "IfcExternallyDefinedSurfaceStyle":
row2.label(text="", icon="APPEND_BLEND")
class BIM_PT_style(Panel):
bl_label = "Style"
bl_idname = "BIM_PT_style"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "material"
@classmethod
def poll(cls, context):
return bool(tool.Ifc.get() and context.material.BIMMaterialProperties.ifc_style_id)
def draw(self, context):
# NOTE: this UI is needed only to indicate whether blender material is linked to IFC
# and shouldn't be overloaded with any other features (they should be added to the general Styles UI).
if not BlenderMaterialStyleData.is_loaded:
BlenderMaterialStyleData.load()
material = context.material
style_id = material.BIMMaterialProperties.ifc_style_id
row = self.layout.row(align=True)
if style_id and not BlenderMaterialStyleData.data["is_linked_to_style"]:
row.label(text="Material has linked IFC from a different project.")
op = row.operator("bim.unlink_style", icon="UNLINKED", text="")
op.blender_material = material.name
return
else:
row.label(text="Material is linked to an IFC style.")
op = row.operator("bim.unlink_style", icon="UNLINKED", text="")
op.blender_material = material.name
row = self.layout.row(align=True)
row.label(text="IFC Style ID:")
row.label(text=str(style_id))
row = self.layout.row(align=True)
row.label(text="IFC Style Name:")
row.label(text=BlenderMaterialStyleData.data["linked_style_name"])