mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 10:06:47 +00:00
Fix #4854. Make IFC edit mode toggle dynamic to prevent editing uneditable things.
This commit is contained in:
@@ -24,6 +24,7 @@ from mathutils import Vector
|
||||
|
||||
|
||||
def refresh():
|
||||
ViewportData.is_loaded = False
|
||||
PlacementData.is_loaded = False
|
||||
DerivedCoordinatesData.is_loaded = False
|
||||
RepresentationsData.is_loaded = False
|
||||
@@ -31,6 +32,28 @@ def refresh():
|
||||
ConnectionsData.is_loaded = False
|
||||
|
||||
|
||||
class ViewportData:
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.is_loaded = True
|
||||
cls.data = {"mode": cls.mode()}
|
||||
|
||||
@classmethod
|
||||
def mode(cls):
|
||||
obj = bpy.context.active_object
|
||||
obj_mode = [("OBJECT", "IFC Object Mode", "", "OBJECT_DATAMODE", 0)]
|
||||
mesh_modes = [
|
||||
("OBJECT", "IFC Object Mode", "", "OBJECT_DATAMODE", 0),
|
||||
("EDIT", "IFC Edit Mode", "", "EDITMODE_HLT", 1),
|
||||
]
|
||||
if not obj or not tool.Blender.is_editable(obj):
|
||||
return obj_mode
|
||||
return mesh_modes
|
||||
|
||||
|
||||
class RepresentationsData:
|
||||
data = {}
|
||||
is_loaded = False
|
||||
@@ -334,11 +357,13 @@ class PlacementData:
|
||||
obj = bpy.context.active_object
|
||||
if obj and props.has_blender_offset:
|
||||
xyz = cls.original_xyz(obj)
|
||||
cls.data.update({
|
||||
"original_x": str(xyz[0]),
|
||||
"original_y": str(xyz[1]),
|
||||
"original_z": str(xyz[2]),
|
||||
})
|
||||
cls.data.update(
|
||||
{
|
||||
"original_x": str(xyz[0]),
|
||||
"original_y": str(xyz[1]),
|
||||
"original_z": str(xyz[2]),
|
||||
}
|
||||
)
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -1531,7 +1531,7 @@ class OverrideModeSetEdit(bpy.types.Operator):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
selected_objs = context.selected_objects or ([context.active_object] if context.active_object else [])
|
||||
selected_objs = tool.Blender.get_selected_objects()
|
||||
active_obj = context.active_object
|
||||
|
||||
if context.active_object:
|
||||
@@ -1542,23 +1542,13 @@ class OverrideModeSetEdit(bpy.types.Operator):
|
||||
return bpy.ops.bim.enable_editing_boundary_geometry()
|
||||
|
||||
for obj in selected_objs:
|
||||
if not obj:
|
||||
continue
|
||||
obj_supports_edit_mode, message = tool.Blender.object_supports_edit_mode(obj)
|
||||
if not obj_supports_edit_mode:
|
||||
self.report({"INFO"}, message)
|
||||
if not tool.Blender.is_editable(obj):
|
||||
self.report({"INFO"}, f"Object cannot be edited: {obj.name}")
|
||||
obj.select_set(False)
|
||||
continue
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
continue
|
||||
usage_type = tool.Model.get_usage_type(element)
|
||||
if usage_type is not None and usage_type not in ("PROFILE", "LAYER3"):
|
||||
# Parametric objects shall not be edited as meshes as they
|
||||
# can be modified to be incompatible with the parametric
|
||||
# constraints.
|
||||
obj.select_set(False)
|
||||
continue
|
||||
representation = tool.Geometry.get_active_representation(obj)
|
||||
if not representation:
|
||||
continue
|
||||
@@ -1566,6 +1556,7 @@ class OverrideModeSetEdit(bpy.types.Operator):
|
||||
obj.select_set(False)
|
||||
continue
|
||||
|
||||
usage_type = tool.Model.get_usage_type(element)
|
||||
is_profile = True
|
||||
representation_class = tool.Geometry.get_ifc_representation_class(element, representation)
|
||||
if usage_type == "PROFILE":
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
import bpy
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from blenderbim.bim.module.geometry.data import RepresentationsData
|
||||
from blenderbim.bim.module.geometry.data import RepresentationsData, ViewportData
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -48,6 +48,12 @@ def update_mode(self, context):
|
||||
bpy.ops.bim.override_mode_set_edit("INVOKE_DEFAULT")
|
||||
|
||||
|
||||
def get_mode(self, context):
|
||||
if not ViewportData.is_loaded:
|
||||
ViewportData.load()
|
||||
return ViewportData.data["mode"]
|
||||
|
||||
|
||||
def get_styles(self, context):
|
||||
# postponed import to avoid circular import
|
||||
from blenderbim.bim.module.material.data import MaterialsData
|
||||
@@ -129,13 +135,5 @@ class BIMGeometryProperties(PropertyGroup):
|
||||
# Navisworks workaround
|
||||
should_force_triangulation: BoolProperty(name="Force Triangulation", default=False)
|
||||
is_changing_mode: BoolProperty(name="Is Changing Mode", default=False)
|
||||
mode: EnumProperty(
|
||||
default="OBJECT",
|
||||
items=[
|
||||
("OBJECT", "IFC Object Mode", "", "OBJECT_DATAMODE", 0),
|
||||
("EDIT", "IFC Edit Mode", "", "EDITMODE_HLT", 1),
|
||||
],
|
||||
name="IFC Interaction Mode",
|
||||
update=update_mode,
|
||||
)
|
||||
mode: EnumProperty(items=get_mode, name="IFC Interaction Mode", update=update_mode)
|
||||
representation_from_object: PointerProperty(type=bpy.types.Object)
|
||||
|
||||
@@ -131,8 +131,12 @@ class Blender(blenderbim.core.tool.Blender):
|
||||
@classmethod
|
||||
def get_selected_objects(cls) -> set[bpy.types.Object]:
|
||||
if bpy.context.selected_objects:
|
||||
return set(bpy.context.selected_objects + [bpy.context.active_object])
|
||||
return set([bpy.context.active_object])
|
||||
if active_obj := bpy.context.active_object:
|
||||
return set(bpy.context.selected_objects + [active_obj])
|
||||
return set(bpy.context.selected_objects)
|
||||
if active_obj := bpy.context.active_object:
|
||||
return {active_obj}
|
||||
return set()
|
||||
|
||||
@classmethod
|
||||
def create_ifc_object(
|
||||
@@ -666,8 +670,7 @@ class Blender(blenderbim.core.tool.Blender):
|
||||
return bpy.ops.object.mode_set(mode="EDIT", toggle=True)
|
||||
elif ao.type in cls.OBJECT_TYPES_THAT_SUPPORT_EDIT_GPENCIL_MODE:
|
||||
return bpy.ops.object.mode_set(mode="EDIT_GPENCIL", toggle=True)
|
||||
else:
|
||||
return {"CANCELLED"}
|
||||
return {"CANCELLED"}
|
||||
|
||||
@classmethod
|
||||
def is_object_an_ifc_class(cls, obj: bpy.types.Object, classes: Iterable[str]) -> bool:
|
||||
@@ -766,12 +769,19 @@ class Blender(blenderbim.core.tool.Blender):
|
||||
return collections_mapping
|
||||
|
||||
@classmethod
|
||||
def object_supports_edit_mode(cls, obj):
|
||||
if not obj.data:
|
||||
return False, "Can't Edit Empty Object"
|
||||
def is_editable(cls, obj):
|
||||
if obj.type not in cls.OBJECT_TYPES_THAT_SUPPORT_EDIT_MODE:
|
||||
return False
|
||||
if not (element := tool.Ifc.get_entity(obj)):
|
||||
return True
|
||||
if obj in bpy.context.scene.BIMProjectProperties.clipping_planes_objs:
|
||||
return False, "Can't Edit Clipping Plane Geometry"
|
||||
return True, ""
|
||||
return False
|
||||
usage_type = tool.Model.get_usage_type(element)
|
||||
if usage_type in ("LAYER1", "LAYER2"):
|
||||
# At the moment, these type types of parametric elements (walls,
|
||||
# and "blocks") cannot be edited as a mesh-like object.
|
||||
return False
|
||||
return True
|
||||
|
||||
class Modifier:
|
||||
@classmethod
|
||||
|
||||
Reference in New Issue
Block a user