Blender  V3.3
outliner_tools.cc
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 "MEM_guardedalloc.h"
9 
10 #include "CLG_log.h"
11 
12 #include "DNA_anim_types.h"
13 #include "DNA_armature_types.h"
14 #include "DNA_collection_types.h"
15 #include "DNA_constraint_types.h"
16 #include "DNA_curves_types.h"
17 #include "DNA_gpencil_types.h"
18 #include "DNA_light_types.h"
19 #include "DNA_linestyle_types.h"
20 #include "DNA_material_types.h"
21 #include "DNA_mesh_types.h"
22 #include "DNA_meta_types.h"
23 #include "DNA_modifier_types.h"
24 #include "DNA_object_types.h"
25 #include "DNA_pointcloud_types.h"
26 #include "DNA_scene_types.h"
27 #include "DNA_sequence_types.h"
28 #include "DNA_simulation_types.h"
29 #include "DNA_volume_types.h"
30 #include "DNA_world_types.h"
31 
32 #include "BLI_blenlib.h"
33 #include "BLI_ghash.h"
34 #include "BLI_linklist.h"
35 #include "BLI_map.hh"
36 #include "BLI_set.hh"
37 #include "BLI_utildefines.h"
38 #include "BLI_vector.hh"
39 
40 #include "BKE_anim_data.h"
41 #include "BKE_animsys.h"
42 #include "BKE_armature.h"
43 #include "BKE_collection.h"
44 #include "BKE_constraint.h"
45 #include "BKE_context.h"
46 #include "BKE_fcurve.h"
47 #include "BKE_global.h"
48 #include "BKE_idtype.h"
49 #include "BKE_layer.h"
50 #include "BKE_lib_id.h"
51 #include "BKE_lib_override.h"
52 #include "BKE_lib_query.h"
53 #include "BKE_lib_remap.h"
54 #include "BKE_main.h"
55 #include "BKE_object.h"
56 #include "BKE_report.h"
57 #include "BKE_scene.h"
58 #include "BKE_screen.h"
59 
60 #include "DEG_depsgraph.h"
61 #include "DEG_depsgraph_build.h"
62 
63 #include "ED_object.h"
64 #include "ED_outliner.h"
65 #include "ED_scene.h"
66 #include "ED_screen.h"
67 #include "ED_sequencer.h"
68 #include "ED_undo.h"
69 
70 #include "WM_api.h"
71 #include "WM_message.h"
72 #include "WM_types.h"
73 
74 #include "UI_interface.h"
75 #include "UI_resources.h"
76 #include "UI_view2d.h"
77 
78 #include "../../blender/blenloader/BLO_readfile.h"
79 
80 #include "RNA_access.h"
81 #include "RNA_define.h"
82 #include "RNA_enum_types.h"
83 
84 #include "SEQ_relations.h"
85 #include "SEQ_sequencer.h"
86 
87 #include "outliner_intern.hh"
88 #include "tree/tree_element_rna.hh"
89 #include "tree/tree_element_seq.hh"
90 #include "tree/tree_iterator.hh"
91 
92 static CLG_LogRef LOG = {"ed.outliner.tools"};
93 
94 using namespace blender::ed::outliner;
95 
96 using blender::Map;
97 using blender::Set;
98 using blender::Vector;
99 
100 /* -------------------------------------------------------------------- */
105  TreeElement *te, int *scenelevel, int *objectlevel, int *idlevel, int *datalevel)
106 {
107  TreeStoreElem *tselem = TREESTORE(te);
108  if (tselem->flag & TSE_SELECTED) {
109  /* Layer collection points to collection ID. */
110  if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) {
111  if (*datalevel == 0) {
112  *datalevel = tselem->type;
113  }
114  else if (*datalevel != tselem->type) {
115  *datalevel = -1;
116  }
117  }
118  else {
119  const int idcode = (int)GS(tselem->id->name);
120  bool is_standard_id = false;
121  switch ((ID_Type)idcode) {
122  case ID_SCE:
123  *scenelevel = 1;
124  break;
125  case ID_OB:
126  *objectlevel = 1;
127  break;
128 
129  case ID_ME:
130  case ID_CU_LEGACY:
131  case ID_MB:
132  case ID_LT:
133  case ID_LA:
134  case ID_AR:
135  case ID_CA:
136  case ID_SPK:
137  case ID_MA:
138  case ID_TE:
139  case ID_IP:
140  case ID_IM:
141  case ID_SO:
142  case ID_KE:
143  case ID_WO:
144  case ID_AC:
145  case ID_TXT:
146  case ID_GR:
147  case ID_LS:
148  case ID_LI:
149  case ID_VF:
150  case ID_NT:
151  case ID_BR:
152  case ID_PA:
153  case ID_GD:
154  case ID_MC:
155  case ID_MSK:
156  case ID_PAL:
157  case ID_PC:
158  case ID_CF:
159  case ID_WS:
160  case ID_LP:
161  case ID_CV:
162  case ID_PT:
163  case ID_VO:
164  case ID_SIM:
165  is_standard_id = true;
166  break;
167  case ID_WM:
168  case ID_SCR:
169  /* Those are ignored here. */
170  /* NOTE: while Screens should be manageable here, deleting a screen used by a workspace
171  * will cause crashes when trying to use that workspace, so for now let's play minimal,
172  * safe change. */
173  break;
174  }
175  if (idcode == ID_NLA) {
176  /* Fake one, not an actual ID type... */
177  is_standard_id = true;
178  }
179 
180  if (is_standard_id) {
181  if (*idlevel == 0) {
182  *idlevel = idcode;
183  }
184  else if (*idlevel != idcode) {
185  *idlevel = -1;
186  }
188  *datalevel = 0;
189  }
190  }
191  }
192  }
193 }
194 
196 {
198 
199  return te;
200 }
201 
203 {
205  return false;
206  }
207  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
208  TreeElement *te = get_target_element(space_outliner);
209  if (te == nullptr) {
210  return false;
211  }
212 
213  return true;
214 }
215 
216 static void unlink_action_fn(bContext *C,
217  ReportList *reports,
218  Scene *UNUSED(scene),
219  TreeElement *UNUSED(te),
220  TreeStoreElem *tsep,
221  TreeStoreElem *tselem,
222  void *UNUSED(user_data))
223 {
224  if (!tsep || !TSE_IS_REAL_ID(tsep)) {
225  /* Valid case, no parent element of the action or it is not an ID (could be a #TSE_ID_BASE
226  * for example) so there's no data to unlink from. */
227  BKE_reportf(reports,
228  RPT_WARNING,
229  "Cannot unlink action '%s'. It's not clear which object or object-data it "
230  "should be unlinked from, there's no object or object-data as parent in the "
231  "Outliner tree",
232  tselem->id->name + 2);
233  return;
234  }
235 
236  /* just set action to nullptr */
237  BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, nullptr);
239 }
240 
242  ReportList *reports,
243  Scene *UNUSED(scene),
244  TreeElement *te,
245  TreeStoreElem *tsep,
246  TreeStoreElem *tselem,
247  void *UNUSED(user_data))
248 {
249  const bool te_is_material = TSE_IS_REAL_ID(tselem) && (GS(tselem->id->name) == ID_MA);
250 
251  if (!te_is_material) {
252  /* Just fail silently. Another element may be selected that is a material, we don't want to
253  * confuse users with an error in that case. */
254  return;
255  }
256 
257  if (!tsep || !TSE_IS_REAL_ID(tsep)) {
258  /* Valid case, no parent element of the material or it is not an ID (could be a #TSE_ID_BASE
259  * for example) so there's no data to unlink from. */
260  BKE_reportf(reports,
261  RPT_WARNING,
262  "Cannot unlink material '%s'. It's not clear which object or object-data it "
263  "should be unlinked from, there's no object or object-data as parent in the "
264  "Outliner tree",
265  tselem->id->name + 2);
266  return;
267  }
268 
269  Material **matar = nullptr;
270  int a, totcol = 0;
271 
272  switch (GS(tsep->id->name)) {
273  case ID_OB: {
274  Object *ob = (Object *)tsep->id;
275  totcol = ob->totcol;
276  matar = ob->mat;
277  break;
278  }
279  case ID_ME: {
280  Mesh *me = (Mesh *)tsep->id;
281  totcol = me->totcol;
282  matar = me->mat;
283  break;
284  }
285  case ID_CU_LEGACY: {
286  Curve *cu = (Curve *)tsep->id;
287  totcol = cu->totcol;
288  matar = cu->mat;
289  break;
290  }
291  case ID_MB: {
292  MetaBall *mb = (MetaBall *)tsep->id;
293  totcol = mb->totcol;
294  matar = mb->mat;
295  break;
296  }
297  case ID_CV: {
298  Curves *curves = (Curves *)tsep->id;
299  totcol = curves->totcol;
300  matar = curves->mat;
301  break;
302  }
303  case ID_PT: {
304  PointCloud *pointcloud = (PointCloud *)tsep->id;
305  totcol = pointcloud->totcol;
306  matar = pointcloud->mat;
307  break;
308  }
309  case ID_VO: {
310  Volume *volume = (Volume *)tsep->id;
311  totcol = volume->totcol;
312  matar = volume->mat;
313  break;
314  }
315  default:
317  }
318 
319  if (LIKELY(matar != nullptr)) {
320  for (a = 0; a < totcol; a++) {
321  if (a == te->index && matar[a]) {
322  id_us_min(&matar[a]->id);
323  matar[a] = nullptr;
324  }
325  }
326  }
327 }
328 
330  ReportList *reports,
331  Scene *UNUSED(scene),
332  TreeElement *te,
333  TreeStoreElem *tsep,
334  TreeStoreElem *tselem,
335  void *UNUSED(user_data))
336 {
337  if (!tsep || !TSE_IS_REAL_ID(tsep)) {
338  /* Valid case, no parent element of the texture or it is not an ID (could be a #TSE_ID_BASE
339  * for example) so there's no data to unlink from. */
340  BKE_reportf(reports,
341  RPT_WARNING,
342  "Cannot unlink texture '%s'. It's not clear which freestyle line style it should "
343  "be unlinked from, there's no freestyle line style as parent in the Outliner tree",
344  tselem->id->name + 2);
345  return;
346  }
347 
348  MTex **mtex = nullptr;
349  int a;
350 
351  if (GS(tsep->id->name) == ID_LS) {
353  mtex = ls->mtex;
354  }
355  else {
356  return;
357  }
358 
359  for (a = 0; a < MAX_MTEX; a++) {
360  if (a == te->index && mtex[a]) {
361  if (mtex[a]->tex) {
362  id_us_min(&mtex[a]->tex->id);
363  mtex[a]->tex = nullptr;
364  }
365  }
366  }
367 }
368 
370  ReportList *reports,
371  Scene *UNUSED(scene),
372  TreeElement *UNUSED(te),
373  TreeStoreElem *tsep,
374  TreeStoreElem *tselem,
375  void *UNUSED(user_data))
376 {
377  Main *bmain = CTX_data_main(C);
378  Collection *collection = (Collection *)tselem->id;
379 
380  if (!tsep || !TSE_IS_REAL_ID(tsep)) {
381  /* Valid case, no parent element of the collection or it is not an ID (could be a #TSE_ID_BASE
382  * for example) so there's no data to unlink from. */
383  BKE_reportf(reports,
384  RPT_WARNING,
385  "Cannot unlink collection '%s'. It's not clear which scene, collection or "
386  "instance empties it should be unlinked from, there's no scene, collection or "
387  "instance empties as parent in the Outliner tree",
388  tselem->id->name + 2);
389  return;
390  }
391 
392  if (tsep) {
393  if (GS(tsep->id->name) == ID_OB) {
394  Object *ob = (Object *)tsep->id;
395  ob->instance_collection = nullptr;
398  }
399  else if (GS(tsep->id->name) == ID_GR) {
400  Collection *parent = (Collection *)tsep->id;
401  id_fake_user_set(&collection->id);
402  BKE_collection_child_remove(bmain, parent, collection);
405  }
406  else if (GS(tsep->id->name) == ID_SCE) {
407  Scene *scene = (Scene *)tsep->id;
409  id_fake_user_set(&collection->id);
410  BKE_collection_child_remove(bmain, parent, collection);
413  }
414  }
415 }
416 
417 static void unlink_object_fn(bContext *C,
418  ReportList *reports,
419  Scene *UNUSED(scene),
420  TreeElement *te,
421  TreeStoreElem *tsep,
422  TreeStoreElem *tselem,
423  void *UNUSED(user_data))
424 {
425  if (tsep && tsep->id) {
426  Main *bmain = CTX_data_main(C);
427  Object *ob = (Object *)tselem->id;
428 
429  if (GS(tsep->id->name) == ID_OB) {
430  /* Parented objects need to find which collection to unlink from. */
431  TreeElement *te_parent = te->parent;
432  while (tsep && GS(tsep->id->name) == ID_OB) {
433  if (ID_IS_LINKED(tsep->id)) {
434  BKE_reportf(reports,
435  RPT_WARNING,
436  "Cannot unlink object '%s' parented to another linked object '%s'",
437  ob->id.name + 2,
438  tsep->id->name + 2);
439  return;
440  }
441  te_parent = te_parent->parent;
442  tsep = te_parent ? TREESTORE(te_parent) : nullptr;
443  }
444  }
445 
446  if (tsep && tsep->id) {
447  if (ID_IS_LINKED(tsep->id) || ID_IS_OVERRIDE_LIBRARY(tsep->id)) {
448  BKE_reportf(reports,
449  RPT_WARNING,
450  "Cannot unlink object '%s' from linked collection or scene '%s'",
451  ob->id.name + 2,
452  tsep->id->name + 2);
453  return;
454  }
455  if (GS(tsep->id->name) == ID_GR) {
456  Collection *parent = (Collection *)tsep->id;
457  BKE_collection_object_remove(bmain, parent, ob, true);
460  }
461  else if (GS(tsep->id->name) == ID_SCE) {
462  Scene *scene = (Scene *)tsep->id;
464  BKE_collection_object_remove(bmain, parent, ob, true);
467  }
468  }
469  }
470 }
471 
473  ReportList *reports,
474  Scene *UNUSED(scene),
475  TreeElement *UNUSED(te),
476  TreeStoreElem *tsep,
477  TreeStoreElem *tselem,
478  void *UNUSED(user_data))
479 {
480  if (!tsep || !TSE_IS_REAL_ID(tsep)) {
481  /* Valid case, no parent element of the world or it is not an ID (could be a #TSE_ID_BASE
482  * for example) so there's no data to unlink from. */
483  BKE_reportf(reports,
484  RPT_WARNING,
485  "Cannot unlink world '%s'. It's not clear which scene it should be unlinked from, "
486  "there's no scene as parent in the Outliner tree",
487  tselem->id->name + 2);
488  return;
489  }
490 
491  Scene *parscene = (Scene *)tsep->id;
492  World *wo = (World *)tselem->id;
493 
494  /* need to use parent scene not just scene, otherwise may end up getting wrong one */
495  id_us_min(&wo->id);
496  parscene->world = nullptr;
497 }
498 
500  ReportList *reports,
501  Scene *scene,
502  SpaceOutliner *space_outliner,
503  outliner_operation_fn operation_fn,
504  void *user_data)
505 {
506  tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
507  TreeStoreElem *tselem = TREESTORE(te);
508  if (tselem->flag & TSE_SELECTED) {
509  if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
510  tselem->type == TSE_LAYER_COLLECTION) {
511  TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr;
512  operation_fn(C, reports, scene, te, tsep, tselem, user_data);
513  }
514  }
515  });
516 }
517 
519  /* Only selected items. */
521  /* Only content 'inside' selected items (their sub-tree). */
523  /* Combining both options above. */
526 
529  "SELECTED",
530  0,
531  "Selected",
532  "Apply the operation over selected data-blocks only"},
534  "CONTENT",
535  0,
536  "Content",
537  "Apply the operation over content of the selected items only (the data-blocks in their "
538  "sub-tree)"},
540  "SELECTED_AND_CONTENT",
541  0,
542  "Selected & Content",
543  "Apply the operation over selected data-blocks and all their dependencies"},
544  {0, nullptr, 0, nullptr, nullptr},
545 };
546 
548  ReportList *reports,
549  Scene *scene,
550  SpaceOutliner *space_outliner,
551  const ListBase &subtree,
552  const bool has_parent_selected,
553  outliner_operation_fn operation_fn,
554  eOutlinerLibOpSelectionSet selection_set,
555  void *user_data)
556 {
557  const bool do_selected = ELEM(selection_set,
560  const bool do_content = ELEM(selection_set,
563 
565  /* Get needed data out in case element gets freed. */
566  TreeStoreElem *tselem = TREESTORE(element);
567  const ListBase subtree = element->subtree;
568 
569  bool is_selected = tselem->flag & TSE_SELECTED;
570  if ((is_selected && do_selected) || (has_parent_selected && do_content)) {
571  if (((tselem->type == TSE_SOME_ID) && (element->idcode != 0)) ||
572  tselem->type == TSE_LAYER_COLLECTION) {
573  TreeStoreElem *tsep = element->parent ? TREESTORE(element->parent) : nullptr;
574  operation_fn(C, reports, scene, element, tsep, tselem, user_data);
575  }
576  }
577 
578  /* Don't access element from now on, it may be freed. Note that the open/collapsed state may
579  * also have been changed in the visitor callback. */
581  reports,
582  scene,
583  space_outliner,
584  subtree,
585  is_selected || has_parent_selected,
586  operation_fn,
587  selection_set,
588  user_data);
589  }
590 }
591 
593  ReportList *reports,
594  Scene *scene,
595  SpaceOutliner *space_outliner,
596  outliner_operation_fn operation_fn,
597  eOutlinerLibOpSelectionSet selection_set,
598  void *user_data)
599 {
601  reports,
602  scene,
603  space_outliner,
604  space_outliner->tree,
605  false,
606  operation_fn,
607  selection_set,
608  user_data);
609 }
610 
613 /* -------------------------------------------------------------------- */
619 };
620 
622  {OL_SCENE_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
623  {0, nullptr, 0, nullptr, nullptr},
624 };
625 
627  bContext *C,
628  SpaceOutliner *space_outliner,
630  bool (*operation_fn)(bContext *, eOutliner_PropSceneOps, TreeElement *, TreeStoreElem *))
631 {
632  bool success = false;
633 
634  tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
635  TreeStoreElem *tselem = TREESTORE(te);
636  if (tselem->flag & TSE_SELECTED) {
637  if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) {
638  if (operation_fn(C, event, te, tselem)) {
639  success = true;
640  }
641  }
642  }
643  });
644 
645  return success;
646 }
647 
648 static bool scene_fn(bContext *C,
650  TreeElement *UNUSED(te),
651  TreeStoreElem *tselem)
652 {
653  Scene *scene = (Scene *)tselem->id;
654 
655  if (event == OL_SCENE_OP_DELETE) {
658  }
659  else {
660  return false;
661  }
662  }
663 
664  return true;
665 }
666 
668 {
669  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
671 
672  if (outliner_do_scene_operation(C, space_outliner, event, scene_fn) == false) {
673  return OPERATOR_CANCELLED;
674  }
675 
676  if (event == OL_SCENE_OP_DELETE) {
677  outliner_cleanup_tree(space_outliner);
678  ED_undo_push(C, "Delete Scene(s)");
679  }
680  else {
682  return OPERATOR_CANCELLED;
683  }
684 
685  return OPERATOR_FINISHED;
686 }
687 
689 {
690  /* identifiers */
691  ot->name = "Outliner Scene Operation";
692  ot->idname = "OUTLINER_OT_scene_operation";
693  ot->description = "Context menu for scene operations";
694 
695  /* callbacks */
699 
700  ot->flag = 0;
701 
702  ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", "");
703 }
704 
707 /* -------------------------------------------------------------------- */
719 };
720 
722  const ListBase *tree, short tselem_type, short type, const char *str, uiSearchItems *items)
723 {
724  char name[64];
725  int iconid;
726 
728  TreeStoreElem *tselem = TREESTORE(te);
729 
730  if (tree_element_id_type_to_index(te) == type && tselem_type == tselem->type) {
731  if (BLI_strcasestr(te->name, str)) {
732  BLI_strncpy(name, te->name, 64);
733 
734  iconid = tree_element_get_icon(tselem, te).icon;
735 
736  /* Don't allow duplicate named items */
737  if (UI_search_items_find_index(items, name) == -1) {
738  if (!UI_search_item_add(items, name, te, iconid, 0, 0)) {
739  break;
740  }
741  }
742  }
743  }
744 
745  merged_element_search_fn_recursive(&te->subtree, tselem_type, type, str, items);
746  }
747 }
748 
749 /* Get a list of elements that match the search string */
751  void *data,
752  const char *str,
753  uiSearchItems *items,
754  const bool UNUSED(is_first))
755 {
756  MergedSearchData *search_data = (MergedSearchData *)data;
757  TreeElement *parent = search_data->parent_element;
758  TreeElement *te = search_data->select_element;
759 
761 
763 }
764 
765 /* Activate an element from the merged element search menu */
766 static void merged_element_search_exec_fn(struct bContext *C, void *UNUSED(arg1), void *element)
767 {
768  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
770 
771  outliner_item_select(C, space_outliner, te, OL_ITEM_SELECT | OL_ITEM_ACTIVATE);
772 
773  ED_outliner_select_sync_from_outliner(C, space_outliner);
774 }
775 
781 {
782  static char search[64] = "";
783  uiBlock *block;
784  uiBut *but;
785 
786  /* Clear search on each menu creation */
787  *search = '\0';
788 
789  block = UI_block_begin(C, region, __func__, UI_EMBOSS);
792 
793  short menu_width = 10 * UI_UNIT_X;
794  but = uiDefSearchBut(
795  block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, 0, 0, "");
797  nullptr,
799  data,
800  false,
801  nullptr,
803  nullptr);
805 
806  /* Fake button to hold space for search items */
807  uiDefBut(block,
809  0,
810  "",
811  10,
812  10 - UI_searchbox_size_y(),
813  menu_width,
815  nullptr,
816  0,
817  0,
818  0,
819  0,
820  nullptr);
821 
822  /* Center the menu on the cursor */
823  const int offset[2] = {-(menu_width / 2), 0};
825 
826  return block;
827 }
828 
830  TreeElement *parent_te,
831  TreeElement *activate_te)
832 {
833  MergedSearchData *select_data = MEM_cnew<MergedSearchData>("merge_search_data");
834  select_data->parent_element = parent_te;
835  select_data->select_element = activate_te;
836 
838 }
839 
840 static void object_select_fn(bContext *C,
841  ReportList *UNUSED(reports),
842  Scene *UNUSED(scene),
843  TreeElement *UNUSED(te),
844  TreeStoreElem *UNUSED(tsep),
845  TreeStoreElem *tselem,
846  void *UNUSED(user_data))
847 {
848  ViewLayer *view_layer = CTX_data_view_layer(C);
849  Object *ob = (Object *)tselem->id;
850  Base *base = BKE_view_layer_base_find(view_layer, ob);
851 
852  if (base) {
854  }
855 }
856 
859 /* -------------------------------------------------------------------- */
864  ReportList *UNUSED(reports),
865  Scene *UNUSED(scene),
866  TreeElement *te,
867  TreeStoreElem *UNUSED(tsep),
868  TreeStoreElem *UNUSED(tselem),
869  void *UNUSED(user_data))
870 {
871  /* Don't extend because this toggles, which is nice for Ctrl-Click but not for a menu item.
872  * it's especially confusing when multiple items are selected since some toggle on/off. */
873  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
875  C, space_outliner, te, OL_ITEM_SELECT | OL_ITEM_ACTIVATE | OL_ITEM_RECURSIVE);
876 }
877 
879  ReportList *UNUSED(reports),
880  Scene *UNUSED(scene),
881  TreeElement *UNUSED(te),
882  TreeStoreElem *UNUSED(tsep),
883  TreeStoreElem *tselem,
884  void *UNUSED(user_data))
885 {
886  ViewLayer *view_layer = CTX_data_view_layer(C);
887  Object *ob = (Object *)tselem->id;
888  Base *base = BKE_view_layer_base_find(view_layer, ob);
889 
890  if (base) {
891  base->flag &= ~BASE_SELECTED;
892  }
893 }
894 
896 {
897  if (ob) {
898  Main *bmain = CTX_data_main(C);
899  if (ob->id.tag & LIB_TAG_INDIRECT) {
900  BKE_reportf(
901  reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2);
902  return;
903  }
904  if (ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0 &&
906  BKE_reportf(reports,
907  RPT_WARNING,
908  "Cannot delete object '%s' from scene '%s', indirectly used objects need at "
909  "least one user",
910  ob->id.name + 2,
911  scene->id.name + 2);
912  return;
913  }
914 
915  /* Check also library later. */
916  if ((ob->mode & OB_MODE_EDIT) && BKE_object_is_in_editmode(ob)) {
918  }
919  BKE_id_delete(bmain, ob);
920  }
921 }
922 
923 static void id_local_fn(bContext *C,
924  ReportList *UNUSED(reports),
925  Scene *UNUSED(scene),
926  TreeElement *UNUSED(te),
927  TreeStoreElem *UNUSED(tsep),
928  TreeStoreElem *tselem,
929  void *UNUSED(user_data))
930 {
931  if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
932  Main *bmain = CTX_data_main(C);
933  if (BKE_lib_id_make_local(bmain, tselem->id, 0)) {
935  }
936  }
937  else if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id)) {
939  }
940 }
941 
945 
949 
956 
959 };
960 
963 
966 
972 
976 
983 
986 
987  void id_root_add(ID *id_hierarchy_root_reference,
988  ID *id_root_reference,
989  ID *id_instance_hint,
990  const bool is_override_instancing_object)
991  {
992  OutlinerLiboverrideDataIDRoot id_root_data;
993  id_root_data.id_root_reference = id_root_reference;
994  id_root_data.id_hierarchy_root_override = nullptr;
995  id_root_data.id_instance_hint = id_instance_hint;
996  id_root_data.is_override_instancing_object = is_override_instancing_object;
997 
999  id_hierarchy_root_reference);
1000  value.append(id_root_data);
1001  }
1002  void id_root_set(ID *id_hierarchy_root_reference)
1003  {
1004  OutlinerLiboverrideDataIDRoot id_root_data;
1005  id_root_data.id_root_reference = nullptr;
1006  id_root_data.id_hierarchy_root_override = nullptr;
1007  id_root_data.id_instance_hint = nullptr;
1008  id_root_data.is_override_instancing_object = false;
1009 
1011  id_hierarchy_root_reference);
1012  if (value.is_empty()) {
1013  value.append(id_root_data);
1014  }
1015  }
1016 };
1017 
1018 /* Store 'UUID' of IDs of selected elements in the Outliner tree, before generating the override
1019  * hierarchy. */
1021  ReportList *reports,
1022  Scene *UNUSED(scene),
1023  TreeElement *te,
1024  TreeStoreElem *tsep,
1025  TreeStoreElem *tselem,
1026  void *user_data)
1027 {
1028  BLI_assert(TSE_IS_REAL_ID(tselem));
1029 
1031  const bool do_hierarchy = data->do_hierarchy;
1032  ID *id_root_reference = tselem->id;
1033 
1034  if (!BKE_idtype_idcode_is_linkable(GS(id_root_reference->name)) ||
1035  (id_root_reference->flag & (LIB_EMBEDDED_DATA | LIB_EMBEDDED_DATA_LIB_OVERRIDE)) != 0) {
1036  return;
1037  }
1038 
1039  BLI_assert(do_hierarchy);
1040  UNUSED_VARS_NDEBUG(do_hierarchy);
1041 
1042  data->selected_id_uid.add(id_root_reference->session_uuid);
1043 
1044  if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root_reference) && !ID_IS_LINKED(id_root_reference)) {
1046  return;
1047  }
1048 
1049  if (GS(id_root_reference->name) == ID_GR && (tselem->flag & TSE_CLOSED) != 0) {
1050  /* If selected element is a (closed) collection, check all of its objects recursively, and also
1051  * consider the armature ones as 'selected' (i.e. to not become system overrides). */
1052  Collection *root_collection = reinterpret_cast<Collection *>(id_root_reference);
1053  FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (root_collection, object_iter) {
1054  if (id_root_reference->lib == object_iter->id.lib && object_iter->type == OB_ARMATURE) {
1055  data->selected_id_uid.add(object_iter->id.session_uuid);
1056  }
1057  }
1059  }
1060 
1061  ID *id_instance_hint = nullptr;
1062  bool is_override_instancing_object = false;
1063  if (tsep != nullptr && tsep->type == TSE_SOME_ID && tsep->id != nullptr &&
1064  GS(tsep->id->name) == ID_OB && !ID_IS_OVERRIDE_LIBRARY(tsep->id)) {
1065  Object *ob = reinterpret_cast<Object *>(tsep->id);
1066  if (ob->type == OB_EMPTY && &ob->instance_collection->id == id_root_reference) {
1067  BLI_assert(GS(id_root_reference->name) == ID_GR);
1068  /* Empty instantiating the collection we override, we need to pass it to BKE overriding code
1069  * for proper handling. */
1070  id_instance_hint = tsep->id;
1071  is_override_instancing_object = true;
1072  }
1073  }
1074 
1075  if (!ID_IS_OVERRIDABLE_LIBRARY(id_root_reference) &&
1076  !(ID_IS_LINKED(id_root_reference) && do_hierarchy)) {
1077  return;
1078  }
1079 
1080  Main *bmain = CTX_data_main(C);
1081 
1082  if (do_hierarchy) {
1083  /* Tag all linked parents in tree hierarchy to be also overridden. */
1084  ID *id_hierarchy_root_reference = id_root_reference;
1085  while ((te = te->parent) != nullptr) {
1086  if (!TSE_IS_REAL_ID(te->store_elem)) {
1087  continue;
1088  }
1089 
1090  /* Tentative hierarchy root. */
1091  ID *id_current_hierarchy_root = te->store_elem->id;
1092 
1093  /* If the parent ID is from a different library than the reference root one, we are done
1094  * with upwards tree processing in any case. */
1095  if (id_current_hierarchy_root->lib != id_root_reference->lib) {
1096  if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id_current_hierarchy_root)) {
1097  /* Virtual overrides (i.e. embedded IDs), we can simply keep processing their parent to
1098  * get an actual real override. */
1099  continue;
1100  }
1101 
1102  /* If the parent ID is already an override, and is valid (i.e. local override), we can
1103  * access its hierarchy root directly. */
1104  if (!ID_IS_LINKED(id_current_hierarchy_root) &&
1105  ID_IS_OVERRIDE_LIBRARY_REAL(id_current_hierarchy_root) &&
1106  id_current_hierarchy_root->override_library->reference->lib ==
1107  id_root_reference->lib) {
1108  id_hierarchy_root_reference =
1109  id_current_hierarchy_root->override_library->hierarchy_root;
1110  BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
1111  break;
1112  }
1113 
1114  if (ID_IS_LINKED(id_current_hierarchy_root)) {
1115  /* No local 'anchor' was found for the hierarchy to override, do not proceed, as this
1116  * would most likely generate invisible/confusing/hard to use and manage overrides. */
1117  BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
1118  BKE_reportf(reports,
1119  RPT_WARNING,
1120  "Invalid anchor ('%s') found, needed to create library override from "
1121  "data-block '%s'",
1122  id_current_hierarchy_root->name,
1123  id_root_reference->name);
1124  return;
1125  }
1126 
1127  /* In all other cases, `id_current_hierarchy_root` cannot be a valid hierarchy root, so
1128  * current `id_hierarchy_root_reference` is our best candidate. */
1129 
1130  break;
1131  }
1132 
1133  /* If some element in the tree needs to be overridden, but its ID is not overridable,
1134  * abort. */
1135  if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id_current_hierarchy_root)) {
1136  BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
1137  BKE_reportf(reports,
1138  RPT_WARNING,
1139  "Could not create library override from data-block '%s', one of its parents "
1140  "is not overridable ('%s')",
1141  id_root_reference->name,
1142  id_current_hierarchy_root->name);
1143  return;
1144  }
1145  id_current_hierarchy_root->tag |= LIB_TAG_DOIT;
1146  id_hierarchy_root_reference = id_current_hierarchy_root;
1147  }
1148 
1149  /* That case can happen when linked data is a complex mix involving several libraries and/or
1150  * linked overrides. E.g. a mix of overrides from one library, and indirectly linked data
1151  * from another library. Do not try to support such cases for now. */
1152  if (!((id_hierarchy_root_reference->lib == id_root_reference->lib) ||
1153  (!ID_IS_LINKED(id_hierarchy_root_reference) &&
1154  ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference) &&
1155  id_hierarchy_root_reference->override_library->reference->lib ==
1156  id_root_reference->lib))) {
1157  BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
1158  BKE_reportf(reports,
1159  RPT_WARNING,
1160  "Invalid hierarchy root ('%s') found, needed to create library override from "
1161  "data-block '%s'",
1162  id_hierarchy_root_reference->name,
1163  id_root_reference->name);
1164  return;
1165  }
1166 
1167  /* While ideally this should not be needed, in practice user almost _never_ wants to actually
1168  * create liboverrides for all data under a selected hierarchy node, and this has currently a
1169  * dreadful consequences over performances (since it would call
1170  * #BKE_lib_override_library_create over _all_ items in the hierarchy). So only the clearing of
1171  * the system override flag is supported for non-selected items for now.
1172  */
1173  const bool is_selected = tselem->flag & TSE_SELECTED;
1174  if (!is_selected && data->id_hierarchy_roots.contains(id_hierarchy_root_reference)) {
1175  return;
1176  }
1177 
1178  data->id_root_add(id_hierarchy_root_reference,
1179  id_root_reference,
1180  id_instance_hint,
1181  is_override_instancing_object);
1182  }
1183  else if (ID_IS_OVERRIDABLE_LIBRARY(id_root_reference)) {
1184  data->id_root_add(
1185  id_root_reference, id_root_reference, id_instance_hint, is_override_instancing_object);
1186  }
1187 }
1188 
1190  Main &bmain,
1191  Scene *scene,
1192  ViewLayer *view_layer,
1194  ID *id_hierarchy_root_reference,
1196  bool &r_aggregated_success)
1197 {
1198  BLI_assert(ID_IS_LINKED(id_hierarchy_root_reference) ||
1199  ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
1200 
1201  const bool do_hierarchy = data.do_hierarchy;
1202 
1203  /* NOTE: This process is not the most efficient, but allows to re-use existing code.
1204  * If this becomes a bottle-neck at some point, we need to implement a new
1205  * `BKE_lib_override_library_hierarchy_create()` function able to process several roots inside of
1206  * a same hierarchy in a single call. */
1207  for (OutlinerLiboverrideDataIDRoot &data_idroot : data_idroots) {
1208  /* For now, remap all local usages of linked ID to local override one here. */
1209  ID *id_iter;
1210  FOREACH_MAIN_ID_BEGIN (&bmain, id_iter) {
1211  if (ID_IS_LINKED(id_iter) || ID_IS_OVERRIDE_LIBRARY(id_iter)) {
1212  id_iter->tag &= ~LIB_TAG_DOIT;
1213  }
1214  else {
1215  id_iter->tag |= LIB_TAG_DOIT;
1216  }
1217  }
1219 
1220  bool success = false;
1221  if (do_hierarchy) {
1222  ID *id_root_override = nullptr;
1223  success = BKE_lib_override_library_create(&bmain,
1224  scene,
1225  view_layer,
1226  nullptr,
1227  data_idroot.id_root_reference,
1228  id_hierarchy_root_reference,
1229  data_idroot.id_instance_hint,
1230  &id_root_override,
1231  data.do_fully_editable);
1232 
1233  if (success) {
1234  BLI_assert(id_root_override != nullptr);
1235  BLI_assert(!ID_IS_LINKED(id_root_override));
1236  BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root_override));
1237 
1238  ID *id_hierarchy_root_override = id_root_override->override_library->hierarchy_root;
1239  BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_override));
1240  if (ID_IS_LINKED(id_hierarchy_root_reference)) {
1241  BLI_assert(id_hierarchy_root_override->override_library->reference ==
1242  id_hierarchy_root_reference);
1243  /* If the hierarchy root reference was a linked data, after the first iteration there is
1244  * now a matching override, which shall be used for all further partial overrides with
1245  * this same hierarchy. */
1246  id_hierarchy_root_reference = id_hierarchy_root_override;
1247  }
1248  else {
1249  BLI_assert(id_hierarchy_root_override == id_hierarchy_root_reference);
1250  }
1251  data_idroot.id_hierarchy_root_override = id_hierarchy_root_override;
1252  data.id_hierarchy_roots_uid.add(id_hierarchy_root_override->session_uuid);
1253  }
1254  }
1255  else if (ID_IS_OVERRIDABLE_LIBRARY(data_idroot.id_root_reference)) {
1256  ID *id_root_override = BKE_lib_override_library_create_from_id(
1257  &bmain, data_idroot.id_root_reference, true);
1258 
1259  success = id_root_override != nullptr;
1260  if (success) {
1261  BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root_override));
1263  }
1264  /* Cleanup. */
1266  BKE_main_id_tag_all(&bmain, LIB_TAG_DOIT, false);
1267  }
1268  else {
1270  }
1271 
1272  /* Remove the instance empty from this scene, the items now have an overridden collection
1273  * instead. */
1274  if (success && data_idroot.is_override_instancing_object) {
1275  BLI_assert(GS(data_idroot.id_instance_hint->name) == ID_OB);
1277  &bmain, scene, reinterpret_cast<Object *>(data_idroot.id_instance_hint));
1278  }
1279 
1280  r_aggregated_success = r_aggregated_success && success;
1281  }
1282 }
1283 
1284 /* Clear system override flag from newly created overrides which linked reference were previously
1285  * selected in the Outliner tree. */
1287  ReportList *reports,
1289 {
1290  Main *bmain = CTX_data_main(C);
1292  ViewLayer *view_layer = CTX_data_view_layer(C);
1293  const bool do_hierarchy = data.do_hierarchy;
1294 
1295  bool success = true;
1296  for (auto &&[id_hierarchy_root_reference, data_idroots] : data.id_hierarchy_roots.items()) {
1298  *bmain, scene, view_layer, data, id_hierarchy_root_reference, data_idroots, success);
1299  }
1300 
1301  if (!success) {
1302  BKE_reportf(reports,
1303  RPT_WARNING,
1304  "Could not create library override from one or more of the selected data-blocks");
1305  }
1306 
1307  if (!do_hierarchy) {
1308  return;
1309  }
1310 
1311  ID *id_iter;
1312  FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
1313  if (ID_IS_LINKED(id_iter) || !ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) {
1314  continue;
1315  }
1316  if (id_iter->override_library->hierarchy_root != nullptr &&
1317  !data.id_hierarchy_roots_uid.contains(
1319  continue;
1320  }
1321  if (data.selected_id_uid.contains(id_iter->override_library->reference->session_uuid) ||
1322  data.selected_id_uid.contains(id_iter->session_uuid)) {
1324  }
1325  }
1327 }
1328 
1330  ReportList *UNUSED(reports),
1331  Scene *UNUSED(scene),
1332  TreeElement *UNUSED(te),
1333  TreeStoreElem *UNUSED(tsep),
1334  TreeStoreElem *tselem,
1335  void *user_data)
1336 {
1337  BLI_assert(TSE_IS_REAL_ID(tselem));
1338  ID *id_root = tselem->id;
1340  const bool do_hierarchy = data->do_hierarchy;
1341 
1342  if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) {
1343  CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name);
1344  return;
1345  }
1346 
1347  Main *bmain = CTX_data_main(C);
1348 
1349  if (do_hierarchy) {
1350  BKE_lib_override_library_id_hierarchy_reset(bmain, id_root, false);
1351  }
1352  else {
1353  BKE_lib_override_library_id_reset(bmain, id_root, false);
1354  }
1355 }
1356 
1358  ReportList *reports,
1359  Scene *scene,
1360  TreeElement *UNUSED(te),
1361  TreeStoreElem *UNUSED(tsep),
1362  TreeStoreElem *tselem,
1363  void *UNUSED(user_data))
1364 {
1365  BLI_assert(TSE_IS_REAL_ID(tselem));
1366  Main *bmain = CTX_data_main(C);
1367  ViewLayer *view_layer = CTX_data_view_layer(C);
1368  ID *id = tselem->id;
1369 
1370  if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || ID_IS_LINKED(id)) {
1371  BKE_reportf(reports,
1372  RPT_WARNING,
1373  "Cannot clear embedded library override id '%s', only overrides of real "
1374  "data-blocks can be directly deleted",
1375  id->name);
1376  return;
1377  }
1378 
1379  /* If given ID is not using any other override (it's a 'leaf' in the override hierarchy),
1380  * delete it and remap its usages to its linked reference. Otherwise, keep it as a reset system
1381  * override. */
1383  bool do_remap_active = false;
1384  if (OBACT(view_layer) == reinterpret_cast<Object *>(id)) {
1385  BLI_assert(GS(id->name) == ID_OB);
1386  do_remap_active = true;
1387  }
1389  if (do_remap_active) {
1390  Object *ref_object = reinterpret_cast<Object *>(id->override_library->reference);
1391  Base *basact = BKE_view_layer_base_find(view_layer, ref_object);
1392  if (basact != nullptr) {
1393  view_layer->basact = basact;
1394  }
1396  }
1397  BKE_id_delete(bmain, id);
1398  }
1399  else {
1400  BKE_lib_override_library_id_reset(bmain, id, true);
1401  }
1402 
1404 }
1405 
1407  ReportList *UNUSED(reports),
1408  Scene *UNUSED(scene),
1409  TreeElement *UNUSED(te),
1410  TreeStoreElem *UNUSED(tsep),
1411  TreeStoreElem *tselem,
1412  void *user_data)
1413 {
1414  BLI_assert(TSE_IS_REAL_ID(tselem));
1415  ID *id_root = tselem->id;
1417 
1418  if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) {
1419  CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name);
1420  return;
1421  }
1422 
1423  if (id_root->override_library->hierarchy_root != nullptr) {
1424  id_root = id_root->override_library->hierarchy_root;
1425  }
1426 
1427  data->id_root_set(id_root);
1428 }
1429 
1430 /* Resync a hierarchy of library overrides. */
1432  ReportList *reports,
1434 {
1435  Main *bmain = CTX_data_main(C);
1437  const bool do_hierarchy_enforce = data.do_resync_hierarchy_enforce;
1438 
1439  BlendFileReadReport report{};
1440  report.reports = reports;
1441 
1442  for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) {
1444  scene,
1446  id_hierarchy_root,
1447  nullptr,
1448  do_hierarchy_enforce,
1449  &report);
1450  }
1451 
1452  WM_event_add_notifier(C, NC_WINDOW, nullptr);
1453 }
1454 
1456  ReportList *UNUSED(reports),
1457  Scene *UNUSED(scene),
1458  TreeElement *UNUSED(te),
1459  TreeStoreElem *UNUSED(tsep),
1460  TreeStoreElem *tselem,
1461  void *user_data)
1462 {
1464 
1465  BLI_assert(TSE_IS_REAL_ID(tselem));
1466  ID *id_root = tselem->id;
1467 
1468  if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) {
1469  CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name);
1470  return;
1471  }
1472 
1473  if (id_root->override_library->hierarchy_root != nullptr) {
1474  id_root = id_root->override_library->hierarchy_root;
1475  }
1476 
1477  data->id_root_set(id_root);
1478 }
1479 
1480 /* Clear (delete) a hierarchy of library overrides. */
1482  ReportList *UNUSED(reports),
1484 {
1485  Main *bmain = CTX_data_main(C);
1486 
1487  for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) {
1488  BKE_lib_override_library_delete(bmain, id_hierarchy_root);
1489  }
1490 }
1491 
1493  ReportList *UNUSED(reports),
1494  Scene *UNUSED(scene),
1495  TreeElement *UNUSED(te),
1496  TreeStoreElem *UNUSED(tsep),
1497  TreeStoreElem *tselem,
1498  void *UNUSED(user_data))
1499 {
1500  ID *id = tselem->id;
1501 
1502  id_fake_user_set(id);
1503 }
1504 
1506  ReportList *UNUSED(reports),
1507  Scene *UNUSED(scene),
1508  TreeElement *UNUSED(te),
1509  TreeStoreElem *UNUSED(tsep),
1510  TreeStoreElem *tselem,
1511  void *UNUSED(user_data))
1512 {
1513  ID *id = tselem->id;
1514 
1515  id_fake_user_clear(id);
1516 }
1517 
1519  ReportList *UNUSED(reports),
1520  Scene *UNUSED(scene),
1521  TreeElement *UNUSED(te),
1522  TreeStoreElem *UNUSED(tsep),
1523  TreeStoreElem *tselem,
1524  void *UNUSED(user_data))
1525 {
1526  ID *id = tselem->id;
1527 
1529 }
1530 
1532  ReportList *UNUSED(reports),
1533  Scene *UNUSED(scene),
1534  TreeElement *te,
1535  TreeStoreElem *tsep,
1536  TreeStoreElem *tselem,
1537  void *UNUSED(user_data))
1538 {
1539  /* This callback runs for all selected elements, some of which may not be actions which results
1540  * in a crash. */
1541  if (te->idcode != ID_AC) {
1542  return;
1543  }
1544 
1545  ID *id = tselem->id;
1546 
1547  if (id) {
1548  IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id;
1549  PointerRNA ptr = {nullptr};
1550  PropertyRNA *prop;
1551 
1552  RNA_pointer_create(&iat->id, &RNA_AnimData, iat->adt, &ptr);
1553  prop = RNA_struct_find_property(&ptr, "action");
1554 
1555  id_single_user(C, id, &ptr, prop);
1556  }
1557 }
1558 
1560  ReportList *UNUSED(reports),
1561  Scene *UNUSED(scene),
1562  TreeElement *UNUSED(te),
1563  TreeStoreElem *tsep,
1564  TreeStoreElem *tselem,
1565  void *UNUSED(user_data))
1566 {
1567  ID *id = tselem->id;
1568 
1569  /* need to use parent scene not just scene, otherwise may end up getting wrong one */
1570  if (id) {
1571  Scene *parscene = (Scene *)tsep->id;
1572  PointerRNA ptr = {nullptr};
1573  PropertyRNA *prop;
1574 
1575  RNA_id_pointer_create(&parscene->id, &ptr);
1576  prop = RNA_struct_find_property(&ptr, "world");
1577 
1578  id_single_user(C, id, &ptr, prop);
1579  }
1580 }
1581 
1583  ReportList *reports,
1584  Scene *scene_act,
1585  SpaceOutliner *space_outliner,
1586  ListBase *lb,
1587  outliner_operation_fn operation_fn,
1588  void *user_data,
1589  bool recurse_selected)
1590 {
1591  LISTBASE_FOREACH (TreeElement *, te, lb) {
1592  TreeStoreElem *tselem = TREESTORE(te);
1593  bool select_handled = false;
1594  if (tselem->flag & TSE_SELECTED) {
1595  if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1596  /* When objects selected in other scenes... dunno if that should be allowed. */
1597  Scene *scene_owner = (Scene *)outliner_search_back(te, ID_SCE);
1598  if (scene_owner && scene_act != scene_owner) {
1600  }
1601  /* Important to use 'scene_owner' not scene_act else deleting objects can crash.
1602  * only use 'scene_act' when 'scene_owner' is nullptr, which can happen when the
1603  * outliner isn't showing scenes: Visible Layer draw mode for eg. */
1604  operation_fn(
1605  C, reports, scene_owner ? scene_owner : scene_act, te, nullptr, tselem, user_data);
1606  select_handled = true;
1607  }
1608  }
1609  if (TSELEM_OPEN(tselem, space_outliner)) {
1610  if ((select_handled == false) || recurse_selected) {
1612  reports,
1613  scene_act,
1614  space_outliner,
1615  &te->subtree,
1616  operation_fn,
1617  nullptr,
1618  recurse_selected);
1619  }
1620  }
1621  }
1622 }
1623 
1625  ReportList *reports,
1626  Scene *scene_act,
1627  SpaceOutliner *space_outliner,
1628  ListBase *lb,
1629  outliner_operation_fn operation_fn)
1630 {
1632  C, reports, scene_act, space_outliner, lb, operation_fn, nullptr, true);
1633 }
1634 
1637 /* -------------------------------------------------------------------- */
1641 static void clear_animdata_fn(int UNUSED(event),
1642  TreeElement *UNUSED(te),
1643  TreeStoreElem *tselem,
1644  void *UNUSED(arg))
1645 {
1646  BKE_animdata_free(tselem->id, true);
1648 }
1649 
1650 static void unlinkact_animdata_fn(int UNUSED(event),
1651  TreeElement *UNUSED(te),
1652  TreeStoreElem *tselem,
1653  void *UNUSED(arg))
1654 {
1655  /* just set action to nullptr */
1656  BKE_animdata_set_action(nullptr, tselem->id, nullptr);
1658 }
1659 
1660 static void cleardrivers_animdata_fn(int UNUSED(event),
1661  TreeElement *UNUSED(te),
1662  TreeStoreElem *tselem,
1663  void *UNUSED(arg))
1664 {
1665  IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id;
1666 
1667  /* just free drivers - stored as a list of F-Curves */
1668  BKE_fcurves_free(&iat->adt->drivers);
1670 }
1671 
1672 static void refreshdrivers_animdata_fn(int UNUSED(event),
1673  TreeElement *UNUSED(te),
1674  TreeStoreElem *tselem,
1675  void *UNUSED(arg))
1676 {
1677  IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id;
1678 
1679  /* Loop over drivers, performing refresh
1680  * (i.e. check graph_buttons.c and rna_fcurve.c for details). */
1681  LISTBASE_FOREACH (FCurve *, fcu, &iat->adt->drivers) {
1682  fcu->flag &= ~FCURVE_DISABLED;
1683 
1684  if (fcu->driver) {
1685  fcu->driver->flag &= ~DRIVER_FLAG_INVALID;
1686  }
1687  }
1688 }
1689 
1692 /* -------------------------------------------------------------------- */
1698 
1702 
1706 };
1707 
1710  "OVERRIDE_LIBRARY_CREATE_HIERARCHY",
1711  0,
1712  "Make",
1713  "Create a local override of the selected linked data-blocks, and their hierarchy of "
1714  "dependencies"},
1716  "OVERRIDE_LIBRARY_RESET",
1717  0,
1718  "Reset",
1719  "Reset the selected local overrides to their linked references values"},
1721  "OVERRIDE_LIBRARY_CLEAR_SINGLE",
1722  0,
1723  "Clear",
1724  "Delete the selected local overrides and relink their usages to the linked data-blocks if "
1725  "possible, else reset them and mark them as non editable"},
1726  {0, nullptr, 0, nullptr, nullptr},
1727 };
1728 
1731  "OVERRIDE_LIBRARY_RESYNC_HIERARCHY",
1732  0,
1733  "Resync",
1734  "Rebuild the selected local overrides from their linked references, as well as their "
1735  "hierarchies of dependencies"},
1737  "OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE",
1738  0,
1739  "Resync Enforce",
1740  "Rebuild the selected local overrides from their linked references, as well as their "
1741  "hierarchies of dependencies, enforcing these hierarchies to match the linked data (i.e. "
1742  "ignoring existing overrides on data-blocks pointer properties)"},
1745  "OVERRIDE_LIBRARY_DELETE_HIERARCHY",
1746  0,
1747  "Delete",
1748  "Delete the selected local overrides (including their hierarchies of override dependencies) "
1749  "and relink their usages to the linked data-blocks"},
1750  {0, nullptr, 0, nullptr, nullptr},
1751 };
1752 
1754 {
1756  return false;
1757  }
1758  return true;
1759 }
1760 
1762 {
1764  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1765  int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
1766 
1767  /* check for invalid states */
1768  if (space_outliner == nullptr) {
1769  return OPERATOR_CANCELLED;
1770  }
1771 
1772  TreeElement *te = get_target_element(space_outliner);
1773  get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
1774 
1775  const eOutlinerLibOpSelectionSet selection_set = static_cast<eOutlinerLibOpSelectionSet>(
1776  RNA_enum_get(op->ptr, "selection_set"));
1777  const eOutlinerLibOverrideOpTypes event = static_cast<eOutlinerLibOverrideOpTypes>(
1778  RNA_enum_get(op->ptr, "type"));
1779  switch (event) {
1781  OutlinerLibOverrideData override_data{};
1782  override_data.do_hierarchy = true;
1783  override_data.do_fully_editable = false;
1784 
1786  C,
1787  op->reports,
1788  scene,
1789  space_outliner,
1791  selection_set,
1792  &override_data);
1793 
1795 
1796  ED_undo_push(C, "Overridden Data Hierarchy");
1797  break;
1798  }
1800  OutlinerLibOverrideData override_data{};
1802  op->reports,
1803  scene,
1804  space_outliner,
1806  selection_set,
1807  &override_data);
1808  ED_undo_push(C, "Reset Overridden Data");
1809  break;
1810  }
1813  op->reports,
1814  scene,
1815  space_outliner,
1817  selection_set,
1818  nullptr);
1819  ED_undo_push(C, "Clear Overridden Data");
1820  break;
1821  }
1822 
1824  OutlinerLibOverrideData override_data{};
1825  override_data.do_hierarchy = true;
1827  op->reports,
1828  scene,
1829  space_outliner,
1832  &override_data);
1833 
1835 
1836  ED_undo_push(C, "Resync Overridden Data Hierarchy");
1837  break;
1838  }
1840  OutlinerLibOverrideData override_data{};
1841  override_data.do_hierarchy = true;
1842  override_data.do_resync_hierarchy_enforce = true;
1844  op->reports,
1845  scene,
1846  space_outliner,
1849  &override_data);
1850 
1852 
1853  ED_undo_push(C, "Resync Overridden Data Hierarchy Enforce");
1854  break;
1855  }
1857  OutlinerLibOverrideData override_data{};
1858  override_data.do_hierarchy = true;
1860  op->reports,
1861  scene,
1862  space_outliner,
1865  &override_data);
1866 
1868 
1869  ED_undo_push(C, "Delete Overridden Data Hierarchy");
1870  break;
1871  }
1872  default:
1873  /* Invalid - unhandled. */
1874  break;
1875  }
1876 
1877  WM_event_add_notifier(C, NC_WINDOW, nullptr);
1880 
1881  return OPERATOR_FINISHED;
1882 }
1883 
1885 {
1886  /* identifiers */
1887  ot->name = "Outliner Library Override Operation";
1888  ot->idname = "OUTLINER_OT_liboverride_operation";
1889  ot->description = "Create, reset or clear library override hierarchies";
1890 
1891  /* callbacks */
1895 
1896  ot->flag = 0;
1897 
1898  RNA_def_enum(ot->srna, "type", prop_liboverride_op_types, 0, "Library Override Operation", "");
1899  ot->prop = RNA_def_enum(ot->srna,
1900  "selection_set",
1902  0,
1903  "Selection Set",
1904  "Over which part of the tree items to apply the operation");
1905 }
1906 
1908 {
1909  /* identifiers */
1910  ot->name = "Outliner Library Override Troubleshoot Operation";
1911  ot->idname = "OUTLINER_OT_liboverride_troubleshoot_operation";
1912  ot->description = "Advanced operations over library override to help fix broken hierarchies";
1913 
1914  /* callbacks */
1918 
1919  ot->flag = 0;
1920 
1921  ot->prop = RNA_def_enum(ot->srna,
1922  "type",
1924  0,
1925  "Library Override Troubleshoot Operation",
1926  "");
1927  RNA_def_enum(ot->srna,
1928  "selection_set",
1930  0,
1931  "Selection Set",
1932  "Over which part of the tree items to apply the operation");
1933 }
1934 
1937 /* -------------------------------------------------------------------- */
1947 };
1948 
1953 };
1954 
1959 };
1960 
1961 static void pchan_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
1962 {
1963  bPoseChannel *pchan = (bPoseChannel *)te->directdata;
1964 
1965  if (event == OL_DOP_SELECT) {
1966  pchan->bone->flag |= BONE_SELECTED;
1967  }
1968  else if (event == OL_DOP_DESELECT) {
1969  pchan->bone->flag &= ~BONE_SELECTED;
1970  }
1971  else if (event == OL_DOP_HIDE) {
1972  pchan->bone->flag |= BONE_HIDDEN_P;
1973  pchan->bone->flag &= ~BONE_SELECTED;
1974  }
1975  else if (event == OL_DOP_UNHIDE) {
1976  pchan->bone->flag &= ~BONE_HIDDEN_P;
1977  }
1978 }
1979 
1980 static void bone_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
1981 {
1982  Bone *bone = (Bone *)te->directdata;
1983 
1984  if (event == OL_DOP_SELECT) {
1985  bone->flag |= BONE_SELECTED;
1986  }
1987  else if (event == OL_DOP_DESELECT) {
1988  bone->flag &= ~BONE_SELECTED;
1989  }
1990  else if (event == OL_DOP_HIDE) {
1991  bone->flag |= BONE_HIDDEN_P;
1992  bone->flag &= ~BONE_SELECTED;
1993  }
1994  else if (event == OL_DOP_UNHIDE) {
1995  bone->flag &= ~BONE_HIDDEN_P;
1996  }
1997 }
1998 
1999 static void ebone_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
2000 {
2001  EditBone *ebone = (EditBone *)te->directdata;
2002 
2003  if (event == OL_DOP_SELECT) {
2004  ebone->flag |= BONE_SELECTED;
2005  }
2006  else if (event == OL_DOP_DESELECT) {
2007  ebone->flag &= ~BONE_SELECTED;
2008  }
2009  else if (event == OL_DOP_HIDE) {
2010  ebone->flag |= BONE_HIDDEN_A;
2011  ebone->flag &= ~BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
2012  }
2013  else if (event == OL_DOP_UNHIDE) {
2014  ebone->flag &= ~BONE_HIDDEN_A;
2015  }
2016 }
2017 
2018 static void sequence_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *scene_ptr)
2019 {
2020  TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te);
2021  Sequence *seq = &te_seq->getSequence();
2022  Scene *scene = (Scene *)scene_ptr;
2023  Editing *ed = SEQ_editing_get(scene);
2024  if (BLI_findindex(ed->seqbasep, seq) != -1) {
2025  if (event == OL_DOP_SELECT) {
2027  }
2028  else if (event == OL_DOP_DESELECT) {
2029  seq->flag &= ~SELECT;
2030  }
2031  else if (event == OL_DOP_HIDE) {
2032  if (!(seq->flag & SEQ_MUTE)) {
2033  seq->flag |= SEQ_MUTE;
2035  }
2036  }
2037  else if (event == OL_DOP_UNHIDE) {
2038  if (seq->flag & SEQ_MUTE) {
2039  seq->flag &= ~SEQ_MUTE;
2041  }
2042  }
2043  }
2044 }
2045 
2046 static void gpencil_layer_fn(int event,
2047  TreeElement *te,
2048  TreeStoreElem *UNUSED(tselem),
2049  void *UNUSED(arg))
2050 {
2051  bGPDlayer *gpl = (bGPDlayer *)te->directdata;
2052 
2053  if (event == OL_DOP_SELECT) {
2054  gpl->flag |= GP_LAYER_SELECT;
2055  }
2056  else if (event == OL_DOP_DESELECT) {
2057  gpl->flag &= ~GP_LAYER_SELECT;
2058  }
2059  else if (event == OL_DOP_HIDE) {
2060  gpl->flag |= GP_LAYER_HIDE;
2061  }
2062  else if (event == OL_DOP_UNHIDE) {
2063  gpl->flag &= ~GP_LAYER_HIDE;
2064  }
2065 }
2066 
2067 static void data_select_linked_fn(int event,
2068  TreeElement *te,
2069  TreeStoreElem *UNUSED(tselem),
2070  void *C_v)
2071 {
2072  const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te);
2073  if (!te_rna_struct) {
2074  return;
2075  }
2076 
2077  if (event == OL_DOP_SELECT_LINKED) {
2078  const PointerRNA &ptr = te_rna_struct->getPointerRNA();
2079  if (RNA_struct_is_ID(ptr.type)) {
2080  bContext *C = (bContext *)C_v;
2081  ID *id = reinterpret_cast<ID *>(ptr.data);
2082 
2084  }
2085  }
2086 }
2087 
2088 static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
2089 {
2090  bContext *C = reinterpret_cast<bContext *>(C_v);
2091  Main *bmain = CTX_data_main(C);
2092  bConstraint *constraint = (bConstraint *)te->directdata;
2093  Object *ob = (Object *)outliner_search_back(te, ID_OB);
2094 
2095  if (event == OL_CONSTRAINTOP_ENABLE) {
2096  constraint->flag &= ~CONSTRAINT_OFF;
2097  ED_object_constraint_update(bmain, ob);
2099  }
2100  else if (event == OL_CONSTRAINTOP_DISABLE) {
2101  constraint->flag |= CONSTRAINT_OFF;
2102  ED_object_constraint_update(bmain, ob);
2104  }
2105  else if (event == OL_CONSTRAINTOP_DELETE) {
2106  ListBase *lb = nullptr;
2107 
2108  if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) {
2109  lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints;
2110  }
2111  else {
2112  lb = &ob->constraints;
2113  }
2114 
2115  if (BKE_constraint_remove_ex(lb, ob, constraint, true)) {
2116  /* there's no active constraint now, so make sure this is the case */
2117  BKE_constraints_active_set(&ob->constraints, nullptr);
2118 
2119  /* needed to set the flags on posebones correctly */
2120  ED_object_constraint_update(bmain, ob);
2121 
2123  te->store_elem->flag &= ~TSE_SELECTED;
2124  }
2125  }
2126 }
2127 
2128 static void modifier_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg)
2129 {
2130  bContext *C = (bContext *)Carg;
2131  Main *bmain = CTX_data_main(C);
2133  ModifierData *md = (ModifierData *)te->directdata;
2134  Object *ob = (Object *)outliner_search_back(te, ID_OB);
2135 
2136  if (event == OL_MODIFIER_OP_TOGVIS) {
2140  }
2141  else if (event == OL_MODIFIER_OP_TOGREN) {
2142  md->mode ^= eModifierMode_Render;
2145  }
2146  else if (event == OL_MODIFIER_OP_DELETE) {
2147  ED_object_modifier_remove(nullptr, bmain, scene, ob, md);
2149  te->store_elem->flag &= ~TSE_SELECTED;
2150  }
2151 }
2152 
2154  SpaceOutliner *space_outliner,
2155  int type,
2156  int event,
2157  void (*operation_fn)(int, TreeElement *, TreeStoreElem *, void *),
2158  void *arg)
2159 {
2160  tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2161  TreeStoreElem *tselem = TREESTORE(te);
2162  if (tselem->flag & TSE_SELECTED) {
2163  if (tselem->type == type) {
2164  operation_fn(event, te, tselem, arg);
2165  }
2166  }
2167  });
2168 }
2169 
2171  ReportList *reports, Main *bmain, ViewLayer *view_layer, Scene *scene, Base *base)
2172 {
2173  Base *child_base, *base_next;
2174  Object *object, *parent;
2175 
2176  if (!base) {
2177  return nullptr;
2178  }
2179 
2180  object = base->object;
2181  for (child_base = reinterpret_cast<Base *>(view_layer->object_bases.first); child_base;
2182  child_base = base_next) {
2183  base_next = child_base->next;
2184  for (parent = child_base->object->parent; parent && (parent != object);
2185  parent = parent->parent) {
2186  /* pass */
2187  }
2188  if (parent) {
2189  base_next = outliner_batch_delete_hierarchy(reports, bmain, view_layer, scene, child_base);
2190  }
2191  }
2192 
2193  base_next = base->next;
2194 
2195  if (object->id.tag & LIB_TAG_INDIRECT) {
2196  BKE_reportf(reports,
2197  RPT_WARNING,
2198  "Cannot delete indirectly linked object '%s'",
2199  base->object->id.name + 2);
2200  return base_next;
2201  }
2202  if (ID_REAL_USERS(object) <= 1 && ID_EXTRA_USERS(object) == 0 &&
2203  BKE_library_ID_is_indirectly_used(bmain, object)) {
2204  BKE_reportf(reports,
2205  RPT_WARNING,
2206  "Cannot delete object '%s' from scene '%s', indirectly used objects need at least "
2207  "one user",
2208  object->id.name + 2,
2209  scene->id.name + 2);
2210  return base_next;
2211  }
2212 
2213  DEG_id_tag_update_ex(bmain, &object->id, ID_RECALC_BASE_FLAGS);
2214  BKE_scene_collections_object_remove(bmain, scene, object, false);
2215 
2216  if (object->id.us == 0) {
2217  object->id.tag |= LIB_TAG_DOIT;
2218  }
2219 
2220  return base_next;
2221 }
2222 
2224  ReportList *reports,
2225  Scene *scene,
2226  Object *ob)
2227 {
2228  ViewLayer *view_layer = CTX_data_view_layer(C);
2229  Object *obedit = CTX_data_edit_object(C);
2230 
2231  Base *base = BKE_view_layer_base_find(view_layer, ob);
2232 
2233  if (base) {
2234  /* Check also library later. */
2235  for (; obedit && (obedit != base->object); obedit = obedit->parent) {
2236  /* pass */
2237  }
2238  if (obedit == base->object) {
2240  }
2241 
2242  outliner_batch_delete_hierarchy(reports, CTX_data_main(C), view_layer, scene, base);
2243  }
2244 }
2245 
2248 /* -------------------------------------------------------------------- */
2252 enum {
2258 };
2259 
2261  {OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""},
2262  {OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
2263  {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
2264  {OL_OP_REMAP,
2265  "REMAP",
2266  0,
2267  "Remap Users",
2268  "Make all users of selected data-blocks to use instead a new chosen one"},
2269  {OL_OP_RENAME, "RENAME", 0, "Rename", ""},
2270  {0, nullptr, 0, nullptr, nullptr},
2271 };
2272 
2274 {
2275  Main *bmain = CTX_data_main(C);
2277  wmWindow *win = CTX_wm_window(C);
2278  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2279  int event;
2280  const char *str = nullptr;
2281  bool selection_changed = false;
2282 
2283  /* check for invalid states */
2284  if (space_outliner == nullptr) {
2285  return OPERATOR_CANCELLED;
2286  }
2287 
2288  event = RNA_enum_get(op->ptr, "type");
2289 
2290  switch (event) {
2291  case OL_OP_SELECT: {
2292  Scene *sce = scene; /* To be able to delete, scenes are set... */
2294  C, op->reports, scene, space_outliner, &space_outliner->tree, object_select_fn);
2295  /* FIXME: This is most certainly broken, maybe check should rather be
2296  * `if (CTX_data_scene(C) != scene)` ? */
2297  if (scene != sce) {
2298  WM_window_set_active_scene(bmain, C, win, sce);
2299  }
2300 
2301  str = "Select Objects";
2302  selection_changed = true;
2303  break;
2304  }
2305  case OL_OP_SELECT_HIERARCHY: {
2306  Scene *sce = scene; /* To be able to delete, scenes are set... */
2308  op->reports,
2309  scene,
2310  space_outliner,
2311  &space_outliner->tree,
2313  nullptr,
2314  false);
2315  /* FIXME: This is most certainly broken, maybe check should rather be
2316  * `if (CTX_data_scene(C) != scene)` ? */
2317  if (scene != sce) {
2318  WM_window_set_active_scene(bmain, C, win, sce);
2319  }
2320  str = "Select Object Hierarchy";
2321  selection_changed = true;
2322  break;
2323  }
2324  case OL_OP_DESELECT:
2326  C, op->reports, scene, space_outliner, &space_outliner->tree, object_deselect_fn);
2327  str = "Deselect Objects";
2328  selection_changed = true;
2329  break;
2330  case OL_OP_REMAP:
2331  outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_remap_fn, nullptr);
2332  /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
2333  * trick does not work here). */
2334  break;
2335  case OL_OP_RENAME:
2337  C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn);
2338  str = "Rename Object";
2339  break;
2340  default:
2342  return OPERATOR_CANCELLED;
2343  }
2344 
2345  if (selection_changed) {
2349  }
2350 
2351  if (str != nullptr) {
2352  ED_undo_push(C, str);
2353  }
2354 
2355  return OPERATOR_FINISHED;
2356 }
2357 
2359 {
2360  /* identifiers */
2361  ot->name = "Outliner Object Operation";
2362  ot->idname = "OUTLINER_OT_object_operation";
2363 
2364  /* callbacks */
2368 
2369  ot->flag = 0;
2370 
2371  ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", "");
2372 }
2373 
2376 /* -------------------------------------------------------------------- */
2380 using OutlinerDeleteFn = void (*)(bContext *C, ReportList *reports, Scene *scene, Object *ob);
2381 
2383  GSet *objects_set;
2386 };
2387 
2389  ReportList *reports,
2390  Scene *scene,
2391  GSet *objects_to_delete,
2392  OutlinerDeleteFn delete_fn)
2393 {
2394  GSetIterator objects_to_delete_iter;
2395  GSET_ITER (objects_to_delete_iter, objects_to_delete) {
2396  Object *ob = (Object *)BLI_gsetIterator_getKey(&objects_to_delete_iter);
2397 
2398  delete_fn(C, reports, scene, ob);
2399  }
2400 }
2401 
2403 {
2404  ObjectEditData *data = reinterpret_cast<ObjectEditData *>(customdata);
2405  GSet *objects_to_delete = data->objects_set;
2406  TreeStoreElem *tselem = TREESTORE(te);
2407 
2409  return TRAVERSE_CONTINUE;
2410  }
2411 
2412  if ((tselem->type != TSE_SOME_ID) || (tselem->id == nullptr) ||
2413  (GS(tselem->id->name) != ID_OB)) {
2414  return TRAVERSE_SKIP_CHILDS;
2415  }
2416 
2417  /* Do not allow to delete children objects of an override collection. */
2418  TreeElement *te_parent = te->parent;
2419  if (te_parent != nullptr && outliner_is_collection_tree_element(te_parent)) {
2420  TreeStoreElem *tselem_parent = TREESTORE(te_parent);
2421  ID *id_parent = tselem_parent->id;
2422  BLI_assert(GS(id_parent->name) == ID_GR);
2423  if (ID_IS_OVERRIDE_LIBRARY_REAL(id_parent)) {
2424  return TRAVERSE_SKIP_CHILDS;
2425  }
2426  }
2427 
2428  ID *id = tselem->id;
2429 
2430  if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
2432  if (!(data->is_liboverride_hierarchy_root_allowed || data->is_liboverride_allowed)) {
2433  return TRAVERSE_SKIP_CHILDS;
2434  }
2435  }
2436  else {
2437  if (!data->is_liboverride_allowed) {
2438  return TRAVERSE_SKIP_CHILDS;
2439  }
2440  }
2441  }
2442 
2443  BLI_gset_add(objects_to_delete, id);
2444 
2445  return TRAVERSE_CONTINUE;
2446 }
2447 
2449 {
2450  Main *bmain = CTX_data_main(C);
2452  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2453  struct wmMsgBus *mbus = CTX_wm_message_bus(C);
2454  ViewLayer *view_layer = CTX_data_view_layer(C);
2455  const Base *basact_prev = BASACT(view_layer);
2456 
2457  const bool delete_hierarchy = RNA_boolean_get(op->ptr, "hierarchy");
2458 
2459  /* Get selected objects skipping duplicates to prevent deleting objects linked to multiple
2460  * collections twice */
2461  ObjectEditData object_delete_data = {};
2462  object_delete_data.objects_set = BLI_gset_ptr_new(__func__);
2463  object_delete_data.is_liboverride_allowed = false;
2464  object_delete_data.is_liboverride_hierarchy_root_allowed = delete_hierarchy;
2465  outliner_tree_traverse(space_outliner,
2466  &space_outliner->tree,
2467  0,
2468  TSE_SELECTED,
2470  &object_delete_data);
2471 
2472  if (delete_hierarchy) {
2473  BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
2474 
2476  C, op->reports, scene, object_delete_data.objects_set, object_batch_delete_hierarchy_fn);
2477 
2479  }
2480  else {
2482  C, op->reports, scene, object_delete_data.objects_set, outliner_object_delete_fn);
2483  }
2484 
2485  BLI_gset_free(object_delete_data.objects_set, nullptr);
2486 
2487  outliner_collection_delete(C, bmain, scene, op->reports, delete_hierarchy);
2488 
2489  /* Tree management normally happens from draw_outliner(), but when
2490  * you're clicking too fast on Delete object from context menu in
2491  * outliner several mouse events can be handled in one cycle without
2492  * handling notifiers/redraw which leads to deleting the same object twice.
2493  * cleanup tree here to prevent such cases. */
2494  outliner_cleanup_tree(space_outliner);
2495 
2497  DEG_relations_tag_update(bmain);
2498 
2499  if (basact_prev != BASACT(view_layer)) {
2501  WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
2502  }
2503 
2508 
2509  return OPERATOR_FINISHED;
2510 }
2511 
2513 {
2514  /* identifiers */
2515  ot->name = "Delete";
2516  ot->idname = "OUTLINER_OT_delete";
2517  ot->description = "Delete selected objects and collections";
2518 
2519  /* callbacks */
2522 
2523  /* flags */
2525 
2526  /* properties */
2527  PropertyRNA *prop = RNA_def_boolean(
2528  ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections");
2530 }
2531 
2534 /* -------------------------------------------------------------------- */
2540 
2546 
2549 
2553 
2555 };
2556 
2557 /* TODO: implement support for changing the ID-block used. */
2559  {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
2560  {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
2561  {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
2562  {OUTLINER_IDOP_DELETE, "DELETE", ICON_X, "Delete", ""},
2564  "REMAP",
2565  0,
2566  "Remap Users",
2567  "Make all users of selected data-blocks to use instead current (clicked) one"},
2569  {OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""},
2570  {OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""},
2573  "ADD_FAKE",
2574  0,
2575  "Add Fake User",
2576  "Ensure data-block gets saved even if it isn't in use (e.g. for motion and material "
2577  "libraries)"},
2578  {OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
2579  {OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""},
2580  {OUTLINER_IDOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
2581  {0, nullptr, 0, nullptr, nullptr},
2582 };
2583 
2585  PointerRNA *UNUSED(ptr),
2586  PropertyRNA *UNUSED(prop),
2587  const int enum_value)
2588 {
2590  return false;
2591  }
2592 
2593  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2594  TreeElement *te = get_target_element(space_outliner);
2595  TreeStoreElem *tselem = TREESTORE(te);
2596  if (!TSE_IS_REAL_ID(tselem)) {
2597  return false;
2598  }
2599 
2600  switch (enum_value) {
2601  case OUTLINER_IDOP_SINGLE:
2602  if (ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
2603  return true;
2604  }
2605  /* TODO(dalai): enable in the few cases where this can be supported
2606  * (i.e., when we have a valid parent for the tselem). */
2607  return false;
2608  }
2609 
2610  return true;
2611 }
2612 
2614  PointerRNA *ptr,
2615  PropertyRNA *prop,
2616  bool *r_free)
2617 {
2618  EnumPropertyItem *items = nullptr;
2619  int totitem = 0;
2620 
2621  if ((C == nullptr) || (ED_operator_outliner_active(C) == false)) {
2622  return prop_id_op_types;
2623  }
2624  for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != nullptr; it++) {
2625  if (!outliner_id_operation_item_poll(C, ptr, prop, it->value)) {
2626  continue;
2627  }
2628  RNA_enum_item_add(&items, &totitem, it);
2629  }
2630  RNA_enum_item_end(&items, &totitem);
2631  *r_free = true;
2632 
2633  return items;
2634 }
2635 
2637 {
2638  Main *bmain = CTX_data_main(C);
2641  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2642  int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
2643 
2644  /* check for invalid states */
2645  if (space_outliner == nullptr) {
2646  return OPERATOR_CANCELLED;
2647  }
2648 
2649  TreeElement *te = get_target_element(space_outliner);
2650  get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
2651 
2652  eOutlinerIdOpTypes event = (eOutlinerIdOpTypes)RNA_enum_get(op->ptr, "type");
2653  switch (event) {
2654  case OUTLINER_IDOP_UNLINK: {
2655  /* unlink datablock from its parent */
2656  if (objectlevel) {
2658  C, op->reports, scene, space_outliner, unlink_object_fn, nullptr);
2659 
2661  ED_undo_push(C, "Unlink Object");
2662  break;
2663  }
2664 
2665  switch (idlevel) {
2666  case ID_AC:
2668  C, op->reports, scene, space_outliner, unlink_action_fn, nullptr);
2669 
2671  ED_undo_push(C, "Unlink action");
2672  break;
2673  case ID_MA:
2675  C, op->reports, scene, space_outliner, unlink_material_fn, nullptr);
2676 
2678  ED_undo_push(C, "Unlink material");
2679  break;
2680  case ID_TE:
2682  C, op->reports, scene, space_outliner, unlink_texture_fn, nullptr);
2683 
2685  ED_undo_push(C, "Unlink texture");
2686  break;
2687  case ID_WO:
2689  C, op->reports, scene, space_outliner, unlink_world_fn, nullptr);
2690 
2692  ED_undo_push(C, "Unlink world");
2693  break;
2694  case ID_GR:
2696  C, op->reports, scene, space_outliner, unlink_collection_fn, nullptr);
2697 
2699  ED_undo_push(C, "Unlink Collection");
2700  break;
2701  default:
2702  BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
2703  break;
2704  }
2705  break;
2706  }
2707  case OUTLINER_IDOP_LOCAL: {
2708  /* make local */
2709  outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_local_fn, nullptr);
2710  ED_undo_push(C, "Localized Data");
2711  break;
2712  }
2713  case OUTLINER_IDOP_SINGLE: {
2714  /* make single user */
2715  switch (idlevel) {
2716  case ID_AC:
2718  C, op->reports, scene, space_outliner, singleuser_action_fn, nullptr);
2719 
2721  ED_undo_push(C, "Single-User Action");
2722  break;
2723 
2724  case ID_WO:
2726  C, op->reports, scene, space_outliner, singleuser_world_fn, nullptr);
2727 
2729  ED_undo_push(C, "Single-User World");
2730  break;
2731 
2732  default:
2733  BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
2734  break;
2735  }
2736  break;
2737  }
2738  case OUTLINER_IDOP_DELETE: {
2739  if (idlevel > 0) {
2740  BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
2742  C, op->reports, scene, space_outliner, id_delete_tag_fn, nullptr);
2744  ED_undo_push(C, "Delete");
2745  }
2746  break;
2747  }
2748  case OUTLINER_IDOP_REMAP: {
2749  if (idlevel > 0) {
2750  outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_remap_fn, nullptr);
2751  /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
2752  * trick does not work here). */
2753  }
2754  break;
2755  }
2756  case OUTLINER_IDOP_COPY: {
2757  wm->op_undo_depth++;
2758  WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
2759  wm->op_undo_depth--;
2760  /* No need for undo, this operation does not change anything... */
2761  break;
2762  }
2763  case OUTLINER_IDOP_PASTE: {
2764  wm->op_undo_depth++;
2765  WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
2766  wm->op_undo_depth--;
2768  ED_undo_push(C, "Paste");
2769  break;
2770  }
2771  case OUTLINER_IDOP_FAKE_ADD: {
2772  /* set fake user */
2774  C, op->reports, scene, space_outliner, id_fake_user_set_fn, nullptr);
2775 
2776  WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
2777  ED_undo_push(C, "Add Fake User");
2778  break;
2779  }
2780  case OUTLINER_IDOP_FAKE_CLEAR: {
2781  /* clear fake user */
2783  C, op->reports, scene, space_outliner, id_fake_user_clear_fn, nullptr);
2784 
2785  WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
2786  ED_undo_push(C, "Clear Fake User");
2787  break;
2788  }
2789  case OUTLINER_IDOP_RENAME: {
2790  /* rename */
2792  C, op->reports, scene, space_outliner, item_rename_fn, nullptr);
2793 
2794  WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
2795  ED_undo_push(C, "Rename");
2796  break;
2797  }
2800  C, op->reports, scene, space_outliner, id_select_linked_fn, nullptr);
2802  ED_undo_push(C, "Select");
2803  break;
2804 
2805  default:
2806  /* Invalid - unhandled. */
2807  break;
2808  }
2809 
2810  /* wrong notifier still... */
2811  WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
2812 
2813  /* XXX: this is just so that outliner is always up to date. */
2815 
2816  return OPERATOR_FINISHED;
2817 }
2818 
2820 {
2821  /* identifiers */
2822  ot->name = "Outliner ID Data Operation";
2823  ot->idname = "OUTLINER_OT_id_operation";
2824  ot->description = "General data-block management operations";
2825 
2826  /* callbacks */
2830 
2831  ot->flag = 0;
2832 
2833  ot->prop = RNA_def_enum(ot->srna, "type", prop_id_op_types, 0, "ID Data Operation", "");
2835 }
2836 
2839 /* -------------------------------------------------------------------- */
2845 
2849 };
2850 
2852  {OL_LIB_DELETE,
2853  "DELETE",
2854  ICON_X,
2855  "Delete",
2856  "Delete this library and all its item.\n"
2857  "Warning: No undo"},
2858  {OL_LIB_RELOCATE,
2859  "RELOCATE",
2860  0,
2861  "Relocate",
2862  "Select a new path for this library, and reload all its data"},
2863  {OL_LIB_RELOAD, "RELOAD", ICON_FILE_REFRESH, "Reload", "Reload all data from this library"},
2864  {0, nullptr, 0, nullptr, nullptr},
2865 };
2866 
2868 {
2869  Main *bmain = CTX_data_main(C);
2871  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2872  int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
2873 
2874  /* check for invalid states */
2875  if (space_outliner == nullptr) {
2876  return OPERATOR_CANCELLED;
2877  }
2878 
2879  TreeElement *te = get_target_element(space_outliner);
2880  get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
2881 
2883  switch (event) {
2884  case OL_LIB_DELETE: {
2885  BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
2887  C, op->reports, scene, space_outliner, id_delete_tag_fn, nullptr);
2889  ED_undo_push(C, "Delete Library");
2890  break;
2891  }
2892  case OL_LIB_RELOCATE: {
2894  C, op->reports, scene, space_outliner, lib_relocate_fn, nullptr);
2895  /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
2896  * trick does not work here). */
2897  break;
2898  }
2899  case OL_LIB_RELOAD: {
2900  outliner_do_libdata_operation(C, op->reports, scene, space_outliner, lib_reload_fn, nullptr);
2901  /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
2902  * trick does not work here). */
2903  break;
2904  }
2905  default:
2906  /* invalid - unhandled */
2907  break;
2908  }
2909 
2910  /* wrong notifier still... */
2911  WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
2912 
2913  /* XXX: this is just so that outliner is always up to date */
2915 
2916  return OPERATOR_FINISHED;
2917 }
2918 
2920 {
2921  /* identifiers */
2922  ot->name = "Outliner Library Operation";
2923  ot->idname = "OUTLINER_OT_lib_operation";
2924 
2925  /* callbacks */
2929 
2930  ot->prop = RNA_def_enum(
2931  ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", "");
2932 }
2933 
2936 /* -------------------------------------------------------------------- */
2941  SpaceOutliner *space_outliner,
2942  int type,
2943  ID *newid,
2944  void (*operation_fn)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *))
2945 {
2946  tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2947  TreeStoreElem *tselem = TREESTORE(te);
2948  if (tselem->flag & TSE_SELECTED) {
2949  if (tselem->type == type) {
2950  TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr;
2951  operation_fn(te, tselem, tsep, newid);
2952  }
2953  }
2954  });
2955 }
2956 
2958  TreeStoreElem *tselem,
2959  TreeStoreElem *tsep,
2960  ID *actId)
2961 {
2962  bAction *act = (bAction *)actId;
2963 
2964  if (tselem->type == TSE_ANIM_DATA) {
2965  /* "animation" entries - action is child of this */
2966  BKE_animdata_set_action(nullptr, tselem->id, act);
2967  }
2968  /* TODO: if any other "expander" channels which own actions need to support this menu,
2969  * add: tselem->type = ...
2970  */
2971  else if (tsep && (tsep->type == TSE_ANIM_DATA)) {
2972  /* "animation" entries case again */
2973  BKE_animdata_set_action(nullptr, tsep->id, act);
2974  }
2975  /* TODO: other cases not supported yet. */
2976 }
2977 
2979 {
2980  Main *bmain = CTX_data_main(C);
2981  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2982  int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
2983  bAction *act;
2984 
2985  TreeElement *te = get_target_element(space_outliner);
2986  get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
2987 
2988  /* get action to use */
2989  act = reinterpret_cast<bAction *>(
2990  BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action")));
2991 
2992  if (act == nullptr) {
2993  BKE_report(op->reports, RPT_ERROR, "No valid action to add");
2994  return OPERATOR_CANCELLED;
2995  }
2996  if (act->idroot == 0) {
2997  /* Hopefully in this case (i.e. library of userless actions),
2998  * the user knows what they're doing. */
2999  BKE_reportf(op->reports,
3000  RPT_WARNING,
3001  "Action '%s' does not specify what data-blocks it can be used on "
3002  "(try setting the 'ID Root Type' setting from the data-blocks editor "
3003  "for this action to avoid future problems)",
3004  act->id.name + 2);
3005  }
3006 
3007  /* perform action if valid channel */
3008  if (datalevel == TSE_ANIM_DATA) {
3009  outliner_do_id_set_operation(space_outliner, datalevel, (ID *)act, actionset_id_fn);
3010  }
3011  else if (idlevel == ID_AC) {
3012  outliner_do_id_set_operation(space_outliner, idlevel, (ID *)act, actionset_id_fn);
3013  }
3014  else {
3015  return OPERATOR_CANCELLED;
3016  }
3017 
3018  /* set notifier that things have changed */
3021  ED_undo_push(C, "Set action");
3022 
3023  /* done */
3024  return OPERATOR_FINISHED;
3025 }
3026 
3028 {
3029  PropertyRNA *prop;
3030 
3031  /* identifiers */
3032  ot->name = "Outliner Set Action";
3033  ot->idname = "OUTLINER_OT_action_set";
3034  ot->description = "Change the active action used";
3035 
3036  /* api callbacks */
3040 
3041  /* flags */
3043 
3044  /* props */
3045  /* TODO: this would be nicer as an ID-pointer... */
3046  prop = RNA_def_enum(ot->srna, "action", DummyRNA_NULL_items, 0, "Action", "");
3049  ot->prop = prop;
3050 }
3051 
3054 /* -------------------------------------------------------------------- */
3060 
3062 
3065 
3068 };
3069 
3072  "CLEAR_ANIMDATA",
3073  0,
3074  "Clear Animation Data",
3075  "Remove this animation data container"},
3076  {OUTLINER_ANIMOP_SET_ACT, "SET_ACT", 0, "Set Action", ""},
3077  {OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""},
3078  {OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""},
3079  {OUTLINER_ANIMOP_CLEAR_DRV, "CLEAR_DRIVERS", 0, "Clear Drivers", ""},
3080  {0, nullptr, 0, nullptr, nullptr},
3081 };
3082 
3084 {
3086  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3087  int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3088  TreeElement *te = get_target_element(space_outliner);
3089  get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3090 
3091  if (datalevel != TSE_ANIM_DATA) {
3092  return OPERATOR_CANCELLED;
3093  }
3094 
3095  /* perform the core operation */
3097  switch (event) {
3099  /* Remove Animation Data - this may remove the active action, in some cases... */
3100  outliner_do_data_operation(space_outliner, datalevel, event, clear_animdata_fn, nullptr);
3101 
3103  ED_undo_push(C, "Clear Animation Data");
3104  break;
3105 
3107  /* delegate once again... */
3108  wm->op_undo_depth++;
3110  C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, nullptr, nullptr);
3111  wm->op_undo_depth--;
3112  ED_undo_push(C, "Set active action");
3113  break;
3114 
3116  /* clear active action - using standard rules */
3117  outliner_do_data_operation(space_outliner, datalevel, event, unlinkact_animdata_fn, nullptr);
3118 
3120  ED_undo_push(C, "Unlink action");
3121  break;
3122 
3125  space_outliner, datalevel, event, refreshdrivers_animdata_fn, nullptr);
3126 
3128  // ED_undo_push(C, "Refresh Drivers"); /* No undo needed - shouldn't have any impact? */
3129  break;
3130 
3133  space_outliner, datalevel, event, cleardrivers_animdata_fn, nullptr);
3134 
3136  ED_undo_push(C, "Clear Drivers");
3137  break;
3138 
3139  default: /* Invalid. */
3140  break;
3141  }
3142 
3143  /* update dependencies */
3145 
3146  return OPERATOR_FINISHED;
3147 }
3148 
3150 {
3151  /* identifiers */
3152  ot->name = "Outliner Animation Data Operation";
3153  ot->idname = "OUTLINER_OT_animdata_operation";
3154 
3155  /* callbacks */
3159 
3160  ot->flag = 0;
3161 
3162  ot->prop = RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", "");
3163 }
3164 
3167 /* -------------------------------------------------------------------- */
3172  {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""},
3173  {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_HIDE_ON, "Disable", ""},
3174  {OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""},
3175  {0, nullptr, 0, nullptr, nullptr},
3176 };
3177 
3179 {
3180  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3182 
3183  outliner_do_data_operation(space_outliner, TSE_CONSTRAINT, event, constraint_fn, C);
3184 
3185  if (event == OL_CONSTRAINTOP_DELETE) {
3186  outliner_cleanup_tree(space_outliner);
3187  }
3188 
3189  ED_undo_push(C, "Constraint operation");
3190 
3191  return OPERATOR_FINISHED;
3192 }
3193 
3195 {
3196  /* identifiers */
3197  ot->name = "Outliner Constraint Operation";
3198  ot->idname = "OUTLINER_OT_constraint_operation";
3199 
3200  /* callbacks */
3204 
3205  ot->flag = 0;
3206 
3207  ot->prop = RNA_def_enum(
3208  ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", "");
3209 }
3210 
3213 /* -------------------------------------------------------------------- */
3218  {OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle Viewport Use", ""},
3219  {OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle Render Use", ""},
3220  {OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
3221  {0, nullptr, 0, nullptr, nullptr},
3222 };
3223 
3225 {
3226  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3228 
3229  outliner_do_data_operation(space_outliner, TSE_MODIFIER, event, modifier_fn, C);
3230 
3231  if (event == OL_MODIFIER_OP_DELETE) {
3232  outliner_cleanup_tree(space_outliner);
3233  }
3234 
3235  ED_undo_push(C, "Modifier operation");
3236 
3237  return OPERATOR_FINISHED;
3238 }
3239 
3241 {
3242  /* identifiers */
3243  ot->name = "Outliner Modifier Operation";
3244  ot->idname = "OUTLINER_OT_modifier_operation";
3245 
3246  /* callbacks */
3250 
3251  ot->flag = 0;
3252 
3253  ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", "");
3254 }
3255 
3258 /* -------------------------------------------------------------------- */
3263 {
3264  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3265  int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3266  TreeElement *te = get_target_element(space_outliner);
3267  get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3268 
3270  switch (datalevel) {
3271  case TSE_POSE_CHANNEL: {
3272  outliner_do_data_operation(space_outliner, datalevel, event, pchan_fn, nullptr);
3274  ED_undo_push(C, "PoseChannel operation");
3275 
3276  break;
3277  }
3278  case TSE_BONE: {
3279  outliner_do_data_operation(space_outliner, datalevel, event, bone_fn, nullptr);
3281  ED_undo_push(C, "Bone operation");
3282 
3283  break;
3284  }
3285  case TSE_EBONE: {
3286  outliner_do_data_operation(space_outliner, datalevel, event, ebone_fn, nullptr);
3288  ED_undo_push(C, "EditBone operation");
3289 
3290  break;
3291  }
3292  case TSE_SEQUENCE: {
3294  outliner_do_data_operation(space_outliner, datalevel, event, sequence_fn, scene);
3296  ED_undo_push(C, "Sequencer operation");
3297 
3298  break;
3299  }
3300  case TSE_GP_LAYER: {
3301  outliner_do_data_operation(space_outliner, datalevel, event, gpencil_layer_fn, nullptr);
3303  ED_undo_push(C, "Grease Pencil Layer operation");
3304 
3305  break;
3306  }
3307  case TSE_RNA_STRUCT:
3308  if (event == OL_DOP_SELECT_LINKED) {
3309  outliner_do_data_operation(space_outliner, datalevel, event, data_select_linked_fn, C);
3310  }
3311 
3312  break;
3313 
3314  default:
3315  BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
3316  break;
3317  }
3318 
3319  return OPERATOR_FINISHED;
3320 }
3321 
3322 /* Dynamically populate an enum of Keying Sets */
3324  PointerRNA *UNUSED(ptr),
3325  PropertyRNA *UNUSED(prop),
3326  bool *UNUSED(r_free))
3327 {
3328  /* Check for invalid states. */
3329  if (C == nullptr) {
3330  return DummyRNA_DEFAULT_items;
3331  }
3332 
3333  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3334  if (space_outliner == nullptr) {
3335  return DummyRNA_DEFAULT_items;
3336  }
3337 
3338  TreeElement *te = get_target_element(space_outliner);
3339  if (te == nullptr) {
3340  return DummyRNA_NULL_items;
3341  }
3342 
3343  TreeStoreElem *tselem = TREESTORE(te);
3344 
3345  static const EnumPropertyItem optype_sel_and_hide[] = {
3346  {OL_DOP_SELECT, "SELECT", 0, "Select", ""},
3347  {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""},
3348  {OL_DOP_HIDE, "HIDE", 0, "Hide", ""},
3349  {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""},
3350  {0, nullptr, 0, nullptr, nullptr}};
3351 
3352  static const EnumPropertyItem optype_sel_linked[] = {
3353  {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
3354  {0, nullptr, 0, nullptr, nullptr}};
3355 
3356  if (tselem->type == TSE_RNA_STRUCT) {
3357  return optype_sel_linked;
3358  }
3359 
3360  return optype_sel_and_hide;
3361 }
3362 
3364 {
3365  /* identifiers */
3366  ot->name = "Outliner Data Operation";
3367  ot->idname = "OUTLINER_OT_data_operation";
3368 
3369  /* callbacks */
3373 
3374  ot->flag = 0;
3375 
3376  ot->prop = RNA_def_enum(ot->srna, "type", DummyRNA_DEFAULT_items, 0, "Data Operation", "");
3378 }
3379 
3382 /* -------------------------------------------------------------------- */
3386 static int outliner_operator_menu(bContext *C, const char *opname)
3387 {
3388  wmOperatorType *ot = WM_operatortype_find(opname, false);
3389  uiPopupMenu *pup = UI_popup_menu_begin(C, WM_operatortype_name(ot, nullptr), ICON_NONE);
3390  uiLayout *layout = UI_popup_menu_layout(pup);
3391 
3392  /* set this so the default execution context is the same as submenus */
3395 
3396  uiItemS(layout);
3397 
3398  uiItemMContents(layout, "OUTLINER_MT_context_menu");
3399 
3400  UI_popup_menu_end(C, pup);
3401 
3402  return OPERATOR_INTERFACE;
3403 }
3404 
3406  ReportList *reports,
3407  ARegion *region,
3408  SpaceOutliner *space_outliner,
3409  TreeElement *te)
3410 {
3411  int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3412  TreeStoreElem *tselem = TREESTORE(te);
3413 
3414  int select_flag = OL_ITEM_ACTIVATE | OL_ITEM_SELECT;
3415  if (tselem->flag & TSE_SELECTED) {
3416  select_flag |= OL_ITEM_EXTEND;
3417  }
3418 
3419  outliner_item_select(C, space_outliner, te, select_flag);
3420 
3421  /* Only redraw, don't rebuild here because TreeElement pointers will
3422  * become invalid and operations will crash. */
3424  ED_outliner_select_sync_from_outliner(C, space_outliner);
3425 
3426  get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3427 
3428  if (scenelevel) {
3429  if (objectlevel || datalevel || idlevel) {
3430  BKE_report(reports, RPT_WARNING, "Mixed selection");
3431  return OPERATOR_CANCELLED;
3432  }
3433  return outliner_operator_menu(C, "OUTLINER_OT_scene_operation");
3434  }
3435  if (objectlevel) {
3436  WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN);
3437  return OPERATOR_FINISHED;
3438  }
3439  if (idlevel) {
3440  if (idlevel == -1 || datalevel) {
3441  BKE_report(reports, RPT_WARNING, "Mixed selection");
3442  return OPERATOR_CANCELLED;
3443  }
3444 
3445  switch (idlevel) {
3446  case ID_GR:
3447  WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
3448  return OPERATOR_FINISHED;
3449  break;
3450  case ID_LI:
3451  return outliner_operator_menu(C, "OUTLINER_OT_lib_operation");
3452  break;
3453  default:
3454  return outliner_operator_menu(C, "OUTLINER_OT_id_operation");
3455  break;
3456  }
3457  }
3458  else if (datalevel) {
3459  if (datalevel == -1) {
3460  BKE_report(reports, RPT_WARNING, "Mixed selection");
3461  return OPERATOR_CANCELLED;
3462  }
3463  if (datalevel == TSE_ANIM_DATA) {
3464  return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation");
3465  }
3466  if (datalevel == TSE_DRIVER_BASE) {
3467  /* do nothing... no special ops needed yet */
3468  return OPERATOR_CANCELLED;
3469  }
3470  if (datalevel == TSE_LAYER_COLLECTION) {
3471  WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
3472  return OPERATOR_FINISHED;
3473  }
3475  WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
3476  return OPERATOR_FINISHED;
3477  }
3478  if (datalevel == TSE_ID_BASE) {
3479  /* do nothing... there are no ops needed here yet */
3480  return OPERATOR_CANCELLED;
3481  }
3482  if (datalevel == TSE_CONSTRAINT) {
3483  return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation");
3484  }
3485  if (datalevel == TSE_MODIFIER) {
3486  return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation");
3487  }
3488  return outliner_operator_menu(C, "OUTLINER_OT_data_operation");
3489  }
3490 
3491  return OPERATOR_CANCELLED;
3492 }
3493 
3494 static int outliner_operation(bContext *C, wmOperator *op, const wmEvent *event)
3495 {
3496  ARegion *region = CTX_wm_region(C);
3497  SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3499  float view_mval[2];
3500 
3501  if (but) {
3503  }
3504 
3506  &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
3507 
3508  TreeElement *hovered_te = outliner_find_item_at_y(
3509  space_outliner, &space_outliner->tree, view_mval[1]);
3510  if (!hovered_te) {
3511  /* Let this fall through to 'OUTLINER_MT_context_menu'. */
3512  return OPERATOR_PASS_THROUGH;
3513  }
3514 
3515  return do_outliner_operation_event(C, op->reports, region, space_outliner, hovered_te);
3516 }
3517 
3519 {
3520  ot->name = "Context Menu";
3521  ot->idname = "OUTLINER_OT_operation";
3522  ot->description = "Context menu for item operations";
3523 
3525 
3527 }
3528 
void BKE_animdata_free(struct ID *id, bool do_id_user)
Definition: anim_data.c:197
bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act)
Definition: anim_data.c:118
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
bool BKE_collection_child_remove(struct Main *bmain, struct Collection *parent, struct Collection *child)
Definition: collection.c:1600
bool BKE_collection_object_remove(struct Main *bmain, struct Collection *collection, struct Object *object, bool free_us)
Definition: collection.c:1170
bool BKE_scene_collections_object_remove(struct Main *bmain, struct Scene *scene, struct Object *object, bool free_us)
Definition: collection.c:1224
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
bool BKE_constraint_remove_ex(ListBase *list, struct Object *ob, struct bConstraint *con, bool clear_dep)
Definition: constraint.c:5603
void BKE_constraints_active_set(ListBase *list, struct bConstraint *con)
Definition: constraint.c:6017
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1370
struct SpaceOutliner * CTX_wm_space_outliner(const bContext *C)
Definition: context.c:860
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 ReportList * CTX_wm_reports(const bContext *C)
Definition: context.c:775
struct wmMsgBus * CTX_wm_message_bus(const bContext *C)
Definition: context.c:770
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
void BKE_fcurves_free(ListBase *list)
Definition: fcurve.c:86
bool BKE_idtype_idcode_is_linkable(short idcode)
Definition: idtype.c:175
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:379
void BKE_id_newptr_and_tag_clear(struct ID *id)
Definition: lib_id.c:359
void BKE_main_id_newptr_and_tag_clear(struct Main *bmain)
Definition: lib_id.c:1465
void BKE_main_id_tag_all(struct Main *mainvar, int tag, bool value)
Definition: lib_id.c:930
void id_us_min(struct ID *id)
Definition: lib_id.c:313
void id_fake_user_set(struct ID *id)
Definition: lib_id.c:343
bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop)
Definition: lib_id.c:762
bool BKE_lib_id_make_local(struct Main *bmain, struct ID *id, int flags)
Definition: lib_id.c:533
void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL()
void id_fake_user_clear(struct ID *id)
Definition: lib_id.c:351
size_t BKE_id_multi_tagged_delete(struct Main *bmain) ATTR_NONNULL()
void BKE_lib_override_library_make_local(struct ID *id)
bool BKE_lib_override_library_create(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct Library *owner_library, struct ID *id_root_reference, struct ID *id_hierarchy_root_reference, struct ID *id_instance_hint, struct ID **r_id_root_override, const bool do_fully_editable)
void BKE_lib_override_library_id_hierarchy_reset(struct Main *bmain, struct ID *id_root, bool do_reset_system_override)
bool BKE_lib_override_library_resync(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct ID *id_root, struct Collection *override_resync_residual_storage, bool do_hierarchy_enforce, struct BlendFileReadReport *reports)
bool BKE_lib_override_library_is_hierarchy_leaf(struct Main *bmain, struct ID *id)
void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root)
void BKE_lib_override_library_id_reset(struct Main *bmain, struct ID *id_root, bool do_reset_system_override)
struct ID * BKE_lib_override_library_create_from_id(struct Main *bmain, struct ID *reference_id, bool do_tagged_remap)
bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv)
Definition: lib_query.c:615
@ ID_REMAP_SKIP_INDIRECT_USAGE
Definition: BKE_lib_remap.h:36
void void BKE_libblock_remap(struct Main *bmain, void *old_idv, void *new_idv, short remap_flags) ATTR_NONNULL(1
#define FOREACH_MAIN_ID_END
Definition: BKE_main.h:367
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition: BKE_main.h:361
General operations, lookup, etc. for blender objects.
bool BKE_object_is_in_editmode(const struct Object *ob)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
struct GSet GSet
Definition: BLI_ghash.h:340
GSet * BLI_gset_ptr_new(const char *info)
#define GSET_ITER(gs_iter_, gset_)
Definition: BLI_ghash.h:471
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1037
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition: BLI_ghash.h:458
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:969
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
char * BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:538
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define ELEM(...)
#define LIKELY(x)
#define CLOG_WARN(clg_ref,...)
Definition: CLG_log.h:189
void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag)
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
#define ID_IS_OVERRIDE_LIBRARY_VIRTUAL(_id)
Definition: DNA_ID.h:585
#define ID_EXTRA_USERS(id)
Definition: DNA_ID.h:554
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:771
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_SELECT
Definition: DNA_ID.h:818
@ ID_RECALC_ANIMATION
Definition: DNA_ID.h:794
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ ID_RECALC_BASE_FLAGS
Definition: DNA_ID.h:821
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition: DNA_ID.h:581
#define ID_IS_OVERRIDABLE_LIBRARY(_id)
Definition: DNA_ID.h:574
#define ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(_id)
Definition: DNA_ID.h:570
#define ID_IS_LINKED(_id)
Definition: DNA_ID.h:566
@ LIB_TAG_INDIRECT
Definition: DNA_ID.h:677
@ LIB_TAG_DOIT
Definition: DNA_ID.h:707
@ LIB_TAG_EXTERN
Definition: DNA_ID.h:674
@ LIB_EMBEDDED_DATA
Definition: DNA_ID.h:635
@ LIB_EMBEDDED_DATA_LIB_OVERRIDE
Definition: DNA_ID.h:646
#define ID_REAL_USERS(id)
Definition: DNA_ID.h:553
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition: DNA_ID.h:588
#define ID_IS_OVERRIDE_LIBRARY_HIERARCHY_ROOT(_id)
Definition: DNA_ID.h:591
@ IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED
Definition: DNA_ID.h:327
ID_Type
Definition: DNA_ID_enums.h:44
@ ID_WM
Definition: DNA_ID_enums.h:72
@ ID_CA
Definition: DNA_ID_enums.h:56
@ ID_AR
Definition: DNA_ID_enums.h:66
@ ID_MC
Definition: DNA_ID_enums.h:73
@ ID_CF
Definition: DNA_ID_enums.h:78
@ ID_LI
Definition: DNA_ID_enums.h:46
@ ID_TE
Definition: DNA_ID_enums.h:52
@ ID_IM
Definition: DNA_ID_enums.h:53
@ ID_VO
Definition: DNA_ID_enums.h:83
@ ID_WS
Definition: DNA_ID_enums.h:79
@ ID_NT
Definition: DNA_ID_enums.h:68
@ ID_LA
Definition: DNA_ID_enums.h:55
@ ID_KE
Definition: DNA_ID_enums.h:58
@ ID_TXT
Definition: DNA_ID_enums.h:62
@ ID_SO
Definition: DNA_ID_enums.h:64
@ ID_SCE
Definition: DNA_ID_enums.h:45
@ ID_LS
Definition: DNA_ID_enums.h:75
@ ID_MSK
Definition: DNA_ID_enums.h:74
@ ID_GD
Definition: DNA_ID_enums.h:71
@ ID_CV
Definition: DNA_ID_enums.h:81
@ ID_PAL
Definition: DNA_ID_enums.h:76
@ ID_BR
Definition: DNA_ID_enums.h:69
@ ID_LP
Definition: DNA_ID_enums.h:80
@ ID_WO
Definition: DNA_ID_enums.h:59
@ ID_SIM
Definition: DNA_ID_enums.h:84
@ ID_MA
Definition: DNA_ID_enums.h:51
@ ID_AC
Definition: DNA_ID_enums.h:67
@ ID_SCR
Definition: DNA_ID_enums.h:60
@ ID_CU_LEGACY
Definition: DNA_ID_enums.h:49
@ ID_VF
Definition: DNA_ID_enums.h:61
@ ID_ME
Definition: DNA_ID_enums.h:48
@ ID_IP
Definition: DNA_ID_enums.h:57
@ ID_GR
Definition: DNA_ID_enums.h:65
@ ID_SPK
Definition: DNA_ID_enums.h:63
@ ID_MB
Definition: DNA_ID_enums.h:50
@ ID_LT
Definition: DNA_ID_enums.h:54
@ ID_OB
Definition: DNA_ID_enums.h:47
@ ID_PA
Definition: DNA_ID_enums.h:70
@ ID_PT
Definition: DNA_ID_enums.h:82
@ ID_PC
Definition: DNA_ID_enums.h:77
#define ID_NLA
Definition: DNA_ID_enums.h:100
@ DRIVER_FLAG_INVALID
@ FCURVE_DISABLED
@ BONE_ROOTSEL
@ BONE_SELECTED
@ BONE_HIDDEN_A
@ BONE_HIDDEN_P
@ BONE_TIPSEL
Object groups, one object can be in many groups at once.
@ CONSTRAINT_OFF
@ GP_LAYER_SELECT
@ GP_LAYER_HIDE
@ BASE_SELECTED
@ eModifierMode_Render
@ eModifierMode_Realtime
@ OB_MODE_EDIT
Object is a sort of wrapper for general info.
@ OB_EMPTY
@ OB_ARMATURE
#define TSE_IS_REAL_ID(_tse)
@ TSE_POSE_CHANNEL
@ TSE_GP_LAYER
@ TSE_SEQUENCE
@ TSE_VIEW_COLLECTION_BASE
@ TSE_ANIM_DATA
@ TSE_EBONE
@ TSE_BONE
@ TSE_CONSTRAINT
@ TSE_SCENE_COLLECTION_BASE
@ TSE_LAYER_COLLECTION
@ TSE_ID_BASE
@ TSE_SOME_ID
@ TSE_DRIVER_BASE
@ TSE_MODIFIER
@ TSE_RNA_STRUCT
@ TSE_SELECTED
@ TSE_CLOSED
@ TSE_ACTIVE
#define BASACT(_view_layer)
#define OBACT(_view_layer)
@ SEQ_MUTE
@ SO_VIEW_LAYER
@ SO_SCENES
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
@ EM_FREEDATA
Definition: ED_object.h:242
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode)
Definition: object_select.c:76
bool ED_object_editmode_exit_ex(struct Main *bmain, struct Scene *scene, struct Object *obedit, int flag)
Definition: object_edit.c:653
void ED_object_constraint_update(struct Main *bmain, struct Object *ob)
bool ED_object_modifier_remove(struct ReportList *reports, struct Main *bmain, struct Scene *scene, struct Object *ob, struct ModifierData *md)
bool ED_object_editmode_exit(struct bContext *C, int flag)
Definition: object_edit.c:695
void ED_object_select_linked_by_id(struct bContext *C, struct ID *id)
void ED_object_base_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob)
Definition: object_add.cc:2190
@ BA_SELECT
Definition: ED_object.h:155
void ED_outliner_select_sync_from_all_tag(struct bContext *C)
void ED_outliner_select_sync_from_object_tag(struct bContext *C)
void ED_outliner_select_sync_from_outliner(struct bContext *C, struct SpaceOutliner *space_outliner)
bool ED_scene_delete(struct bContext *C, struct Main *bmain, struct Scene *scene) ATTR_NONNULL()
Definition: scene_edit.c:128
void ED_region_tag_redraw_no_rebuild(struct ARegion *region)
Definition: area.c:674
bool ED_operator_outliner_active(struct bContext *C)
Definition: screen_ops.c:253
void ED_sequencer_select_sequence_single(struct Scene *scene, struct Sequence *seq, bool deselect_all)
void ED_undo_push(struct bContext *C, const char *str)
Definition: ed_undo.c:100
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Map
const EnumPropertyItem * RNA_action_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free)
#define RNA_ENUM_ITEM_SEPR
Definition: RNA_types.h:483
@ PROP_ENUM_NO_TRANSLATE
Definition: RNA_types.h:294
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
#define C
Definition: RandGen.cpp:25
#define MAX_MTEX
Definition: Stroke.h:31
#define UI_UNIT_Y
@ UI_BUT_ACTIVATE_ON_INIT
Definition: UI_interface.h:219
@ UI_EMBOSS
Definition: UI_interface.h:108
void UI_block_theme_style_set(uiBlock *block, char theme_style)
Definition: interface.cc:3634
int UI_searchbox_size_y(void)
uiBut * uiDefBut(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:4806
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2])
Definition: interface.cc:598
@ UI_BLOCK_THEME_STYLE_POPUP
Definition: UI_interface.h:770
void UI_but_func_search_set(uiBut *but, uiButSearchCreateFn search_create_fn, uiButSearchUpdateFn search_update_fn, void *arg, bool free_arg, uiFreeArgFunc search_arg_free_fn, uiButHandleFunc search_exec_fn, void *active)
Definition: interface.cc:6242
uiBut * UI_context_active_but_get(const struct bContext *C)
bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid, int but_flag, uint8_t name_prefix_offset)
struct uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void UI_but_tooltip_timer_remove(struct bContext *C, uiBut *but)
void uiItemS(uiLayout *layout)
void uiItemMContents(uiLayout *layout, const char *menuname)
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
uiBlock * UI_block_begin(const struct bContext *C, struct ARegion *region, const char *name, eUIEmbossType emboss)
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup)
uiBut * uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, int x, int y, short width, short height, float a1, float a2, const char *tip)
Definition: interface.cc:6217
int UI_search_items_find_index(uiSearchItems *items, const char *name)
#define UI_UNIT_X
void UI_block_flag_enable(uiBlock *block, int flag)
Definition: interface.cc:5848
@ UI_BTYPE_LABEL
Definition: UI_interface.h:354
void UI_popup_block_invoke(struct bContext *C, uiBlockCreateFunc func, void *arg, uiFreeArgFunc arg_free)
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
void UI_but_flag_enable(uiBut *but, int flag)
Definition: interface.cc:5858
uiPopupMenu * UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL()
@ UI_BLOCK_SEARCH_MENU
Definition: UI_interface.h:147
@ UI_BLOCK_LOOP
Definition: UI_interface.h:135
@ UI_BLOCK_MOVEMOUSE_QUIT
Definition: UI_interface.h:143
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
#define ND_SEQUENCER
Definition: WM_types.h:385
#define ND_WORLD
Definition: WM_types.h:401
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_WINDOW
Definition: WM_types.h:325
#define NC_ID
Definition: WM_types.h:345
#define ND_NLA_ACTCHANGE
Definition: WM_types.h:446
#define ND_OB_ACTIVE
Definition: WM_types.h:388
#define NC_WM
Definition: WM_types.h:324
#define ND_DATA
Definition: WM_types.h:456
#define NC_ANIMATION
Definition: WM_types.h:338
#define ND_LIB_OVERRIDE_CHANGED
Definition: WM_types.h:367
#define ND_OB_SELECT
Definition: WM_types.h:390
#define NC_SCENE
Definition: WM_types.h:328
#define ND_LAYER_CONTENT
Definition: WM_types.h:402
#define ND_MODIFIER
Definition: WM_types.h:411
#define ND_POSE
Definition: WM_types.h:407
#define NA_EDITED
Definition: WM_types.h:523
#define ND_CONSTRAINT
Definition: WM_types.h:413
#define NA_REMOVED
Definition: WM_types.h:526
#define NC_GPENCIL
Definition: WM_types.h:349
#define ND_LAYER
Definition: WM_types.h:398
@ WM_OP_INVOKE_REGION_WIN
Definition: WM_types.h:202
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:201
#define ND_OB_SHADING
Definition: WM_types.h:406
#define ND_SPACE_VIEW3D
Definition: WM_types.h:471
#define NC_OBJECT
Definition: WM_types.h:329
#define ND_ANIMCHAN
Definition: WM_types.h:444
#define NC_SPACE
Definition: WM_types.h:342
#define NA_SELECTED
Definition: WM_types.h:528
#define ND_SPACE_OUTLINER
Definition: WM_types.h:470
ATTR_WARN_UNUSED_RESULT const void * element
Value & lookup_or_add_default(const Key &key)
Definition: BLI_map.hh:580
void append(const T &value)
Definition: BLI_vector.hh:433
bool is_empty() const
Definition: BLI_vector.hh:706
#define SELECT
Scene scene
void * user_data
SyclQueue void void size_t num_bytes void
void * tree
#define str(s)
#define GS(x)
Definition: iris.c:225
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
static unsigned a[3]
Definition: RandGen.cpp:78
bool active
all scheduled work for the GPU.
void all_open(const SpaceOutliner &space_outliner, const VisitorFn visitor)
bool outliner_is_collection_tree_element(const TreeElement *te)
void outliner_collection_delete(bContext *C, Main *bmain, Scene *scene, ReportList *reports, bool do_hierarchy)
int tree_element_id_type_to_index(TreeElement *te)
TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
void id_remap_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
void lib_reload_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
void item_rename_fn(bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
void id_delete_tag_fn(bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
void lib_relocate_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
@ OL_ITEM_EXTEND
@ OL_ITEM_RECURSIVE
@ OL_ITEM_SELECT
@ OL_ITEM_ACTIVATE
bool outliner_tree_traverse(const SpaceOutliner *space_outliner, ListBase *tree, int filter_te_flag, int filter_tselem_flag, TreeTraversalFunc func, void *customdata)
TreeElement * outliner_find_element_with_flag(const ListBase *lb, short flag)
void outliner_item_select(struct bContext *C, struct SpaceOutliner *space_outliner, struct TreeElement *te, short select_flag)
#define TREESTORE(a)
void outliner_cleanup_tree(struct SpaceOutliner *space_outliner)
void(* outliner_operation_fn)(struct bContext *C, struct ReportList *, struct Scene *scene, struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *)
TreeElement * outliner_find_item_at_y(const SpaceOutliner *space_outliner, const ListBase *tree, float view_co_y)
struct ID * outliner_search_back(TreeElement *te, short idcode)
#define TSELEM_OPEN(telm, sv)
TreeTraversalAction
@ TRAVERSE_SKIP_CHILDS
@ TRAVERSE_CONTINUE
static const EnumPropertyItem prop_lib_op_selection_set[]
static void outliner_object_delete_fn(bContext *C, ReportList *reports, Scene *scene, Object *ob)
static void id_select_linked_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
static void outliner_do_id_set_operation(SpaceOutliner *space_outliner, int type, ID *newid, void(*operation_fn)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *))
void OUTLINER_OT_object_operation(wmOperatorType *ot)
static void id_local_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
static int outliner_modifier_operation_exec(bContext *C, wmOperator *op)
eOutliner_PropConstraintOps
@ OL_CONSTRAINTOP_DISABLE
@ OL_CONSTRAINTOP_ENABLE
@ OL_CONSTRAINTOP_DELETE
static void id_override_library_reset_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *user_data)
static void object_batch_delete_hierarchy_fn(bContext *C, ReportList *reports, Scene *scene, Object *ob)
static int do_outliner_operation_event(bContext *C, ReportList *reports, ARegion *region, SpaceOutliner *space_outliner, TreeElement *te)
struct ObjectEditData { GSet *objects_set ObjectEditData
static int outliner_scene_operation_exec(bContext *C, wmOperator *op)
static void outliner_do_object_delete(bContext *C, ReportList *reports, Scene *scene, GSet *objects_to_delete, OutlinerDeleteFn delete_fn)
static void ebone_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
static void refreshdrivers_animdata_fn(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem, void *UNUSED(arg))
eOutliner_AnimDataOps
@ OUTLINER_ANIMOP_INVALID
@ OUTLINER_ANIMOP_CLEAR_ADT
@ OUTLINER_ANIMOP_CLEAR_DRV
@ OUTLINER_ANIMOP_REFRESH_DRV
@ OUTLINER_ANIMOP_CLEAR_ACT
@ OUTLINER_ANIMOP_SET_ACT
static void sequence_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *scene_ptr)
static int outliner_action_set_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_object_op_types[]
static void id_override_library_create_hierarchy(Main &bmain, Scene *scene, ViewLayer *view_layer, OutlinerLibOverrideData &data, ID *id_hierarchy_root_reference, Vector< OutlinerLiboverrideDataIDRoot > &data_idroots, bool &r_aggregated_success)
eOutlinerLibOverrideOpTypes
@ OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY
@ OUTLINER_LIBOVERRIDE_OP_DELETE_HIERARCHY
@ OUTLINER_LIBOVERRIDE_OP_RESET
@ OUTLINER_LIBOVERRIDE_OP_INVALID
@ OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY_ENFORCE
@ OUTLINER_LIBOVERRIDE_OP_CREATE_HIERARCHY
@ OUTLINER_LIBOVERRIDE_OP_CLEAR_SINGLE
eOutliner_PropDataOps
@ OL_DOP_HIDE
@ OL_DOP_SELECT_LINKED
@ OL_DOP_SELECT
@ OL_DOP_DESELECT
@ OL_DOP_UNHIDE
static void merged_element_search_exec_fn(struct bContext *C, void *UNUSED(arg1), void *element)
static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void *customdata)
bool is_liboverride_hierarchy_root_allowed
static void outliner_do_data_operation(SpaceOutliner *space_outliner, int type, int event, void(*operation_fn)(int, TreeElement *, TreeStoreElem *, void *), void *arg)
static bool outliner_id_operation_item_poll(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), const int enum_value)
static void outliner_do_libdata_operation_selection_set(bContext *C, ReportList *reports, Scene *scene, SpaceOutliner *space_outliner, const ListBase &subtree, const bool has_parent_selected, outliner_operation_fn operation_fn, eOutlinerLibOpSelectionSet selection_set, void *user_data)
static void actionset_id_fn(TreeElement *UNUSED(te), TreeStoreElem *tselem, TreeStoreElem *tsep, ID *actId)
static void object_select_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
static int outliner_liboverride_operation_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_data_operation(wmOperatorType *ot)
static void unlink_world_fn(bContext *UNUSED(C), ReportList *reports, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
static const EnumPropertyItem prop_liboverride_troubleshoot_op_types[]
static const EnumPropertyItem prop_id_op_types[]
static const EnumPropertyItem * outliner_id_operation_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
void OUTLINER_OT_action_set(wmOperatorType *ot)
eOutlinerLibOpSelectionSet
@ OUTLINER_LIB_SELECTIONSET_SELECTED
@ OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT
@ OUTLINER_LIB_LIB_SELECTIONSET_CONTENT
static void unlink_texture_fn(bContext *UNUSED(C), ReportList *reports, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
eOutlinerLibOpTypes
@ OL_LIB_RELOAD
@ OL_LIB_DELETE
@ OL_LIB_INVALID
@ OL_LIB_RELOCATE
static void merged_element_search_update_fn(const bContext *UNUSED(C), void *data, const char *str, uiSearchItems *items, const bool UNUSED(is_first))
static void data_select_linked_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
static void id_fake_user_set_fn(bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
static void pchan_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
static void id_override_library_create_hierarchy_pre_process_fn(bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem, void *user_data)
void OUTLINER_OT_delete(wmOperatorType *ot)
static TreeElement * get_target_element(SpaceOutliner *space_outliner)
static void get_element_operation_type(TreeElement *te, int *scenelevel, int *objectlevel, int *idlevel, int *datalevel)
static int outliner_delete_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_lib_operation(wmOperatorType *ot)
static void unlinkact_animdata_fn(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem, void *UNUSED(arg))
void OUTLINER_OT_animdata_operation(wmOperatorType *ot)
eOutlinerIdOpTypes
@ OUTLINER_IDOP_SINGLE
@ OUTLINER_IDOP_UNLINK
@ OUTLINER_IDOP_FAKE_ADD
@ OUTLINER_IDOP_SELECT_LINKED
@ OUTLINER_IDOP_INVALID
@ OUTLINER_IDOP_REMAP
@ OUTLINER_IDOP_FAKE_CLEAR
@ OUTLINER_IDOP_COPY
@ OUTLINER_IDOP_DELETE
@ OUTLINER_IDOP_PASTE
@ OUTLINER_IDOP_LOCAL
@ OUTLINER_IDOP_RENAME
static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_animdata_op_types[]
static void object_deselect_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
static uiBlock * merged_element_search_menu(bContext *C, ARegion *region, void *data)
void merged_element_search_menu_invoke(bContext *C, TreeElement *parent_te, TreeElement *activate_te)
static void id_override_library_clear_single_fn(bContext *C, ReportList *reports, Scene *scene, TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
static void object_select_hierarchy_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
static void id_fake_user_clear_fn(bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
static int outliner_data_operation_exec(bContext *C, wmOperator *op)
static void id_override_library_resync_hierarchy_process(bContext *C, ReportList *reports, OutlinerLibOverrideData &data)
static bool outliner_operation_tree_element_poll(bContext *C)
static void modifier_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg)
void outliner_do_object_operation(bContext *C, ReportList *reports, Scene *scene_act, SpaceOutliner *space_outliner, ListBase *lb, outliner_operation_fn operation_fn)
static bool outliner_liboverride_operation_poll(bContext *C)
static void id_override_library_delete_hierarchy_fn(bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *user_data)
static void merged_element_search_fn_recursive(const ListBase *tree, short tselem_type, short type, const char *str, uiSearchItems *items)
static const EnumPropertyItem outliner_lib_op_type_items[]
static void unlink_action_fn(bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
void OUTLINER_OT_liboverride_operation(wmOperatorType *ot)
static void singleuser_world_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
static void unlink_collection_fn(bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
static const EnumPropertyItem prop_modifier_op_types[]
static void singleuser_action_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
static Base * outliner_batch_delete_hierarchy(ReportList *reports, Main *bmain, ViewLayer *view_layer, Scene *scene, Base *base)
eOutliner_PropModifierOps
@ OL_MODIFIER_OP_TOGVIS
@ OL_MODIFIER_OP_TOGREN
@ OL_MODIFIER_OP_DELETE
static int outliner_constraint_operation_exec(bContext *C, wmOperator *op)
static void id_override_library_delete_hierarchy_process(bContext *C, ReportList *UNUSED(reports), OutlinerLibOverrideData &data)
void OUTLINER_OT_scene_operation(wmOperatorType *ot)
void OUTLINER_OT_id_operation(wmOperatorType *ot)
static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
static void cleardrivers_animdata_fn(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem, void *UNUSED(arg))
static int outliner_object_operation_exec(bContext *C, wmOperator *op)
static bool scene_fn(bContext *C, eOutliner_PropSceneOps event, TreeElement *UNUSED(te), TreeStoreElem *tselem)
static void clear_animdata_fn(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem, void *UNUSED(arg))
static CLG_LogRef LOG
void OUTLINER_OT_operation(wmOperatorType *ot)
static void bone_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
static int outliner_operator_menu(bContext *C, const char *opname)
eOutliner_PropSceneOps
@ OL_SCENE_OP_DELETE
void outliner_do_object_operation_ex(bContext *C, ReportList *reports, Scene *scene_act, SpaceOutliner *space_outliner, ListBase *lb, outliner_operation_fn operation_fn, void *user_data, bool recurse_selected)
static void unlink_material_fn(bContext *UNUSED(C), ReportList *reports, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
static void id_override_library_create_hierarchy_process(bContext *C, ReportList *reports, OutlinerLibOverrideData &data)
static const EnumPropertyItem prop_scene_op_types[]
static const EnumPropertyItem * outliner_data_op_sets_enum_item_fn(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
void OUTLINER_OT_liboverride_troubleshoot_operation(wmOperatorType *ot)
static int outliner_id_operation_exec(bContext *C, wmOperator *op)
void(*)(bContext *C, ReportList *reports, Scene *scene, Object *ob) OutlinerDeleteFn
static void unlink_object_fn(bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
@ OL_OP_REMAP
@ OL_OP_RENAME
@ OL_OP_SELECT_HIERARCHY
@ OL_OP_SELECT
@ OL_OP_DESELECT
bool is_liboverride_allowed
void OUTLINER_OT_constraint_operation(wmOperatorType *ot)
static void outliner_do_libdata_operation(bContext *C, ReportList *reports, Scene *scene, SpaceOutliner *space_outliner, outliner_operation_fn operation_fn, void *user_data)
static bool outliner_do_scene_operation(bContext *C, SpaceOutliner *space_outliner, eOutliner_PropSceneOps event, bool(*operation_fn)(bContext *, eOutliner_PropSceneOps, TreeElement *, TreeStoreElem *))
void OUTLINER_OT_modifier_operation(wmOperatorType *ot)
static const EnumPropertyItem prop_constraint_op_types[]
static void id_override_library_resync_fn(bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *user_data)
static void gpencil_layer_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
static int outliner_operation(bContext *C, wmOperator *op, const wmEvent *event)
static const EnumPropertyItem prop_liboverride_op_types[]
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:112
bool RNA_struct_is_ID(const StructRNA *type)
Definition: rna_access.c:655
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1000
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4487
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
Definition: rna_define.c:4436
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3830
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
const EnumPropertyItem DummyRNA_DEFAULT_items[]
Definition: rna_rna.c:31
const EnumPropertyItem DummyRNA_NULL_items[]
Definition: rna_rna.c:26
Editing * SEQ_editing_get(const Scene *scene)
Definition: sequencer.c:241
void SEQ_relations_invalidate_dependent(Scene *scene, Sequence *seq)
ListBase drivers
struct Base * next
short flag
struct Object * object
struct ReportList * reports
Definition: BLO_readfile.h:80
struct Material ** mat
short totcol
ListBase * seqbasep
const char * identifier
Definition: RNA_types.h:461
struct MTex * mtex[18]
unsigned int flag
Definition: DNA_ID.h:312
struct ID * hierarchy_root
Definition: DNA_ID.h:303
struct ID * reference
Definition: DNA_ID.h:294
Definition: DNA_ID.h:368
int tag
Definition: DNA_ID.h:387
struct Library * lib
Definition: DNA_ID.h:372
int us
Definition: DNA_ID.h:388
IDOverrideLibrary * override_library
Definition: DNA_ID.h:412
short flag
Definition: DNA_ID.h:383
unsigned int session_uuid
Definition: DNA_ID.h:407
char name[66]
Definition: DNA_ID.h:378
AnimData * adt
ID id
Definition: DNA_ID.h:458
void * first
Definition: DNA_listBase.h:31
struct Tex * tex
Definition: BKE_main.h:121
ListBase actions
Definition: BKE_main.h:191
TreeElement * select_element
TreeElement * parent_element
struct Material ** mat
short totcol
short totcol
struct Material ** mat
struct Collection * instance_collection
struct Material ** mat
struct Object * parent
void id_root_add(ID *id_hierarchy_root_reference, ID *id_root_reference, ID *id_instance_hint, const bool is_override_instancing_object)
Map< ID *, Vector< OutlinerLiboverrideDataIDRoot > > id_hierarchy_roots
Set< uint > id_hierarchy_roots_uid
void id_root_set(ID *id_hierarchy_root_reference)
struct Material ** mat
struct StructRNA * type
Definition: RNA_types.h:37
void * data
Definition: RNA_types.h:38
struct Collection * master_collection
struct World * world
struct TreeElement * parent
ListBase subtree
TreeStoreElem * store_elem
const char * name
struct Base * basact
ListBase object_bases
short totcol
struct Material ** mat
struct Bone * bone
int mval[2]
Definition: WM_types.h:684
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
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
struct ReportList * reports
struct PointerRNA * ptr
void WM_menu_name_call(bContext *C, const char *menu_name, short context)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
const char * WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *properties)
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)
Definition: wm_window.c:2188