Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Inch <mythologylover75@gmail.com>2021-03-16 23:57:56 +0300
committerRyan Inch <mythologylover75@gmail.com>2021-03-17 00:03:51 +0300
commit88db9c67be6b851ca1a0edf9afab35531f5b1961 (patch)
tree271f2ec1d3ec0a4c60485396854fd24f33d4f5a8 /object_collection_manager
parente24ff87b48445467f673641504fde759da531148 (diff)
Collection Manager: Add undo support. Task: T69577
Add undo and redo buttons to the CM popup. These buttons use operators that wrap the internal undo/redo operators with handling of CM internal data.
Diffstat (limited to 'object_collection_manager')
-rw-r--r--object_collection_manager/__init__.py2
-rw-r--r--object_collection_manager/cm_init.py2
-rw-r--r--object_collection_manager/internals.py74
-rw-r--r--object_collection_manager/operators.py47
-rw-r--r--object_collection_manager/ui.py77
5 files changed, 133 insertions, 69 deletions
diff --git a/object_collection_manager/__init__.py b/object_collection_manager/__init__.py
index 392c8d73..246e6bd7 100644
--- a/object_collection_manager/__init__.py
+++ b/object_collection_manager/__init__.py
@@ -22,7 +22,7 @@ bl_info = {
"name": "Collection Manager",
"description": "Manage collections and their objects",
"author": "Ryan Inch",
- "version": (2, 19, 3),
+ "version": (2, 20, 0),
"blender": (2, 80, 0),
"location": "View3D - Object Mode (Shortcut - M)",
"warning": '', # used for warning icon and text in addons panel
diff --git a/object_collection_manager/cm_init.py b/object_collection_manager/cm_init.py
index 9d0afea3..54d616ce 100644
--- a/object_collection_manager/cm_init.py
+++ b/object_collection_manager/cm_init.py
@@ -104,6 +104,8 @@ classes = (
operators.CMDisableObjectsOperator,
operators.CMDisableUnSelectedObjectsOperator,
operators.CMRestoreDisabledObjectsOperator,
+ operators.CMUndoWrapper,
+ operators.CMRedoWrapper,
preferences.CMPreferences,
ui.CM_UL_items,
ui.CollectionManager,
diff --git a/object_collection_manager/internals.py b/object_collection_manager/internals.py
index 77e801f6..eb80ae40 100644
--- a/object_collection_manager/internals.py
+++ b/object_collection_manager/internals.py
@@ -621,6 +621,80 @@ def generate_state(*, qcd=False):
return state
+def check_state(context, *, cm_popup=False, phantom_mode=False, qcd=False):
+ view_layer = context.view_layer
+
+ # check if expanded & history/buffer state still correct
+ if cm_popup and collection_state:
+ new_state = generate_state()
+
+ if new_state["name"] != collection_state["name"]:
+ copy_buffer["RTO"] = ""
+ copy_buffer["values"].clear()
+
+ swap_buffer["A"]["RTO"] = ""
+ swap_buffer["A"]["values"].clear()
+ swap_buffer["B"]["RTO"] = ""
+ swap_buffer["B"]["values"].clear()
+
+ for name in list(expanded):
+ laycol = layer_collections.get(name)
+ if not laycol or not laycol["has_children"]:
+ expanded.remove(name)
+
+ for name in list(expand_history["history"]):
+ laycol = layer_collections.get(name)
+ if not laycol or not laycol["has_children"]:
+ expand_history["history"].remove(name)
+
+ for rto, history in rto_history.items():
+ if view_layer.name in history:
+ del history[view_layer.name]
+
+
+ else:
+ for rto in ["exclude", "select", "hide", "disable", "render", "holdout", "indirect"]:
+ if new_state[rto] != collection_state[rto]:
+ if view_layer.name in rto_history[rto]:
+ del rto_history[rto][view_layer.name]
+
+ if view_layer.name in rto_history[rto+"_all"]:
+ del rto_history[rto+"_all"][view_layer.name]
+
+
+ if phantom_mode:
+ cm = context.scene.collection_manager
+
+ # check if in phantom mode and if it's still viable
+ if cm.in_phantom_mode:
+ if layer_collections.keys() != phantom_history["initial_state"].keys():
+ cm.in_phantom_mode = False
+
+ if view_layer.name != phantom_history["view_layer"]:
+ cm.in_phantom_mode = False
+
+ if not cm.in_phantom_mode:
+ for key, value in phantom_history.items():
+ try:
+ value.clear()
+ except AttributeError:
+ if key == "view_layer":
+ phantom_history["view_layer"] = ""
+
+
+ if qcd and qcd_collection_state:
+ from .qcd_operators import QCDAllBase
+ new_state = generate_state(qcd=True)
+
+ if (new_state["name"] != qcd_collection_state["name"]
+ or new_state["exclude"] != qcd_collection_state["exclude"]
+ or new_state["qcd"] != qcd_collection_state["qcd"]):
+ if view_layer.name in qcd_history:
+ del qcd_history[view_layer.name]
+ qcd_collection_state.clear()
+ QCDAllBase.clear()
+
+
def get_move_selection(*, names_only=False):
global move_selection
diff --git a/object_collection_manager/operators.py b/object_collection_manager/operators.py
index 45dc4df5..b38e2fe6 100644
--- a/object_collection_manager/operators.py
+++ b/object_collection_manager/operators.py
@@ -38,6 +38,8 @@ from . import internals
# For FUNCTIONS
from .internals import (
update_property_group,
+ generate_state,
+ check_state,
get_modifiers,
get_move_selection,
get_move_active,
@@ -1499,3 +1501,48 @@ class CMRestoreDisabledObjectsOperator(Operator):
obj.select_set(True)
return {'FINISHED'}
+
+
+class CMUndoWrapper(Operator):
+ bl_label = "Undo"
+ bl_description = "Undo previous action"
+ bl_idname = "view3d.undo_wrapper"
+
+ @classmethod
+ def poll(self, context):
+ return bpy.ops.ed.undo.poll()
+
+ def execute(self, context):
+ internals.collection_state.clear()
+ internals.collection_state.update(generate_state())
+ bpy.ops.ed.undo()
+ update_property_group(context)
+
+ check_state(context, cm_popup=True)
+
+ # clear buffers
+ internals.copy_buffer["RTO"] = ""
+ internals.copy_buffer["values"].clear()
+
+ internals.swap_buffer["A"]["RTO"] = ""
+ internals.swap_buffer["A"]["values"].clear()
+ internals.swap_buffer["B"]["RTO"] = ""
+ internals.swap_buffer["B"]["values"].clear()
+
+ return {'FINISHED'}
+
+
+class CMRedoWrapper(Operator):
+ bl_label = "Redo"
+ bl_description = "Redo previous action"
+ bl_idname = "view3d.redo_wrapper"
+
+ @classmethod
+ def poll(self, context):
+ return bpy.ops.ed.redo.poll()
+
+ def execute(self, context):
+ bpy.ops.ed.redo()
+ update_property_group(context)
+
+ return {'FINISHED'}
diff --git a/object_collection_manager/ui.py b/object_collection_manager/ui.py
index b11a08bc..d5740e86 100644
--- a/object_collection_manager/ui.py
+++ b/object_collection_manager/ui.py
@@ -40,16 +40,12 @@ from .internals import (
update_collection_tree,
update_property_group,
generate_state,
+ check_state,
get_move_selection,
get_move_active,
update_qcd_header,
)
-from .qcd_operators import (
- QCDAllBase,
-)
-
-
preview_collections = {}
last_icon_theme_text = None
last_icon_theme_text_sel = None
@@ -136,6 +132,11 @@ class CollectionManager(Operator):
renum_sec.alignment = 'LEFT'
renum_sec.operator("view3d.renumerate_qcd_slots")
+ undo_sec = op_sec.row(align=True)
+ undo_sec.alignment = 'LEFT'
+ undo_sec.operator("view3d.undo_wrapper", text="", icon='LOOP_BACK')
+ undo_sec.operator("view3d.redo_wrapper", text="", icon='LOOP_FORWARDS')
+
# menu & filter
right_sec = button_row_1.row()
right_sec.alignment = 'RIGHT'
@@ -387,58 +388,8 @@ class CollectionManager(Operator):
if cm.cm_list_index >= len(cm.cm_list_collection):
cm.cm_list_index = -1
- # check if expanded & history/buffer state still correct
- if internals.collection_state:
- new_state = generate_state()
-
- if new_state["name"] != internals.collection_state["name"]:
- internals.copy_buffer["RTO"] = ""
- internals.copy_buffer["values"].clear()
-
- internals.swap_buffer["A"]["RTO"] = ""
- internals.swap_buffer["A"]["values"].clear()
- internals.swap_buffer["B"]["RTO"] = ""
- internals.swap_buffer["B"]["values"].clear()
-
- for name in list(internals.expanded):
- laycol = internals.layer_collections.get(name)
- if not laycol or not laycol["has_children"]:
- internals.expanded.remove(name)
-
- for name in list(internals.expand_history["history"]):
- laycol = internals.layer_collections.get(name)
- if not laycol or not laycol["has_children"]:
- internals.expand_history["history"].remove(name)
-
- for rto, history in internals.rto_history.items():
- if view_layer.name in history:
- del history[view_layer.name]
-
-
- else:
- for rto in ["exclude", "select", "hide", "disable", "render", "holdout", "indirect"]:
- if new_state[rto] != internals.collection_state[rto]:
- if view_layer.name in internals.rto_history[rto]:
- del internals.rto_history[rto][view_layer.name]
-
- if view_layer.name in internals.rto_history[rto+"_all"]:
- del internals.rto_history[rto+"_all"][view_layer.name]
-
- # check if in phantom mode and if it's still viable
- if cm.in_phantom_mode:
- if internals.layer_collections.keys() != internals.phantom_history["initial_state"].keys():
- cm.in_phantom_mode = False
-
- if view_layer.name != internals.phantom_history["view_layer"]:
- cm.in_phantom_mode = False
-
- if not cm.in_phantom_mode:
- for key, value in internals.phantom_history.items():
- try:
- value.clear()
- except AttributeError:
- if key == "view_layer":
- internals.phantom_history["view_layer"] = ""
+ # check if history/buffer/phantom state still correct
+ check_state(context, cm_popup=True, phantom_mode=True)
# handle window sizing
max_width = 960
@@ -930,17 +881,7 @@ def view3d_header_qcd_slots(self, context):
layout = self.layout
idx = 1
- if internals.qcd_collection_state:
- view_layer = context.view_layer
- new_state = generate_state(qcd=True)
-
- if (new_state["name"] != internals.qcd_collection_state["name"]
- or new_state["exclude"] != internals.qcd_collection_state["exclude"]
- or new_state["qcd"] != internals.qcd_collection_state["qcd"]):
- if view_layer.name in internals.qcd_history:
- del internals.qcd_history[view_layer.name]
- internals.qcd_collection_state.clear()
- QCDAllBase.clear()
+ check_state(context, qcd=True)
main_row = layout.row(align=True)