Undo System: remove accumulate/store modes
authorCampbell Barton <ideasman42@gmail.com>
Tue, 5 Feb 2019 03:24:11 +0000 (14:24 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 6 Feb 2019 00:52:04 +0000 (11:52 +1100)
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.

18 files changed:
source/blender/blenkernel/BKE_undo_system.h
source/blender/blenkernel/intern/undo_system.c
source/blender/editors/armature/editarmature_undo.c
source/blender/editors/curve/editcurve_undo.c
source/blender/editors/curve/editfont_undo.c
source/blender/editors/include/ED_paint.h
source/blender/editors/lattice/editlattice_undo.c
source/blender/editors/mesh/editmesh_undo.c
source/blender/editors/metaball/editmball_undo.c
source/blender/editors/physics/particle_edit_undo.c
source/blender/editors/sculpt_paint/paint_curve_undo.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_image_proj.c
source/blender/editors/sculpt_paint/paint_image_undo.c
source/blender/editors/sculpt_paint/sculpt_undo.c
source/blender/editors/space_image/image_ops.c
source/blender/editors/space_text/text_undo.c
source/blender/editors/undo/memfile_undo.c

index 2b1c67f372b63d1b46ad568bb5db57d96d444a78..15f4bac17a929fdf0615135957a3756629395cd3 100644 (file)
@@ -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);
index f56dd953283f7b547dec52600c6cd24965c8074f..b0836f822a6679754edb271eb74a5ac52b75cac2 100644 (file)
@@ -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);
index 597e0ab0891686ef5308bcda8790ca3c450558fb..e6b794f047d68a1c4f495993cfa898b71b91a82d 100644 (file)
@@ -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);
index 1a66ae33508bd4a68e8b4f6e586c47a5157c8775..2099a5093429f6599d7e1922a15d5f63b5640ad2 100644 (file)
@@ -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);
index d0d00150447611f528219e25a9606bcf10fa8170..02539dd4dbea3896059067e8af2e7cb544302f35 100644 (file)
@@ -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);
index 0c4143664848ef0410b0652a2ad85f44ce428803..7608f2c7a1307d5101a1e420e85a2dc7431fb9f1 100644 (file)
@@ -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);
 
index 950870605366143d342e23a710a07eb1294b7e8f..aa37ff2df420ecb34855a00d0761ee2373af0da2 100644 (file)
@@ -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);
index cfaa3da2f9b00e9c926616e7404961eb60635b1c..f1b57c8143fbbbb7d98bfa4c776f6a0b906bde53 100644 (file)
@@ -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);
index c20c61f5a06d7f7668bb40297961dbc097a6f50f..91af12c08a27493db64da84cead9d3c6c125d621 100644 (file)
@@ -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);
index 983397a51fc8cc5b9910191f8589ada7ea9df74f..0ffd6fb5a94bd6645f2972d604c787810bc2d07c 100644 (file)
@@ -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);
index fbd2d0153a1cc3164f6ae5b4d34acaf984d3eb72..02d95ed54f8f0f268ad7c116c7cd12800bc187ae 100644 (file)
@@ -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);
index 8bd83900439dfaab857d8ad9cc4ba3f8caa96a59..92b00a1505ff0d99dbc453950144c0b31b2b8201 100644 (file)
@@ -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);
 
index 182a09125336275aa040e8cca34a1de87d98755e..bb9391a052c145d6086f78f861599e11630e48e9 100644 (file)
@@ -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);
index 04d58877608d1c8c2604baea7f67e9b0899eaf46..20696ed1e919c7d872fafeff087039a358c3abf5 100644 (file)
@@ -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);
+}
+
 /** \} */
index 1794fbfe41f4537a08ed33486793e6913bcc7c43..a8c8490fb79c47205daaad7d0c619315186d5d51 100644 (file)
@@ -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);
index 6afe7538dd1c82d008b7f44a67a03c5eb21251e3..5669cbe532ba15e497e658ba0fa71719fbf84c41 100644 (file)
@@ -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 */
index e945481a2bd21aa94c2604891a48079069009508..869c7d03af93fb9704021e292e58d6342dfdd6fb 100644 (file)
@@ -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);
index 8fdbfa389a0c0610116b28853847509a463a5e6b..04a2c220f730a552c0a86553fedd8805ef660996 100644 (file)
@@ -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);