diff options
author | Campbell Barton <ideasman42@gmail.com> | 2020-10-30 12:24:13 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2020-10-30 12:48:15 +0300 |
commit | 8d2576fd295fc67e2b70c282117928173ec1af8a (patch) | |
tree | ca3ff57fff108f282dad8484e77856a5b141ee08 /source/blender/blenkernel | |
parent | 3624c0600747d9ebde1d55f1811f810ba08c6d17 (diff) |
Undo System: support for grouping steps with begin/end calls
This adds support for treating multiple undo steps as a single step
from the user perspective.
This is needed for outliner mode switching and `object.switch_object`
operator which change active object and mode in a single action.
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_undo_system.h | 9 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/undo_system.c | 45 |
2 files changed, 54 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h index 4f933ca7a87..58872d6be58 100644 --- a/source/blender/blenkernel/BKE_undo_system.h +++ b/source/blender/blenkernel/BKE_undo_system.h @@ -70,6 +70,12 @@ typedef struct UndoStack { * That is done once end is called. */ struct UndoStep *step_init; + + /** + * Keep track of nested group begin/end calls, + * within which all but the last undo-step is marked for skipping. + */ + int group_level; } UndoStack; typedef struct UndoStep { @@ -156,6 +162,9 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size #define BKE_undosys_stack_limit_steps_and_memory_defaults(ustack) \ BKE_undosys_stack_limit_steps_and_memory(ustack, U.undosteps, (size_t)U.undomemory * 1024 * 1024) +void BKE_undosys_stack_group_begin(UndoStack *ustack); +void BKE_undosys_stack_group_end(UndoStack *ustack); + /* Only some UndoType's require init. */ UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack, struct bContext *C, diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c index 0a0f81f7829..93f70b606dc 100644 --- a/source/blender/blenkernel/intern/undo_system.c +++ b/source/blender/blenkernel/intern/undo_system.c @@ -580,6 +580,12 @@ bool BKE_undosys_step_push_with_type(UndoStack *ustack, } } + if (ustack->group_level > 0) { + /* Temporarily set skip for the active step. + * This is an invalid state which must be corrected once the last group ends. */ + ustack->step_active->skip = true; + } + undosys_stack_validate(ustack, true); return true; } @@ -849,6 +855,45 @@ void BKE_undosys_type_free_all(void) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Undo Stack Grouping + * + * This enables skip while group-level is set. + * In general it's not allowed that #UndoStack.step_active have 'skip' enabled. + * + * This rule is relaxed for grouping, however it's important each call to + * #BKE_undosys_stack_group_begin has a matching #BKE_undosys_stack_group_end. + * + * - Levels are used so nesting is supported, where the last call to #BKE_undosys_stack_group_end + * will set the active undo step that should not be skipped. + * + * - Correct begin/end is checked by an assert since any errors here will cause undo + * to consider all steps part of one large group. + * + * - Calls to begin/end with no undo steps being pushed is supported and does nothing. + * + * \{ */ + +void BKE_undosys_stack_group_begin(UndoStack *ustack) +{ + BLI_assert(ustack->group_level >= 0); + ustack->group_level += 1; +} + +void BKE_undosys_stack_group_end(UndoStack *ustack) +{ + ustack->group_level -= 1; + BLI_assert(ustack->group_level >= 0); + + if (ustack->group_level == 0) { + if (LIKELY(ustack->step_active != NULL)) { + ustack->step_active->skip = false; + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name ID Reference Utilities * * Unfortunately we need this for a handful of places. |