Undo System: remove accumulate/store modes
[blender.git] / source / blender / editors / undo / memfile_undo.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file blender/editors/undo/memfile_undo.c
18  *  \ingroup edundo
19  *
20  * Wrapper between 'ED_undo.h' and 'BKE_undo_system.h' API's.
21  */
22
23 #include "BLI_utildefines.h"
24 #include "BLI_sys_types.h"
25
26 #include "DNA_object_enums.h"
27
28 #include "BKE_blender_undo.h"
29 #include "BKE_context.h"
30 #include "BKE_undo_system.h"
31
32 #include "WM_api.h"
33 #include "WM_types.h"
34
35 #include "ED_object.h"
36 #include "ED_undo.h"
37 #include "ED_util.h"
38
39 #include "../blenloader/BLO_undofile.h"
40
41 #include "undo_intern.h"
42
43 /* -------------------------------------------------------------------- */
44 /** \name Implements ED Undo System
45  * \{ */
46
47 typedef struct MemFileUndoStep {
48         UndoStep step;
49         MemFileUndoData *data;
50 } MemFileUndoStep;
51
52 static bool memfile_undosys_poll(bContext *C)
53 {
54         /* other poll functions must run first, this is a catch-all. */
55
56         if ((U.uiflag & USER_GLOBALUNDO) == 0) {
57                 return false;
58         }
59
60         /* Allow a single memfile undo step (the first). */
61         UndoStack *ustack = ED_undo_stack_get();
62         if ((ustack->step_active != NULL) &&
63             (ED_undo_is_memfile_compatible(C) == false))
64         {
65                 return false;
66         }
67         return true;
68 }
69
70 static bool memfile_undosys_step_encode(struct bContext *UNUSED(C), struct Main *bmain, UndoStep *us_p)
71 {
72         MemFileUndoStep *us = (MemFileUndoStep *)us_p;
73
74         /* Important we only use 'main' from the context (see: BKE_undosys_stack_init_from_main). */
75         UndoStack *ustack = ED_undo_stack_get();
76
77         /* can be NULL, use when set. */
78         MemFileUndoStep *us_prev = (MemFileUndoStep *)BKE_undosys_step_find_by_type(ustack, BKE_UNDOSYS_TYPE_MEMFILE);
79         us->data = BKE_memfile_undo_encode(bmain, us_prev ? us_prev->data : NULL);
80         us->step.data_size = us->data->undo_size;
81
82         return true;
83 }
84
85 static void memfile_undosys_step_decode(struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir))
86 {
87         ED_editors_exit(bmain, false);
88
89         MemFileUndoStep *us = (MemFileUndoStep *)us_p;
90         BKE_memfile_undo_decode(us->data, C);
91
92         for (UndoStep *us_iter = us_p->next; us_iter; us_iter = us_iter->next) {
93                 if (BKE_UNDOSYS_TYPE_IS_MEMFILE_SKIP(us_iter->type)) {
94                         continue;
95                 }
96                 us_iter->is_applied = false;
97         }
98         for (UndoStep *us_iter = us_p; us_iter; us_iter = us_iter->prev) {
99                 if (BKE_UNDOSYS_TYPE_IS_MEMFILE_SKIP(us_iter->type)) {
100                         continue;
101                 }
102                 us_iter->is_applied = true;
103         }
104
105         /* bmain has been freed. */
106         bmain = CTX_data_main(C);
107         ED_editors_init_for_undo(bmain);
108
109         WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
110 }
111
112 static void memfile_undosys_step_free(UndoStep *us_p)
113 {
114         /* To avoid unnecessary slow down, free backwards (so we don't need to merge when clearing all). */
115         MemFileUndoStep *us = (MemFileUndoStep *)us_p;
116         if (us_p->next != NULL) {
117                 UndoStep *us_next_p = BKE_undosys_step_same_type_next(us_p);
118                 if (us_next_p != NULL) {
119                         MemFileUndoStep *us_next = (MemFileUndoStep *)us_next_p;
120                         BLO_memfile_merge(&us->data->memfile, &us_next->data->memfile);
121                 }
122         }
123
124         BKE_memfile_undo_free(us->data);
125 }
126
127 /* Export for ED_undo_sys. */
128 void ED_memfile_undosys_type(UndoType *ut)
129 {
130         ut->name = "Global Undo";
131         ut->poll = memfile_undosys_poll;
132         ut->step_encode = memfile_undosys_step_encode;
133         ut->step_decode = memfile_undosys_step_decode;
134         ut->step_free = memfile_undosys_step_free;
135
136         ut->use_context = true;
137
138         ut->step_size = sizeof(MemFileUndoStep);
139 }
140
141 /** \} */
142
143 /* -------------------------------------------------------------------- */
144 /** \name Utilities
145  * \{ */
146
147 /**
148  * Ideally we wouldn't need to export global undo internals, there are some cases where it's needed though.
149  */
150 static struct MemFile *ed_undosys_step_get_memfile(UndoStep *us_p)
151 {
152         MemFileUndoStep *us = (MemFileUndoStep *)us_p;
153         return &us->data->memfile;
154 }
155
156 struct MemFile *ED_undosys_stack_memfile_get_active(UndoStack *ustack)
157 {
158         UndoStep *us = BKE_undosys_stack_active_with_type(ustack, BKE_UNDOSYS_TYPE_MEMFILE);
159         if (us) {
160                 return ed_undosys_step_get_memfile(us);
161         }
162         return NULL;
163 }
164
165
166 /** \} */