32 #define undo_stack _wm_undo_stack_disallow
35 #define WITH_GLOBAL_UNDO_KEEP_ONE
38 #define WITH_GLOBAL_UNDO_ENSURE_UPDATED
44 #define WITH_GLOBAL_UNDO_CORRECT_ORDER
66 if (ut->poll && ut->poll(
C)) {
83 #define WITH_NESTED_UNDO_CHECK
85 #ifdef WITH_NESTED_UNDO_CHECK
87 # define UNDO_NESTED_ASSERT(state) BLI_assert(g_undo_callback_running == state)
88 # define UNDO_NESTED_CHECK_BEGIN \
90 UNDO_NESTED_ASSERT(false); \
91 g_undo_callback_running = true; \
94 # define UNDO_NESTED_CHECK_END \
96 UNDO_NESTED_ASSERT(true); \
97 g_undo_callback_running = false; \
101 # define UNDO_NESTED_ASSERT(state) ((void)0)
102 # define UNDO_NESTED_CHECK_BEGIN ((void)0)
103 # define UNDO_NESTED_CHECK_END ((void)0)
153 #ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
160 CLOG_INFO(&
LOG, 2,
"encode callback didn't create undo step");
175 #ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
203 #ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
220 #ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
240 if (expect_non_empty) {
295 bool is_not_empty =
true;
302 }
while ((us != us_iter));
308 if (us && us == us_exclude) {
313 bool is_not_empty =
true;
317 if (us_iter == us_exclude) {
318 us_iter = us_iter->
next;
323 }
while ((us != us_iter));
358 return us && us->
prev;
367 while (us && (us->
type != ut)) {
394 size_t data_size_all = 0;
402 "At step %zu: data_size_all=%zu >= memory_limit=%zu",
410 if (us_count ==
steps) {
413 if (us->
skip ==
false) {
419 CLOG_INFO(&
LOG, 1,
"Total steps %zu: data_size_all=%zu", us_count, data_size_all);
422 #ifdef WITH_GLOBAL_UNDO_KEEP_ONE
425 us_exclude = us->
prev;
427 us_exclude = us_exclude->
prev;
433 us_exclude->
skip =
true;
520 #ifdef WITH_GLOBAL_UNDO_ENSURE_UPDATED
522 if (
G_MAIN->is_memfile_undo_written ==
false) {
523 const char *name_internal =
"MemFile Internal (pre)";
534 # ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
542 bool use_memfile_step =
false;
546 if (us->
name[0] ==
'\0') {
566 if (use_memfile_step) {
570 const char *name_internal = us_prev->
name;
575 us_prev->
skip =
true;
576 #ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
608 while ((us = us->
next)) {
609 if (us->
type == ut) {
621 while ((us = us->
prev)) {
622 if (us->
type == ut) {
635 if (us->type == ut) {
636 if (
STREQ(name, us->name)) {
652 if (us->type == ut) {
663 if (us_reference ==
NULL) {
675 if (
ELEM(us_target, us_reference, us_reference->
prev)) {
678 if (us_target == us_reference->
next) {
683 for (
UndoStep *us_iter = us_reference->
next; us_iter !=
NULL; us_iter = us_iter->next) {
684 if (us_iter == us_target) {
688 for (
UndoStep *us_iter = us_reference->
prev; us_iter !=
NULL; us_iter = us_iter->prev) {
689 if (us_iter == us_target) {
695 "Target undo step not found, this should not happen and may indicate an undo "
711 return (undo_dir == -1) ? us_reference : us_reference->
next;
715 return (undo_dir == -1) ? us_reference->
prev : us_reference->
next;
725 if (us_target ==
NULL) {
731 if (us_reference ==
NULL) {
734 if (us_reference ==
NULL) {
735 CLOG_ERROR(&
LOG,
"could not find a valid initial active target step as reference");
747 UndoStep *us_target_active = us_target;
749 while (us_target_active !=
NULL && us_target_active->
skip) {
750 us_target_active = (undo_dir == -1) ? us_target_active->
prev : us_target_active->
next;
752 if (us_target_active ==
NULL) {
755 "undo/redo did not find a step after stepping over skip-steps "
756 "(undo limit exceeded)");
763 "addr=%p, name='%s', type='%s', undo_dir=%d",
771 bool is_processing_extra_skipped_steps =
false;
773 us_iter = (undo_dir == -1) ? us_iter->prev : us_iter->next) {
776 const bool is_final = (us_iter == us_target_active);
778 if (!is_final && is_processing_extra_skipped_steps) {
782 "undo/redo continue with skip addr=%p, name='%s', type='%s'",
785 us_iter->
type->name);
791 if (us_iter == us_target) {
792 is_processing_extra_skipped_steps =
true;
802 !
"This should never be reached, either undo stack is corrupted, or code above is buggy");
965 printf(
"Undo %d Steps (*: active, #=applied, M=memfile-active, S=skip)\n",
969 printf(
"[%c%c%c%c] %3d {%p} type='%s', name='%s'\n",
971 us->is_applied ?
'#' :
' ',
973 us->skip ?
'S' :
' ',
bContext * CTX_create(void)
void CTX_free(bContext *C)
void CTX_data_main_set(bContext *C, struct Main *bmain)
bool BKE_lib_override_library_main_operations_create(struct Main *bmain, bool force_auto)
struct ListBase * which_libbase(struct Main *bmain, short type)
@ UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE
@ UNDOTYPE_FLAG_DECODE_ACTIVE_STEP
@ UNDO_PUSH_RET_OVERRIDE_CHANGED
void(* UndoTypeForEachIDRefFn)(void *user_data, struct UndoRefID *id_ref)
#define BLI_assert_msg(a, msg)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_rfindstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
#define CLOG_ERROR(clg_ref,...)
#define CLOG_INFO(clg_ref, level,...)
#define ID_IS_LINKED(_id)
These structs are the foundation for all linked lists in the library system.
Read Guarded memory(de)allocation.
void(* MEM_freeN)(void *vmemh)
void *(* MEM_callocN)(size_t len, const char *str)
struct UndoStep * step_active
struct UndoStep * step_active_memfile
struct UndoStep * step_init
const struct UndoType * type
void(* step_decode)(struct bContext *C, struct Main *bmain, UndoStep *us, eUndoStepDir dir, bool is_final)
bool(* step_encode)(struct bContext *C, struct Main *bmain, UndoStep *us)
void(* step_encode_init)(struct bContext *C, UndoStep *us)
void(* step_foreach_ID_ref)(UndoStep *us, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
void(* step_free)(UndoStep *us)
static void undosys_id_ref_resolve(void *user_data, UndoRefID *id_ref)
UndoType * BKE_undosys_type_append(void(*undosys_fn)(UndoType *))
UndoStep * BKE_undosys_step_push_init_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
UndoStep * BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char *name)
bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack, bContext *C, UndoStep *us_target, bool use_skip)
bool BKE_undosys_stack_has_undo(const UndoStack *ustack, const char *name)
const UndoType * BKE_UNDOSYS_TYPE_SCULPT
bool BKE_undosys_step_redo_with_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
void BKE_undosys_stack_init_from_context(UndoStack *ustack, bContext *C)
bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C)
static void undosys_stack_validate(UndoStack *ustack, bool expect_non_empty)
bool BKE_undosys_step_undo(UndoStack *ustack, bContext *C)
void BKE_undosys_stack_clear_active(UndoStack *ustack)
#define UNDO_NESTED_CHECK_END
static void UNUSED_FUNCTION(BKE_undosys_foreach_ID_ref(UndoStack *ustack, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data))
static const UndoType * BKE_undosys_type_from_context(bContext *C)
static ListBase g_undo_types
bool BKE_undosys_step_undo_with_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
UndoStack * BKE_undosys_stack_create(void)
static bool g_undo_callback_running
#define UNDO_NESTED_CHECK_BEGIN
eUndoPushReturn BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char *name)
eUndoStepDir BKE_undosys_step_calc_direction(const UndoStack *ustack, const UndoStep *us_target, const UndoStep *us_reference)
UndoStep * BKE_undosys_step_same_type_prev(UndoStep *us)
UndoStep * BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut)
static void undosys_stack_clear_all_last(UndoStack *ustack, UndoStep *us)
const UndoType * BKE_UNDOSYS_TYPE_MEMFILE
const UndoType * BKE_UNDOSYS_TYPE_PARTICLE
static void undosys_stack_clear_all_first(UndoStack *ustack, UndoStep *us, UndoStep *us_exclude)
void BKE_undosys_stack_clear(UndoStack *ustack)
const UndoType * BKE_UNDOSYS_TYPE_TEXT
UndoStep * BKE_undosys_step_find_by_name(UndoStack *ustack, const char *name)
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit)
UndoStep * BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut)
bool BKE_undosys_step_load_data_ex(UndoStack *ustack, bContext *C, UndoStep *us_target, UndoStep *us_reference, const bool use_skip)
UndoStep * BKE_undosys_step_find_by_name_with_type(UndoStack *ustack, const char *name, const UndoType *ut)
static void undosys_step_free_and_unlink(UndoStack *ustack, UndoStep *us)
void BKE_undosys_step_load_from_index(UndoStack *ustack, bContext *C, const int index)
UndoStep * BKE_undosys_step_same_type_next(UndoStep *us)
eUndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
UndoStep * BKE_undosys_step_find_by_type(UndoStack *ustack, const UndoType *ut)
static void undosys_id_ref_store(void *UNUSED(user_data), UndoRefID *id_ref)
void BKE_undosys_stack_destroy(UndoStack *ustack)
#define UNDO_NESTED_ASSERT(state)
void BKE_undosys_stack_group_end(UndoStack *ustack)
static bool undosys_step_encode(bContext *C, Main *bmain, UndoStack *ustack, UndoStep *us)
static UndoStep * undosys_step_iter_first(UndoStep *us_reference, const eUndoStepDir undo_dir)
static bool undosys_stack_push_main(UndoStack *ustack, const char *name, struct Main *bmain)
bool BKE_undosys_step_load_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
const UndoType * BKE_UNDOSYS_TYPE_PAINTCURVE
void BKE_undosys_type_free_all(void)
bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack, bContext *C, UndoStep *us_target, bool use_skip)
void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain)
void BKE_undosys_print(UndoStack *ustack)
static void undosys_step_decode(bContext *C, Main *bmain, UndoStack *ustack, UndoStep *us, const eUndoStepDir dir, bool is_final)
void BKE_undosys_stack_group_begin(UndoStack *ustack)
const UndoType * BKE_UNDOSYS_TYPE_IMAGE