1 /* SPDX-FileCopyrightText: 2023 Blender Authors
3 * SPDX-License-Identifier: GPL-2.0-or-later */
10 #include "BLI_path_utils.hh"
11 #include "BLI_utildefines.h"
13 #include "DNA_listBase.h"
30 char name
[MAX_ID_NAME
];
31 char library_filepath_abs
[FILE_MAX
];
33 /* UndoRefID_Mesh & friends. */
34 #define UNDO_REF_ID_TYPE(ptr_ty) \
35 struct UndoRefID_##ptr_ty { \
37 char name[MAX_ID_NAME]; \
38 char library_filepath_abs[FILE_MAX]; \
40 UNDO_REF_ID_TYPE(GreasePencil
);
41 UNDO_REF_ID_TYPE(Mesh
);
42 UNDO_REF_ID_TYPE(Object
);
43 UNDO_REF_ID_TYPE(Scene
);
44 UNDO_REF_ID_TYPE(Text
);
45 UNDO_REF_ID_TYPE(Image
);
46 UNDO_REF_ID_TYPE(PaintCurve
);
50 UndoStep
*step_active
;
52 * The last memfile state read, used so we can be sure the names from the
53 * library state matches the state an undo step was written in.
55 UndoStep
*step_active_memfile
;
58 * Some undo systems require begin/end, see: #UndoType.step_encode_init
60 * \note This is not included in the 'steps' list.
61 * That is done once end is called.
66 * Keep track of nested group begin/end calls,
67 * within which all but the last undo-step is marked for skipping.
73 UndoStep
*next
, *prev
;
76 /** Size in bytes of all data in step (not including the step). */
78 /** Users should never see this step (only use for internal consistency). */
80 /** Some situations require the global state to be stored, edge cases when exiting modes. */
81 bool use_memfile_step
;
82 /** When this is true, undo/memfile read code is allowed to re-use old data-blocks for unchanged
83 * IDs, and existing depsgraphs. This has to be forbidden in some cases (like renamed IDs). */
84 bool use_old_bmain_data
;
85 /** For use by undo systems that accumulate changes (mesh-sculpt & image-painting). */
87 /* Over alloc 'type->struct_size'. */
96 enum eUndoPushReturn
{
97 UNDO_PUSH_RET_FAILURE
= 0,
98 UNDO_PUSH_RET_SUCCESS
= (1 << 0),
99 UNDO_PUSH_RET_OVERRIDE_CHANGED
= (1 << 1),
101 ENUM_OPERATORS(eUndoPushReturn
, UNDO_PUSH_RET_OVERRIDE_CHANGED
)
103 using UndoTypeForEachIDRefFn
= void (*)(void *user_data
, UndoRefID
*id_ref
);
106 UndoType
*next
, *prev
;
107 /** Only for debugging. */
111 * When NULL, we don't consider this undo type for context checks.
112 * Operators must explicitly set the undo type and handle adding the undo step.
113 * This is needed when tools operate on data which isn't the primary mode
114 * (eg, paint-curve in sculpt mode).
116 bool (*poll
)(struct bContext
*C
);
119 * None of these callbacks manage list add/removal.
121 * Note that 'step_encode_init' is optional,
122 * some undo types need to perform operations before undo push finishes.
124 void (*step_encode_init
)(bContext
*C
, UndoStep
*us
);
126 bool (*step_encode
)(bContext
*C
, Main
*bmain
, UndoStep
*us
);
127 void (*step_decode
)(bContext
*C
, Main
*bmain
, UndoStep
*us
, eUndoStepDir dir
, bool is_final
);
130 * \note When freeing all steps,
131 * free from the last since #BKE_UNDOSYS_TYPE_MEMFILE
132 * will merge with the next undo type in the list.
134 void (*step_free
)(UndoStep
*us
);
136 void (*step_foreach_ID_ref
)(UndoStep
*us
,
137 UndoTypeForEachIDRefFn foreach_ID_ref_fn
,
140 /** Information for the generic undo system to refine handling of this specific undo type. */
144 * The size of the undo struct 'inherited' from #UndoStep for that specific type. Used for
145 * generic allocation in BKE's `undo_system.cc`. */
149 /** #UndoType.flag bit-flags. */
150 enum eUndoTypeFlags
{
152 * This undo type `encode` callback needs a valid context, it will fail otherwise.
153 * \note Callback is still supposed to properly deal with a NULL context pointer.
155 UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE
= 1 << 0,
158 * When the active undo step is of this type, it must be read before loading other undo steps.
160 * This is typically used for undo systems that store both before/after states.
162 UNDOTYPE_FLAG_DECODE_ACTIVE_STEP
= 1 << 1,
165 /* -------------------------------------------------------------------- */
166 /** \name Public Undo Types
168 * Expose since we need to perform operations on specific undo types (rarely).
171 extern const UndoType
*BKE_UNDOSYS_TYPE_IMAGE
;
172 extern const UndoType
*BKE_UNDOSYS_TYPE_MEMFILE
;
173 extern const UndoType
*BKE_UNDOSYS_TYPE_PAINTCURVE
;
174 extern const UndoType
*BKE_UNDOSYS_TYPE_PARTICLE
;
175 extern const UndoType
*BKE_UNDOSYS_TYPE_SCULPT
;
176 extern const UndoType
*BKE_UNDOSYS_TYPE_TEXT
;
180 #define BKE_UNDOSYS_TYPE_IS_MEMFILE_SKIP(ty) ELEM(ty, BKE_UNDOSYS_TYPE_IMAGE)
182 UndoStack
*BKE_undosys_stack_create();
183 void BKE_undosys_stack_destroy(UndoStack
*ustack
);
184 void BKE_undosys_stack_clear(UndoStack
*ustack
);
185 void BKE_undosys_stack_clear_active(UndoStack
*ustack
);
187 bool BKE_undosys_stack_has_undo(const UndoStack
*ustack
, const char *name
);
188 void BKE_undosys_stack_init_from_main(UndoStack
*ustack
, Main
*bmain
);
189 /* called after 'BKE_undosys_stack_init_from_main' */
190 void BKE_undosys_stack_init_from_context(UndoStack
*ustack
, bContext
*C
);
191 UndoStep
*BKE_undosys_stack_active_with_type(UndoStack
*ustack
, const UndoType
*ut
);
192 UndoStep
*BKE_undosys_stack_init_or_active_with_type(UndoStack
*ustack
, const UndoType
*ut
);
194 * \param steps: Limit the number of undo steps.
195 * \param memory_limit: Limit the amount of memory used by the undo stack.
197 void BKE_undosys_stack_limit_steps_and_memory(UndoStack
*ustack
, int steps
, size_t memory_limit
);
198 #define BKE_undosys_stack_limit_steps_and_memory_defaults(ustack) \
199 BKE_undosys_stack_limit_steps_and_memory(ustack, U.undosteps, (size_t)U.undomemory * 1024 * 1024)
201 void BKE_undosys_stack_group_begin(UndoStack
*ustack
);
202 void BKE_undosys_stack_group_end(UndoStack
*ustack
);
205 * Only some UndoType's require init.
207 UndoStep
*BKE_undosys_step_push_init_with_type(UndoStack
*ustack
,
211 UndoStep
*BKE_undosys_step_push_init(UndoStack
*ustack
, bContext
*C
, const char *name
);
214 * \param C: Can be NULL from some callers if their encoding function doesn't need it
216 eUndoPushReturn
BKE_undosys_step_push_with_type(UndoStack
*ustack
,
220 eUndoPushReturn
BKE_undosys_step_push(UndoStack
*ustack
, bContext
*C
, const char *name
);
222 UndoStep
*BKE_undosys_step_find_by_name_with_type(UndoStack
*ustack
,
225 UndoStep
*BKE_undosys_step_find_by_type(UndoStack
*ustack
, const UndoType
*ut
);
226 UndoStep
*BKE_undosys_step_find_by_name(UndoStack
*ustack
, const char *name
);
229 * Return direction of the undo/redo from `us_reference` (or `ustack->step_active` if NULL), and
232 * \note If `us_reference` and `us_target` are the same, we consider this is an undo.
234 * \return -1 for undo, 1 for redo, 0 in case of error.
236 eUndoStepDir
BKE_undosys_step_calc_direction(const UndoStack
*ustack
,
237 const UndoStep
*us_target
,
238 const UndoStep
*us_reference
);
241 * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
243 * \note Unless `us_target` is a 'skipped' one and `use_skip` is true, `us_target`
244 * will become the active step.
246 * \note In case `use_skip` is true, the final target will always be **beyond** the given one
247 * (if the given one has to be skipped).
249 * \param us_reference: If NULL, will be set to current active step in the undo stack. Otherwise,
250 * it is assumed to match the current state, and will be used as basis for the undo/redo process
251 * (i.e. all steps in-between `us_reference` and `us_target` will be processed).
253 bool BKE_undosys_step_load_data_ex(
254 UndoStack
*ustack
, bContext
*C
, UndoStep
*us_target
, UndoStep
*us_reference
, bool use_skip
);
256 * Undo/Redo until the given `us_target` step becomes the active (currently loaded) one.
258 bool BKE_undosys_step_load_data(UndoStack
*ustack
, bContext
*C
, UndoStep
*us_target
);
260 * Undo/Redo until the step matching given `index` in the undo stack becomes the active
261 * (currently loaded) one.
263 void BKE_undosys_step_load_from_index(UndoStack
*ustack
, bContext
*C
, int index
);
266 * Undo until `us_target` step becomes the active (currently loaded) one.
268 * \warning This function assumes that the given target step is _before_ current active one.
270 * \note Unless `us_target` is a 'skipped' one and `use_skip` is true,
271 * `us_target` will become the active step.
273 * \note In case `use_skip` is true, the final target will always be **before** the given one
274 * (if the given one has to be skipped).
276 bool BKE_undosys_step_undo_with_data_ex(UndoStack
*ustack
,
281 * Undo until `us_target` step becomes the active (currently loaded) one.
283 * \note See #BKE_undosys_step_undo_with_data_ex for details.
285 bool BKE_undosys_step_undo_with_data(UndoStack
*ustack
, bContext
*C
, UndoStep
*us_target
);
287 * Undo one step from current active (currently loaded) one.
289 bool BKE_undosys_step_undo(UndoStack
*ustack
, bContext
*C
);
292 * Redo until `us_target` step becomes the active (currently loaded) one.
294 * \warning This function assumes that the given target step is _after_ current active one.
296 * \note Unless `us_target` is a 'skipped' one and `use_skip` is true,
297 * `us_target` will become the active step.
299 * \note In case `use_skip` is true, the final target will always be **after** the given one
300 * (if the given one has to be skipped).
302 bool BKE_undosys_step_redo_with_data_ex(UndoStack
*ustack
,
307 * Redo until `us_target` step becomes the active (currently loaded) one.
309 * \note See #BKE_undosys_step_redo_with_data_ex for details.
311 bool BKE_undosys_step_redo_with_data(UndoStack
*ustack
, bContext
*C
, UndoStep
*us_target
);
313 * Redo one step from current active one.
315 bool BKE_undosys_step_redo(UndoStack
*ustack
, bContext
*C
);
318 * Useful when we want to diff against previous undo data but can't be sure the types match.
320 UndoStep
*BKE_undosys_step_same_type_next(UndoStep
*us
);
322 * Useful when we want to diff against previous undo data but can't be sure the types match.
324 UndoStep
*BKE_undosys_step_same_type_prev(UndoStep
*us
);
329 * Similar to #WM_operatortype_append
331 UndoType
*BKE_undosys_type_append(void (*undosys_fn
)(UndoType
*));
332 void BKE_undosys_type_free_all();
336 #if 0 /* functionality is only used internally for now. */
337 void BKE_undosys_foreach_ID_ref(UndoStack
*ustack
,
338 UndoTypeForEachIDRefFn foreach_ID_ref_fn
,
342 void BKE_undosys_print(UndoStack
*ustack
);