[Bf-extensions-cvs] [88db9c67] master: Collection Manager: Add undo support. Task: T69577

Ryan Inch noreply at git.blender.org
Tue Mar 16 22:04:00 CET 2021


Commit: 88db9c67be6b851ca1a0edf9afab35531f5b1961
Author: Ryan Inch
Date:   Tue Mar 16 16:57:56 2021 -0400
Branches: master
https://developer.blender.org/rBA88db9c67be6b851ca1a0edf9afab35531f5b1961

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.

===================================================================

M	object_collection_manager/__init__.py
M	object_collection_manager/cm_init.py
M	object_collection_manager/internals.py
M	object_collection_manager/operators.py
M	object_collection_manager/ui.py

===================================================================

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)
-
-

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list