mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
Exiting current editing decorator if user switches from EDIT mode
Switching from EDIT mode acts like canceling editing which seems intuitive. Now it's also possible to add similar thing to other use of decorators - beware of the possible Blender bug - mentioned it in `ProfileDecorator.install description` Added this change to editing of profiles, extrusion axis, roof and railing paths, extrusion profiles.
This commit is contained in:
@@ -42,12 +42,16 @@ class ProfileDecorator:
|
||||
installed = None
|
||||
|
||||
@classmethod
|
||||
def install(cls, context, get_custom_bmesh=None, draw_faces=False):
|
||||
def install(cls, context, get_custom_bmesh=None, draw_faces=False, exit_edit_mode_callback=None):
|
||||
"""Note that operators that change mesh in `exit_edit_mode_callback` can freeze blender.
|
||||
The workaround is to move their code to function and use it for callback.
|
||||
|
||||
Example: https://devtalk.blender.org/t/calling-operator-that-saves-bmesh-freezes-blender-forever/28595"""
|
||||
if cls.installed:
|
||||
cls.uninstall()
|
||||
handler = cls()
|
||||
cls.installed = SpaceView3D.draw_handler_add(
|
||||
handler, (context, get_custom_bmesh, draw_faces), "WINDOW", "POST_VIEW"
|
||||
handler, (context, get_custom_bmesh, draw_faces, exit_edit_mode_callback), "WINDOW", "POST_VIEW"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@@ -76,10 +80,13 @@ class ProfileDecorator:
|
||||
face_indices = [[v.index for v in f.verts] for f in traingulated_bm.faces]
|
||||
self.create_batch("TRIS", vertices_coords, faces_color, face_indices)
|
||||
|
||||
def __call__(self, context, get_custom_bmesh=None, draw_faces=False):
|
||||
def __call__(self, context, get_custom_bmesh=None, draw_faces=False, exit_edit_mode_callback=None):
|
||||
obj = context.active_object
|
||||
|
||||
if obj.mode != "EDIT":
|
||||
if exit_edit_mode_callback:
|
||||
ProfileDecorator.uninstall()
|
||||
exit_edit_mode_callback()
|
||||
return
|
||||
|
||||
if get_custom_bmesh:
|
||||
|
||||
@@ -938,12 +938,32 @@ class EnableEditingExtrusionAxis(bpy.types.Operator, tool.Ifc.Operator):
|
||||
tool.Model.import_axis([Vector((0, 0, 0)), direction * extrusion.Depth], obj=obj, position=position)
|
||||
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
ProfileDecorator.install(context)
|
||||
ProfileDecorator.install(context, exit_edit_mode_callback=lambda: disable_editing_extrusion_axis(context))
|
||||
if not bpy.app.background:
|
||||
bpy.ops.wm.tool_set_by_id(tool.Blender.get_viewport_context(), name="bim.cad_tool")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
def disable_editing_extrusion_axis(context):
|
||||
ProfileDecorator.uninstall()
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
|
||||
obj = context.active_object
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||
|
||||
blenderbim.core.geometry.switch_representation(
|
||||
tool.Ifc,
|
||||
tool.Geometry,
|
||||
obj=obj,
|
||||
representation=body,
|
||||
should_reload=True,
|
||||
is_global=True,
|
||||
should_sync_changes_first=False,
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableEditingExtrusionAxis(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.disable_editing_extrusion_axis"
|
||||
bl_label = "Disable Editing Extrusion Axis"
|
||||
@@ -954,23 +974,7 @@ class DisableEditingExtrusionAxis(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return context.selected_objects
|
||||
|
||||
def _execute(self, context):
|
||||
ProfileDecorator.uninstall()
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
|
||||
obj = context.active_object
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||
|
||||
blenderbim.core.geometry.switch_representation(
|
||||
tool.Ifc,
|
||||
tool.Geometry,
|
||||
obj=obj,
|
||||
representation=body,
|
||||
should_reload=True,
|
||||
is_global=True,
|
||||
should_sync_changes_first=False,
|
||||
)
|
||||
return {"FINISHED"}
|
||||
return disable_editing_extrusion_axis()
|
||||
|
||||
|
||||
class EditExtrusionAxis(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
@@ -364,26 +364,30 @@ class EnableEditingRailingPath(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if bpy.context.object.mode != "EDIT":
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
bpy.ops.wm.tool_set_by_id(tool.Blender.get_viewport_context(), name="bim.cad_tool")
|
||||
ProfileDecorator.install(context)
|
||||
ProfileDecorator.install(context, exit_edit_mode_callback=lambda: cancel_editing_railing_path(context))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
def cancel_editing_railing_path(context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMRailingProperties
|
||||
|
||||
ProfileDecorator.uninstall()
|
||||
props.is_editing_path = False
|
||||
|
||||
update_railing_modifier_bmesh(context)
|
||||
if bpy.context.object.mode == "EDIT":
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CancelEditingRailingPath(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.cancel_editing_railing_path"
|
||||
bl_label = "Cancel Editing Railing Path"
|
||||
bl_options = {"REGISTER"}
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMRailingProperties
|
||||
|
||||
ProfileDecorator.uninstall()
|
||||
props.is_editing_path = False
|
||||
|
||||
update_railing_modifier_bmesh(context)
|
||||
if bpy.context.object.mode == "EDIT":
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
return {"FINISHED"}
|
||||
return cancel_editing_railing_path(context)
|
||||
|
||||
|
||||
class FinishEditingRailingPath(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
@@ -215,7 +215,7 @@ def generate_hiped_roof_bmesh(bm, mode="ANGLE", height=1.0, angle=pi / 18, mutat
|
||||
|
||||
# find footprint edges
|
||||
for edge in bm.edges:
|
||||
if all(float_is_zero(v.co.z-footprint_z) for v in edge.verts):
|
||||
if all(float_is_zero(v.co.z - footprint_z) for v in edge.verts):
|
||||
footprint_edges.append(edge)
|
||||
footprint_verts.update(edge.verts)
|
||||
|
||||
@@ -557,26 +557,35 @@ class EnableEditingRoofPath(bpy.types.Operator, tool.Ifc.Operator):
|
||||
tool.Blender.bmesh_join(main_bm, second_bm, callback=mark_preview_edges)
|
||||
return main_bm
|
||||
|
||||
ProfileDecorator.install(context, get_custom_bmesh, draw_faces=True)
|
||||
ProfileDecorator.install(
|
||||
context,
|
||||
get_custom_bmesh,
|
||||
draw_faces=True,
|
||||
exit_edit_mode_callback=lambda: cancel_editing_roof_path(context),
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
def cancel_editing_roof_path(context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMRoofProperties
|
||||
|
||||
ProfileDecorator.uninstall()
|
||||
props.is_editing_path = False
|
||||
|
||||
update_roof_modifier_bmesh(context)
|
||||
if bpy.context.object.mode == "EDIT":
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CancelEditingRoofPath(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.cancel_editing_roof_path"
|
||||
bl_label = "Cancel Editing Roof Path"
|
||||
bl_options = {"REGISTER"}
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMRoofProperties
|
||||
|
||||
ProfileDecorator.uninstall()
|
||||
props.is_editing_path = False
|
||||
|
||||
update_roof_modifier_bmesh(context)
|
||||
if bpy.context.object.mode == "EDIT":
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
return {"FINISHED"}
|
||||
return cancel_editing_roof_path(context)
|
||||
|
||||
|
||||
class FinishEditingRoofPath(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
@@ -554,6 +554,26 @@ class DisableEditingSketchExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
def disable_editing_extrusion_profile(context):
|
||||
ProfileDecorator.uninstall()
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
|
||||
obj = context.active_object
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||
|
||||
blenderbim.core.geometry.switch_representation(
|
||||
tool.Ifc,
|
||||
tool.Geometry,
|
||||
obj=obj,
|
||||
representation=body,
|
||||
should_reload=True,
|
||||
is_global=True,
|
||||
should_sync_changes_first=False,
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableEditingExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.disable_editing_extrusion_profile"
|
||||
bl_label = "Disable Editing Extrusion Profile"
|
||||
@@ -564,23 +584,7 @@ class DisableEditingExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return context.selected_objects
|
||||
|
||||
def _execute(self, context):
|
||||
ProfileDecorator.uninstall()
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
|
||||
obj = context.active_object
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||
|
||||
blenderbim.core.geometry.switch_representation(
|
||||
tool.Ifc,
|
||||
tool.Geometry,
|
||||
obj=obj,
|
||||
representation=body,
|
||||
should_reload=True,
|
||||
is_global=True,
|
||||
should_sync_changes_first=False,
|
||||
)
|
||||
return {"FINISHED"}
|
||||
return disable_editing_extrusion_profile(context)
|
||||
|
||||
|
||||
class EnableEditingExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
@@ -611,7 +615,7 @@ class EnableEditingExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
tool.Model.import_profile(extrusion.SweptArea, obj=obj, position=position)
|
||||
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
ProfileDecorator.install(context)
|
||||
ProfileDecorator.install(context, exit_edit_mode_callback=lambda: disable_editing_extrusion_profile(context))
|
||||
if not bpy.app.background:
|
||||
bpy.ops.wm.tool_set_by_id(tool.Blender.get_viewport_context(), name="bim.cad_tool")
|
||||
return {"FINISHED"}
|
||||
@@ -648,7 +652,9 @@ class EditExtrusionProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
self.layout.label(text="INVALID PROFILE")
|
||||
|
||||
bpy.context.window_manager.popup_menu(msg, title="Error", icon="ERROR")
|
||||
ProfileDecorator.install(context)
|
||||
ProfileDecorator.install(
|
||||
context, exit_edit_mode_callback=lambda: disable_editing_extrusion_profile(context)
|
||||
)
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
return
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import blenderbim.tool as tool
|
||||
import blenderbim.bim.module.model.profile as model_profile
|
||||
from blenderbim.bim.module.model.decorator import ProfileDecorator
|
||||
from blenderbim.bim.module.profile.prop import generate_thumbnail_for_active_profile
|
||||
from blenderbim.bim.module.profile.data import refresh
|
||||
|
||||
|
||||
class LoadProfiles(bpy.types.Operator):
|
||||
@@ -138,21 +139,29 @@ class EnableEditingArbitraryProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bpy.context.scene.collection.objects.link(obj)
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
ProfileDecorator.install(context)
|
||||
ProfileDecorator.install(context, exit_edit_mode_callback=lambda: disable_editing_arbitrary_profile(context))
|
||||
bpy.ops.wm.tool_set_by_id(tool.Blender.get_viewport_context(), name="bim.cad_tool")
|
||||
|
||||
|
||||
def disable_editing_arbitrary_profile(context):
|
||||
obj = context.active_object
|
||||
if obj and obj.data and obj.data.BIMMeshProperties.subshape_type == "PROFILE":
|
||||
ProfileDecorator.uninstall()
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
bpy.data.objects.remove(obj)
|
||||
|
||||
# need to update profile manager ui
|
||||
# if this was called from decorator
|
||||
refresh()
|
||||
|
||||
|
||||
class DisableEditingArbitraryProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.disable_editing_arbitrary_profile"
|
||||
bl_label = "Disable Editing Arbitrary Profile"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
if obj and obj.data and obj.data.BIMMeshProperties.subshape_type == "PROFILE":
|
||||
ProfileDecorator.uninstall()
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
bpy.data.objects.remove(obj)
|
||||
return disable_editing_arbitrary_profile(context)
|
||||
|
||||
|
||||
class EditArbitraryProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
@@ -176,7 +185,9 @@ class EditArbitraryProfile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
self.layout.label(text="INVALID PROFILE: " + indices[1])
|
||||
|
||||
bpy.context.window_manager.popup_menu(msg, title="Error", icon="ERROR")
|
||||
ProfileDecorator.install(context)
|
||||
ProfileDecorator.install(
|
||||
context, exit_edit_mode_callback=lambda: disable_editing_arbitrary_profile(context)
|
||||
)
|
||||
bpy.ops.object.mode_set(mode="EDIT")
|
||||
return
|
||||
|
||||
|
||||
Reference in New Issue
Block a user