UI: Wider Dyntopo popover to fit all settings
[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 #include "DNA_object_types.h"
40
41 #include "BLI_utildefines.h"
42 #include "BLI_callbacks.h"
43 #include "BLI_listbase.h"
44
45 #include "BLT_translation.h"
46
47 #include "BKE_blender_undo.h"
48 #include "BKE_context.h"
49 #include "BKE_global.h"
50 #include "BKE_main.h"
51 #include "BKE_screen.h"
52 #include "BKE_layer.h"
53 #include "BKE_undo_system.h"
54
55 #include "ED_gpencil.h"
56 #include "ED_render.h"
57 #include "ED_screen.h"
58 #include "ED_undo.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62 #include "WM_toolsystem.h"
63
64 #include "RNA_access.h"
65 #include "RNA_define.h"
66
67 #include "UI_interface.h"
68 #include "UI_resources.h"
69
70 /** We only need this locally. */
71 static CLG_LogRef LOG = {"ed.undo"};
72
73 /* -------------------------------------------------------------------- */
74 /** \name Generic Undo System Access
75  *
76  * Non-operator undo editor functions.
77  * \{ */
78
79 void ED_undo_push(bContext *C, const char *str)
80 {
81         CLOG_INFO(&LOG, 1, "name='%s'", str);
82
83         const int steps = U.undosteps;
84
85         if (steps <= 0) {
86                 return;
87         }
88
89         wmWindowManager *wm = CTX_wm_manager(C);
90
91         /* Only apply limit if this is the last undo step. */
92         if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) {
93                 BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, steps - 1, 0);
94         }
95
96         BKE_undosys_step_push(wm->undo_stack, C, str);
97
98         if (U.undomemory != 0) {
99                 const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024;
100                 BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, 0, memory_limit);
101         }
102
103         WM_file_tag_modified();
104 }
105
106 /* note: also check undo_history_exec() in bottom if you change notifiers */
107 static int ed_undo_step(bContext *C, int step, const char *undoname)
108 {
109         CLOG_INFO(&LOG, 1, "name='%s', step=%d", undoname, step);
110         wmWindowManager *wm = CTX_wm_manager(C);
111         wmWindow *win = CTX_wm_window(C);
112         Scene *scene = CTX_data_scene(C);
113
114         /* undo during jobs are running can easily lead to freeing data using by jobs,
115          * or they can just lead to freezing job in some other cases */
116         if (WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY)) {
117                 return OPERATOR_CANCELLED;
118         }
119
120         /* TODO(campbell): undo_system: use undo system */
121         /* grease pencil can be can be used in plenty of spaces, so check it first */
122         if (ED_gpencil_session_active()) {
123                 return ED_undo_gpencil_step(C, step, undoname);
124         }
125
126         UndoStep *step_data_from_name = NULL;
127         int step_for_callback = step;
128         if (undoname != NULL) {
129                 step_data_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undoname);
130                 if (step_data_from_name == NULL) {
131                         return OPERATOR_CANCELLED;
132                 }
133
134                 /* happens on redo. */
135                 // BLI_assert(step_data_from_name != wm->undo_stack->step_active);
136                 /* TODO(campbell): could use simple optimization. */
137                 step_for_callback = (
138                         BLI_findindex(&wm->undo_stack->steps, step_data_from_name) <
139                         BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ? 1 : -1;
140         }
141
142         /* App-Handlers (pre). */
143         {
144                 /* Note: ignore grease pencil for now. */
145                 Main *bmain = CTX_data_main(C);
146                 wm->op_undo_depth++;
147                 BLI_callback_exec(bmain, &scene->id, (step_for_callback > 0) ? BLI_CB_EVT_UNDO_PRE : BLI_CB_EVT_REDO_PRE);
148                 wm->op_undo_depth--;
149         }
150
151
152         /* Undo System */
153         {
154                 if (undoname) {
155                         BKE_undosys_step_undo_with_data(wm->undo_stack, C, step_data_from_name);
156                 }
157                 else {
158                         BKE_undosys_step_undo_compat_only(wm->undo_stack, C, step);
159                 }
160         }
161
162         /* App-Handlers (post). */
163         {
164                 Main *bmain = CTX_data_main(C);
165                 scene = CTX_data_scene(C);
166                 wm->op_undo_depth++;
167                 BLI_callback_exec(bmain, &scene->id, step_for_callback > 0 ? BLI_CB_EVT_UNDO_PRE : BLI_CB_EVT_REDO_PRE);
168                 wm->op_undo_depth--;
169         }
170
171         WM_event_add_notifier(C, NC_WINDOW, NULL);
172         WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL);
173
174         Main *bmain = CTX_data_main(C);
175         WM_toolsystem_refresh_screen_all(bmain);
176
177         if (win) {
178                 win->addmousemove = true;
179         }
180
181         return OPERATOR_FINISHED;
182 }
183
184 void ED_undo_grouped_push(bContext *C, const char *str)
185 {
186         /* do nothing if previous undo task is the same as this one (or from the same undo group) */
187         wmWindowManager *wm = CTX_wm_manager(C);
188         const UndoStep *us = wm->undo_stack->step_active;
189         if (us && STREQ(str, us->name)) {
190                 BKE_undosys_stack_clear_active(wm->undo_stack);
191         }
192
193         /* push as usual */
194         ED_undo_push(C, str);
195 }
196
197 void ED_undo_pop(bContext *C)
198 {
199         ed_undo_step(C, 1, NULL);
200 }
201 void ED_undo_redo(bContext *C)
202 {
203         ed_undo_step(C, -1, NULL);
204 }
205
206 void ED_undo_push_op(bContext *C, wmOperator *op)
207 {
208         /* in future, get undo string info? */
209         ED_undo_push(C, op->type->name);
210 }
211
212 void ED_undo_grouped_push_op(bContext *C, wmOperator *op)
213 {
214         if (op->type->undo_group[0] != '\0') {
215                 ED_undo_grouped_push(C, op->type->undo_group);
216         }
217         else {
218                 ED_undo_grouped_push(C, op->type->name);
219         }
220 }
221
222 void ED_undo_pop_op(bContext *C, wmOperator *op)
223 {
224         /* search back a couple of undo's, in case something else added pushes */
225         ed_undo_step(C, 0, op->type->name);
226 }
227
228 /* name optionally, function used to check for operator redo panel */
229 bool ED_undo_is_valid(const bContext *C, const char *undoname)
230 {
231         wmWindowManager *wm = CTX_wm_manager(C);
232         return BKE_undosys_stack_has_undo(wm->undo_stack, undoname);
233 }
234
235 /**
236  * Ideally we wont access the stack directly,
237  * this is needed for modes which handle undo themselves (bypassing #ED_undo_push).
238  *
239  * Using global isn't great, this just avoids doing inline,
240  * causing 'BKE_global.h' & 'BKE_main.h' includes.
241  */
242 UndoStack *ED_undo_stack_get(void)
243 {
244         wmWindowManager *wm = G_MAIN->wm.first;
245         return wm->undo_stack;
246 }
247
248 /** \} */
249
250 /* -------------------------------------------------------------------- */
251 /** \name Undo, Undo Push & Redo Operators
252  * \{ */
253
254 static int ed_undo_exec(bContext *C, wmOperator *UNUSED(op))
255 {
256         /* "last operator" should disappear, later we can tie this with undo stack nicer */
257         WM_operator_stack_clear(CTX_wm_manager(C));
258         return ed_undo_step(C, 1, NULL);
259 }
260
261 static int ed_undo_push_exec(bContext *C, wmOperator *op)
262 {
263         char str[BKE_UNDO_STR_MAX];
264         RNA_string_get(op->ptr, "message", str);
265         ED_undo_push(C, str);
266         return OPERATOR_FINISHED;
267 }
268
269 static int ed_redo_exec(bContext *C, wmOperator *UNUSED(op))
270 {
271         return ed_undo_step(C, -1, NULL);
272 }
273
274 static int ed_undo_redo_exec(bContext *C, wmOperator *UNUSED(op))
275 {
276         wmOperator *last_op = WM_operator_last_redo(C);
277         const int ret = ED_undo_operator_repeat(C, last_op);
278         return ret ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
279 }
280
281 static bool ed_undo_redo_poll(bContext *C)
282 {
283         wmOperator *last_op = WM_operator_last_redo(C);
284         return last_op && ED_operator_screenactive(C) &&
285                 WM_operator_check_ui_enabled(C, last_op->type->name);
286 }
287
288 void ED_OT_undo(wmOperatorType *ot)
289 {
290         /* identifiers */
291         ot->name = "Undo";
292         ot->description = "Undo previous action";
293         ot->idname = "ED_OT_undo";
294
295         /* api callbacks */
296         ot->exec = ed_undo_exec;
297         ot->poll = ED_operator_screenactive;
298 }
299
300 void ED_OT_undo_push(wmOperatorType *ot)
301 {
302         /* identifiers */
303         ot->name = "Undo Push";
304         ot->description = "Add an undo state (internal use only)";
305         ot->idname = "ED_OT_undo_push";
306
307         /* api callbacks */
308         ot->exec = ed_undo_push_exec;
309
310         ot->flag = OPTYPE_INTERNAL;
311
312         RNA_def_string(ot->srna, "message", "Add an undo step *function may be moved*", BKE_UNDO_STR_MAX, "Undo Message", "");
313 }
314
315 void ED_OT_redo(wmOperatorType *ot)
316 {
317         /* identifiers */
318         ot->name = "Redo";
319         ot->description = "Redo previous action";
320         ot->idname = "ED_OT_redo";
321
322         /* api callbacks */
323         ot->exec = ed_redo_exec;
324         ot->poll = ED_operator_screenactive;
325 }
326
327 void ED_OT_undo_redo(wmOperatorType *ot)
328 {
329         /* identifiers */
330         ot->name = "Undo and Redo";
331         ot->description = "Undo and redo previous action";
332         ot->idname = "ED_OT_undo_redo";
333
334         /* api callbacks */
335         ot->exec = ed_undo_redo_exec;
336         ot->poll = ed_undo_redo_poll;
337 }
338
339 /** \} */
340
341 /* -------------------------------------------------------------------- */
342 /** \name Operator Repeat
343  * \{ */
344
345 /* ui callbacks should call this rather than calling WM_operator_repeat() themselves */
346 int ED_undo_operator_repeat(bContext *C, wmOperator *op)
347 {
348         int ret = 0;
349
350         if (op) {
351                 CLOG_INFO(&LOG, 1, "idname='%s'", op->type->idname);
352                 wmWindowManager *wm = CTX_wm_manager(C);
353                 struct Scene *scene = CTX_data_scene(C);
354
355                 /* keep in sync with logic in view3d_panel_operator_redo() */
356                 ARegion *ar_orig = CTX_wm_region(C);
357                 ARegion *ar_win = BKE_area_find_region_active_win(CTX_wm_area(C));
358
359                 if (ar_win) {
360                         CTX_wm_region_set(C, ar_win);
361                 }
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                         if (G.debug & G_DEBUG)
375                                 printf("redo_cb: operator redo %s\n", op->type->name);
376
377                         WM_operator_free_all_after(wm, op);
378
379                         ED_undo_pop_op(C, op);
380
381                         if (op->type->check) {
382                                 if (op->type->check(C, op)) {
383                                         /* check for popup and re-layout buttons */
384                                         ARegion *ar_menu = CTX_wm_menu(C);
385                                         if (ar_menu) {
386                                                 ED_region_tag_refresh_ui(ar_menu);
387                                         }
388                                 }
389                         }
390
391                         retval = WM_operator_repeat(C, op);
392                         if ((retval & OPERATOR_FINISHED) == 0) {
393                                 if (G.debug & G_DEBUG)
394                                         printf("redo_cb: operator redo failed: %s, return %d\n", op->type->name, retval);
395                                 ED_undo_redo(C);
396                         }
397                         else {
398                                 ret = 1;
399                         }
400                 }
401                 else {
402                         if (G.debug & G_DEBUG) {
403                                 printf("redo_cb: WM_operator_repeat_check returned false %s\n", op->type->name);
404                         }
405                 }
406
407                 /* set region back */
408                 CTX_wm_region_set(C, ar_orig);
409         }
410         else {
411                 CLOG_WARN(&LOG, "called with NULL 'op'");
412         }
413
414         return ret;
415 }
416
417
418 void ED_undo_operator_repeat_cb(bContext *C, void *arg_op, void *UNUSED(arg_unused))
419 {
420         ED_undo_operator_repeat(C, (wmOperator *)arg_op);
421 }
422
423 void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_event))
424 {
425         ED_undo_operator_repeat(C, (wmOperator *)arg_op);
426 }
427
428 /** \} */
429
430 /* -------------------------------------------------------------------- */
431 /** \name Undo History Operator
432  * \{ */
433
434 /* create enum based on undo items */
435 static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem)
436 {
437         EnumPropertyItem item_tmp = {0}, *item = NULL;
438         int i = 0;
439
440         wmWindowManager *wm = CTX_wm_manager(C);
441         if (wm->undo_stack == NULL) {
442                 return NULL;
443         }
444
445         for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
446                 if (us->skip == false) {
447                         item_tmp.identifier = us->name;
448                         item_tmp.name = IFACE_(us->name);
449                         if (us == wm->undo_stack->step_active) {
450                                 item_tmp.icon = ICON_HIDE_OFF;
451                         }
452                         else {
453                                 item_tmp.icon = ICON_NONE;
454                         }
455                         item_tmp.value = i;
456                         RNA_enum_item_add(&item, totitem, &item_tmp);
457                 }
458         }
459         RNA_enum_item_end(&item, totitem);
460
461         return item;
462 }
463
464
465 static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
466 {
467         int totitem = 0;
468
469         {
470                 const EnumPropertyItem *item = rna_undo_itemf(C, &totitem);
471
472                 if (totitem > 0) {
473                         uiPopupMenu *pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE);
474                         uiLayout *layout = UI_popup_menu_layout(pup);
475                         uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
476                         uiLayout *column = NULL;
477                         const int col_size = 20 + totitem / 12;
478                         int i, c;
479                         bool add_col = true;
480
481                         for (c = 0, i = totitem; i--;) {
482                                 if (add_col && !(c % col_size)) {
483                                         column = uiLayoutColumn(split, false);
484                                         add_col = false;
485                                 }
486                                 if (item[i].identifier) {
487                                         uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value);
488                                         ++c;
489                                         add_col = true;
490                                 }
491                         }
492
493                         MEM_freeN((void *)item);
494
495                         UI_popup_menu_end(C, pup);
496                 }
497
498         }
499         return OPERATOR_CANCELLED;
500 }
501
502 /* note: also check ed_undo_step() in top if you change notifiers */
503 static int undo_history_exec(bContext *C, wmOperator *op)
504 {
505         PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
506         if (RNA_property_is_set(op->ptr, prop)) {
507                 int item = RNA_property_int_get(op->ptr, prop);
508                 wmWindowManager *wm = CTX_wm_manager(C);
509                 BKE_undosys_step_undo_from_index(wm->undo_stack, C, item);
510                 WM_event_add_notifier(C, NC_WINDOW, NULL);
511                 return OPERATOR_FINISHED;
512         }
513         return OPERATOR_CANCELLED;
514 }
515
516 void ED_OT_undo_history(wmOperatorType *ot)
517 {
518         /* identifiers */
519         ot->name = "Undo History";
520         ot->description = "Redo specific action in history";
521         ot->idname = "ED_OT_undo_history";
522
523         /* api callbacks */
524         ot->invoke = undo_history_invoke;
525         ot->exec = undo_history_exec;
526         ot->poll = ED_operator_screenactive;
527
528         RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
529
530 }
531
532 /** \} */
533
534 /* -------------------------------------------------------------------- */
535 /** \name Undo Helper Functions
536  * \{ */
537
538 void ED_undo_object_set_active_or_warn(ViewLayer *view_layer, Object *ob, const char *info, CLG_LogRef *log)
539 {
540         Object *ob_prev = OBACT(view_layer);
541         if (ob_prev != ob) {
542                 Base *base = BKE_view_layer_base_find(view_layer, ob);
543                 if (base != NULL) {
544                         view_layer->basact = base;
545                 }
546                 else {
547                         /* Should never fail, may not crash but can give odd behavior. */
548                         CLOG_WARN(log, "'%s' failed to restore active object: '%s'", info, ob->id.name + 2);
549                 }
550         }
551 }
552
553 /** \} */