Blender  V3.3
ed_undo.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2004 Blender Foundation. All rights reserved. */
3 
8 #include <string.h>
9 
10 #include "MEM_guardedalloc.h"
11 
12 #include "CLG_log.h"
13 
14 #include "DNA_object_types.h"
15 #include "DNA_scene_types.h"
16 
17 #include "BLI_listbase.h"
18 #include "BLI_utildefines.h"
19 
20 #include "BLT_translation.h"
21 
22 #include "BKE_blender_undo.h"
23 #include "BKE_callbacks.h"
24 #include "BKE_context.h"
25 #include "BKE_global.h"
26 #include "BKE_layer.h"
27 #include "BKE_main.h"
28 #include "BKE_paint.h"
29 #include "BKE_report.h"
30 #include "BKE_scene.h"
31 #include "BKE_screen.h"
32 #include "BKE_undo_system.h"
33 #include "BKE_workspace.h"
34 
35 #include "BLO_blend_validate.h"
36 
37 #include "ED_asset.h"
38 #include "ED_gpencil.h"
39 #include "ED_object.h"
40 #include "ED_outliner.h"
41 #include "ED_render.h"
42 #include "ED_screen.h"
43 #include "ED_undo.h"
44 
45 #include "WM_api.h"
46 #include "WM_toolsystem.h"
47 #include "WM_types.h"
48 
49 #include "RNA_access.h"
50 #include "RNA_define.h"
51 #include "RNA_enum_types.h"
52 
53 #include "UI_interface.h"
54 #include "UI_resources.h"
55 
57 static CLG_LogRef LOG = {"ed.undo"};
58 
59 /* -------------------------------------------------------------------- */
66 {
68 
69  /* Currently only checks matching begin/end calls. */
70  if (wm->undo_stack == NULL) {
71  /* No undo stack is valid, nothing to do. */
72  return true;
73  }
74  if (wm->undo_stack->group_level != 0) {
75  /* If this fails #ED_undo_grouped_begin, #ED_undo_grouped_end calls don't match. */
76  return false;
77  }
78  if (wm->undo_stack->step_active != NULL) {
79  if (wm->undo_stack->step_active->skip == true) {
80  /* Skip is only allowed between begin/end calls,
81  * a state that should never happen in main event loop. */
82  return false;
83  }
84  }
85  return true;
86 }
87 
89 {
92 }
93 
95 {
98 }
99 
100 void ED_undo_push(bContext *C, const char *str)
101 {
102  CLOG_INFO(&LOG, 1, "name='%s'", str);
104 
106  int steps = U.undosteps;
107 
108  /* Ensure steps that have been initialized are always pushed,
109  * even when undo steps are zero.
110  *
111  * Note that some modes (paint, sculpt) initialize an undo step before an action runs,
112  * then accumulate changes there, or restore data from it in the case of 2D painting.
113  *
114  * For this reason we need to handle the undo step even when undo steps is set to zero.
115  */
116  if ((steps <= 0) && wm->undo_stack->step_init != NULL) {
117  steps = 1;
118  }
119  if (steps <= 0) {
120  return;
121  }
122  if (G.background) {
123  /* Python developers may have explicitly created the undo stack in background mode,
124  * otherwise allow it to be NULL, see: T60934.
125  * Otherwise it must never be NULL, even when undo is disabled. */
126  if (wm->undo_stack == NULL) {
127  return;
128  }
129  }
130 
131  eUndoPushReturn push_retval;
132 
133  /* Only apply limit if this is the last undo step. */
134  if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) {
136  }
137 
138  push_retval = BKE_undosys_step_push(wm->undo_stack, C, str);
139 
140  if (U.undomemory != 0) {
141  const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024;
143  }
144 
145  if (CLOG_CHECK(&LOG, 1)) {
147  }
148 
149  if (push_retval & UNDO_PUSH_RET_OVERRIDE_CHANGED) {
151  }
152 }
153 
158  wmWindowManager *wm,
159  const enum eUndoStepDir undo_dir,
160  ReportList *reports)
161 {
162  BLI_assert(ELEM(undo_dir, STEP_UNDO, STEP_REDO));
163 
164  Main *bmain = CTX_data_main(C);
167 
168  /* undo during jobs are running can easily lead to freeing data using by jobs,
169  * or they can just lead to freezing job in some other cases */
170  WM_jobs_kill_all(wm);
171 
172  if (G.debug & G_DEBUG_IO) {
173  if (bmain->lock != NULL) {
174  BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* undo step");
175  BLO_main_validate_libraries(bmain, reports);
176  }
177  }
178 
179  if (area && (area->spacetype == SPACE_VIEW3D)) {
180  Object *obact = CTX_data_active_object(C);
181  if (obact && (obact->type == OB_GPENCIL)) {
183  }
184  }
185 
186  /* App-Handlers (pre). */
187  {
188  /* NOTE: ignore grease pencil for now. */
189  wm->op_undo_depth++;
191  bmain, &scene->id, (undo_dir == STEP_UNDO) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE);
192  wm->op_undo_depth--;
193  }
194 }
195 
202  wmWindowManager *wm,
203  const enum eUndoStepDir undo_dir,
204  ReportList *reports)
205 {
206  BLI_assert(ELEM(undo_dir, STEP_UNDO, STEP_REDO));
207 
208  Main *bmain = CTX_data_main(C);
211 
212  /* Set special modes for grease pencil */
213  if (area != NULL && (area->spacetype == SPACE_VIEW3D)) {
214  Object *obact = CTX_data_active_object(C);
215  if (obact && (obact->type == OB_GPENCIL)) {
216  /* set cursor */
217  if (ELEM(obact->mode,
223  }
224  else {
226  }
227  /* set workspace mode */
228  Base *basact = CTX_data_active_base(C);
229  ED_object_base_activate(C, basact);
230  }
231  }
232 
233  /* App-Handlers (post). */
234  {
235  wm->op_undo_depth++;
237  bmain, &scene->id, (undo_dir == STEP_UNDO) ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST);
238  wm->op_undo_depth--;
239  }
240 
241  if (G.debug & G_DEBUG_IO) {
242  if (bmain->lock != NULL) {
243  BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *AFTER* undo step");
244  BLO_main_validate_libraries(bmain, reports);
245  }
246  }
247 
250 
253 
255 
256  if (CLOG_CHECK(&LOG, 1)) {
258  }
259 }
260 
266 static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports)
267 {
269 
270  CLOG_INFO(&LOG, 1, "direction=%s", (step == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO");
271 
272  /* TODO(campbell): undo_system: use undo system */
273  /* grease pencil can be can be used in plenty of spaces, so check it first */
274  /* FIXME: This gpencil undo effectively only supports the one step undo/redo, undo based on name
275  * or index is fully not implemented.
276  * FIXME: However, it seems to never be used in current code (`ED_gpencil_session_active` seems
277  * to always return false). */
279  return ED_undo_gpencil_step(C, step);
280  }
281 
283 
284  ed_undo_step_pre(C, wm, step, reports);
285 
286  if (step == STEP_UNDO) {
288  }
289  else {
291  }
292 
293  ed_undo_step_post(C, wm, step, reports);
294 
295  return OPERATOR_FINISHED;
296 }
297 
303 static int ed_undo_step_by_name(bContext *C, const char *undo_name, ReportList *reports)
304 {
305  BLI_assert(undo_name != NULL);
306 
307  /* FIXME: See comments in `ed_undo_step_direction`. */
309  BLI_assert_msg(0, "Not implemented currently.");
310  }
311 
313  UndoStep *undo_step_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undo_name);
314  if (undo_step_from_name == NULL) {
315  CLOG_ERROR(&LOG, "Step name='%s' not found in current undo stack", undo_name);
316 
317  return OPERATOR_CANCELLED;
318  }
319 
320  UndoStep *undo_step_target = undo_step_from_name->prev;
321  if (undo_step_target == NULL) {
322  CLOG_ERROR(&LOG, "Step name='%s' cannot be undone", undo_name);
323 
324  return OPERATOR_CANCELLED;
325  }
326 
327  const int undo_dir_i = BKE_undosys_step_calc_direction(wm->undo_stack, undo_step_target, NULL);
328  BLI_assert(ELEM(undo_dir_i, -1, 1));
329  const enum eUndoStepDir undo_dir = (undo_dir_i == -1) ? STEP_UNDO : STEP_REDO;
330 
331  CLOG_INFO(&LOG,
332  1,
333  "name='%s', found direction=%s",
334  undo_name,
335  (undo_dir == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO");
336 
337  ed_undo_step_pre(C, wm, undo_dir, reports);
338 
339  BKE_undosys_step_load_data_ex(wm->undo_stack, C, undo_step_target, NULL, true);
340 
341  ed_undo_step_post(C, wm, undo_dir, reports);
342 
343  return OPERATOR_FINISHED;
344 }
345 
351 static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *reports)
352 {
353  BLI_assert(undo_index >= 0);
354 
355  /* FIXME: See comments in `ed_undo_step_direction`. */
357  BLI_assert_msg(0, "Not implemented currently.");
358  }
359 
361  const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active);
362  if (undo_index == active_step_index) {
363  return OPERATOR_CANCELLED;
364  }
365  const enum eUndoStepDir undo_dir = (undo_index < active_step_index) ? STEP_UNDO : STEP_REDO;
366 
367  CLOG_INFO(&LOG,
368  1,
369  "index='%d', found direction=%s",
370  undo_index,
371  (undo_dir == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO");
372 
373  ed_undo_step_pre(C, wm, undo_dir, reports);
374 
376 
377  ed_undo_step_post(C, wm, undo_dir, reports);
378 
379  return OPERATOR_FINISHED;
380 }
381 
382 void ED_undo_grouped_push(bContext *C, const char *str)
383 {
384  /* do nothing if previous undo task is the same as this one (or from the same undo group) */
386  const UndoStep *us = wm->undo_stack->step_active;
387  if (us && STREQ(str, us->name)) {
389  }
390 
391  /* push as usual */
392  ED_undo_push(C, str);
393 }
394 
396 {
398 }
400 {
402 }
403 
405 {
406  /* in future, get undo string info? */
407  ED_undo_push(C, op->type->name);
408 }
409 
411 {
412  if (op->type->undo_group[0] != '\0') {
414  }
415  else {
417  }
418 }
419 
421 {
422  /* search back a couple of undo's, in case something else added pushes */
423  ed_undo_step_by_name(C, op->type->name, op->reports);
424 }
425 
426 bool ED_undo_is_valid(const bContext *C, const char *undoname)
427 {
429  return BKE_undosys_stack_has_undo(wm->undo_stack, undoname);
430 }
431 
433 {
434  /* Some modes don't co-exist with memfile undo, disable their use: T60593
435  * (this matches 2.7x behavior). */
436  ViewLayer *view_layer = CTX_data_view_layer(C);
437  if (view_layer != NULL) {
438  Object *obact = OBACT(view_layer);
439  if (obact != NULL) {
440  if (obact->mode & OB_MODE_EDIT) {
441  return false;
442  }
443  }
444  }
445  return true;
446 }
447 
449 {
450  ViewLayer *view_layer = CTX_data_view_layer(C);
451  if (view_layer != NULL) {
452  Object *obact = OBACT(view_layer);
453  if (obact != NULL) {
454  if (obact->mode & OB_MODE_ALL_PAINT) {
455  /* Don't store property changes when painting
456  * (only do undo pushes on brush strokes which each paint operator handles on its own). */
457  CLOG_INFO(&LOG, 1, "skipping undo for paint-mode");
458  return false;
459  }
460  if (obact->mode & OB_MODE_EDIT) {
461  if ((id == NULL) || (obact->data == NULL) ||
462  (GS(id->name) != GS(((ID *)obact->data)->name))) {
463  /* No undo push on id type mismatch in edit-mode. */
464  CLOG_INFO(&LOG, 1, "skipping undo for edit-mode");
465  return false;
466  }
467  }
468  }
469  }
470  return true;
471 }
472 
474 {
475  wmWindowManager *wm = G_MAIN->wm.first;
476  return wm->undo_stack;
477 }
478 
481 /* -------------------------------------------------------------------- */
489 {
490  /* The "last operator" should disappear, later we can tie this with undo stack nicer. */
492 
493  /* Keep button under the cursor active. */
495 
497 }
498 
500 {
501  /* "last operator" should disappear, later we can tie this with undo stack nicer */
504  if (ret & OPERATOR_FINISHED) {
506  }
507  return ret;
508 }
509 
511 {
512  if (G.background) {
513  /* Exception for background mode, see: T60934.
514  * NOTE: since the undo stack isn't initialized on startup, background mode behavior
515  * won't match regular usage, this is just for scripts to do explicit undo pushes. */
517  if (wm->undo_stack == NULL) {
519  }
520  }
521  char str[BKE_UNDO_STR_MAX];
522  RNA_string_get(op->ptr, "message", str);
523  ED_undo_push(C, str);
524  return OPERATOR_FINISHED;
525 }
526 
528 {
530  if (ret & OPERATOR_FINISHED) {
532  }
533  return ret;
534 }
535 
537 {
538  wmOperator *last_op = WM_operator_last_redo(C);
539  int ret = ED_undo_operator_repeat(C, last_op);
541  if (ret & OPERATOR_FINISHED) {
542  /* Keep button under the cursor active. */
544  }
545  return ret;
546 }
547 
548 /* Disable in background mode, we could support if it's useful, T60934. */
549 
551 {
553  if (wm->undo_stack == NULL) {
554  /* This message is intended for Python developers,
555  * it will be part of the exception when attempting to call undo in background mode. */
557  C,
558  "Undo disabled at startup in background-mode "
559  "(call `ed.undo_push()` to explicitly initialize the undo-system)");
560  return false;
561  }
562  return true;
563 }
564 
566 {
567  if (ed_undo_is_init_poll(C) == false) {
568  return false;
569  }
570  return ED_operator_screenactive(C);
571 }
572 
574 {
575  wmOperator *last_op = WM_operator_last_redo(C);
576  return (last_op && ed_undo_is_init_and_screenactive_poll(C) &&
578 }
579 
580 static bool ed_undo_poll(bContext *C)
581 {
583  return false;
584  }
586  return (undo_stack->step_active != NULL) && (undo_stack->step_active->prev != NULL);
587 }
588 
590 {
591  /* identifiers */
592  ot->name = "Undo";
593  ot->description = "Undo previous action";
594  ot->idname = "ED_OT_undo";
595 
596  /* api callbacks */
597  ot->exec = ed_undo_exec;
598  ot->poll = ed_undo_poll;
599 }
600 
602 {
603  /* identifiers */
604  ot->name = "Undo Push";
605  ot->description = "Add an undo state (internal use only)";
606  ot->idname = "ED_OT_undo_push";
607 
608  /* api callbacks */
610  /* Unlike others undo operators this initializes undo stack. */
612 
614 
616  "message",
617  "Add an undo step *function may be moved*",
619  "Undo Message",
620  "");
621 }
622 
623 static bool ed_redo_poll(bContext *C)
624 {
626  return false;
627  }
629  return (undo_stack->step_active != NULL) && (undo_stack->step_active->next != NULL);
630 }
631 
633 {
634  /* identifiers */
635  ot->name = "Redo";
636  ot->description = "Redo previous action";
637  ot->idname = "ED_OT_redo";
638 
639  /* api callbacks */
640  ot->exec = ed_redo_exec;
641  ot->poll = ed_redo_poll;
642 }
643 
645 {
646  /* identifiers */
647  ot->name = "Undo and Redo";
648  ot->description = "Undo and redo previous action";
649  ot->idname = "ED_OT_undo_redo";
650 
651  /* api callbacks */
654 }
655 
658 /* -------------------------------------------------------------------- */
663 {
664  int ret = 0;
665 
666  if (op) {
667  CLOG_INFO(&LOG, 1, "idname='%s'", op->type->idname);
669  struct Scene *scene = CTX_data_scene(C);
670 
671  /* keep in sync with logic in view3d_panel_operator_redo() */
672  ARegion *region_orig = CTX_wm_region(C);
674 
675  if (region_win) {
676  CTX_wm_region_set(C, region_win);
677  }
678 
679  if (WM_operator_repeat_check(C, op) && WM_operator_poll(C, op->type) &&
680  /* NOTE: undo/redo can't run if there are jobs active,
681  * check for screen jobs only so jobs like material/texture/world preview
682  * (which copy their data), won't stop redo, see T29579],
683  *
684  * NOTE: WM_operator_check_ui_enabled() jobs test _must_ stay in sync with this. */
685  (WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY) == 0)) {
686  int retval;
687 
688  if (G.debug & G_DEBUG) {
689  printf("redo_cb: operator redo %s\n", op->type->name);
690  }
691 
693 
694  ED_undo_pop_op(C, op);
695 
696  if (op->type->check) {
697  if (op->type->check(C, op)) {
698  /* check for popup and re-layout buttons */
699  ARegion *region_menu = CTX_wm_menu(C);
700  if (region_menu) {
701  ED_region_tag_refresh_ui(region_menu);
702  }
703  }
704  }
705 
706  retval = WM_operator_repeat(C, op);
707  if ((retval & OPERATOR_FINISHED) == 0) {
708  if (G.debug & G_DEBUG) {
709  printf("redo_cb: operator redo failed: %s, return %d\n", op->type->name, retval);
710  }
711  ED_undo_redo(C);
712  }
713  else {
714  ret = 1;
715  }
716  }
717  else {
718  if (G.debug & G_DEBUG) {
719  printf("redo_cb: WM_operator_repeat_check returned false %s\n", op->type->name);
720  }
721  }
722 
723  /* set region back */
724  CTX_wm_region_set(C, region_orig);
725  }
726  else {
727  CLOG_WARN(&LOG, "called with NULL 'op'");
728  }
729 
730  return ret;
731 }
732 
733 void ED_undo_operator_repeat_cb(bContext *C, void *arg_op, void *UNUSED(arg_unused))
734 {
736 }
737 
738 void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_unused))
739 {
741 }
742 
745 /* -------------------------------------------------------------------- */
751 /* NOTE: also check #ed_undo_step() in top if you change notifiers. */
753 {
754  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
755  if (RNA_property_is_set(op->ptr, prop)) {
756  const int item = RNA_property_int_get(op->ptr, prop);
757  const int ret = ed_undo_step_by_index(C, item, op->reports);
758  if (ret & OPERATOR_FINISHED) {
760 
762  return OPERATOR_FINISHED;
763  }
764  }
765  return OPERATOR_CANCELLED;
766 }
767 
768 static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
769 {
770  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
771  if (RNA_property_is_set(op->ptr, prop)) {
772  return undo_history_exec(C, op);
773  }
774 
775  WM_menu_name_call(C, "TOPBAR_MT_undo_history", WM_OP_INVOKE_DEFAULT);
776  return OPERATOR_FINISHED;
777 }
778 
780 {
781  /* identifiers */
782  ot->name = "Undo History";
783  ot->description = "Redo specific action in history";
784  ot->idname = "ED_OT_undo_history";
785 
786  /* api callbacks */
790 
791  RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
792 }
793 
796 /* -------------------------------------------------------------------- */
801  Scene *scene, ViewLayer *view_layer, Object *ob, const char *info, CLG_LogRef *log)
802 {
803  Object *ob_prev = OBACT(view_layer);
804  if (ob_prev != ob) {
805  Base *base = BKE_view_layer_base_find(view_layer, ob);
806  if (base != NULL) {
807  view_layer->basact = base;
809  }
810  else {
811  /* Should never fail, may not crash but can give odd behavior. */
812  CLOG_WARN(log, "'%s' failed to restore active object: '%s'", info, ob->id.name + 2);
813  }
814  }
815 }
816 
818  Object **object_array,
819  uint object_array_len,
820  uint object_array_stride)
821 {
822  Main *bmain = CTX_data_main(C);
823  ViewLayer *view_layer = CTX_data_view_layer(C);
824  uint bases_len = 0;
825  /* Don't request unique data because we want to de-select objects when exiting edit-mode
826  * for that to be done on all objects we can't skip ones that share data. */
827  Base **bases = ED_undo_editmode_bases_from_view_layer(view_layer, &bases_len);
828  for (uint i = 0; i < bases_len; i++) {
829  ((ID *)bases[i]->object->data)->tag |= LIB_TAG_DOIT;
830  }
832  Object **ob_p = object_array;
833  for (uint i = 0; i < object_array_len; i++, ob_p = POINTER_OFFSET(ob_p, object_array_stride)) {
834  Object *obedit = *ob_p;
836  ((ID *)obedit->data)->tag &= ~LIB_TAG_DOIT;
837  }
838  for (uint i = 0; i < bases_len; i++) {
839  ID *id = bases[i]->object->data;
840  if (id->tag & LIB_TAG_DOIT) {
841  ED_object_editmode_exit_ex(bmain, scene, bases[i]->object, EM_FREEDATA);
842  /* Ideally we would know the selection state it was before entering edit-mode,
843  * for now follow the convention of having them unselected when exiting the mode. */
845  }
846  }
847  MEM_freeN(bases);
848 }
849 
852 /* -------------------------------------------------------------------- */
863 {
864  const short object_type = obact->type;
865 
866  LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
867  Object *ob = base->object;
868  if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
869  ID *id = ob->data;
870  id->tag &= ~LIB_TAG_DOIT;
871  }
872  }
873 
874  int len = 0;
875  LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
876  Object *ob = base->object;
877  if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
878  ID *id = ob->data;
879  if ((id->tag & LIB_TAG_DOIT) == 0) {
880  len += 1;
881  id->tag |= LIB_TAG_DOIT;
882  }
883  }
884  }
885  return len;
886 }
887 
889 {
890  Base *baseact = BASACT(view_layer);
891  if ((baseact == NULL) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
892  return MEM_mallocN(0, __func__);
893  }
894  const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, baseact->object);
895  const short object_type = baseact->object->type;
896  int i = 0;
897  Object **objects = MEM_malloc_arrayN(len, sizeof(*objects), __func__);
898  /* Base iteration, starting with the active-base to ensure it's the first item in the array.
899  * Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
900  for (Base *base = baseact, *base_next = FIRSTBASE(view_layer); base;
901  base = base_next, base_next = base_next ? base_next->next : NULL) {
902  Object *ob = base->object;
903  if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
904  ID *id = ob->data;
905  if (id->tag & LIB_TAG_DOIT) {
906  objects[i++] = ob;
907  id->tag &= ~LIB_TAG_DOIT;
908  }
909  }
910  }
911  BLI_assert(i == len);
912  BLI_assert(objects[0] == baseact->object);
913  *r_len = len;
914  return objects;
915 }
916 
918 {
919  Base *baseact = BASACT(view_layer);
920  if ((baseact == NULL) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
921  return MEM_mallocN(0, __func__);
922  }
923  const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, baseact->object);
924  const short object_type = baseact->object->type;
925  int i = 0;
926  Base **base_array = MEM_malloc_arrayN(len, sizeof(*base_array), __func__);
927  /* Base iteration, starting with the active-base to ensure it's the first item in the array.
928  * Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
929  for (Base *base = BASACT(view_layer), *base_next = FIRSTBASE(view_layer); base;
930  base = base_next, base_next = base_next ? base_next->next : NULL) {
931  Object *ob = base->object;
932  if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
933  ID *id = ob->data;
934  if (id->tag & LIB_TAG_DOIT) {
935  base_array[i++] = base;
936  id->tag &= ~LIB_TAG_DOIT;
937  }
938  }
939  }
940 
941  BLI_assert(i == len);
942  BLI_assert(base_array[0] == baseact);
943  *r_len = len;
944  return base_array;
945 }
946 
#define BKE_UNDO_STR_MAX
@ BKE_CB_EVT_REDO_POST
Definition: BKE_callbacks.h:91
@ BKE_CB_EVT_REDO_PRE
Definition: BKE_callbacks.h:90
@ BKE_CB_EVT_UNDO_PRE
Definition: BKE_callbacks.h:88
@ BKE_CB_EVT_UNDO_POST
Definition: BKE_callbacks.h:89
void BKE_callback_exec_id(struct Main *bmain, struct ID *id, eCbEvent evt)
Definition: callbacks.c:46
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
void CTX_wm_region_set(bContext *C, struct ARegion *region)
Definition: context.c:1009
struct ARegion * CTX_wm_menu(const bContext *C)
Definition: context.c:760
struct Base * CTX_data_active_base(const bContext *C)
Definition: context.c:1358
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1042
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
#define G_MAIN
Definition: BKE_global.h:267
@ G_DEBUG
Definition: BKE_global.h:174
@ G_DEBUG_IO
Definition: BKE_global.h:194
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:379
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
struct ARegion * BKE_area_find_region_active_win(struct ScrArea *area)
Definition: screen.c:883
bool BKE_undosys_stack_has_undo(const UndoStack *ustack, const char *name)
Definition: undo_system.c:354
void BKE_undosys_stack_clear_active(UndoStack *ustack)
Definition: undo_system.c:274
eUndoPushReturn BKE_undosys_step_push(UndoStack *ustack, struct bContext *C, const char *name)
Definition: undo_system.c:593
UndoStack * BKE_undosys_stack_create(void)
Definition: undo_system.c:250
eUndoStepDir BKE_undosys_step_calc_direction(const UndoStack *ustack, const UndoStep *us_target, const UndoStep *us_reference)
Definition: undo_system.c:659
bool BKE_undosys_step_undo(UndoStack *ustack, struct bContext *C)
Definition: undo_system.c:842
eUndoStepDir
@ STEP_UNDO
@ STEP_REDO
bool BKE_undosys_step_load_data_ex(UndoStack *ustack, struct bContext *C, UndoStep *us_target, UndoStep *us_reference, bool use_skip)
Definition: undo_system.c:718
UndoStep * BKE_undosys_step_find_by_name(UndoStack *ustack, const char *name)
Definition: undo_system.c:644
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit)
Definition: undo_system.c:383
eUndoPushReturn
@ UNDO_PUSH_RET_OVERRIDE_CHANGED
void BKE_undosys_stack_group_end(UndoStack *ustack)
Definition: undo_system.c:925
void BKE_undosys_step_load_from_index(UndoStack *ustack, struct bContext *C, int index)
Definition: undo_system.c:812
bool BKE_undosys_step_redo(UndoStack *ustack, struct bContext *C)
Definition: undo_system.c:869
void BKE_undosys_print(UndoStack *ustack)
Definition: undo_system.c:963
void BKE_undosys_stack_group_begin(UndoStack *ustack)
Definition: undo_system.c:919
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
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:67
#define UNUSED(x)
#define ELEM(...)
#define POINTER_OFFSET(v, ofs)
#define STREQ(a, b)
Utilities 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 CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:190
#define CLOG_WARN(clg_ref,...)
Definition: CLG_log.h:189
#define CLOG_CHECK(clg_ref, verbose_level,...)
Definition: CLG_log.h:151
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:187
@ LIB_TAG_DOIT
Definition: DNA_ID.h:707
#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_assetlist_storage_tag_main_data_dirty(void)
Definition: asset_list.cc:533
@ EM_NO_CONTEXT
Definition: ED_object.h:243
@ EM_FREEDATA
Definition: ED_object.h:242
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode)
Definition: object_select.c:76
void ED_object_base_active_refresh(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer)
bool ED_object_editmode_exit_ex(struct Main *bmain, struct Scene *scene, struct Object *obedit, int flag)
Definition: object_edit.c:653
bool ED_object_editmode_enter_ex(struct Main *bmain, struct Scene *scene, struct Object *ob, int flag)
Definition: object_edit.c:734
void ED_object_base_activate(struct bContext *C, struct Base *base)
@ BA_DESELECT
Definition: ED_object.h:154
void ED_outliner_select_sync_from_all_tag(struct bContext *C)
bool ED_operator_screenactive(struct bContext *C)
Definition: screen_ops.c:119
void ED_region_tag_refresh_ui(struct ARegion *region)
Definition: area.c:683
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
@ WM_JOB_TYPE_ANY
Definition: WM_api.h:1347
@ OPTYPE_INTERNAL
Definition: WM_types.h:168
#define NC_WINDOW
Definition: WM_types.h:325
#define NC_WM
Definition: WM_types.h:324
#define ND_LIB_OVERRIDE_CHANGED
Definition: WM_types.h:367
#define ND_UNDO
Definition: WM_types.h:365
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:201
unsigned int U
Definition: btGjkEpa3.h:78
Scene scene
int len
Definition: draw_manager.c:108
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:800
void ED_undo_push(bContext *C, const char *str)
Definition: ed_undo.c:100
void ED_OT_redo(wmOperatorType *ot)
Definition: ed_undo.c:632
bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id)
Definition: ed_undo.c:448
static int ed_undo_push_exec(bContext *C, wmOperator *op)
Definition: ed_undo.c:510
static void ed_undo_step_pre(bContext *C, wmWindowManager *wm, const enum eUndoStepDir undo_dir, ReportList *reports)
Definition: ed_undo.c:157
void ED_undo_push_op(bContext *C, wmOperator *op)
Definition: ed_undo.c:404
UndoStack * ED_undo_stack_get(void)
Definition: ed_undo.c:473
void ED_undo_pop_op(bContext *C, wmOperator *op)
Definition: ed_undo.c:420
Base ** ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len)
Definition: ed_undo.c:917
void ED_undo_group_begin(bContext *C)
Definition: ed_undo.c:88
bool ED_undo_is_valid(const bContext *C, const char *undoname)
Definition: ed_undo.c:426
void ED_OT_undo_redo(wmOperatorType *ot)
Definition: ed_undo.c:644
static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *reports)
Definition: ed_undo.c:351
static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer, Object *obact)
Definition: ed_undo.c:862
void ED_OT_undo_push(wmOperatorType *ot)
Definition: ed_undo.c:601
int ED_undo_operator_repeat(bContext *C, wmOperator *op)
Definition: ed_undo.c:662
static void ed_undo_step_post(bContext *C, wmWindowManager *wm, const enum eUndoStepDir undo_dir, ReportList *reports)
Definition: ed_undo.c:201
static void ed_undo_refresh_for_op(bContext *C)
Definition: ed_undo.c:488
void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_unused))
Definition: ed_undo.c:738
static int ed_undo_exec(bContext *C, wmOperator *op)
Definition: ed_undo.c:499
static int undo_history_exec(bContext *C, wmOperator *op)
Definition: ed_undo.c:752
static bool ed_redo_poll(bContext *C)
Definition: ed_undo.c:623
void ED_undo_operator_repeat_cb(bContext *C, void *arg_op, void *UNUSED(arg_unused))
Definition: ed_undo.c:733
static bool ed_undo_is_init_poll(bContext *C)
Definition: ed_undo.c:550
static bool ed_undo_is_init_and_screenactive_poll(bContext *C)
Definition: ed_undo.c:565
Object ** ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r_len)
Definition: ed_undo.c:888
static int ed_redo_exec(bContext *C, wmOperator *op)
Definition: ed_undo.c:527
static int ed_undo_step_by_name(bContext *C, const char *undo_name, ReportList *reports)
Definition: ed_undo.c:303
void ED_undo_redo(bContext *C)
Definition: ed_undo.c:399
static int ed_undo_redo_exec(bContext *C, wmOperator *UNUSED(op))
Definition: ed_undo.c:536
bool ED_undo_is_state_valid(bContext *C)
Definition: ed_undo.c:65
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:817
void ED_OT_undo(wmOperatorType *ot)
Definition: ed_undo.c:589
static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: ed_undo.c:768
static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports)
Definition: ed_undo.c:266
void ED_OT_undo_history(wmOperatorType *ot)
Definition: ed_undo.c:779
static bool ed_undo_poll(bContext *C)
Definition: ed_undo.c:580
static CLG_LogRef LOG
Definition: ed_undo.c:57
void ED_undo_grouped_push_op(bContext *C, wmOperator *op)
Definition: ed_undo.c:410
static bool ed_undo_redo_poll(bContext *C)
Definition: ed_undo.c:573
bool ED_undo_is_memfile_compatible(const bContext *C)
Definition: ed_undo.c:432
void ED_undo_pop(bContext *C)
Definition: ed_undo.c:395
void ED_undo_group_end(bContext *C)
Definition: ed_undo.c:94
void ED_undo_grouped_push(bContext *C, const char *str)
Definition: ed_undo.c:382
#define str(s)
int ED_gpencil_session_active(void)
Definition: gpencil_undo.c:44
int ED_undo_gpencil_step(bContext *C, const int step)
Definition: gpencil_undo.c:49
void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
#define GS(x)
Definition: iris.c:225
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
ccl_device_inline float3 log(float3 v)
Definition: math_float3.h:397
#define G(x, y, z)
static void area(int d1, int d2, int e1, int e2, float weights[2])
return ret
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2429
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
Definition: rna_access.c:5116
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:3687
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:3597
static const int steps
Definition: sky_nishita.cpp:19
struct Object * object
Definition: DNA_ID.h:368
int tag
Definition: DNA_ID.h:387
char name[66]
Definition: DNA_ID.h:378
Definition: BKE_main.h:121
struct MainLock * lock
Definition: BKE_main.h:226
void * data
vector< Object * > objects
Definition: scene.h:213
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:919
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
bool(* check)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:911
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
const char * undo_group
Definition: WM_types.h:895
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
struct UndoStack * undo_stack
#define undo_stack
Definition: undo_system.c:32
void WM_operator_stack_clear(wmWindowManager *wm)
Definition: wm.c:390
void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op)
Definition: wm.c:325
void WM_menu_name_call(bContext *C, const char *menu_name, short context)
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:150
wmOperatorType * ot
Definition: wm_files.c:3479
void WM_jobs_kill_all(wmWindowManager *wm)
Definition: wm_jobs.c:551
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition: wm_jobs.c:214
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:273
void WM_toolsystem_refresh_screen_all(Main *bmain)
void WM_toolsystem_refresh_active(bContext *C)