Blender  V2.93
ed_undo.c
Go to the documentation of this file.
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 
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 
71 static CLG_LogRef LOG = {"ed.undo"};
72 
73 /* -------------------------------------------------------------------- */
83 {
85 
86  /* Currently only checks matching begin/end calls. */
87  if (wm->undo_stack == NULL) {
88  /* No undo stack is valid, nothing to do. */
89  return true;
90  }
91  if (wm->undo_stack->group_level != 0) {
92  /* If this fails #ED_undo_grouped_begin, #ED_undo_grouped_end calls don't match. */
93  return false;
94  }
95  if (wm->undo_stack->step_active != NULL) {
96  if (wm->undo_stack->step_active->skip == true) {
97  /* Skip is only allowed between begin/end calls,
98  * a state that should never happen in main event loop. */
99  return false;
100  }
101  }
102  return true;
103 }
104 
106 {
109 }
110 
112 {
115 }
116 
117 void ED_undo_push(bContext *C, const char *str)
118 {
119  CLOG_INFO(&LOG, 1, "name='%s'", str);
121 
123  int steps = U.undosteps;
124 
125  /* Ensure steps that have been initialized are always pushed,
126  * even when undo steps are zero.
127  *
128  * Note that some modes (paint, sculpt) initialize an undo step before an action runs,
129  * then accumulate changes there, or restore data from it in the case of 2D painting.
130  *
131  * For this reason we need to handle the undo step even when undo steps is set to zero.
132  */
133  if ((steps <= 0) && wm->undo_stack->step_init != NULL) {
134  steps = 1;
135  }
136  if (steps <= 0) {
137  return;
138  }
139  if (G.background) {
140  /* Python developers may have explicitly created the undo stack in background mode,
141  * otherwise allow it to be NULL, see: T60934.
142  * Otherwise it must never be NULL, even when undo is disabled. */
143  if (wm->undo_stack == NULL) {
144  return;
145  }
146  }
147 
148  UndoPushReturn push_retval;
149 
150  /* Only apply limit if this is the last undo step. */
151  if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) {
153  }
154 
155  push_retval = BKE_undosys_step_push(wm->undo_stack, C, str);
156 
157  if (U.undomemory != 0) {
158  const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024;
160  }
161 
162  if (CLOG_CHECK(&LOG, 1)) {
164  }
165 
166  if (push_retval & UNDO_PUSH_RET_OVERRIDE_CHANGED) {
168  }
169 }
170 
175  wmWindowManager *wm,
176  const enum eUndoStepDir undo_dir,
177  ReportList *reports)
178 {
179  BLI_assert(ELEM(undo_dir, STEP_UNDO, STEP_REDO));
180 
181  Main *bmain = CTX_data_main(C);
184 
185  /* undo during jobs are running can easily lead to freeing data using by jobs,
186  * or they can just lead to freezing job in some other cases */
187  WM_jobs_kill_all(wm);
188 
189  if (G.debug & G_DEBUG_IO) {
190  if (bmain->lock != NULL) {
191  BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* undo step");
192  BLO_main_validate_libraries(bmain, reports);
193  }
194  }
195 
196  if (area && (area->spacetype == SPACE_VIEW3D)) {
197  Object *obact = CTX_data_active_object(C);
198  if (obact && (obact->type == OB_GPENCIL)) {
200  }
201  }
202 
203  /* App-Handlers (pre). */
204  {
205  /* Note: ignore grease pencil for now. */
206  wm->op_undo_depth++;
208  bmain, &scene->id, (undo_dir == STEP_UNDO) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE);
209  wm->op_undo_depth--;
210  }
211 }
212 
219  wmWindowManager *wm,
220  const enum eUndoStepDir undo_dir,
221  ReportList *reports)
222 {
223  BLI_assert(ELEM(undo_dir, STEP_UNDO, STEP_REDO));
224 
225  Main *bmain = CTX_data_main(C);
228 
229  /* Set special modes for grease pencil */
230  if (area != NULL && (area->spacetype == SPACE_VIEW3D)) {
231  Object *obact = CTX_data_active_object(C);
232  if (obact && (obact->type == OB_GPENCIL)) {
233  /* set cursor */
234  if (ELEM(obact->mode,
240  }
241  else {
243  }
244  /* set workspace mode */
245  Base *basact = CTX_data_active_base(C);
246  ED_object_base_activate(C, basact);
247  }
248  }
249 
250  /* App-Handlers (post). */
251  {
252  wm->op_undo_depth++;
254  bmain, &scene->id, (undo_dir == STEP_UNDO) ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST);
255  wm->op_undo_depth--;
256  }
257 
258  if (G.debug & G_DEBUG_IO) {
259  if (bmain->lock != NULL) {
260  BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *AFTER* undo step");
261  BLO_main_validate_libraries(bmain, reports);
262  }
263  }
264 
267 
270 
271  if (CLOG_CHECK(&LOG, 1)) {
273  }
274 }
275 
281 static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports)
282 {
284 
285  CLOG_INFO(&LOG, 1, "direction=%s", (step == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO");
286 
287  /* TODO(campbell): undo_system: use undo system */
288  /* grease pencil can be can be used in plenty of spaces, so check it first */
289  /* FIXME: This gpencil undo effectively only supports the one step undo/redo, undo based on name
290  * or index is fully not implemented.
291  * FIXME: However, it seems to never be used in current code (`ED_gpencil_session_active` seems
292  * to always return false). */
294  return ED_undo_gpencil_step(C, step);
295  }
296 
298 
299  ed_undo_step_pre(C, wm, step, reports);
300 
301  if (step == STEP_UNDO) {
303  }
304  else {
306  }
307 
308  ed_undo_step_post(C, wm, step, reports);
309 
310  return OPERATOR_FINISHED;
311 }
312 
318 static int ed_undo_step_by_name(bContext *C, const char *undo_name, ReportList *reports)
319 {
320  BLI_assert(undo_name != NULL);
321 
322  /* FIXME: See comments in `ed_undo_step_direction`. */
324  BLI_assert(!"Not implemented currently.");
325  }
326 
328  UndoStep *undo_step_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undo_name);
329  if (undo_step_from_name == NULL) {
330  CLOG_ERROR(&LOG, "Step name='%s' not found in current undo stack", undo_name);
331 
332  return OPERATOR_CANCELLED;
333  }
334 
335  UndoStep *undo_step_target = undo_step_from_name->prev;
336  if (undo_step_target == NULL) {
337  CLOG_ERROR(&LOG, "Step name='%s' cannot be undone", undo_name);
338 
339  return OPERATOR_CANCELLED;
340  }
341 
342  const int undo_dir_i = BKE_undosys_step_calc_direction(wm->undo_stack, undo_step_target, NULL);
343  BLI_assert(ELEM(undo_dir_i, -1, 1));
344  const enum eUndoStepDir undo_dir = (undo_dir_i == -1) ? STEP_UNDO : STEP_REDO;
345 
346  CLOG_INFO(&LOG,
347  1,
348  "name='%s', found direction=%s",
349  undo_name,
350  (undo_dir == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO");
351 
352  ed_undo_step_pre(C, wm, undo_dir, reports);
353 
354  BKE_undosys_step_load_data_ex(wm->undo_stack, C, undo_step_target, NULL, true);
355 
356  ed_undo_step_post(C, wm, undo_dir, reports);
357 
358  return OPERATOR_FINISHED;
359 }
360 
366 static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *reports)
367 {
368  BLI_assert(undo_index >= 0);
369 
370  /* FIXME: See comments in `ed_undo_step_direction`. */
372  BLI_assert(!"Not implemented currently.");
373  }
374 
376  const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active);
377  const enum eUndoStepDir undo_dir = (undo_index < active_step_index) ? STEP_UNDO : STEP_REDO;
378 
379  CLOG_INFO(&LOG,
380  1,
381  "index='%d', found direction=%s",
382  undo_index,
383  (undo_dir == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO");
384 
385  ed_undo_step_pre(C, wm, undo_dir, reports);
386 
388 
389  ed_undo_step_post(C, wm, undo_dir, reports);
390 
391  return OPERATOR_FINISHED;
392 }
393 
394 void ED_undo_grouped_push(bContext *C, const char *str)
395 {
396  /* do nothing if previous undo task is the same as this one (or from the same undo group) */
398  const UndoStep *us = wm->undo_stack->step_active;
399  if (us && STREQ(str, us->name)) {
401  }
402 
403  /* push as usual */
404  ED_undo_push(C, str);
405 }
406 
408 {
410 }
412 {
414 }
415 
417 {
418  /* in future, get undo string info? */
419  ED_undo_push(C, op->type->name);
420 }
421 
423 {
424  if (op->type->undo_group[0] != '\0') {
426  }
427  else {
429  }
430 }
431 
433 {
434  /* search back a couple of undo's, in case something else added pushes */
435  ed_undo_step_by_name(C, op->type->name, op->reports);
436 }
437 
438 /* name optionally, function used to check for operator redo panel */
439 bool ED_undo_is_valid(const bContext *C, const char *undoname)
440 {
442  return BKE_undosys_stack_has_undo(wm->undo_stack, undoname);
443 }
444 
446 {
447  /* Some modes don't co-exist with memfile undo, disable their use: T60593
448  * (this matches 2.7x behavior). */
449  ViewLayer *view_layer = CTX_data_view_layer(C);
450  if (view_layer != NULL) {
451  Object *obact = OBACT(view_layer);
452  if (obact != NULL) {
453  if (obact->mode & OB_MODE_EDIT) {
454  return false;
455  }
456  }
457  }
458  return true;
459 }
460 
470 {
471  ViewLayer *view_layer = CTX_data_view_layer(C);
472  if (view_layer != NULL) {
473  Object *obact = OBACT(view_layer);
474  if (obact != NULL) {
475  if (obact->mode & OB_MODE_ALL_PAINT) {
476  /* Don't store property changes when painting
477  * (only do undo pushes on brush strokes which each paint operator handles on its own). */
478  CLOG_INFO(&LOG, 1, "skipping undo for paint-mode");
479  return false;
480  }
481  if (obact->mode & OB_MODE_EDIT) {
482  if ((id == NULL) || (obact->data == NULL) ||
483  (GS(id->name) != GS(((ID *)obact->data)->name))) {
484  /* No undo push on id type mismatch in edit-mode. */
485  CLOG_INFO(&LOG, 1, "skipping undo for edit-mode");
486  return false;
487  }
488  }
489  }
490  }
491  return true;
492 }
493 
502 {
503  wmWindowManager *wm = G_MAIN->wm.first;
504  return wm->undo_stack;
505 }
506 
509 /* -------------------------------------------------------------------- */
514 {
515  /* "last operator" should disappear, later we can tie this with undo stack nicer */
518  if (ret & OPERATOR_FINISHED) {
519  /* Keep button under the cursor active. */
521  }
522 
524  return ret;
525 }
526 
528 {
529  if (G.background) {
530  /* Exception for background mode, see: T60934.
531  * Note: since the undo stack isn't initialized on startup, background mode behavior
532  * won't match regular usage, this is just for scripts to do explicit undo pushes. */
534  if (wm->undo_stack == NULL) {
536  }
537  }
538  char str[BKE_UNDO_STR_MAX];
539  RNA_string_get(op->ptr, "message", str);
540  ED_undo_push(C, str);
541  return OPERATOR_FINISHED;
542 }
543 
545 {
547  if (ret & OPERATOR_FINISHED) {
548  /* Keep button under the cursor active. */
550  }
551 
553  return ret;
554 }
555 
557 {
558  wmOperator *last_op = WM_operator_last_redo(C);
559  int ret = ED_undo_operator_repeat(C, last_op);
561  if (ret & OPERATOR_FINISHED) {
562  /* Keep button under the cursor active. */
564  }
565  return ret;
566 }
567 
568 /* Disable in background mode, we could support if it's useful, T60934. */
569 
571 {
573  if (wm->undo_stack == NULL) {
574  CTX_wm_operator_poll_msg_set(C, "Undo disabled at startup");
575  return false;
576  }
577  return true;
578 }
579 
581 {
582  if (ed_undo_is_init_poll(C) == false) {
583  return false;
584  }
585  return ED_operator_screenactive(C);
586 }
587 
589 {
590  wmOperator *last_op = WM_operator_last_redo(C);
591  return (last_op && ed_undo_is_init_and_screenactive_poll(C) &&
593 }
594 
595 static bool ed_undo_poll(bContext *C)
596 {
598  return false;
599  }
601  return (undo_stack->step_active != NULL) && (undo_stack->step_active->prev != NULL);
602 }
603 
605 {
606  /* identifiers */
607  ot->name = "Undo";
608  ot->description = "Undo previous action";
609  ot->idname = "ED_OT_undo";
610 
611  /* api callbacks */
612  ot->exec = ed_undo_exec;
613  ot->poll = ed_undo_poll;
614 }
615 
617 {
618  /* identifiers */
619  ot->name = "Undo Push";
620  ot->description = "Add an undo state (internal use only)";
621  ot->idname = "ED_OT_undo_push";
622 
623  /* api callbacks */
625  /* Unlike others undo operators this initializes undo stack. */
627 
629 
631  "message",
632  "Add an undo step *function may be moved*",
634  "Undo Message",
635  "");
636 }
637 
638 static bool ed_redo_poll(bContext *C)
639 {
641  return false;
642  }
644  return (undo_stack->step_active != NULL) && (undo_stack->step_active->next != NULL);
645 }
646 
648 {
649  /* identifiers */
650  ot->name = "Redo";
651  ot->description = "Redo previous action";
652  ot->idname = "ED_OT_redo";
653 
654  /* api callbacks */
655  ot->exec = ed_redo_exec;
656  ot->poll = ed_redo_poll;
657 }
658 
660 {
661  /* identifiers */
662  ot->name = "Undo and Redo";
663  ot->description = "Undo and redo previous action";
664  ot->idname = "ED_OT_undo_redo";
665 
666  /* api callbacks */
669 }
670 
673 /* -------------------------------------------------------------------- */
677 /* ui callbacks should call this rather than calling WM_operator_repeat() themselves */
679 {
680  int ret = 0;
681 
682  if (op) {
683  CLOG_INFO(&LOG, 1, "idname='%s'", op->type->idname);
685  struct Scene *scene = CTX_data_scene(C);
686 
687  /* keep in sync with logic in view3d_panel_operator_redo() */
688  ARegion *region_orig = CTX_wm_region(C);
690 
691  if (region_win) {
692  CTX_wm_region_set(C, region_win);
693  }
694 
695  if ((WM_operator_repeat_check(C, op)) && (WM_operator_poll(C, op->type)) &&
696  /* note, undo/redo cant run if there are jobs active,
697  * check for screen jobs only so jobs like material/texture/world preview
698  * (which copy their data), wont stop redo, see T29579],
699  *
700  * note, - WM_operator_check_ui_enabled() jobs test _must_ stay in sync with this */
701  (WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY) == 0)) {
702  int retval;
703 
704  if (G.debug & G_DEBUG) {
705  printf("redo_cb: operator redo %s\n", op->type->name);
706  }
707 
709 
710  ED_undo_pop_op(C, op);
711 
712  if (op->type->check) {
713  if (op->type->check(C, op)) {
714  /* check for popup and re-layout buttons */
715  ARegion *region_menu = CTX_wm_menu(C);
716  if (region_menu) {
717  ED_region_tag_refresh_ui(region_menu);
718  }
719  }
720  }
721 
722  retval = WM_operator_repeat(C, op);
723  if ((retval & OPERATOR_FINISHED) == 0) {
724  if (G.debug & G_DEBUG) {
725  printf("redo_cb: operator redo failed: %s, return %d\n", op->type->name, retval);
726  }
727  ED_undo_redo(C);
728  }
729  else {
730  ret = 1;
731  }
732  }
733  else {
734  if (G.debug & G_DEBUG) {
735  printf("redo_cb: WM_operator_repeat_check returned false %s\n", op->type->name);
736  }
737  }
738 
739  /* set region back */
740  CTX_wm_region_set(C, region_orig);
741  }
742  else {
743  CLOG_WARN(&LOG, "called with NULL 'op'");
744  }
745 
746  return ret;
747 }
748 
749 void ED_undo_operator_repeat_cb(bContext *C, void *arg_op, void *UNUSED(arg_unused))
750 {
752 }
753 
754 void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_unused))
755 {
757 }
758 
761 /* -------------------------------------------------------------------- */
765 /* create enum based on undo items */
766 static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem)
767 {
768  EnumPropertyItem item_tmp = {0}, *item = NULL;
769  int i = 0;
770 
772  if (wm->undo_stack == NULL) {
773  return NULL;
774  }
775 
776  for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
777  if (us->skip == false) {
778  item_tmp.identifier = us->name;
779  item_tmp.name = IFACE_(us->name);
780  if (us == wm->undo_stack->step_active) {
781  item_tmp.icon = ICON_LAYER_ACTIVE;
782  }
783  else {
784  item_tmp.icon = ICON_NONE;
785  }
786  item_tmp.value = i;
787  RNA_enum_item_add(&item, totitem, &item_tmp);
788  }
789  }
790  RNA_enum_item_end(&item, totitem);
791 
792  return item;
793 }
794 
795 static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
796 {
797  int totitem = 0;
798 
799  {
800  const EnumPropertyItem *item = rna_undo_itemf(C, &totitem);
801 
802  if (totitem > 0) {
804  C, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
805  uiLayout *layout = UI_popup_menu_layout(pup);
806  uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
807  uiLayout *column = NULL;
808  const int col_size = 20 + totitem / 12;
809  int i, c;
810  bool add_col = true;
811 
812  for (c = 0, i = totitem; i--;) {
813  if (add_col && !(c % col_size)) {
814  column = uiLayoutColumn(split, false);
815  add_col = false;
816  }
817  if (item[i].identifier) {
818  uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value);
819  c++;
820  add_col = true;
821  }
822  }
823 
824  MEM_freeN((void *)item);
825 
826  UI_popup_menu_end(C, pup);
827  }
828  }
829  return OPERATOR_CANCELLED;
830 }
831 
832 /* note: also check ed_undo_step() in top if you change notifiers */
834 {
835  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
836  if (RNA_property_is_set(op->ptr, prop)) {
837  int item = RNA_property_int_get(op->ptr, prop);
839  ed_undo_step_by_index(C, item, op->reports);
841  return OPERATOR_FINISHED;
842  }
843  return OPERATOR_CANCELLED;
844 }
845 
847 {
849  return false;
850  }
852  /* More than just original state entry. */
853  return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1;
854 }
855 
857 {
858  /* identifiers */
859  ot->name = "Undo History";
860  ot->description = "Redo specific action in history";
861  ot->idname = "ED_OT_undo_history";
862 
863  /* api callbacks */
867 
868  RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
869 }
870 
873 /* -------------------------------------------------------------------- */
878  Scene *scene, ViewLayer *view_layer, Object *ob, const char *info, CLG_LogRef *log)
879 {
880  Object *ob_prev = OBACT(view_layer);
881  if (ob_prev != ob) {
882  Base *base = BKE_view_layer_base_find(view_layer, ob);
883  if (base != NULL) {
884  view_layer->basact = base;
886  }
887  else {
888  /* Should never fail, may not crash but can give odd behavior. */
889  CLOG_WARN(log, "'%s' failed to restore active object: '%s'", info, ob->id.name + 2);
890  }
891  }
892 }
893 
898  Object **object_array,
899  uint object_array_len,
900  uint object_array_stride)
901 {
902  Main *bmain = CTX_data_main(C);
903  ViewLayer *view_layer = CTX_data_view_layer(C);
904  uint bases_len = 0;
905  /* Don't request unique data because we want to de-select objects when exiting edit-mode
906  * for that to be done on all objects we can't skip ones that share data. */
907  Base **bases = ED_undo_editmode_bases_from_view_layer(view_layer, &bases_len);
908  for (uint i = 0; i < bases_len; i++) {
909  ((ID *)bases[i]->object->data)->tag |= LIB_TAG_DOIT;
910  }
912  Object **ob_p = object_array;
913  for (uint i = 0; i < object_array_len; i++, ob_p = POINTER_OFFSET(ob_p, object_array_stride)) {
914  Object *obedit = *ob_p;
916  ((ID *)obedit->data)->tag &= ~LIB_TAG_DOIT;
917  }
918  for (uint i = 0; i < bases_len; i++) {
919  ID *id = bases[i]->object->data;
920  if (id->tag & LIB_TAG_DOIT) {
921  ED_object_editmode_exit_ex(bmain, scene, bases[i]->object, EM_FREEDATA);
922  /* Ideally we would know the selection state it was before entering edit-mode,
923  * for now follow the convention of having them unselected when exiting the mode. */
925  }
926  }
927  MEM_freeN(bases);
928 }
929 
932 /* -------------------------------------------------------------------- */
943 {
944  const short object_type = obact->type;
945 
946  LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
947  Object *ob = base->object;
948  if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
949  ID *id = ob->data;
950  id->tag &= ~LIB_TAG_DOIT;
951  }
952  }
953 
954  int len = 0;
955  LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
956  Object *ob = base->object;
957  if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
958  ID *id = ob->data;
959  if ((id->tag & LIB_TAG_DOIT) == 0) {
960  len += 1;
961  id->tag |= LIB_TAG_DOIT;
962  }
963  }
964  }
965  return len;
966 }
967 
969 {
970  Base *baseact = BASACT(view_layer);
971  if ((baseact == NULL) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
972  return MEM_mallocN(0, __func__);
973  }
974  const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, baseact->object);
975  const short object_type = baseact->object->type;
976  int i = 0;
977  Object **objects = MEM_malloc_arrayN(len, sizeof(*objects), __func__);
978  /* Base iteration, starting with the active-base to ensure it's the first item in the array.
979  * Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
980  for (Base *base = baseact, *base_next = FIRSTBASE(view_layer); base;
981  base = base_next, base_next = base_next ? base_next->next : NULL) {
982  Object *ob = base->object;
983  if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
984  ID *id = ob->data;
985  if (id->tag & LIB_TAG_DOIT) {
986  objects[i++] = ob;
987  id->tag &= ~LIB_TAG_DOIT;
988  }
989  }
990  }
991  BLI_assert(i == len);
992  BLI_assert(objects[0] == baseact->object);
993  *r_len = len;
994  return objects;
995 }
996 
998 {
999  Base *baseact = BASACT(view_layer);
1000  if ((baseact == NULL) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
1001  return MEM_mallocN(0, __func__);
1002  }
1003  const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, baseact->object);
1004  const short object_type = baseact->object->type;
1005  int i = 0;
1006  Base **base_array = MEM_malloc_arrayN(len, sizeof(*base_array), __func__);
1007  /* Base iteration, starting with the active-base to ensure it's the first item in the array.
1008  * Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
1009  for (Base *base = BASACT(view_layer), *base_next = FIRSTBASE(view_layer); base;
1010  base = base_next, base_next = base_next ? base_next->next : NULL) {
1011  Object *ob = base->object;
1012  if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
1013  ID *id = ob->data;
1014  if (id->tag & LIB_TAG_DOIT) {
1015  base_array[i++] = base;
1016  id->tag &= ~LIB_TAG_DOIT;
1017  }
1018  }
1019  }
1020 
1021  BLI_assert(i == len);
1022  BLI_assert(base_array[0] == baseact);
1023  *r_len = len;
1024  return base_array;
1025 }
1026 
#define BKE_UNDO_STR_MAX
@ BKE_CB_EVT_REDO_POST
Definition: BKE_callbacks.h:56
@ BKE_CB_EVT_REDO_PRE
Definition: BKE_callbacks.h:55
@ BKE_CB_EVT_UNDO_PRE
Definition: BKE_callbacks.h:53
@ BKE_CB_EVT_UNDO_POST
Definition: BKE_callbacks.h:54
void BKE_callback_exec_id(struct Main *bmain, struct ID *id, eCbEvent evt)
Definition: callbacks.c:51
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
void CTX_wm_region_set(bContext *C, struct ARegion *region)
Definition: context.c:985
struct ARegion * CTX_wm_menu(const bContext *C)
Definition: context.c:736
struct Base * CTX_data_active_base(const bContext *C)
Definition: context.c:1284
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1006
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
#define G_MAIN
Definition: BKE_global.h:232
@ G_DEBUG
Definition: BKE_global.h:133
@ G_DEBUG_IO
Definition: BKE_global.h:152
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:394
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
struct ARegion * BKE_area_find_region_active_win(struct ScrArea *area)
Definition: screen.c:918
void BKE_undosys_stack_clear_active(UndoStack *ustack)
Definition: undo_system.c:289
UndoStack * BKE_undosys_stack_create(void)
Definition: undo_system.c:265
eUndoStepDir BKE_undosys_step_calc_direction(const UndoStack *ustack, const UndoStep *us_target, const UndoStep *us_reference)
Definition: undo_system.c:685
bool BKE_undosys_step_undo(UndoStack *ustack, struct bContext *C)
Definition: undo_system.c:890
eUndoStepDir
@ STEP_UNDO
@ STEP_REDO
UndoStep * BKE_undosys_step_find_by_name(UndoStack *ustack, const char *name)
Definition: undo_system.c:662
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit)
Definition: undo_system.c:404
UndoPushReturn
@ UNDO_PUSH_RET_OVERRIDE_CHANGED
bool BKE_undosys_stack_has_undo(UndoStack *ustack, const char *name)
Definition: undo_system.c:371
void BKE_undosys_stack_group_end(UndoStack *ustack)
Definition: undo_system.c:995
bool BKE_undosys_step_load_data_ex(UndoStack *ustack, struct bContext *C, UndoStep *us_target, UndoStep *us_reference, const bool use_skip)
Definition: undo_system.c:738
bool BKE_undosys_step_redo(UndoStack *ustack, struct bContext *C)
Definition: undo_system.c:936
UndoPushReturn BKE_undosys_step_push(UndoStack *ustack, struct bContext *C, const char *name)
Definition: undo_system.c:605
void BKE_undosys_step_load_from_index(UndoStack *ustack, struct bContext *C, const int index)
Definition: undo_system.c:844
void BKE_undosys_print(UndoStack *ustack)
Definition: undo_system.c:1033
void BKE_undosys_stack_group_begin(UndoStack *ustack)
Definition: undo_system.c:989
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
int BLI_listbase_count_at_most(const struct ListBase *listbase, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED(x)
#define ELEM(...)
#define POINTER_OFFSET(v, ofs)
#define STREQ(a, b)
Utils ensuring .blend file (i.e. Main) is in valid state during write and/or read process.
bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports)
#define IFACE_(msgid)
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:204
#define CLOG_WARN(clg_ref,...)
Definition: CLG_log.h:203
#define CLOG_CHECK(clg_ref, verbose_level,...)
Definition: CLG_log.h:165
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:201
@ LIB_TAG_DOIT
Definition: DNA_ID.h:554
#define OB_MODE_ALL_PAINT
@ OB_MODE_VERTEX_GPENCIL
@ OB_MODE_EDIT
@ OB_MODE_WEIGHT_GPENCIL
@ OB_MODE_SCULPT_GPENCIL
@ OB_MODE_PAINT_GPENCIL
Object is a sort of wrapper for general info.
@ OB_GPENCIL
#define FIRSTBASE(_view_layer)
#define BASACT(_view_layer)
#define OBACT(_view_layer)
@ SPACE_VIEW3D
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode)
Definition: object_select.c:98
void ED_object_base_active_refresh(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer)
@ EM_NO_CONTEXT
Definition: ED_object.h:205
@ EM_FREEDATA
Definition: ED_object.h:204
bool ED_object_editmode_exit_ex(struct Main *bmain, struct Scene *scene, struct Object *obedit, int flag)
Definition: object_edit.c:676
bool ED_object_editmode_enter_ex(struct Main *bmain, struct Scene *scene, struct Object *ob, int flag)
Definition: object_edit.c:762
void ED_object_base_activate(struct bContext *C, struct Base *base)
@ BA_DESELECT
Definition: ED_object.h:146
void ED_outliner_select_sync_from_all_tag(struct bContext *C)
Definition: outliner_sync.c:80
bool ED_operator_screenactive(struct bContext *C)
Definition: screen_ops.c:133
void ED_region_tag_refresh_ui(struct ARegion *region)
Definition: area.c:695
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
struct uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
uiLayout * uiLayoutSplit(uiLayout *layout, float percentage, bool align)
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup)
uiPopupMenu * UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL()
@ WM_JOB_TYPE_ANY
Definition: WM_api.h:734
#define NC_WINDOW
Definition: WM_types.h:277
@ OPTYPE_INTERNAL
Definition: WM_types.h:175
#define NC_WM
Definition: WM_types.h:276
#define ND_LIB_OVERRIDE_CHANGED
Definition: WM_types.h:318
#define ND_UNDO
Definition: WM_types.h:316
unsigned int U
Definition: btGjkEpa3.h:78
Scene scene
void ED_undo_object_set_active_or_warn(Scene *scene, ViewLayer *view_layer, Object *ob, const char *info, CLG_LogRef *log)
Definition: ed_undo.c:877
void ED_undo_push(bContext *C, const char *str)
Definition: ed_undo.c:117
void ED_OT_redo(wmOperatorType *ot)
Definition: ed_undo.c:647
bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id)
Definition: ed_undo.c:469
static int ed_undo_push_exec(bContext *C, wmOperator *op)
Definition: ed_undo.c:527
static void ed_undo_step_pre(bContext *C, wmWindowManager *wm, const enum eUndoStepDir undo_dir, ReportList *reports)
Definition: ed_undo.c:174
void ED_undo_push_op(bContext *C, wmOperator *op)
Definition: ed_undo.c:416
UndoStack * ED_undo_stack_get(void)
Definition: ed_undo.c:501
void ED_undo_pop_op(bContext *C, wmOperator *op)
Definition: ed_undo.c:432
static const EnumPropertyItem * rna_undo_itemf(bContext *C, int *totitem)
Definition: ed_undo.c:766
Base ** ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len)
Definition: ed_undo.c:997
void ED_undo_group_begin(bContext *C)
Definition: ed_undo.c:105
bool ED_undo_is_valid(const bContext *C, const char *undoname)
Definition: ed_undo.c:439
void ED_OT_undo_redo(wmOperatorType *ot)
Definition: ed_undo.c:659
static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *reports)
Definition: ed_undo.c:366
static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer, Object *obact)
Definition: ed_undo.c:942
void ED_OT_undo_push(wmOperatorType *ot)
Definition: ed_undo.c:616
int ED_undo_operator_repeat(bContext *C, wmOperator *op)
Definition: ed_undo.c:678
static bool undo_history_poll(bContext *C)
Definition: ed_undo.c:846
static void ed_undo_step_post(bContext *C, wmWindowManager *wm, const enum eUndoStepDir undo_dir, ReportList *reports)
Definition: ed_undo.c:218
void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_unused))
Definition: ed_undo.c:754
static int ed_undo_exec(bContext *C, wmOperator *op)
Definition: ed_undo.c:513
static int undo_history_exec(bContext *C, wmOperator *op)
Definition: ed_undo.c:833
static bool ed_redo_poll(bContext *C)
Definition: ed_undo.c:638
void ED_undo_operator_repeat_cb(bContext *C, void *arg_op, void *UNUSED(arg_unused))
Definition: ed_undo.c:749
static bool ed_undo_is_init_poll(bContext *C)
Definition: ed_undo.c:570
static bool ed_undo_is_init_and_screenactive_poll(bContext *C)
Definition: ed_undo.c:580
Object ** ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r_len)
Definition: ed_undo.c:968
static int ed_redo_exec(bContext *C, wmOperator *op)
Definition: ed_undo.c:544
static int ed_undo_step_by_name(bContext *C, const char *undo_name, ReportList *reports)
Definition: ed_undo.c:318
void ED_undo_redo(bContext *C)
Definition: ed_undo.c:411
static int ed_undo_redo_exec(bContext *C, wmOperator *UNUSED(op))
Definition: ed_undo.c:556
bool ED_undo_is_state_valid(bContext *C)
Definition: ed_undo.c:82
void ED_undo_object_editmode_restore_helper(struct bContext *C, Object **object_array, uint object_array_len, uint object_array_stride)
Definition: ed_undo.c:897
void ED_OT_undo(wmOperatorType *ot)
Definition: ed_undo.c:604
static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: ed_undo.c:795
static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports)
Definition: ed_undo.c:281
void ED_OT_undo_history(wmOperatorType *ot)
Definition: ed_undo.c:856
static bool ed_undo_poll(bContext *C)
Definition: ed_undo.c:595
static CLG_LogRef LOG
Definition: ed_undo.c:71
void ED_undo_grouped_push_op(bContext *C, wmOperator *op)
Definition: ed_undo.c:422
static bool ed_undo_redo_poll(bContext *C)
Definition: ed_undo.c:588
bool ED_undo_is_memfile_compatible(const bContext *C)
Definition: ed_undo.c:445
void ED_undo_pop(bContext *C)
Definition: ed_undo.c:407
void ED_undo_group_end(bContext *C)
Definition: ed_undo.c:111
void ED_undo_grouped_push(bContext *C, const char *str)
Definition: ed_undo.c:394
#define str(s)
int ED_gpencil_session_active(void)
Definition: gpencil_undo.c:60
int ED_undo_gpencil_step(bContext *C, const int step)
Definition: gpencil_undo.c:68
void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
#define GS(x)
Definition: iris.c:241
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:48
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static unsigned c
Definition: RandGen.cpp:97
INLINE Rall1d< T, V, S > log(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:303
static void area(int d1, int d2, int e1, int e2, float weights[2])
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:115
return ret
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:6655
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2607
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
Definition: rna_access.c:6514
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4470
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
Definition: rna_define.c:4416
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, int maxlen, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3675
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3585
static const int steps
Definition: sky_nishita.cpp:28
struct Object * object
const char * identifier
Definition: RNA_types.h:446
const char * name
Definition: RNA_types.h:450
Definition: DNA_ID.h:273
int tag
Definition: DNA_ID.h:292
char name[66]
Definition: DNA_ID.h:283
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
struct MainLock * lock
Definition: BKE_main.h:194
void * data
string name
Definition: scene.h:222
vector< Object * > objects
Definition: scene.h:234
struct UndoStep * step_active
struct UndoStep * step_init
ListBase steps
struct UndoStep * prev
struct UndoStep * next
char name[64]
struct Base * basact
ListBase object_bases
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
bool(* check)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:744
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
const char * undo_group
Definition: WM_types.h:728
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
struct UndoStack * undo_stack
#define undo_stack
Definition: undo_system.c:46
#define G(x, y, z)
uint len
void WM_operator_stack_clear(wmWindowManager *wm)
Definition: wm.c:401
void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op)
Definition: wm.c:327
bool WM_operator_poll(bContext *C, wmOperatorType *ot)
void WM_main_add_notifier(unsigned int type, void *reference)
int WM_operator_repeat(bContext *C, wmOperator *op)
bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_event_add_mousemove(wmWindow *win)
void WM_file_tag_modified(void)
Definition: wm_files.c:158
wmOperatorType * ot
Definition: wm_files.c:3156
bool WM_jobs_test(wmWindowManager *wm, void *owner, int job_type)
Definition: wm_jobs.c:223
void WM_jobs_kill_all(wmWindowManager *wm)
Definition: wm_jobs.c:550
const char * WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *properties)
bool WM_operator_check_ui_enabled(const bContext *C, const char *idname)
wmOperator * WM_operator_last_redo(const bContext *C)
size_t memory_limit
Definition: wm_playanim.c:267
void WM_toolsystem_refresh_screen_all(Main *bmain)
void WM_toolsystem_refresh_active(bContext *C)