WM: move mousemove out of internal undo function
[blender.git] / source / blender / editors / undo / ed_undo.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2004 Blender Foundation
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/undo/ed_undo.c
29  *  \ingroup edundo
30  */
31
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "CLG_log.h"
37
38 #include "DNA_scene_types.h"
39
40 #include "BLI_utildefines.h"
41 #include "BLI_callbacks.h"
42 #include "BLI_listbase.h"
43
44 #include "BLT_translation.h"
45
46 #include "BKE_blender_undo.h"
47 #include "BKE_context.h"
48 #include "BKE_global.h"
49 #include "BKE_main.h"
50 #include "BKE_screen.h"
51 #include "BKE_undo_system.h"
52
53 #include "ED_gpencil.h"
54 #include "ED_render.h"
55 #include "ED_screen.h"
56 #include "ED_undo.h"
57
58 #include "WM_api.h"
59 #include "WM_types.h"
60
61 #include "RNA_access.h"
62 #include "RNA_define.h"
63
64 #include "UI_interface.h"
65 #include "UI_resources.h"
66
67 /** We only need this locally. */
68 static CLG_LogRef LOG = {"ed.undo"};
69
70 /* -------------------------------------------------------------------- */
71 /** \name Generic Undo System Access
72  *
73  * Non-operator undo editor functions.
74  * \{ */
75
76 void ED_undo_push(bContext *C, const char *str)
77 {
78         CLOG_INFO(&LOG, 1, "name='%s'", str);
79
80         const int steps = U.undosteps;
81
82         if (steps <= 0) {
83                 return;
84         }
85
86         wmWindowManager *wm = CTX_wm_manager(C);
87
88         /* Only apply limit if this is the last undo step. */
89         if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) {
90                 BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, steps - 1, 0);
91         }
92
93         BKE_undosys_step_push(wm->undo_stack, C, str);
94
95         if (U.undomemory != 0) {
96                 const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024;
97                 BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, 0, memory_limit);
98         }
99
100         WM_file_tag_modified();
101 }
102
103 /* note: also check undo_history_exec() in bottom if you change notifiers */
104 static int ed_undo_step(bContext *C, int step, const char *undoname)
105 {
106         CLOG_INFO(&LOG, 1, "name='%s', step=%d", undoname, step);
107         wmWindowManager *wm = CTX_wm_manager(C);
108         Scene *scene = CTX_data_scene(C);
109
110         /* undo during jobs are running can easily lead to freeing data using by jobs,
111          * or they can just lead to freezing job in some other cases */
112         WM_jobs_kill_all(wm);
113
114         /* TODO(campbell): undo_system: use undo system */
115         /* grease pencil can be can be used in plenty of spaces, so check it first */
116         if (ED_gpencil_session_active()) {
117                 return ED_undo_gpencil_step(C, step, undoname);
118         }
119
120         UndoStep *step_data_from_name = NULL;
121         int step_for_callback = step;
122         if (undoname != NULL) {
123                 step_data_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undoname);
124                 if (step_data_from_name == NULL) {
125                         return OPERATOR_CANCELLED;
126                 }
127
128                 /* TODO(campbell), could use simple optimization. */
129                 /* Pointers match on redo. */
130                 step_for_callback = (
131                         BLI_findindex(&wm->undo_stack->steps, step_data_from_name) <
132                         BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ? 1 : -1;
133         }
134
135         /* App-Handlers (pre). */
136         {
137                 /* Note: ignore grease pencil for now. */
138                 Main *bmain = CTX_data_main(C);
139                 wm->op_undo_depth++;
140                 BLI_callback_exec(bmain, &scene->id, (step_for_callback > 0) ? BLI_CB_EVT_UNDO_PRE : BLI_CB_EVT_REDO_PRE);
141                 wm->op_undo_depth--;
142         }
143
144
145         /* Undo System */
146         {
147                 if (undoname) {
148                         BKE_undosys_step_undo_with_data(wm->undo_stack, C, step_data_from_name);
149                 }
150                 else {
151                         BKE_undosys_step_undo_compat_only(wm->undo_stack, C, step);
152                 }
153         }
154
155         /* App-Handlers (post). */
156         {
157                 Main *bmain = CTX_data_main(C);
158                 scene = CTX_data_scene(C);
159                 wm->op_undo_depth++;
160                 BLI_callback_exec(bmain, &scene->id, step_for_callback > 0 ? BLI_CB_EVT_UNDO_PRE : BLI_CB_EVT_REDO_PRE);
161                 wm->op_undo_depth--;
162         }
163
164         WM_event_add_notifier(C, NC_WINDOW, NULL);
165         WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL);
166
167         return OPERATOR_FINISHED;
168 }
169
170 void ED_undo_grouped_push(bContext *C, const char *str)
171 {
172         /* do nothing if previous undo task is the same as this one (or from the same undo group) */
173         wmWindowManager *wm = CTX_wm_manager(C);
174         const UndoStep *us = wm->undo_stack->step_active;
175         if (us && STREQ(str, us->name)) {
176                 BKE_undosys_stack_clear_active(wm->undo_stack);
177         }
178
179         /* push as usual */
180         ED_undo_push(C, str);
181 }
182
183 void ED_undo_pop(bContext *C)
184 {
185         ed_undo_step(C, 1, NULL);
186 }
187 void ED_undo_redo(bContext *C)
188 {
189         ed_undo_step(C, -1, NULL);
190 }
191
192 void ED_undo_push_op(bContext *C, wmOperator *op)
193 {
194         /* in future, get undo string info? */
195         ED_undo_push(C, op->type->name);
196 }
197
198 void ED_undo_grouped_push_op(bContext *C, wmOperator *op)
199 {
200         if (op->type->undo_group[0] != '\0') {
201                 ED_undo_grouped_push(C, op->type->undo_group);
202         }
203         else {
204                 ED_undo_grouped_push(C, op->type->name);
205         }
206 }
207
208 void ED_undo_pop_op(bContext *C, wmOperator *op)
209 {
210         /* search back a couple of undo's, in case something else added pushes */
211         ed_undo_step(C, 0, op->type->name);
212 }
213
214 /* name optionally, function used to check for operator redo panel */
215 bool ED_undo_is_valid(const bContext *C, const char *undoname)
216 {
217         wmWindowManager *wm = CTX_wm_manager(C);
218         return BKE_undosys_stack_has_undo(wm->undo_stack, undoname);
219 }
220
221 /**
222  * Ideally we wont access the stack directly,
223  * this is needed for modes which handle undo themselves (bypassing #ED_undo_push).
224  *
225  * Using global isn't great, this just avoids doing inline,
226  * causing 'BKE_global.h' & 'BKE_main.h' includes.
227  */
228 UndoStack *ED_undo_stack_get(void)
229 {
230         wmWindowManager *wm = G_MAIN->wm.first;
231         return wm->undo_stack;
232 }
233
234 /** \} */
235
236 /* -------------------------------------------------------------------- */
237 /** \name Undo, Undo Push & Redo Operators
238  * \{ */
239
240 static int ed_undo_exec(bContext *C, wmOperator *UNUSED(op))
241 {
242         /* "last operator" should disappear, later we can tie this with undo stack nicer */
243         WM_operator_stack_clear(CTX_wm_manager(C));
244         int ret = ed_undo_step(C, 1, NULL);
245         if (ret & OPERATOR_FINISHED) {
246                 /* Keep button under the cursor active. */
247                 WM_event_add_mousemove(C);
248         }
249         return ret;
250 }
251
252 static int ed_undo_push_exec(bContext *C, wmOperator *op)
253 {
254         char str[BKE_UNDO_STR_MAX];
255         RNA_string_get(op->ptr, "message", str);
256         ED_undo_push(C, str);
257         return OPERATOR_FINISHED;
258 }
259
260 static int ed_redo_exec(bContext *C, wmOperator *UNUSED(op))
261 {
262         int ret = ed_undo_step(C, -1, NULL);
263         if (ret & OPERATOR_FINISHED) {
264                 /* Keep button under the cursor active. */
265                 WM_event_add_mousemove(C);
266         }
267         return ret;
268 }
269
270 static int ed_undo_redo_exec(bContext *C, wmOperator *UNUSED(op))
271 {
272         wmOperator *last_op = WM_operator_last_redo(C);
273         int ret = ED_undo_operator_repeat(C, last_op);
274         ret = ret ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
275         if (ret & OPERATOR_FINISHED) {
276                 /* Keep button under the cursor active. */
277                 WM_event_add_mousemove(C);
278         }
279         return ret;
280 }
281
282 static bool ed_undo_redo_poll(bContext *C)
283 {
284         wmOperator *last_op = WM_operator_last_redo(C);
285         return last_op && ED_operator_screenactive(C) &&
286                 WM_operator_check_ui_enabled(C, last_op->type->name);
287 }
288
289 void ED_OT_undo(wmOperatorType *ot)
290 {
291         /* identifiers */
292         ot->name = "Undo";
293         ot->description = "Undo previous action";
294         ot->idname = "ED_OT_undo";
295
296         /* api callbacks */
297         ot->exec = ed_undo_exec;
298         ot->poll = ED_operator_screenactive;
299 }
300
301 void ED_OT_undo_push(wmOperatorType *ot)
302 {
303         /* identifiers */
304         ot->name = "Undo Push";
305         ot->description = "Add an undo state (internal use only)";
306         ot->idname = "ED_OT_undo_push";
307
308         /* api callbacks */
309         ot->exec = ed_undo_push_exec;
310
311         ot->flag = OPTYPE_INTERNAL;
312
313         RNA_def_string(ot->srna, "message", "Add an undo step *function may be moved*", BKE_UNDO_STR_MAX, "Undo Message", "");
314 }
315
316 void ED_OT_redo(wmOperatorType *ot)
317 {
318         /* identifiers */
319         ot->name = "Redo";
320         ot->description = "Redo previous action";
321         ot->idname = "ED_OT_redo";
322
323         /* api callbacks */
324         ot->exec = ed_redo_exec;
325         ot->poll = ED_operator_screenactive;
326 }
327
328 void ED_OT_undo_redo(wmOperatorType *ot)
329 {
330         /* identifiers */
331         ot->name = "Undo and Redo";
332         ot->description = "Undo and redo previous action";
333         ot->idname = "ED_OT_undo_redo";
334
335         /* api callbacks */
336         ot->exec = ed_undo_redo_exec;
337         ot->poll = ed_undo_redo_poll;
338 }
339
340 /** \} */
341
342 /* -------------------------------------------------------------------- */
343 /** \name Operator Repeat
344  * \{ */
345
346 /* ui callbacks should call this rather than calling WM_operator_repeat() themselves */
347 int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
348 {
349         int ret = 0;
350
351         if (op) {
352                 CLOG_INFO(&LOG, 1, "idname='%s'", op->type->idname);
353                 wmWindowManager *wm = CTX_wm_manager(C);
354                 struct Scene *scene = CTX_data_scene(C);
355
356                 /* keep in sync with logic in view3d_panel_operator_redo() */
357                 ARegion *ar = CTX_wm_region(C);
358                 ARegion *ar1 = BKE_area_find_region_active_win(CTX_wm_area(C));
359
360                 if (ar1)
361                         CTX_wm_region_set(C, ar1);
362
363                 if ((WM_operator_repeat_check(C, op)) &&
364                     (WM_operator_poll(C, op->type)) &&
365                      /* note, undo/redo cant run if there are jobs active,
366                       * check for screen jobs only so jobs like material/texture/world preview
367                       * (which copy their data), wont stop redo, see [#29579]],
368                       *
369                       * note, - WM_operator_check_ui_enabled() jobs test _must_ stay in sync with this */
370                     (WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY) == 0))
371                 {
372                         int retval;
373
374                         ED_viewport_render_kill_jobs(wm, CTX_data_main(C), true);
375
376                         if (G.debug & G_DEBUG)
377                                 printf("redo_cb: operator redo %s\n", op->type->name);
378
379                         WM_operator_free_all_after(wm, op);
380
381                         ED_undo_pop_op(C, op);
382
383                         if (op->type->check) {
384                                 if (op->type->check(C, op)) {
385                                         /* check for popup and re-layout buttons */
386                                         ARegion *ar_menu = CTX_wm_menu(C);
387                                         if (ar_menu) {
388                                                 ED_region_tag_refresh_ui(ar_menu);
389                                         }
390                                 }
391                         }
392
393                         retval = WM_operator_repeat(C, op);
394                         if ((retval & OPERATOR_FINISHED) == 0) {
395                                 if (G.debug & G_DEBUG)
396                                         printf("redo_cb: operator redo failed: %s, return %d\n", op->type->name, retval);
397                                 ED_undo_redo(C);
398                         }
399                         else {
400                                 ret = 1;
401                         }
402                 }
403                 else {
404                         if (G.debug & G_DEBUG) {
405                                 printf("redo_cb: WM_operator_repeat_check returned false %s\n", op->type->name);
406                         }
407                 }
408
409                 /* set region back */
410                 CTX_wm_region_set(C, ar);
411         }
412         else {
413                 CLOG_WARN(&LOG, "called with NULL 'op'");
414         }
415
416         return ret;
417 }
418
419
420 void ED_undo_operator_repeat_cb(bContext *C, void *arg_op, void *UNUSED(arg_unused))
421 {
422         ED_undo_operator_repeat(C, (wmOperator *)arg_op);
423 }
424
425 void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_event))
426 {
427         ED_undo_operator_repeat(C, (wmOperator *)arg_op);
428 }
429
430 /** \} */
431
432 /* -------------------------------------------------------------------- */
433 /** \name Undo History Operator
434  * \{ */
435
436 /* create enum based on undo items */
437 static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem)
438 {
439         EnumPropertyItem item_tmp = {0}, *item = NULL;
440         int i = 0;
441
442         wmWindowManager *wm = CTX_wm_manager(C);
443         if (wm->undo_stack == NULL) {
444                 return NULL;
445         }
446
447         for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
448                 if (us->skip == false) {
449                         item_tmp.identifier = us->name;
450                         item_tmp.name = IFACE_(us->name);
451                         if (us == wm->undo_stack->step_active) {
452                                 item_tmp.icon = ICON_RESTRICT_VIEW_OFF;
453                         }
454                         else {
455                                 item_tmp.icon = ICON_NONE;
456                         }
457                         item_tmp.value = i;
458                         RNA_enum_item_add(&item, totitem, &item_tmp);
459                 }
460         }
461         RNA_enum_item_end(&item, totitem);
462
463         return item;
464 }
465
466
467 static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
468 {
469         int totitem = 0;
470
471         {
472                 const EnumPropertyItem *item = rna_undo_itemf(C, &totitem);
473
474                 if (totitem > 0) {
475                         uiPopupMenu *pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
476                         uiLayout *layout = UI_popup_menu_layout(pup);
477                         uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
478                         uiLayout *column = NULL;
479                         const int col_size = 20 + totitem / 12;
480                         int i, c;
481                         bool add_col = true;
482
483                         for (c = 0, i = totitem; i--;) {
484                                 if (add_col && !(c % col_size)) {
485                                         column = uiLayoutColumn(split, false);
486                                         add_col = false;
487                                 }
488                                 if (item[i].identifier) {
489                                         uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value);
490                                         ++c;
491                                         add_col = true;
492                                 }
493                         }
494
495                         MEM_freeN((void *)item);
496
497                         UI_popup_menu_end(C, pup);
498                 }
499
500         }
501         return OPERATOR_CANCELLED;
502 }
503
504 /* note: also check ed_undo_step() in top if you change notifiers */
505 static int undo_history_exec(bContext *C, wmOperator *op)
506 {
507         PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
508         if (RNA_property_is_set(op->ptr, prop)) {
509                 int item = RNA_property_int_get(op->ptr, prop);
510                 wmWindowManager *wm = CTX_wm_manager(C);
511                 BKE_undosys_step_undo_from_index(wm->undo_stack, C, item);
512                 WM_event_add_notifier(C, NC_WINDOW, NULL);
513                 return OPERATOR_FINISHED;
514         }
515         return OPERATOR_CANCELLED;
516 }
517
518 void ED_OT_undo_history(wmOperatorType *ot)
519 {
520         /* identifiers */
521         ot->name = "Undo History";
522         ot->description = "Redo specific action in history";
523         ot->idname = "ED_OT_undo_history";
524
525         /* api callbacks */
526         ot->invoke = undo_history_invoke;
527         ot->exec = undo_history_exec;
528         ot->poll = ED_operator_screenactive;
529
530         RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
531
532 }
533
534 /** \} */