mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
Undo: Support global (memfile) undo in Texture Paint
When in Texture Paint mode or in the image editor, certain actions do not push undo steps (e.g. changing the active texture) that users would expect. Additionally, some actions that *do* push undo steps (e.g. changing face selection) have no effect when undone. To fix the former, remove the code preventing property changes from pushing undo steps while in Texture Paint mode. To fix the latter, remove the poll function from `image_undo.cc`. This prevents global undo steps from being tagged as image undo steps. This works because the `poll` function is only needed when creating the undo step to identify steps that do not have a `step_init` defined. This is similar to, but notably different from !139871: Image Undo (and Sculpt Undo) store deltas encoded as part of the undo step and require explicit tagging of the begin and end state (see `ED_image_undo_push_begin` and `ED_image_undo_push_end`). This allows us to use memfile undo in the general case and image undo when explicitly requested, avoiding the memory concerns of the previously linked PR. Addresses: #69346, #62520, #71895 Pull Request: https://projects.blender.org/blender/blender/pulls/151399
This commit is contained in:
parent
f1aa11974a
commit
0ac5946a89
3 changed files with 25 additions and 26 deletions
|
|
@ -615,6 +615,7 @@ def view3d_texture_paint_simple():
|
|||
|
||||
|
||||
def view3d_texture_paint_complex():
|
||||
import bpy
|
||||
# More complex test than `view3d_texture_paint_simple`,
|
||||
# including interleaved memfile steps,
|
||||
# and a call to history to undo several steps at once.
|
||||
|
|
@ -628,16 +629,33 @@ def view3d_texture_paint_complex():
|
|||
yield from _call_by_name(e, "Add Texture Paint Slot")
|
||||
yield e.ret() # Accept popup.
|
||||
|
||||
initial_data = tuple(bpy.data.images['Suzanne Base Color'].pixels)
|
||||
|
||||
yield from e.leftmouse.cursor_motion(_cursor_motion_data_x(window))
|
||||
yield from e.leftmouse.cursor_motion(_cursor_motion_data_y(window))
|
||||
|
||||
after_strokes = tuple(bpy.data.images['Suzanne Base Color'].pixels)
|
||||
t.assertTrue(any([orig != new for (orig, new) in zip(initial_data, after_strokes)]),
|
||||
"At least one pixel should differ in color component")
|
||||
|
||||
yield from _call_by_name(e, "Add Texture Paint Slot")
|
||||
yield e.ret() # Accept popup.
|
||||
|
||||
yield from _call_by_name(e, "Add Modifier")
|
||||
yield e.a() # Array modifier
|
||||
t.assertEqual(len(bpy.context.active_object.modifiers), 1, "One modifier should exist")
|
||||
|
||||
yield from e.leftmouse.cursor_motion(_cursor_motion_data_x(window))
|
||||
yield from e.leftmouse.cursor_motion(_cursor_motion_data_y(window))
|
||||
|
||||
yield e.ctrl.z(6) # Undo: initial texture paint.
|
||||
yield e.ctrl.z(6) # Undo: second slot added.
|
||||
t.assertEqual(len(bpy.context.active_object.modifiers), 0, "No modifiers should exist")
|
||||
|
||||
after_undo = tuple(bpy.data.images['Suzanne Base Color'].pixels)
|
||||
t.assertTrue(all([orig == new for (orig, new) in zip(initial_data, after_undo)]),
|
||||
"All pixels should be the same as their original state")
|
||||
|
||||
yield e.ctrl.z(1) # Undo: initial texture paint.
|
||||
t.assertEqual(window.view_layer.objects.active.mode, 'TEXTURE_PAINT')
|
||||
yield e.ctrl.z() # Undo: object mode.
|
||||
t.assertEqual(window.view_layer.objects.active.mode, 'OBJECT')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue