40#define undo_stack _wm_undo_stack_disallow
43#define WITH_GLOBAL_UNDO_KEEP_ONE
46#define WITH_GLOBAL_UNDO_ENSURE_UPDATED
52#define WITH_GLOBAL_UNDO_CORRECT_ORDER
83 if (ut->poll && ut->poll(C)) {
100#define WITH_NESTED_UNDO_CHECK
102#ifdef WITH_NESTED_UNDO_CHECK
104# define UNDO_NESTED_ASSERT(state) BLI_assert(g_undo_callback_running == state)
105# define UNDO_NESTED_CHECK_BEGIN \
107 UNDO_NESTED_ASSERT(false); \
108 g_undo_callback_running = true; \
111# define UNDO_NESTED_CHECK_END \
113 UNDO_NESTED_ASSERT(true); \
114 g_undo_callback_running = false; \
118# define UNDO_NESTED_ASSERT(state) ((void)0)
119# define UNDO_NESTED_CHECK_BEGIN ((void)0)
120# define UNDO_NESTED_CHECK_END ((void)0)
145 id_ref->
ptr =
nullptr;
153 Main *bmain =
static_cast<Main *
>(user_data);
174#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
181 CLOG_INFO(&
LOG, 2,
"encode callback didn't create undo step");
196#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
198 for (
UndoStep *us_iter = us->
prev; us_iter; us_iter = us_iter->prev) {
224#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
241#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
261 if (expect_non_empty) {
271 UndoStack *ustack = MEM_cnew<UndoStack>(__func__);
304 bool is_not_empty = ustack->
step_active !=
nullptr;
318 bool is_not_empty =
true;
325 }
while (us != us_iter);
331 if (us && us == us_exclude) {
336 bool is_not_empty =
true;
340 if (us_iter == us_exclude) {
341 us_iter = us_iter->
next;
346 }
while (us != us_iter);
382 return us && us->
prev;
391 while (us && (us->
type != ut)) {
418 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_INFO(&
LOG, 1,
"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;
493 if (name !=
nullptr) {
528 bool is_not_empty = ustack->
step_active !=
nullptr;
550#ifdef WITH_GLOBAL_UNDO_ENSURE_UPDATED
552 if (
G_MAIN->is_memfile_undo_written ==
false) {
553 const char *name_internal =
"MemFile Internal (pre)";
564# ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
572 bool use_memfile_step =
false;
578 if (us->
name[0] ==
'\0') {
598 if (use_memfile_step) {
602 const char *name_internal = us_prev->
name;
607 us_prev->
skip =
true;
608#ifdef WITH_GLOBAL_UNDO_CORRECT_ORDER
640 while ((us = us->
next)) {
641 if (us->
type == ut) {
653 while ((us = us->
prev)) {
654 if (us->
type == ut) {
667 if (us->type == ut) {
668 if (
STREQ(name, us->name)) {
684 if (us->type == ut) {
695 if (us_reference ==
nullptr) {
707 if (
ELEM(us_target, us_reference, us_reference->
prev)) {
710 if (us_target == us_reference->
next) {
715 for (
UndoStep *us_iter = us_reference->
next; us_iter !=
nullptr; us_iter = us_iter->next) {
716 if (us_iter == us_target) {
720 for (
UndoStep *us_iter = us_reference->
prev; us_iter !=
nullptr; us_iter = us_iter->prev) {
721 if (us_iter == us_target) {
727 "Target undo step not found, this should not happen and may indicate an undo "
743 return (undo_dir == -1) ? us_reference : us_reference->
next;
747 return (undo_dir == -1) ? us_reference->
prev : us_reference->
next;
757 if (us_target ==
nullptr) {
763 if (us_reference ==
nullptr) {
766 if (us_reference ==
nullptr) {
767 CLOG_ERROR(&
LOG,
"could not find a valid initial active target step as reference");
779 UndoStep *us_target_active = us_target;
781 while (us_target_active !=
nullptr && us_target_active->
skip) {
782 us_target_active = (undo_dir == -1) ? us_target_active->
prev : us_target_active->
next;
784 if (us_target_active ==
nullptr) {
787 "undo/redo did not find a step after stepping over skip-steps "
788 "(undo limit exceeded)");
795 "addr=%p, name='%s', type='%s', undo_dir=%d",
803 bool is_processing_extra_skipped_steps =
false;
805 us_iter = (undo_dir == -1) ? us_iter->
prev : us_iter->next)
809 const bool is_final = (us_iter == us_target_active);
811 if (!is_final && is_processing_extra_skipped_steps) {
815 "undo/redo continue with skip addr=%p, name='%s', type='%s'",
818 us_iter->
type->name);
824 if (us_iter == us_target) {
825 is_processing_extra_skipped_steps =
true;
836 "This should never be reached, either undo stack is corrupted, or code above is buggy");
913 UndoType *ut = MEM_cnew<UndoType>(__func__);
996 printf(
"Undo %d Steps (*: active, #=applied, M=memfile-active, S=skip)\n",
1000 printf(
"[%c%c%c%c] %3d {%p} type='%s', name='%s'\n",
1002 us->is_applied ?
'#' :
' ',
1004 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
void(*)(void *user_data, UndoRefID *id_ref) UndoTypeForEachIDRefFn
@ UNDO_PUSH_RET_OVERRIDE_CHANGED
#define BLI_assert_unreachable()
#define BLI_assert_msg(a, msg)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
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_rfindstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define STRNCPY(dst, src)
#define UNUSED_FUNCTION(x)
#define CLOG_ERROR(clg_ref,...)
#define CLOG_INFO(clg_ref, level,...)
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_freeN(void *vmemh)
void *(* MEM_callocN)(size_t len, const char *str)
struct Library_Runtime 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)
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)
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)
const UndoType * BKE_UNDOSYS_TYPE_MEMFILE
UndoStep * BKE_undosys_step_same_type_prev(UndoStep *us)
const UndoType * BKE_UNDOSYS_TYPE_PARTICLE
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)
const UndoType * BKE_UNDOSYS_TYPE_TEXT
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()
const UndoType * BKE_UNDOSYS_TYPE_PAINTCURVE
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)
const UndoType * BKE_UNDOSYS_TYPE_IMAGE