diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index b94ad9e1e31..07554987143 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -1299,6 +1299,7 @@ if(WITH_UI_TESTS) test_undo.view3d_multi_mode_select test_undo.view3d_sculpt_dyntopo_and_edit test_undo.view3d_sculpt_dyntopo_simple + test_undo.view3d_sculpt_dyntopo_stroke_toggle test_undo.view3d_sculpt_with_memfile_step test_undo.view3d_sculpt_trim test_undo.view3d_simple diff --git a/tests/python/ui_simulate/test_undo.py b/tests/python/ui_simulate/test_undo.py index 309e9804a66..0251e8fd5a2 100644 --- a/tests/python/ui_simulate/test_undo.py +++ b/tests/python/ui_simulate/test_undo.py @@ -507,6 +507,59 @@ def view3d_sculpt_trim(): t.assertEqual(after_trim_positions, after_redo_positions) +def view3d_sculpt_dyntopo_stroke_toggle(): + e, t = _test_vars(window := _test_window()) + yield from _view3d_startup_area_maximized(e) + + yield from _call_menu(e, "Add -> Mesh -> Torus") + yield e.numpad_period() # View all. + yield from _call_by_name(e, "Remove UV Map") + yield e.ctrl.tab().s() # Sculpt via pie menu. + + # Utility to extract current mesh coordinates (used to ensure undo/redo steps are applied properly). + def extract_mesh_positions(window): + # TODO: Find/add a way to get that info when there is a multires active in Sculpt mode. + window.view_layer.update() + tmp_mesh = window.view_layer.objects.active.to_mesh(preserve_all_data_layers=True) + tmp_cos = [0.0] * len(tmp_mesh.vertices) * 3 + tmp_mesh.vertices.foreach_get("co", tmp_cos) + window.view_layer.objects.active.to_mesh_clear() + return tmp_cos + + original_positions = extract_mesh_positions(window) + yield from _call_by_name(e, "Dynamic Topology") # On + + yield from e.leftmouse.cursor_motion(_cursor_motion_data_x(window)) + + yield from _call_by_name(e, "Dynamic Topology") # Off + after_toggle_off = extract_mesh_positions(window) + t.assertNotEqual(original_positions, after_toggle_off) + + yield from e.leftmouse.cursor_motion(_cursor_motion_data_y(window)) + after_normal_stroke = extract_mesh_positions(window) + t.assertNotEqual(after_toggle_off, after_normal_stroke) + + yield e.ctrl.z() # Undo Stroke + after_first_undo = extract_mesh_positions(window) + t.assertEqual(after_first_undo, after_toggle_off) + + yield e.ctrl.z() # Undo Toggle Off + yield e.ctrl.z() # Undo Dyntopo Stroke + yield e.ctrl.z() # Undo Toggle On + after_full_undo = extract_mesh_positions(window) + t.assertEqual(after_full_undo, original_positions) + + yield e.ctrl.shift.z() # Redo Toggle On + yield e.ctrl.shift.z() # Redo Dyntopo Stroke + yield e.ctrl.shift.z() # Redo Toggle Off + after_toggle_off_redo = extract_mesh_positions(window) + t.assertEqual(after_toggle_off_redo, after_toggle_off) + + yield e.ctrl.shift.z() # Redo Normal Stroke + after_normal_stroke_redo = extract_mesh_positions(window) + t.assertEqual(after_normal_stroke, after_normal_stroke_redo) + + def view3d_texture_paint_simple(): e, t = _test_vars(window := _test_window()) yield from _view3d_startup_area_maximized(e)