From e535ff44ffd686def7aafec401acec657f5a614c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 5 Feb 2019 14:24:11 +1100 Subject: Undo System: remove accumulate/store modes This complicated handling of undo steps in a generic way especially switching between undo systems that stored data to ones that accumulated changes. Now each undo system must treat it's steps as check-point, internally it can apply/rewind changes. This commit also fixes projection paint where the object mode wasn't following the undo steps. --- source/blender/blenkernel/BKE_undo_system.h | 21 +-- source/blender/blenkernel/intern/undo_system.c | 33 +++-- .../blender/editors/armature/editarmature_undo.c | 1 - source/blender/editors/curve/editcurve_undo.c | 1 - source/blender/editors/curve/editfont_undo.c | 1 - source/blender/editors/include/ED_paint.h | 2 +- source/blender/editors/lattice/editlattice_undo.c | 1 - source/blender/editors/mesh/editmesh_undo.c | 1 - source/blender/editors/metaball/editmball_undo.c | 1 - .../blender/editors/physics/particle_edit_undo.c | 1 - .../editors/sculpt_paint/paint_curve_undo.c | 1 - source/blender/editors/sculpt_paint/paint_image.c | 4 +- .../editors/sculpt_paint/paint_image_proj.c | 2 +- .../editors/sculpt_paint/paint_image_undo.c | 145 ++++++++++++++++----- source/blender/editors/sculpt_paint/sculpt_undo.c | 58 ++++++++- source/blender/editors/space_image/image_ops.c | 2 +- source/blender/editors/space_text/text_undo.c | 73 +++++++++-- source/blender/editors/undo/memfile_undo.c | 14 +- 18 files changed, 268 insertions(+), 94 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h index 2b1c67f372b..15f4bac17a9 100644 --- a/source/blender/blenkernel/BKE_undo_system.h +++ b/source/blender/blenkernel/BKE_undo_system.h @@ -72,24 +72,11 @@ typedef struct UndoStep { bool skip; /** Some situations require the global state to be stored, edge cases when exiting modes. */ bool use_memfile_step; + /** For use by undo systems that accumulate changes (text editor, painting). */ + bool is_applied; /* Over alloc 'type->struct_size'. */ } UndoStep; -typedef enum eUndoTypeMode { - /** - * Each undo step stores a version of the state. - * This means we can simply load in a previous state at any time. - */ - BKE_UNDOTYPE_MODE_STORE = 1, - /** - * Each undo step is a series of edits. - * This means to change states we need to apply each edit. - * It also means the 'step_decode' callback needs to detect the difference between undo and redo. - * (Currently used for text edit and image & sculpt painting). - */ - BKE_UNDOTYPE_MODE_ACCUMULATE = 2, -} eUndoTypeMode; - typedef void (*UndoTypeForEachIDRefFn)(void *user_data, struct UndoRefID *id_ref); typedef struct UndoType { @@ -122,7 +109,6 @@ typedef struct UndoType { void (*step_foreach_ID_ref)(UndoStep *us, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data); - eUndoTypeMode mode; bool use_context; int step_size; @@ -136,6 +122,9 @@ extern const UndoType *BKE_UNDOSYS_TYPE_PARTICLE; extern const UndoType *BKE_UNDOSYS_TYPE_SCULPT; extern const UndoType *BKE_UNDOSYS_TYPE_TEXT; +#define BKE_UNDOSYS_TYPE_IS_MEMFILE_SKIP(ty) \ + ELEM(ty, BKE_UNDOSYS_TYPE_IMAGE) + UndoStack *BKE_undosys_stack_create(void); void BKE_undosys_stack_destroy(UndoStack *ustack); void BKE_undosys_stack_clear(UndoStack *ustack); diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c index f56dd953283..b0836f822a6 100644 --- a/source/blender/blenkernel/intern/undo_system.c +++ b/source/blender/blenkernel/intern/undo_system.c @@ -337,7 +337,7 @@ void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain) void BKE_undosys_stack_init_from_context(UndoStack *ustack, bContext *C) { const UndoType *ut = BKE_undosys_type_from_context(C); - if ((ut != NULL) && (ut != BKE_UNDOSYS_TYPE_MEMFILE) && (ut->mode == BKE_UNDOTYPE_MODE_STORE)) { + if ((ut != NULL) && (ut != BKE_UNDOSYS_TYPE_MEMFILE)) { BKE_undosys_step_push_with_type(ustack, C, "original mode", ut); } } @@ -657,16 +657,17 @@ bool BKE_undosys_step_undo_with_data_ex( if (ustack->step_active) { UndoStep *us_iter = ustack->step_active; while (us_iter != us) { - if (us_iter->type->mode == BKE_UNDOTYPE_MODE_ACCUMULATE) { - undosys_step_decode(C, G_MAIN, ustack, us_iter, -1); - } + /* TODO: + * - skip successive steps that store the same data, eg: memfile steps. + * - or steps that include another steps data, eg: a memfile step includes text undo data. + */ + undosys_step_decode(C, G_MAIN, ustack, us_iter, -1); us_iter = us_iter->prev; } } - if (us->type->mode != BKE_UNDOTYPE_MODE_ACCUMULATE) { - undosys_step_decode(C, G_MAIN, ustack, us, -1); - } + undosys_step_decode(C, G_MAIN, ustack, us, -1); + ustack->step_active = us_prev; undosys_stack_validate(ustack, true); if (use_skip) { @@ -712,14 +713,11 @@ bool BKE_undosys_step_redo_with_data_ex( if (ustack->step_active && ustack->step_active->next) { UndoStep *us_iter = ustack->step_active->next; while (us_iter != us) { - if (us_iter->type->mode == BKE_UNDOTYPE_MODE_ACCUMULATE) { - undosys_step_decode(C, G_MAIN, ustack, us_iter, 1); - } + undosys_step_decode(C, G_MAIN, ustack, us_iter, 1); us_iter = us_iter->next; } } - /* Unlike undo, always redo accumulation state. */ undosys_step_decode(C, G_MAIN, ustack, us, 1); ustack->step_active = us_next; if (use_skip) { @@ -793,8 +791,6 @@ UndoType *BKE_undosys_type_append(void (*undosys_fn)(UndoType *)) undosys_fn(ut); - BLI_assert(ut->mode != 0); - BLI_addtail(&g_undo_types, ut); return ut; @@ -1010,14 +1006,15 @@ ID *BKE_undosys_ID_map_lookup_with_prev(const UndoIDPtrMap *map, ID *id_src, ID void BKE_undosys_print(UndoStack *ustack) { - printf("Undo %d Steps (A: active, M=memfile-active, S=skip)\n", + printf("Undo %d Steps (*: active, #=applied, M=memfile-active, S=skip)\n", BLI_listbase_count(&ustack->steps)); int index = 0; for (UndoStep *us = ustack->steps.first; us; us = us->next) { - printf("[%c%c%c] %3d type='%s', name='%s'\n", - (us == ustack->step_active) ? 'A' : '_', - (us == ustack->step_active_memfile) ? 'M' : '_', - us->skip ? 'S' : '_', + printf("[%c%c%c%c] %3d type='%s', name='%s'\n", + (us == ustack->step_active) ? '*' : ' ', + us->is_applied ? '#' : ' ', + (us == ustack->step_active_memfile) ? 'M' : ' ', + us->skip ? 'S' : ' ', index, us->type->name, us->name); diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c index 597e0ab0891..e6b794f047d 100644 --- a/source/blender/editors/armature/editarmature_undo.c +++ b/source/blender/editors/armature/editarmature_undo.c @@ -227,7 +227,6 @@ void ED_armature_undosys_type(UndoType *ut) ut->step_foreach_ID_ref = armature_undosys_foreach_ID_ref; - ut->mode = BKE_UNDOTYPE_MODE_STORE; ut->use_context = true; ut->step_size = sizeof(ArmatureUndoStep); diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c index 1a66ae33508..2099a509342 100644 --- a/source/blender/editors/curve/editcurve_undo.c +++ b/source/blender/editors/curve/editcurve_undo.c @@ -294,7 +294,6 @@ void ED_curve_undosys_type(UndoType *ut) ut->step_foreach_ID_ref = curve_undosys_foreach_ID_ref; - ut->mode = BKE_UNDOTYPE_MODE_STORE; ut->use_context = true; ut->step_size = sizeof(CurveUndoStep); diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c index d0d00150447..02539dd4dbe 100644 --- a/source/blender/editors/curve/editfont_undo.c +++ b/source/blender/editors/curve/editfont_undo.c @@ -383,7 +383,6 @@ void ED_font_undosys_type(UndoType *ut) ut->step_foreach_ID_ref = font_undosys_foreach_ID_ref; - ut->mode = BKE_UNDOTYPE_MODE_STORE; ut->use_context = true; ut->step_size = sizeof(FontUndoStep); diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h index 0c414366484..7608f2c7a13 100644 --- a/source/blender/editors/include/ED_paint.h +++ b/source/blender/editors/include/ED_paint.h @@ -40,7 +40,7 @@ void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op); /* paint_image_undo.c */ -void ED_image_undo_push_begin(const char *name); +void ED_image_undo_push_begin(const char *name, int paint_mode); void ED_image_undo_push_end(void); void ED_image_undo_restore(struct UndoStep *us); diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c index 95087060536..aa37ff2df42 100644 --- a/source/blender/editors/lattice/editlattice_undo.c +++ b/source/blender/editors/lattice/editlattice_undo.c @@ -230,7 +230,6 @@ void ED_lattice_undosys_type(UndoType *ut) ut->step_foreach_ID_ref = lattice_undosys_foreach_ID_ref; - ut->mode = BKE_UNDOTYPE_MODE_STORE; ut->use_context = true; ut->step_size = sizeof(LatticeUndoStep); diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index cfaa3da2f9b..f1b57c8143f 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -794,7 +794,6 @@ void ED_mesh_undosys_type(UndoType *ut) ut->step_foreach_ID_ref = mesh_undosys_foreach_ID_ref; - ut->mode = BKE_UNDOTYPE_MODE_STORE; ut->use_context = true; ut->step_size = sizeof(MeshUndoStep); diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c index c20c61f5a06..91af12c08a2 100644 --- a/source/blender/editors/metaball/editmball_undo.c +++ b/source/blender/editors/metaball/editmball_undo.c @@ -237,7 +237,6 @@ void ED_mball_undosys_type(UndoType *ut) ut->step_foreach_ID_ref = mball_undosys_foreach_ID_ref; - ut->mode = BKE_UNDOTYPE_MODE_STORE; ut->use_context = true; ut->step_size = sizeof(MBallUndoStep); diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c index 983397a51fc..0ffd6fb5a94 100644 --- a/source/blender/editors/physics/particle_edit_undo.c +++ b/source/blender/editors/physics/particle_edit_undo.c @@ -283,7 +283,6 @@ void ED_particle_undosys_type(UndoType *ut) ut->step_foreach_ID_ref = particle_undosys_foreach_ID_ref; - ut->mode = BKE_UNDOTYPE_MODE_STORE; ut->use_context = true; ut->step_size = sizeof(ParticleUndoStep); diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c index fbd2d0153a1..02d95ed54f8 100644 --- a/source/blender/editors/sculpt_paint/paint_curve_undo.c +++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c @@ -134,7 +134,6 @@ void ED_paintcurve_undosys_type(UndoType *ut) ut->step_decode = paintcurve_undosys_step_decode; ut->step_free = paintcurve_undosys_step_free; - ut->mode = BKE_UNDOTYPE_MODE_STORE; ut->use_context = false; ut->step_size = sizeof(PaintCurveUndoStep); diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 8bd83900439..92b00a1505f 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -489,7 +489,7 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo } settings->imapaint.flag |= IMAGEPAINT_DRAWING; - ED_image_undo_push_begin(op->type->name); + ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D); return pop; } @@ -1234,7 +1234,7 @@ void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op) BKE_undosys_step_push_init_with_type(wm->undo_stack, C, op->type->name, BKE_UNDOSYS_TYPE_IMAGE); - ED_image_undo_push_begin(op->type->name); + ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D); paint_2d_bucket_fill(C, color, NULL, NULL, NULL); diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 182a0912533..bb9391a052c 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -5546,7 +5546,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING; - ED_image_undo_push_begin(op->type->name); + ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_3D); /* allocate and initialize spatial data structures */ project_paint_begin(C, &ps, false, 0); diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c index 04d58877608..20696ed1e91 100644 --- a/source/blender/editors/sculpt_paint/paint_image_undo.c +++ b/source/blender/editors/sculpt_paint/paint_image_undo.c @@ -36,6 +36,7 @@ #include "BKE_context.h" #include "BKE_image.h" +#include "BKE_paint.h" #include "BKE_undo_system.h" #include "DEG_depsgraph.h" @@ -43,6 +44,7 @@ #include "ED_paint.h" #include "ED_undo.h" #include "ED_util.h" +#include "ED_object.h" #include "GPU_draw.h" @@ -349,19 +351,6 @@ static void image_undo_free_list(ListBase *lb) } } -void ED_image_undo_push_begin(const char *name) -{ - UndoStack *ustack = ED_undo_stack_get(); - bContext *C = NULL; /* special case, we never read from this. */ - BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE); -} - -void ED_image_undo_push_end(void) -{ - UndoStack *ustack = ED_undo_stack_get(); - BKE_undosys_step_push(ustack, NULL, NULL); -} - static void image_undo_invalidate(void) { UndoImageTile *tile; @@ -381,6 +370,8 @@ static void image_undo_invalidate(void) typedef struct ImageUndoStep { UndoStep step; ListBase tiles; + bool is_encode_init; + ePaintMode paint_mode; /* Use for all ID lookups (can be NULL). */ struct UndoIDPtrMap *id_map; @@ -432,10 +423,11 @@ static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep { ImageUndoStep *us = (ImageUndoStep *)us_p; /* dummy, memory is cleared anyway. */ + us->is_encode_init = true; BLI_listbase_clear(&us->tiles); } -static bool image_undosys_step_encode(struct bContext *UNUSED(C), struct Main *UNUSED(bmain), UndoStep *us_p) +static bool image_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p) { /* dummy, encoding is done along the way by adding tiles * to the current 'ImageUndoStep' added by encode_init. */ @@ -445,33 +437,100 @@ static bool image_undosys_step_encode(struct bContext *UNUSED(C), struct Main *U int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; - - /* first dispose of invalid tiles (may happen due to drag dot for instance) */ - for (UndoImageTile *tile = us->tiles.first; tile;) { - if (!tile->valid) { - UndoImageTile *tmp_tile = tile->next; - MEM_freeN(tile->rect.pt); - BLI_freelinkN(&us->tiles, tile); - tile = tmp_tile; - } - else { - us->step.data_size += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char)); - tile = tile->next; + if (us->is_encode_init) { + /* first dispose of invalid tiles (may happen due to drag dot for instance) */ + for (UndoImageTile *tile = us->tiles.first; tile;) { + if (!tile->valid) { + UndoImageTile *tmp_tile = tile->next; + MEM_freeN(tile->rect.pt); + BLI_freelinkN(&us->tiles, tile); + tile = tmp_tile; + } + else { + us->step.data_size += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char)); + tile = tile->next; + } } } + else { + /* Happens when switching modes. */ + ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C); + BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D)); + us->paint_mode = paint_mode; + } image_undosys_step_encode_store_ids(us); + us_p->is_applied = true; + return true; } -static void image_undosys_step_decode(struct bContext *UNUSED(C), struct Main *bmain, UndoStep *us_p, int UNUSED(dir)) + +static void image_undosys_step_decode_undo_impl(ImageUndoStep *us) +{ + BLI_assert(us->step.is_applied == true); + image_undo_restore_list(&us->tiles, us->id_map); + us->step.is_applied = false; +} + +static void image_undosys_step_decode_redo_impl(ImageUndoStep *us) +{ + BLI_assert(us->step.is_applied == false); + image_undo_restore_list(&us->tiles, us->id_map); + us->step.is_applied = true; +} + +static void image_undosys_step_decode_undo(ImageUndoStep *us) +{ + ImageUndoStep *us_iter = us; + while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) { + if (us_iter->step.next->is_applied == false) { + break; + } + us_iter = (ImageUndoStep *)us_iter->step.next; + } + while (us_iter != us) { + image_undosys_step_decode_undo_impl(us_iter); + us_iter = (ImageUndoStep *)us_iter->step.prev; + } +} + +static void image_undosys_step_decode_redo(ImageUndoStep *us) +{ + ImageUndoStep *us_iter = us; + while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) { + if (us_iter->step.prev->is_applied == true) { + break; + } + us_iter = (ImageUndoStep *)us_iter->step.prev; + } + while (us_iter && (us_iter->step.is_applied == false)) { + image_undosys_step_decode_redo_impl(us_iter); + if (us_iter == us) { + break; + } + us_iter = (ImageUndoStep *)us_iter->step.next; + } +} + +static void image_undosys_step_decode(struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir) { ImageUndoStep *us = (ImageUndoStep *)us_p; #if 0 paint_undosys_step_decode_restore_ids(us); #endif - image_undo_restore_list(&us->tiles, us->id_map); + + if (dir < 0) { + image_undosys_step_decode_undo(us); + } + else { + image_undosys_step_decode_redo(us); + } + + if (us->paint_mode == PAINT_MODE_TEXTURE_3D) { + ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT); + } /* Refresh texture slots. */ ED_editors_init_for_undo(bmain); @@ -505,7 +564,6 @@ void ED_image_undosys_type(UndoType *ut) ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref; - ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE; ut->use_context = true; ut->step_size = sizeof(ImageUndoStep); @@ -527,8 +585,17 @@ ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p) ListBase *ED_image_undo_get_tiles(void) { UndoStack *ustack = ED_undo_stack_get(); - UndoStep *us = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE); - return ED_image_undosys_step_get_tiles(us); + UndoStep *us_prev = ustack->step_init; + UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE); + ImageUndoStep *us = (ImageUndoStep *)us_p; + /* We should always have an undo push started when accessing tiles, + * not doing this means we won't have paint_mode correctly set. */ + BLI_assert(us_p == us_prev); + if (us_p != us_prev) { + /* Fallback value until we can be sure this never happens. */ + us->paint_mode = PAINT_MODE_TEXTURE_2D; + } + return ED_image_undosys_step_get_tiles(us_p); } /* restore painting image to previous state. Used for anchored and drag-dot style brushes*/ @@ -539,4 +606,20 @@ void ED_image_undo_restore(UndoStep *us) image_undo_invalidate(); } +void ED_image_undo_push_begin(const char *name, int paint_mode) +{ + UndoStack *ustack = ED_undo_stack_get(); + bContext *C = NULL; /* special case, we never read from this. */ + UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE); + ImageUndoStep *us = (ImageUndoStep *)us_p; + BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D)); + us->paint_mode = paint_mode; +} + +void ED_image_undo_push_end(void) +{ + UndoStack *ustack = ED_undo_stack_get(); + BKE_undosys_step_push(ustack, NULL, NULL); +} + /** \} */ diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 1794fbfe41f..a8c8490fb79 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -1048,17 +1048,70 @@ static bool sculpt_undosys_step_encode(struct bContext *UNUSED(C), struct Main * if (unode && unode->type == SCULPT_UNDO_DYNTOPO_END) { us->step.use_memfile_step = true; } + us->step.is_applied = true; return true; } -static void sculpt_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int UNUSED(dir)) +static void sculpt_undosys_step_decode_undo_impl(struct bContext *C, SculptUndoStep *us) +{ + BLI_assert(us->step.is_applied == true); + sculpt_undo_restore_list(C, &us->data.nodes); + us->step.is_applied = false; +} + +static void sculpt_undosys_step_decode_redo_impl(struct bContext *C, SculptUndoStep *us) +{ + BLI_assert(us->step.is_applied == false); + sculpt_undo_restore_list(C, &us->data.nodes); + us->step.is_applied = true; +} + +static void sculpt_undosys_step_decode_undo(struct bContext *C, SculptUndoStep *us) +{ + SculptUndoStep *us_iter = us; + while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) { + if (us_iter->step.next->is_applied == false) { + break; + } + us_iter = (SculptUndoStep *)us_iter->step.next; + } + while (us_iter != us) { + sculpt_undosys_step_decode_undo_impl(C, us_iter); + us_iter = (SculptUndoStep *)us_iter->step.prev; + } +} + +static void sculpt_undosys_step_decode_redo(struct bContext *C, SculptUndoStep *us) +{ + SculptUndoStep *us_iter = us; + while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) { + if (us_iter->step.prev->is_applied == true) { + break; + } + us_iter = (SculptUndoStep *)us_iter->step.prev; + } + while (us_iter && (us_iter->step.is_applied == false)) { + sculpt_undosys_step_decode_redo_impl(C, us_iter); + if (us_iter == us) { + break; + } + us_iter = (SculptUndoStep *)us_iter->step.next; + } +} + +static void sculpt_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int dir) { /* TODO(campbell): undo_system: use low-level API to set mode. */ ED_object_mode_set(C, OB_MODE_SCULPT); BLI_assert(sculpt_undosys_poll(C)); SculptUndoStep *us = (SculptUndoStep *)us_p; - sculpt_undo_restore_list(C, &us->data.nodes); + if (dir < 0) { + sculpt_undosys_step_decode_undo(C, us); + } + else { + sculpt_undosys_step_decode_redo(C, us); + } } static void sculpt_undosys_step_free(UndoStep *us_p) @@ -1077,7 +1130,6 @@ void ED_sculpt_undosys_type(UndoType *ut) ut->step_decode = sculpt_undosys_step_decode; ut->step_free = sculpt_undosys_step_free; - ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE; ut->use_context = true; ut->step_size = sizeof(SculptUndoStep); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 6afe7538dd1..5669cbe532b 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -2609,7 +2609,7 @@ static int image_invert_exec(bContext *C, wmOperator *op) } if (support_undo) { - ED_image_undo_push_begin(op->type->name); + ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D); /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles * but better do this right in case someone copies this for a tool that uses partial * redraw better */ diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c index e945481a2bd..869c7d03af9 100644 --- a/source/blender/editors/space_text/text_undo.c +++ b/source/blender/editors/space_text/text_undo.c @@ -101,6 +101,8 @@ static bool text_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bma return false; } + us_p->is_applied = true; + us->text_ref.ptr = text; us->step.data_size = us->data.len; @@ -108,25 +110,73 @@ static bool text_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bma return true; } + +static void text_undosys_step_decode_undo_impl(Text *text, TextUndoStep *us) +{ + BLI_assert(us->step.is_applied == true); + TextUndoBuf data = us->data; + while (data.pos > -1) { + txt_do_undo(text, &data); + } + BLI_assert(data.pos == -1); + us->step.is_applied = false; +} + +static void text_undosys_step_decode_redo_impl(Text *text, TextUndoStep *us) +{ + BLI_assert(us->step.is_applied == false); + TextUndoBuf data = us->data; + data.pos = -1; + while (data.pos < us->data.pos) { + txt_do_redo(text, &data); + } + BLI_assert(data.pos == us->data.pos); + us->step.is_applied = true; +} + +static void text_undosys_step_decode_undo(Text *text, TextUndoStep *us) +{ + TextUndoStep *us_iter = us; + while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) { + if (us_iter->step.next->is_applied == false) { + break; + } + us_iter = (TextUndoStep *)us_iter->step.next; + } + while (us_iter != us) { + text_undosys_step_decode_undo_impl(text, us_iter); + us_iter = (TextUndoStep *)us_iter->step.prev; + } +} + +static void text_undosys_step_decode_redo(Text *text, TextUndoStep *us) +{ + TextUndoStep *us_iter = us; + while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) { + if (us_iter->step.prev->is_applied == true) { + break; + } + us_iter = (TextUndoStep *)us_iter->step.prev; + } + while (us_iter && (us_iter->step.is_applied == false)) { + text_undosys_step_decode_redo_impl(text, us_iter); + if (us_iter == us) { + break; + } + us_iter = (TextUndoStep *)us_iter->step.next; + } +} + static void text_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int dir) { TextUndoStep *us = (TextUndoStep *)us_p; Text *text = us->text_ref.ptr; if (dir < 0) { - TextUndoBuf data = us->data; - while (data.pos > -1) { - txt_do_undo(text, &data); - } - BLI_assert(data.pos == -1); + text_undosys_step_decode_undo(text, us); } else { - TextUndoBuf data = us->data; - data.pos = -1; - while (data.pos < us->data.pos) { - txt_do_redo(text, &data); - } - BLI_assert(data.pos == us->data.pos); + text_undosys_step_decode_redo(text, us); } SpaceText *st = CTX_wm_space_text(C); @@ -166,7 +216,6 @@ void ED_text_undosys_type(UndoType *ut) ut->step_foreach_ID_ref = text_undosys_foreach_ID_ref; - ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE; ut->use_context = false; ut->step_size = sizeof(TextUndoStep); diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index 8fdbfa389a0..04a2c220f73 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -89,6 +89,19 @@ static void memfile_undosys_step_decode(struct bContext *C, struct Main *bmain, MemFileUndoStep *us = (MemFileUndoStep *)us_p; BKE_memfile_undo_decode(us->data, C); + for (UndoStep *us_iter = us_p->next; us_iter; us_iter = us_iter->next) { + if (BKE_UNDOSYS_TYPE_IS_MEMFILE_SKIP(us_iter->type)) { + continue; + } + us_iter->is_applied = false; + } + for (UndoStep *us_iter = us_p; us_iter; us_iter = us_iter->prev) { + if (BKE_UNDOSYS_TYPE_IS_MEMFILE_SKIP(us_iter->type)) { + continue; + } + us_iter->is_applied = true; + } + /* bmain has been freed. */ bmain = CTX_data_main(C); ED_editors_init_for_undo(bmain); @@ -120,7 +133,6 @@ void ED_memfile_undosys_type(UndoType *ut) ut->step_decode = memfile_undosys_step_decode; ut->step_free = memfile_undosys_step_free; - ut->mode = BKE_UNDOTYPE_MODE_STORE; ut->use_context = true; ut->step_size = sizeof(MemFileUndoStep); -- cgit v1.2.3