Fix #4854. Make IFC edit mode toggle dynamic to prevent editing uneditable things.

This commit is contained in:
Dion Moult
2024-06-15 16:40:53 +10:00
parent 1db26aab15
commit 3a6cf0e5ae
4 changed files with 61 additions and 37 deletions
@@ -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)
+19 -9
View File
@@ -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