diff options
Diffstat (limited to 'source/blender/editors/undo')
-rw-r--r-- | source/blender/editors/undo/ed_undo.c | 53 | ||||
-rw-r--r-- | source/blender/editors/undo/memfile_undo.c | 38 |
2 files changed, 62 insertions, 29 deletions
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index 123fd5f35da..6633e1c427c 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -79,15 +79,26 @@ static CLG_LogRef LOG = {"ed.undo"}; void ED_undo_push(bContext *C, const char *str) { CLOG_INFO(&LOG, 1, "name='%s'", str); + WM_file_tag_modified(); - const int steps = U.undosteps; - + wmWindowManager *wm = CTX_wm_manager(C); + int steps = U.undosteps; + + /* Ensure steps that have been initialized are always pushed, + * even when undo steps are zero. + * + * Note that some modes (paint, sculpt) initialize an undo step before an action runs, + * then accumulate changes there, or restore data from it in the case of 2D painting. + * + * For this reason we need to handle the undo step even when undo steps is set to zero. + */ + if ((steps <= 0) && wm->undo_stack->step_init != NULL) { + steps = 1; + } if (steps <= 0) { return; } - wmWindowManager *wm = CTX_wm_manager(C); - /* Only apply limit if this is the last undo step. */ if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) { BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, steps - 1, 0); @@ -97,14 +108,12 @@ void ED_undo_push(bContext *C, const char *str) if (U.undomemory != 0) { const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024; - BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, 0, memory_limit); + BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, -1, memory_limit); } if (CLOG_CHECK(&LOG, 1)) { BKE_undosys_print(wm->undo_stack); } - - WM_file_tag_modified(); } /** @@ -119,7 +128,7 @@ static int ed_undo_step_impl( CLOG_INFO(&LOG, 1, "name='%s', step=%d", undoname, step); wmWindowManager *wm = CTX_wm_manager(C); Scene *scene = CTX_data_scene(C); - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); /* undo during jobs are running can easily lead to freeing data using by jobs, * or they can just lead to freezing job in some other cases */ @@ -138,7 +147,7 @@ static int ed_undo_step_impl( if (ED_gpencil_session_active()) { return ED_undo_gpencil_step(C, step, undoname); } - if (sa && (sa->spacetype == SPACE_VIEW3D)) { + if (area && (area->spacetype == SPACE_VIEW3D)) { Object *obact = CTX_data_active_object(C); if (obact && (obact->type == OB_GPENCIL)) { ED_gpencil_toggle_brush_cursor(C, false, NULL); @@ -195,7 +204,7 @@ static int ed_undo_step_impl( } /* Set special modes for grease pencil */ - if (sa && (sa->spacetype == SPACE_VIEW3D)) { + if (area && (area->spacetype == SPACE_VIEW3D)) { Object *obact = CTX_data_active_object(C); if (obact && (obact->type == OB_GPENCIL)) { /* set cursor */ @@ -558,11 +567,11 @@ int ED_undo_operator_repeat(bContext *C, wmOperator *op) struct Scene *scene = CTX_data_scene(C); /* keep in sync with logic in view3d_panel_operator_redo() */ - ARegion *ar_orig = CTX_wm_region(C); - ARegion *ar_win = BKE_area_find_region_active_win(CTX_wm_area(C)); + ARegion *region_orig = CTX_wm_region(C); + ARegion *region_win = BKE_area_find_region_active_win(CTX_wm_area(C)); - if (ar_win) { - CTX_wm_region_set(C, ar_win); + if (region_win) { + CTX_wm_region_set(C, region_win); } if ((WM_operator_repeat_check(C, op)) && (WM_operator_poll(C, op->type)) && @@ -585,9 +594,9 @@ int ED_undo_operator_repeat(bContext *C, wmOperator *op) if (op->type->check) { if (op->type->check(C, op)) { /* check for popup and re-layout buttons */ - ARegion *ar_menu = CTX_wm_menu(C); - if (ar_menu) { - ED_region_tag_refresh_ui(ar_menu); + ARegion *region_menu = CTX_wm_menu(C); + if (region_menu) { + ED_region_tag_refresh_ui(region_menu); } } } @@ -610,7 +619,7 @@ int ED_undo_operator_repeat(bContext *C, wmOperator *op) } /* set region back */ - CTX_wm_region_set(C, ar_orig); + CTX_wm_region_set(C, region_orig); } else { CLOG_WARN(&LOG, "called with NULL 'op'"); @@ -816,7 +825,7 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer, { const short object_type = obact->type; - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { Object *ob = base->object; if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) { ID *id = ob->data; @@ -825,7 +834,7 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer, } int len = 0; - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { Object *ob = base->object; if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) { if (ob == obact) { @@ -852,7 +861,7 @@ Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r const short object_type = obact->type; int i = 0; Object **objects = MEM_malloc_arrayN(len, sizeof(*objects), __func__); - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { Object *ob = base->object; if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) { ID *id = ob->data; @@ -881,7 +890,7 @@ Base **ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len const short object_type = obact->type; int i = 0; Base **base_array = MEM_malloc_arrayN(len, sizeof(*base_array), __func__); - for (Base *base = view_layer->object_bases.first; base; base = base->next) { + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { Object *ob = base->object; if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) { ID *id = ob->data; diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index 086aa6c4c9d..2df26abe8b3 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -25,14 +25,17 @@ #include "BLI_ghash.h" +#include "DNA_node_types.h" #include "DNA_object_enums.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BKE_blender_undo.h" #include "BKE_context.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" +#include "BKE_node.h" #include "BKE_scene.h" #include "BKE_undo_system.h" @@ -106,7 +109,6 @@ static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data) ID *id_self = cb_data->id_self; ID **id_pointer = cb_data->id_pointer; BLI_assert((id_self->tag & LIB_TAG_UNDO_OLD_ID_REUSED) != 0); - Main *bmain = cb_data->user_data; ID *id = *id_pointer; if (id != NULL && id->lib == NULL && (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) == 0) { @@ -129,9 +131,6 @@ static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data) } } - /* In case an old, re-used ID is using a newly read data-block (i.e. one of its ID pointers got - * updated), we have to tell the depsgraph about it. */ - DEG_id_tag_update_ex(bmain, id_self, ID_RECALC_COPY_ON_WRITE); return do_stop_iter ? IDWALK_RET_STOP_ITER : IDWALK_RET_NOP; } @@ -148,7 +147,7 @@ static void memfile_undosys_step_decode(struct bContext *C, bool use_old_bmain_data = true; - if (!U.experimental.use_undo_speedup) { + if (USER_EXPERIMENTAL_TEST(&U, use_undo_legacy)) { use_old_bmain_data = false; } else if (undo_direction > 0) { @@ -217,12 +216,37 @@ static void memfile_undosys_step_decode(struct bContext *C, FOREACH_MAIN_ID_BEGIN (bmain, id) { if (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) { BKE_library_foreach_ID_link( - bmain, id, memfile_undosys_step_id_reused_cb, bmain, IDWALK_READONLY); + bmain, id, memfile_undosys_step_id_reused_cb, NULL, IDWALK_READONLY); + } + + /* Tag depsgraph to update data-block for changes that happened between the + * current and the target state, see direct_link_id_restore_recalc(). */ + if (id->recalc) { + DEG_id_tag_update_ex(bmain, id, id->recalc); } } FOREACH_MAIN_ID_END; - BKE_main_id_tag_all(bmain, LIB_TAG_UNDO_OLD_ID_REUSED, false); + FOREACH_MAIN_ID_BEGIN (bmain, id) { + /* Clear temporary tag. */ + id->tag &= ~LIB_TAG_UNDO_OLD_ID_REUSED; + + /* We only start accumulating from this point, any tags set up to here + * are already part of the current undo state. This is done in a second + * loop because DEG_id_tag_update may set tags on other datablocks. */ + id->recalc_after_undo_push = 0; + bNodeTree *nodetree = ntreeFromID(id); + if (nodetree != NULL) { + nodetree->id.recalc_after_undo_push = 0; + } + if (GS(id->name) == ID_SCE) { + Scene *scene = (Scene *)id; + if (scene->master_collection != NULL) { + scene->master_collection->id.recalc_after_undo_push = 0; + } + } + } + FOREACH_MAIN_ID_END; } WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); |