41#define undo_stack _wm_undo_stack_disallow
44#define WITH_GLOBAL_UNDO_KEEP_ONE
47#define WITH_GLOBAL_UNDO_ENSURE_UPDATED
53#define WITH_GLOBAL_UNDO_CORRECT_ORDER
84 if (ut->poll && ut->poll(
C)) {
101#define WITH_NESTED_UNDO_CHECK
103#ifdef WITH_NESTED_UNDO_CHECK
105# define UNDO_NESTED_ASSERT(state) BLI_assert(g_undo_callback_running == state)
106# define UNDO_NESTED_CHECK_BEGIN \
108 UNDO_NESTED_ASSERT(false); \
109 g_undo_callback_running = true; \
112# define UNDO_NESTED_CHECK_END \
114 UNDO_NESTED_ASSERT(true); \
115 g_undo_callback_running = false; \
119# define UNDO_NESTED_ASSERT(state) ((void)0)
120# define UNDO_NESTED_CHECK_BEGIN ((void)0)
121# define UNDO_NESTED_CHECK_END ((void)0)
146 id_ref->
ptr =
nullptr;
154 Main *bmain =
static_cast<Main *
>(user_data);
175#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
197#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
225#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
242#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
262 if (expect_non_empty) {
305 bool is_not_empty = ustack->
step_active !=
nullptr;
319 bool is_not_empty =
true;
326 }
while (us != us_iter);
332 if (us && us == us_exclude) {
337 bool is_not_empty =
true;
341 if (us_iter == us_exclude) {
342 us_iter = us_iter->
next;
347 }
while (us != us_iter);
383 return us && us->
prev;
392 while (us && (us->
type != ut)) {
419 size_t data_size_all = 0;
426 "At step %zu: data_size_all=%zu >= memory_limit=%zu",
434 if (us_count == steps) {
437 if (us->
skip ==
false) {
443 CLOG_DEBUG(&
LOG,
"Total steps %zu: data_size_all=%zu", us_count, data_size_all);
446#ifdef WITH_GLOBAL_UNDO_KEEP_ONE
449 us_exclude = us->
prev;
451 us_exclude = us_exclude->
prev;
457 us_exclude->
skip =
true;
491 if (
name !=
nullptr) {
524 bool is_not_empty = ustack->
step_active !=
nullptr;
546#ifdef WITH_GLOBAL_UNDO_ENSURE_UPDATED
548 if (
G_MAIN->is_memfile_undo_written ==
false) {
549 const char *name_internal =
"MemFile Internal (pre)";
560# ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
568 bool use_memfile_step =
false;
574 if (us->
name[0] ==
'\0') {
594 if (use_memfile_step) {
598 const char *name_internal = us_prev->
name;
603 us_prev->
skip =
true;
604#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
636 while ((us = us->
next)) {
637 if (us->
type == ut) {
649 while ((us = us->
prev)) {
650 if (us->
type == ut) {
663 if (us->type == ut) {
680 if (us->type == ut) {
691 if (us_reference ==
nullptr) {
703 if (
ELEM(us_target, us_reference, us_reference->
prev)) {
706 if (us_target == us_reference->
next) {
711 for (
UndoStep *us_iter = us_reference->
next; us_iter !=
nullptr; us_iter = us_iter->
next) {
712 if (us_iter == us_target) {
716 for (
UndoStep *us_iter = us_reference->
prev; us_iter !=
nullptr; us_iter = us_iter->
prev) {
717 if (us_iter == us_target) {
723 "Target undo step not found, this should not happen and may indicate an undo "
739 return (undo_dir == -1) ? us_reference : us_reference->
next;
743 return (undo_dir == -1) ? us_reference->
prev : us_reference->
next;
753 if (us_target ==
nullptr) {
759 if (us_reference ==
nullptr) {
762 if (us_reference ==
nullptr) {
763 CLOG_ERROR(&
LOG,
"could not find a valid initial active target step as reference");
775 UndoStep *us_target_active = us_target;
777 while (us_target_active !=
nullptr && us_target_active->
skip) {
778 us_target_active = (undo_dir == -1) ? us_target_active->
prev : us_target_active->
next;
780 if (us_target_active ==
nullptr) {
782 "undo/redo did not find a step after stepping over skip-steps "
783 "(undo limit exceeded)");
789 "addr=%p, name='%s', type='%s', undo_dir=%d",
797 bool is_processing_extra_skipped_steps =
false;
799 us_iter = (undo_dir == -1) ? us_iter->
prev : us_iter->
next)
803 const bool is_final = (us_iter == us_target_active);
805 if (!is_final && is_processing_extra_skipped_steps) {
808 "undo/redo continue with skip addr=%p, name='%s', type='%s'",
811 us_iter->type->name);
817 if (us_iter == us_target) {
818 is_processing_extra_skipped_steps =
true;
829 "This should never be reached, either undo stack is corrupted, or code above is buggy");
989 printf(
"Undo %d Steps (*: active, #=applied, M=memfile-active, S=skip)\n",
993 printf(
"[%c%c%c%c] %3d {%p} type='%s', name='%s'\n",
995 us->is_applied ?
'#' :
' ',
997 us->skip ?
'S' :
' ',
void BKE_memfile_undo_free(MemFileUndoData *mfu)
void CTX_data_main_set(bContext *C, Main *bmain)
void CTX_free(bContext *C)
ID * BKE_libblock_find_name_and_library_filepath(Main *bmain, short type, const char *name, const char *lib_filepath_abs)
void BKE_lib_override_library_main_operations_create(Main *bmain, bool force_auto, int *r_report_flags)
@ UNDOTYPE_FLAG_NEED_CONTEXT_FOR_ENCODE
@ UNDOTYPE_FLAG_DECODE_ACTIVE_STEP
const UndoType * BKE_UNDOSYS_TYPE_SCULPT
void(*)(void *user_data, UndoRefID *id_ref) UndoTypeForEachIDRefFn
const UndoType * BKE_UNDOSYS_TYPE_MEMFILE
const UndoType * BKE_UNDOSYS_TYPE_PARTICLE
const UndoType * BKE_UNDOSYS_TYPE_TEXT
@ UNDO_PUSH_RET_OVERRIDE_CHANGED
const UndoType * BKE_UNDOSYS_TYPE_PAINTCURVE
const UndoType * BKE_UNDOSYS_TYPE_IMAGE
#define BLI_assert_unreachable()
#define BLI_assert_msg(a, msg)
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
void * BLI_rfindstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
char * STRNCPY(char(&dst)[N], const char *src)
#define UNUSED_FUNCTION(x)
#define CLOG_ERROR(clg_ref,...)
#define CLOG_DEBUG(clg_ref,...)
#define CLOG_INFO(clg_ref,...)
These structs are the foundation for all linked lists in the library system.
Read Guarded memory(de)allocation.
@ RNA_OVERRIDE_MATCH_RESULT_CREATED
@ RNA_OVERRIDE_MATCH_RESULT_INIT
void * MEM_callocN(size_t len, const char *str)
void MEM_freeN(void *vmemh)
LibraryRuntimeHandle * runtime
char library_filepath_abs[FILE_MAX]
UndoStep * step_active_memfile
void(* step_encode_init)(bContext *C, UndoStep *us)
void(* step_foreach_ID_ref)(UndoStep *us, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
void(* step_free)(UndoStep *us)
void(* step_decode)(bContext *C, Main *bmain, UndoStep *us, eUndoStepDir dir, bool is_final)
bool(* step_encode)(bContext *C, Main *bmain, UndoStep *us)
static void undosys_id_ref_resolve(void *user_data, UndoRefID *id_ref)
static UndoStep * undosys_step_iter_first(UndoStep *us_reference, const eUndoStepDir undo_dir)
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)
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)
UndoStep * BKE_undosys_step_find_by_name_with_type(UndoStack *ustack, const char *name, const UndoType *ut)
bool BKE_undosys_step_redo(UndoStack *ustack, bContext *C)
UndoStep * BKE_undosys_step_find_by_type(UndoStack *ustack, const UndoType *ut)
UndoStep * BKE_undosys_step_same_type_next(UndoStep *us)
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 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)
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)
static void undosys_id_ref_store(void *, UndoRefID *id_ref)
static void undosys_stack_clear_all_last(UndoStack *ustack, UndoStep *us)
UndoStep * BKE_undosys_step_same_type_prev(UndoStep *us)
static void undosys_stack_clear_all_first(UndoStack *ustack, UndoStep *us, UndoStep *us_exclude)
void BKE_undosys_type_free_all()
void BKE_undosys_stack_clear(UndoStack *ustack)
static bool undosys_stack_push_main(UndoStack *ustack, const char *name, Main *bmain)
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit)
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(UndoStack *ustack, const char *name)
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)
eUndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
UndoStep * BKE_undosys_step_push_init_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
void BKE_undosys_stack_destroy(UndoStack *ustack)
void BKE_undosys_stack_init_from_main(UndoStack *ustack, Main *bmain)
#define UNDO_NESTED_ASSERT(state)
void bke_undo_system_linker_workaround()
void BKE_undosys_stack_group_end(UndoStack *ustack)
static bool undosys_step_encode(bContext *C, Main *bmain, UndoStack *ustack, UndoStep *us)
UndoStep * BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut)
bool BKE_undosys_step_load_data(UndoStack *ustack, bContext *C, UndoStep *us_target)
UndoStack * BKE_undosys_stack_create()
bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack, bContext *C, UndoStep *us_target, bool use_skip)
UndoType * BKE_undosys_type_append(void(*undosys_fn)(UndoType *))
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)
UndoStep * BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut)
UndoStep * BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char *name)
void BKE_undosys_stack_group_begin(UndoStack *ustack)