mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-07 08:21:42 +00:00
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:
@@ -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"])
|
||||
|
||||
Reference in New Issue
Block a user