Cleanup: Remove unnecessary step in calling snap callback
[blender.git] / source / blender / editors / undo / ed_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  * The Original Code is Copyright (C) 2004 Blender Foundation
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edundo
22  */
23
24 #include <string.h>
25
26 #include "MEM_guardedalloc.h"
27
28 #include "CLG_log.h"
29
30 #include "DNA_object_types.h"
31 #include "DNA_scene_types.h"
32
33 #include "BLI_listbase.h"
34 #include "BLI_utildefines.h"
35
36 #include "BLT_translation.h"
37
38 #include "BKE_blender_undo.h"
39 #include "BKE_callbacks.h"
40 #include "BKE_context.h"
41 #include "BKE_global.h"
42 #include "BKE_layer.h"
43 #include "BKE_main.h"
44 #include "BKE_paint.h"
45 #include "BKE_report.h"
46 #include "BKE_scene.h"
47 #include "BKE_screen.h"
48 #include "BKE_undo_system.h"
49 #include "BKE_workspace.h"
50
51 #include "BLO_blend_validate.h"
52
53 #include "ED_gpencil.h"
54 #include "ED_object.h"
55 #include "ED_outliner.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_toolsystem.h"
62 #include "WM_types.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   WM_file_tag_modified();
83
84   wmWindowManager *wm = CTX_wm_manager(C);
85   int steps = U.undosteps;
86
87   /* Ensure steps that have been initialized are always pushed,
88    * even when undo steps are zero.
89    *
90    * Note that some modes (paint, sculpt) initialize an undo step before an action runs,
91    * then accumulate changes there, or restore data from it in the case of 2D painting.
92    *
93    * For this reason we need to handle the undo step even when undo steps is set to zero.
94    */
95   if ((steps <= 0) && wm->undo_stack->step_init != NULL) {
96     steps = 1;
97   }
98   if (steps <= 0) {
99     return;
100   }
101
102   /* Only apply limit if this is the last undo step. */
103   if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) {
104     BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, steps - 1, 0);
105   }
106
107   BKE_undosys_step_push(wm->undo_stack, C, str);
108
109   if (U.undomemory != 0) {
110     const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024;
111     BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, -1, memory_limit);
112   }
113
114   if (CLOG_CHECK(&LOG, 1)) {
115     BKE_undosys_print(wm->undo_stack);
116   }
117 }
118
119 /**
120  * \note Also check #undo_history_exec in bottom if you change notifiers.
121  */
122 static int ed_undo_step_impl(
123     bContext *C, int step, const char *undoname, int undo_index, ReportList *reports)
124 {
125   /* Mutually exclusives, ensure correct input. */
126   BLI_assert(((undoname || undo_index != -1) && !step) ||
127              (!(undoname || undo_index != -1) && step));
128   CLOG_INFO(&LOG, 1, "name='%s', step=%d", undoname, step);
129   wmWindowManager *wm = CTX_wm_manager(C);
130   Scene *scene = CTX_data_scene(C);
131   ScrArea *area = CTX_wm_area(C);
132
133   /* undo during jobs are running can easily lead to freeing data using by jobs,
134    * or they can just lead to freezing job in some other cases */
135   WM_jobs_kill_all(wm);
136
137   if (G.debug & G_DEBUG_IO) {
138     Main *bmain = CTX_data_main(C);
139     if (bmain->lock != NULL) {
140       BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* undo step");
141       BLO_main_validate_libraries(bmain, reports);
142     }
143   }
144
145   /* TODO(campbell): undo_system: use undo system */
146   /* grease pencil can be can be used in plenty of spaces, so check it first */
147   if (ED_gpencil_session_active()) {
148     return ED_undo_gpencil_step(C, step, undoname);
149   }
150   if (area && (area->spacetype == SPACE_VIEW3D)) {
151     Object *obact = CTX_data_active_object(C);
152     if (obact && (obact->type == OB_GPENCIL)) {
153       ED_gpencil_toggle_brush_cursor(C, false, NULL);
154     }
155   }
156
157   UndoStep *step_data_from_name = NULL;
158   int step_for_callback = step;
159   if (undoname != NULL) {
160     step_data_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undoname);
161     if (step_data_from_name == NULL) {
162       return OPERATOR_CANCELLED;
163     }
164
165     /* TODO(campbell), could use simple optimization. */
166     /* Pointers match on redo. */
167     step_for_callback = (BLI_findindex(&wm->undo_stack->steps, step_data_from_name) <
168                          BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ?
169                             1 :
170                             -1;
171   }
172   else if (undo_index != -1) {
173     step_for_callback = (undo_index <
174                          BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ?
175                             1 :
176                             -1;
177   }
178
179   /* App-Handlers (pre). */
180   {
181     /* Note: ignore grease pencil for now. */
182     Main *bmain = CTX_data_main(C);
183     wm->op_undo_depth++;
184     BKE_callback_exec_id(
185         bmain, &scene->id, (step_for_callback > 0) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE);
186     wm->op_undo_depth--;
187   }
188
189   /* Undo System */
190   {
191     if (undoname) {
192       BKE_undosys_step_undo_with_data(wm->undo_stack, C, step_data_from_name);
193     }
194     else if (undo_index != -1) {
195       BKE_undosys_step_undo_from_index(wm->undo_stack, C, undo_index);
196     }
197     else {
198       if (step == 1) {
199         BKE_undosys_step_undo(wm->undo_stack, C);
200       }
201       else {
202         BKE_undosys_step_redo(wm->undo_stack, C);
203       }
204     }
205
206     /* Set special modes for grease pencil */
207     if (area && (area->spacetype == SPACE_VIEW3D)) {
208       Object *obact = CTX_data_active_object(C);
209       if (obact && (obact->type == OB_GPENCIL)) {
210         /* set cursor */
211         if (ELEM(obact->mode,
212                  OB_MODE_PAINT_GPENCIL,
213                  OB_MODE_SCULPT_GPENCIL,
214                  OB_MODE_WEIGHT_GPENCIL,
215                  OB_MODE_VERTEX_GPENCIL)) {
216           ED_gpencil_toggle_brush_cursor(C, true, NULL);
217         }
218         else {
219           ED_gpencil_toggle_brush_cursor(C, false, NULL);
220         }
221         /* set workspace mode */
222         Base *basact = CTX_data_active_base(C);
223         ED_object_base_activate(C, basact);
224       }
225     }
226   }
227
228   /* App-Handlers (post). */
229   {
230     Main *bmain = CTX_data_main(C);
231     scene = CTX_data_scene(C);
232     wm->op_undo_depth++;
233     BKE_callback_exec_id(
234         bmain, &scene->id, step_for_callback > 0 ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST);
235     wm->op_undo_depth--;
236   }
237
238   if (G.debug & G_DEBUG_IO) {
239     Main *bmain = CTX_data_main(C);
240     if (bmain->lock != NULL) {
241       BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *AFTER* undo step");
242       BLO_main_validate_libraries(bmain, reports);
243     }
244   }
245
246   WM_event_add_notifier(C, NC_WINDOW, NULL);
247   WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL);
248
249   WM_toolsystem_refresh_active(C);
250
251   Main *bmain = CTX_data_main(C);
252   WM_toolsystem_refresh_screen_all(bmain);
253
254   if (CLOG_CHECK(&LOG, 1)) {
255     BKE_undosys_print(wm->undo_stack);
256   }
257
258   return OPERATOR_FINISHED;
259 }
260
261 static int ed_undo_step_direction(bContext *C, int step, ReportList *reports)
262 {
263   return ed_undo_step_impl(C, step, NULL, -1, reports);
264 }
265
266 static int ed_undo_step_by_name(bContext *C, const char *undo_name, ReportList *reports)
267 {
268   return ed_undo_step_impl(C, 0, undo_name, -1, reports);
269 }
270
271 static int ed_undo_step_by_index(bContext *C, int index, ReportList *reports)
272 {
273   return ed_undo_step_impl(C, 0, NULL, index, reports);
274 }
275
276 void ED_undo_grouped_push(bContext *C, const char *str)
277 {
278   /* do nothing if previous undo task is the same as this one (or from the same undo group) */
279   wmWindowManager *wm = CTX_wm_manager(C);
280   const UndoStep *us = wm->undo_stack->step_active;
281   if (us && STREQ(str, us->name)) {
282     BKE_undosys_stack_clear_active(wm->undo_stack);
283   }
284
285   /* push as usual */
286   ED_undo_push(C, str);
287 }
288
289 void ED_undo_pop(bContext *C)
290 {
291   ed_undo_step_direction(C, 1, NULL);
292 }
293 void ED_undo_redo(bContext *C)
294 {
295   ed_undo_step_direction(C, -1, NULL);
296 }
297
298 void ED_undo_push_op(bContext *C, wmOperator *op)
299 {
300   /* in future, get undo string info? */
301   ED_undo_push(C, op->type->name);
302 }
303
304 void ED_undo_grouped_push_op(bContext *C, wmOperator *op)
305 {
306   if (op->type->undo_group[0] != '\0') {
307     ED_undo_grouped_push(C, op->type->undo_group);
308   }
309   else {
310     ED_undo_grouped_push(C, op->type->name);
311   }
312 }
313
314 void ED_undo_pop_op(bContext *C, wmOperator *op)
315 {
316   /* search back a couple of undo's, in case something else added pushes */
317   ed_undo_step_by_name(C, op->type->name, op->reports);
318 }
319
320 /* name optionally, function used to check for operator redo panel */
321 bool ED_undo_is_valid(const bContext *C, const char *undoname)
322 {
323   wmWindowManager *wm = CTX_wm_manager(C);
324   return BKE_undosys_stack_has_undo(wm->undo_stack, undoname);
325 }
326
327 bool ED_undo_is_memfile_compatible(const bContext *C)
328 {
329   /* Some modes don't co-exist with memfile undo, disable their use: T60593
330    * (this matches 2.7x behavior). */
331   ViewLayer *view_layer = CTX_data_view_layer(C);
332   if (view_layer != NULL) {
333     Object *obact = OBACT(view_layer);
334     if (obact != NULL) {
335       if (obact->mode & OB_MODE_EDIT) {
336         return false;
337       }
338     }
339   }
340   return true;
341 }
342
343 /**
344  * When a property of ID changes, return false.
345  *
346  * This is to avoid changes to a property making undo pushes
347  * which are ignored by the undo-system.
348  * For example, changing a brush property isn't stored by sculpt-mode undo steps.
349  * This workaround is needed until the limitation is removed, see: T61948.
350  */
351 bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id)
352 {
353   ViewLayer *view_layer = CTX_data_view_layer(C);
354   if (view_layer != NULL) {
355     Object *obact = OBACT(view_layer);
356     if (obact != NULL) {
357       if (obact->mode & OB_MODE_ALL_PAINT) {
358         /* Don't store property changes when painting
359          * (only do undo pushes on brush strokes which each paint operator handles on it's own). */
360         CLOG_INFO(&LOG, 1, "skipping undo for paint-mode");
361         return false;
362       }
363       else if (obact->mode & OB_MODE_EDIT) {
364         if ((id == NULL) || (obact->data == NULL) ||
365             (GS(id->name) != GS(((ID *)obact->data)->name))) {
366           /* No undo push on id type mismatch in edit-mode. */
367           CLOG_INFO(&LOG, 1, "skipping undo for edit-mode");
368           return false;
369         }
370       }
371     }
372   }
373   return true;
374 }
375
376 /**
377  * Ideally we wont access the stack directly,
378  * this is needed for modes which handle undo themselves (bypassing #ED_undo_push).
379  *
380  * Using global isn't great, this just avoids doing inline,
381  * causing 'BKE_global.h' & 'BKE_main.h' includes.
382  */
383 UndoStack *ED_undo_stack_get(void)
384 {
385   wmWindowManager *wm = G_MAIN->wm.first;
386   return wm->undo_stack;
387 }
388
389 /** \} */
390
391 /* -------------------------------------------------------------------- */
392 /** \name Undo, Undo Push & Redo Operators
393  * \{ */
394
395 static int ed_undo_exec(bContext *C, wmOperator *op)
396 {
397   /* "last operator" should disappear, later we can tie this with undo stack nicer */
398   WM_operator_stack_clear(CTX_wm_manager(C));
399   int ret = ed_undo_step_direction(C, 1, op->reports);
400   if (ret & OPERATOR_FINISHED) {
401     /* Keep button under the cursor active. */
402     WM_event_add_mousemove(CTX_wm_window(C));
403   }
404
405   ED_outliner_select_sync_from_all_tag(C);
406   return ret;
407 }
408
409 static int ed_undo_push_exec(bContext *C, wmOperator *op)
410 {
411   if (G.background) {
412     /* Exception for background mode, see: T60934.
413      * Note: since the undo stack isn't initialized on startup, background mode behavior
414      * won't match regular usage, this is just for scripts to do explicit undo pushes. */
415     wmWindowManager *wm = CTX_wm_manager(C);
416     if (wm->undo_stack == NULL) {
417       wm->undo_stack = BKE_undosys_stack_create();
418     }
419   }
420   char str[BKE_UNDO_STR_MAX];
421   RNA_string_get(op->ptr, "message", str);
422   ED_undo_push(C, str);
423   return OPERATOR_FINISHED;
424 }
425
426 static int ed_redo_exec(bContext *C, wmOperator *op)
427 {
428   int ret = ed_undo_step_direction(C, -1, op->reports);
429   if (ret & OPERATOR_FINISHED) {
430     /* Keep button under the cursor active. */
431     WM_event_add_mousemove(CTX_wm_window(C));
432   }
433
434   ED_outliner_select_sync_from_all_tag(C);
435   return ret;
436 }
437
438 static int ed_undo_redo_exec(bContext *C, wmOperator *UNUSED(op))
439 {
440   wmOperator *last_op = WM_operator_last_redo(C);
441   int ret = ED_undo_operator_repeat(C, last_op);
442   ret = ret ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
443   if (ret & OPERATOR_FINISHED) {
444     /* Keep button under the cursor active. */
445     WM_event_add_mousemove(CTX_wm_window(C));
446   }
447   return ret;
448 }
449
450 /* Disable in background mode, we could support if it's useful, T60934. */
451
452 static bool ed_undo_is_init_poll(bContext *C)
453 {
454   wmWindowManager *wm = CTX_wm_manager(C);
455   if (wm->undo_stack == NULL) {
456     CTX_wm_operator_poll_msg_set(C, "Undo disabled at startup");
457     return false;
458   }
459   return true;
460 }
461
462 static bool ed_undo_is_init_and_screenactive_poll(bContext *C)
463 {
464   if (ed_undo_is_init_poll(C) == false) {
465     return false;
466   }
467   return ED_operator_screenactive(C);
468 }
469
470 static bool ed_undo_redo_poll(bContext *C)
471 {
472   wmOperator *last_op = WM_operator_last_redo(C);
473   return (last_op && ed_undo_is_init_and_screenactive_poll(C) &&
474           WM_operator_check_ui_enabled(C, last_op->type->name));
475 }
476
477 static bool ed_undo_poll(bContext *C)
478 {
479   if (!ed_undo_is_init_and_screenactive_poll(C)) {
480     return false;
481   }
482   UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack;
483   return (undo_stack->step_active != NULL) && (undo_stack->step_active->prev != NULL);
484 }
485
486 void ED_OT_undo(wmOperatorType *ot)
487 {
488   /* identifiers */
489   ot->name = "Undo";
490   ot->description = "Undo previous action";
491   ot->idname = "ED_OT_undo";
492
493   /* api callbacks */
494   ot->exec = ed_undo_exec;
495   ot->poll = ed_undo_poll;
496 }
497
498 void ED_OT_undo_push(wmOperatorType *ot)
499 {
500   /* identifiers */
501   ot->name = "Undo Push";
502   ot->description = "Add an undo state (internal use only)";
503   ot->idname = "ED_OT_undo_push";
504
505   /* api callbacks */
506   ot->exec = ed_undo_push_exec;
507   /* Unlike others undo operators this initializes undo stack. */
508   ot->poll = ED_operator_screenactive;
509
510   ot->flag = OPTYPE_INTERNAL;
511
512   RNA_def_string(ot->srna,
513                  "message",
514                  "Add an undo step *function may be moved*",
515                  BKE_UNDO_STR_MAX,
516                  "Undo Message",
517                  "");
518 }
519
520 static bool ed_redo_poll(bContext *C)
521 {
522   if (!ed_undo_is_init_and_screenactive_poll(C)) {
523     return false;
524   }
525   UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack;
526   return (undo_stack->step_active != NULL) && (undo_stack->step_active->next != NULL);
527 }
528
529 void ED_OT_redo(wmOperatorType *ot)
530 {
531   /* identifiers */
532   ot->name = "Redo";
533   ot->description = "Redo previous action";
534   ot->idname = "ED_OT_redo";
535
536   /* api callbacks */
537   ot->exec = ed_redo_exec;
538   ot->poll = ed_redo_poll;
539 }
540
541 void ED_OT_undo_redo(wmOperatorType *ot)
542 {
543   /* identifiers */
544   ot->name = "Undo and Redo";
545   ot->description = "Undo and redo previous action";
546   ot->idname = "ED_OT_undo_redo";
547
548   /* api callbacks */
549   ot->exec = ed_undo_redo_exec;
550   ot->poll = ed_undo_redo_poll;
551 }
552
553 /** \} */
554
555 /* -------------------------------------------------------------------- */
556 /** \name Operator Repeat
557  * \{ */
558
559 /* ui callbacks should call this rather than calling WM_operator_repeat() themselves */
560 int ED_undo_operator_repeat(bContext *C, wmOperator *op)
561 {
562   int ret = 0;
563
564   if (op) {
565     CLOG_INFO(&LOG, 1, "idname='%s'", op->type->idname);
566     wmWindowManager *wm = CTX_wm_manager(C);
567     struct Scene *scene = CTX_data_scene(C);
568
569     /* keep in sync with logic in view3d_panel_operator_redo() */
570     ARegion *region_orig = CTX_wm_region(C);
571     ARegion *region_win = BKE_area_find_region_active_win(CTX_wm_area(C));
572
573     if (region_win) {
574       CTX_wm_region_set(C, region_win);
575     }
576
577     if ((WM_operator_repeat_check(C, op)) && (WM_operator_poll(C, op->type)) &&
578         /* note, undo/redo cant run if there are jobs active,
579          * check for screen jobs only so jobs like material/texture/world preview
580          * (which copy their data), wont stop redo, see [#29579]],
581          *
582          * note, - WM_operator_check_ui_enabled() jobs test _must_ stay in sync with this */
583         (WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY) == 0)) {
584       int retval;
585
586       if (G.debug & G_DEBUG) {
587         printf("redo_cb: operator redo %s\n", op->type->name);
588       }
589
590       WM_operator_free_all_after(wm, op);
591
592       ED_undo_pop_op(C, op);
593
594       if (op->type->check) {
595         if (op->type->check(C, op)) {
596           /* check for popup and re-layout buttons */
597           ARegion *region_menu = CTX_wm_menu(C);
598           if (region_menu) {
599             ED_region_tag_refresh_ui(region_menu);
600           }
601         }
602       }
603
604       retval = WM_operator_repeat(C, op);
605       if ((retval & OPERATOR_FINISHED) == 0) {
606         if (G.debug & G_DEBUG) {
607           printf("redo_cb: operator redo failed: %s, return %d\n", op->type->name, retval);
608         }
609         ED_undo_redo(C);
610       }
611       else {
612         ret = 1;
613       }
614     }
615     else {
616       if (G.debug & G_DEBUG) {
617         printf("redo_cb: WM_operator_repeat_check returned false %s\n", op->type->name);
618       }
619     }
620
621     /* set region back */
622     CTX_wm_region_set(C, region_orig);
623   }
624   else {
625     CLOG_WARN(&LOG, "called with NULL 'op'");
626   }
627
628   return ret;
629 }
630
631 void ED_undo_operator_repeat_cb(bContext *C, void *arg_op, void *UNUSED(arg_unused))
632 {
633   ED_undo_operator_repeat(C, (wmOperator *)arg_op);
634 }
635
636 void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_event))
637 {
638   ED_undo_operator_repeat(C, (wmOperator *)arg_op);
639 }
640
641 /** \} */
642
643 /* -------------------------------------------------------------------- */
644 /** \name Undo History Operator
645  * \{ */
646
647 /* create enum based on undo items */
648 static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem)
649 {
650   EnumPropertyItem item_tmp = {0}, *item = NULL;
651   int i = 0;
652
653   wmWindowManager *wm = CTX_wm_manager(C);
654   if (wm->undo_stack == NULL) {
655     return NULL;
656   }
657
658   for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
659     if (us->skip == false) {
660       item_tmp.identifier = us->name;
661       item_tmp.name = IFACE_(us->name);
662       if (us == wm->undo_stack->step_active) {
663         item_tmp.icon = ICON_LAYER_ACTIVE;
664       }
665       else {
666         item_tmp.icon = ICON_NONE;
667       }
668       item_tmp.value = i;
669       RNA_enum_item_add(&item, totitem, &item_tmp);
670     }
671   }
672   RNA_enum_item_end(&item, totitem);
673
674   return item;
675 }
676
677 static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
678 {
679   int totitem = 0;
680
681   {
682     const EnumPropertyItem *item = rna_undo_itemf(C, &totitem);
683
684     if (totitem > 0) {
685       uiPopupMenu *pup = UI_popup_menu_begin(
686           C, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
687       uiLayout *layout = UI_popup_menu_layout(pup);
688       uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
689       uiLayout *column = NULL;
690       const int col_size = 20 + totitem / 12;
691       int i, c;
692       bool add_col = true;
693
694       for (c = 0, i = totitem; i--;) {
695         if (add_col && !(c % col_size)) {
696           column = uiLayoutColumn(split, false);
697           add_col = false;
698         }
699         if (item[i].identifier) {
700           uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value);
701           c++;
702           add_col = true;
703         }
704       }
705
706       MEM_freeN((void *)item);
707
708       UI_popup_menu_end(C, pup);
709     }
710   }
711   return OPERATOR_CANCELLED;
712 }
713
714 /* note: also check ed_undo_step() in top if you change notifiers */
715 static int undo_history_exec(bContext *C, wmOperator *op)
716 {
717   PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
718   if (RNA_property_is_set(op->ptr, prop)) {
719     int item = RNA_property_int_get(op->ptr, prop);
720     WM_operator_stack_clear(CTX_wm_manager(C));
721     ed_undo_step_by_index(C, item, op->reports);
722     WM_event_add_notifier(C, NC_WINDOW, NULL);
723     return OPERATOR_FINISHED;
724   }
725   return OPERATOR_CANCELLED;
726 }
727
728 static bool undo_history_poll(bContext *C)
729 {
730   if (!ed_undo_is_init_and_screenactive_poll(C)) {
731     return false;
732   }
733   UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack;
734   /* More than just original state entry. */
735   return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1;
736 }
737
738 void ED_OT_undo_history(wmOperatorType *ot)
739 {
740   /* identifiers */
741   ot->name = "Undo History";
742   ot->description = "Redo specific action in history";
743   ot->idname = "ED_OT_undo_history";
744
745   /* api callbacks */
746   ot->invoke = undo_history_invoke;
747   ot->exec = undo_history_exec;
748   ot->poll = undo_history_poll;
749
750   RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
751 }
752
753 /** \} */
754
755 /* -------------------------------------------------------------------- */
756 /** \name Undo Helper Functions
757  * \{ */
758
759 void ED_undo_object_set_active_or_warn(ViewLayer *view_layer,
760                                        Object *ob,
761                                        const char *info,
762                                        CLG_LogRef *log)
763 {
764   Object *ob_prev = OBACT(view_layer);
765   if (ob_prev != ob) {
766     Base *base = BKE_view_layer_base_find(view_layer, ob);
767     if (base != NULL) {
768       view_layer->basact = base;
769     }
770     else {
771       /* Should never fail, may not crash but can give odd behavior. */
772       CLOG_WARN(log, "'%s' failed to restore active object: '%s'", info, ob->id.name + 2);
773     }
774   }
775 }
776
777 void ED_undo_object_editmode_restore_helper(struct bContext *C,
778                                             Object **object_array,
779                                             uint object_array_len,
780                                             uint object_array_stride)
781 {
782   Main *bmain = CTX_data_main(C);
783   ViewLayer *view_layer = CTX_data_view_layer(C);
784   uint bases_len = 0;
785   /* Don't request unique data because we want to de-select objects when exiting edit-mode
786    * for that to be done on all objects we can't skip ones that share data. */
787   Base **bases = ED_undo_editmode_bases_from_view_layer(view_layer, &bases_len);
788   for (uint i = 0; i < bases_len; i++) {
789     ((ID *)bases[i]->object->data)->tag |= LIB_TAG_DOIT;
790   }
791   Scene *scene = CTX_data_scene(C);
792   Object **ob_p = object_array;
793   for (uint i = 0; i < object_array_len; i++, ob_p = POINTER_OFFSET(ob_p, object_array_stride)) {
794     Object *obedit = *ob_p;
795     ED_object_editmode_enter_ex(bmain, scene, obedit, EM_NO_CONTEXT);
796     ((ID *)obedit->data)->tag &= ~LIB_TAG_DOIT;
797   }
798   for (uint i = 0; i < bases_len; i++) {
799     ID *id = bases[i]->object->data;
800     if (id->tag & LIB_TAG_DOIT) {
801       ED_object_editmode_exit_ex(bmain, scene, bases[i]->object, EM_FREEDATA);
802       /* Ideally we would know the selection state it was before entering edit-mode,
803        * for now follow the convention of having them unselected when exiting the mode. */
804       ED_object_base_select(bases[i], BA_DESELECT);
805     }
806   }
807   MEM_freeN(bases);
808 }
809
810 /** \} */
811
812 /* -------------------------------------------------------------------- */
813 /** \name Undo View Layer Helper Functions
814  *
815  * Needed because view layer functions such as
816  * #BKE_view_layer_array_from_objects_in_edit_mode_unique_data also check visibility,
817  * which is not reliable when it comes to object undo operations,
818  * since hidden objects can be operated on in the properties editor,
819  * and local collections may be used.
820  * \{ */
821
822 static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
823                                                          Object *obact,
824                                                          int *r_active_index)
825 {
826   const short object_type = obact->type;
827
828   LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
829     Object *ob = base->object;
830     if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
831       ID *id = ob->data;
832       id->tag &= ~LIB_TAG_DOIT;
833     }
834   }
835
836   int len = 0;
837   LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
838     Object *ob = base->object;
839     if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
840       if (ob == obact) {
841         *r_active_index = len;
842       }
843       ID *id = ob->data;
844       if ((id->tag & LIB_TAG_DOIT) == 0) {
845         len += 1;
846         id->tag |= LIB_TAG_DOIT;
847       }
848     }
849   }
850   return len;
851 }
852
853 Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r_len)
854 {
855   Object *obact = OBACT(view_layer);
856   if ((obact == NULL) || (obact->mode & OB_MODE_EDIT) == 0) {
857     return MEM_mallocN(0, __func__);
858   }
859   int active_index = 0;
860   const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, obact, &active_index);
861   const short object_type = obact->type;
862   int i = 0;
863   Object **objects = MEM_malloc_arrayN(len, sizeof(*objects), __func__);
864   LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
865     Object *ob = base->object;
866     if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
867       ID *id = ob->data;
868       if (id->tag & LIB_TAG_DOIT) {
869         objects[i++] = ob;
870         id->tag &= ~LIB_TAG_DOIT;
871       }
872     }
873   }
874   BLI_assert(i == len);
875   if (active_index > 0) {
876     SWAP(Object *, objects[0], objects[active_index]);
877   }
878   *r_len = len;
879   return objects;
880 }
881
882 Base **ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len)
883 {
884   Object *obact = OBACT(view_layer);
885   if ((obact == NULL) || (obact->mode & OB_MODE_EDIT) == 0) {
886     return MEM_mallocN(0, __func__);
887   }
888   int active_index = 0;
889   const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, obact, &active_index);
890   const short object_type = obact->type;
891   int i = 0;
892   Base **base_array = MEM_malloc_arrayN(len, sizeof(*base_array), __func__);
893   LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
894     Object *ob = base->object;
895     if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
896       ID *id = ob->data;
897       if (id->tag & LIB_TAG_DOIT) {
898         base_array[i++] = base;
899         id->tag &= ~LIB_TAG_DOIT;
900       }
901     }
902   }
903   BLI_assert(i == len);
904   if (active_index > 0) {
905     SWAP(Base *, base_array[0], base_array[active_index]);
906   }
907   *r_len = len;
908   return base_array;
909 }
910
911 /** \} */