[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [39526] trunk/blender/release/scripts/ startup/bl_operators/wm.py: fix for undo issues with generic, multi-purpose WM_OT_context* operators, operators now check if they modify certain ID data (not screne, wm, brush or scene) and only do undo in those cass.

Campbell Barton ideasman42 at gmail.com
Thu Aug 18 18:01:12 CEST 2011


Revision: 39526
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=39526
Author:   campbellbarton
Date:     2011-08-18 16:01:11 +0000 (Thu, 18 Aug 2011)
Log Message:
-----------
fix for undo issues with generic, multi-purpose WM_OT_context* operators, operators now check if they modify certain ID data (not screne, wm, brush or scene) and only do undo in those cass.

- Zkey to switch shading was pushing undo's.
- Wkey to interactively edit camera, lamp settings wasnt doing an undo push when it should.
- Toggling settings (such as bone boolean options) now skips an undo push if there are no items selected.

Modified Paths:
--------------
    trunk/blender/release/scripts/startup/bl_operators/wm.py

Modified: trunk/blender/release/scripts/startup/bl_operators/wm.py
===================================================================
--- trunk/blender/release/scripts/startup/bl_operators/wm.py	2011-08-18 15:53:30 UTC (rev 39525)
+++ trunk/blender/release/scripts/startup/bl_operators/wm.py	2011-08-18 16:01:11 UTC (rev 39526)
@@ -76,6 +76,54 @@
     return value
 
 
+def operator_value_is_undo(value):
+    if value in {None, Ellipsis}:
+        return False
+
+    # typical properties or objects
+    id_data = getattr(value, "id_data", Ellipsis)
+
+    if id_data is None:
+        return False
+    elif id_data is Ellipsis:
+        # handle mathutils types
+        id_data = getattr(getattr(value, "owner", None), "id_data", None)
+
+        if id_data is None:
+            return False
+
+    # return True if its a non window ID type
+    return (isinstance(id_data, bpy.types.ID) and
+            (not isinstance(id_data, (bpy.types.WindowManager,
+                                      bpy.types.Screen,
+                                      bpy.types.Scene,
+                                      bpy.types.Brush,
+                                      ))))
+
+
+def operator_path_is_undo(context, data_path):
+    # note that if we have data paths that use strings this could fail
+    # luckily we dont do this!
+    #
+    # When we cant find the data owner assume no undo is needed.
+    data_path_head, data_path_sep, data_path_tail = data_path.rpartition(".")
+
+    if not data_path_head:
+        return False
+
+    value = context_path_validate(context, data_path_head)
+
+    return operator_value_is_undo(value)
+
+
+def operator_path_undo_return(context, data_path):
+    return {'FINISHED'} if operator_path_is_undo(context, data_path) else {'CANCELLED'}
+
+
+def operator_value_undo_return(value):
+    return {'FINISHED'} if operator_value_is_undo(value) else {'CANCELLED'}
+
+
 def execute_context_assign(self, context):
     data_path = self.data_path
     if context_path_validate(context, data_path) is Ellipsis:
@@ -86,7 +134,7 @@
     else:
         exec("context.%s = self.value" % data_path)
 
-    return {'FINISHED'}
+    return operator_path_undo_return(context, data_path)
 
 
 class BRUSH_OT_active_index_set(Operator):
@@ -196,7 +244,7 @@
         else:
             exec("context.%s *= value" % data_path)
 
-        return {'FINISHED'}
+        return operator_path_undo_return(context, data_path)
 
 
 class WM_OT_context_set_float(Operator):  # same as enum
@@ -266,7 +314,7 @@
         if context_path_validate(context, data_path) is Ellipsis:
             return {'PASS_THROUGH'}
         exec("context.%s = %s" % (data_path, self.value))
-        return {'FINISHED'}
+        return operator_path_undo_return(context, data_path)
 
 
 class WM_OT_context_toggle(Operator):
@@ -285,7 +333,7 @@
 
         exec("context.%s = not (context.%s)" % (data_path, data_path))
 
-        return {'FINISHED'}
+        return operator_path_undo_return(context, data_path)
 
 
 class WM_OT_context_toggle_enum(Operator):
@@ -318,7 +366,7 @@
               self.value_2,
               ))
 
-        return {'FINISHED'}
+        return operator_path_undo_return(context, data_path)
 
 
 class WM_OT_context_cycle_int(Operator):
@@ -353,7 +401,7 @@
 
             exec("context.%s = value" % data_path)
 
-        return {'FINISHED'}
+        return operator_path_undo_return(context, data_path)
 
 
 class WM_OT_context_cycle_enum(Operator):
@@ -405,7 +453,7 @@
 
         # set the new value
         exec("context.%s = advance_enum" % data_path)
-        return {'FINISHED'}
+        return operator_path_undo_return(context, data_path)
 
 
 class WM_OT_context_cycle_array(Operator):
@@ -433,7 +481,7 @@
 
         exec("context.%s = cycle(context.%s[:])" % (data_path, data_path))
 
-        return {'FINISHED'}
+        return operator_path_undo_return(context, data_path)
 
 
 class WM_MT_context_menu_enum(Menu):
@@ -504,7 +552,7 @@
             value_id = getattr(bpy.data, id_iter).get(value)
             exec("context.%s = value_id" % data_path)
 
-        return {'FINISHED'}
+        return operator_path_undo_return(context, data_path)
 
 
 doc_id = StringProperty(
@@ -568,6 +616,10 @@
 
             items_ok.append(item)
 
+        # avoid undo push when nothing to do
+        if not items_ok:
+            return {'CANCELLED'}
+
         if self.type == 'ENABLE':
             is_set = True
         elif self.type == 'DISABLE':
@@ -579,14 +631,14 @@
         for item in items_ok:
             exec(exec_str)
 
-        return {'FINISHED'}
+        return operator_value_undo_return(item)
 
 
 class WM_OT_context_modal_mouse(Operator):
     '''Adjust arbitrary values with mouse input'''
     bl_idname = "wm.context_modal_mouse"
     bl_label = "Context Modal Mouse"
-    bl_options = {'GRAB_POINTER', 'BLOCKING', 'INTERNAL'}
+    bl_options = {'GRAB_POINTER', 'BLOCKING', 'UNDO', 'INTERNAL'}
 
     data_path_iter = data_path_iter
     data_path_item = data_path_item
@@ -651,12 +703,13 @@
             self._values_delta(delta)
 
         elif 'LEFTMOUSE' == event_type:
+            item = next(iter(self._values.keys()))
             self._values_clear()
-            return {'FINISHED'}
+            return operator_value_undo_return(item)
 
         elif event_type in {'RIGHTMOUSE', 'ESC'}:
             self._values_restore()
-            return {'FINISHED'}
+            return {'CANCELLED'}
 
         return {'RUNNING_MODAL'}
 




More information about the Bf-blender-cvs mailing list