Blender V4.3
outliner_tools.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2004 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include "CLG_log.h"
12
13#include "DNA_anim_types.h"
14#include "DNA_armature_types.h"
17#include "DNA_curves_types.h"
19#include "DNA_light_types.h"
20#include "DNA_linestyle_types.h"
21#include "DNA_material_types.h"
22#include "DNA_mesh_types.h"
23#include "DNA_meta_types.h"
24#include "DNA_modifier_types.h"
25#include "DNA_object_types.h"
27#include "DNA_scene_types.h"
28#include "DNA_sequence_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.hh"
41#include "BKE_animsys.h"
42#include "BKE_armature.hh"
43#include "BKE_collection.hh"
44#include "BKE_constraint.h"
45#include "BKE_context.hh"
46#include "BKE_fcurve.hh"
47#include "BKE_global.hh"
48#include "BKE_grease_pencil.hh"
49#include "BKE_idtype.hh"
50#include "BKE_layer.hh"
51#include "BKE_lib_id.hh"
52#include "BKE_lib_override.hh"
53#include "BKE_lib_query.hh"
54#include "BKE_lib_remap.hh"
55#include "BKE_main.hh"
56#include "BKE_object.hh"
57#include "BKE_report.hh"
58#include "BKE_scene.hh"
59#include "BKE_screen.hh"
60
61#include "DEG_depsgraph.hh"
63
64#include "ED_node.hh"
65#include "ED_object.hh"
66#include "ED_outliner.hh"
67#include "ED_scene.hh"
68#include "ED_screen.hh"
69#include "ED_sequencer.hh"
70#include "ED_undo.hh"
71
72#include "WM_api.hh"
73#include "WM_message.hh"
74#include "WM_types.hh"
75
76#include "UI_interface.hh"
77#include "UI_resources.hh"
78#include "UI_view2d.hh"
79
81
82#include "RNA_access.hh"
83#include "RNA_define.hh"
84#include "RNA_enum_types.hh"
85
86#include "SEQ_relations.hh"
87#include "SEQ_sequencer.hh"
88
89#include "outliner_intern.hh"
93#include "tree/tree_iterator.hh"
94
95namespace blender::ed::outliner {
96
97static CLG_LogRef LOG = {"ed.outliner.tools"};
98
99/* -------------------------------------------------------------------- */
104 const TreeElement *te, int *scenelevel, int *objectlevel, int *idlevel, int *datalevel)
105{
106 *scenelevel = *objectlevel = *idlevel = *datalevel = 0;
107
108 const TreeStoreElem *tselem = TREESTORE(te);
109 if ((tselem->flag & TSE_SELECTED) == 0) {
110 return;
111 }
112
113 /* Layer collection points to collection ID. */
114 if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) {
115 *datalevel = tselem->type;
116 }
117 else {
118 const int idcode = int(GS(tselem->id->name));
119 bool is_standard_id = false;
120 switch ((ID_Type)idcode) {
121 case ID_SCE:
122 *scenelevel = 1;
123 break;
124 case ID_OB:
125 *objectlevel = 1;
126 break;
127
128 case ID_ME:
129 case ID_CU_LEGACY:
130 case ID_MB:
131 case ID_LT:
132 case ID_LA:
133 case ID_AR:
134 case ID_CA:
135 case ID_SPK:
136 case ID_MA:
137 case ID_TE:
138 case ID_IP:
139 case ID_IM:
140 case ID_SO:
141 case ID_KE:
142 case ID_WO:
143 case ID_AC:
144 case ID_TXT:
145 case ID_GR:
146 case ID_LS:
147 case ID_LI:
148 case ID_VF:
149 case ID_NT:
150 case ID_BR:
151 case ID_PA:
152 case ID_GD_LEGACY:
153 case ID_MC:
154 case ID_MSK:
155 case ID_PAL:
156 case ID_PC:
157 case ID_CF:
158 case ID_WS:
159 case ID_LP:
160 case ID_CV:
161 case ID_PT:
162 case ID_VO:
163 case ID_GP:
164 is_standard_id = true;
165 break;
166 case ID_WM:
167 case ID_SCR:
168 /* Those are ignored here. */
169 /* NOTE: while Screens should be manageable here, deleting a screen used by a workspace
170 * will cause crashes when trying to use that workspace, so for now let's play minimal,
171 * safe change. */
172 break;
173 }
174 if (idcode == ID_NLA) {
175 /* Fake one, not an actual ID type... */
176 is_standard_id = true;
177 }
178
179 if (is_standard_id) {
180 *idlevel = idcode;
181 }
182 }
183
184 /* Return values are exclusive, only one may be non-null. */
185 BLI_assert(((*scenelevel != 0) && (*objectlevel == 0) && (*idlevel == 0) && (*datalevel == 0)) ||
186 ((*scenelevel == 0) && (*objectlevel != 0) && (*idlevel == 0) && (*datalevel == 0)) ||
187 ((*scenelevel == 0) && (*objectlevel == 0) && (*idlevel != 0) && (*datalevel == 0)) ||
188 ((*scenelevel == 0) && (*objectlevel == 0) && (*idlevel == 0) && (*datalevel != 0)) ||
189 /* All null. */
190 ((*scenelevel == 0) && (*objectlevel == 0) && (*idlevel == 0) && (*datalevel == 0)));
191}
192
193static TreeElement *get_target_element(const SpaceOutliner *space_outliner)
194{
196
197 return te;
198}
199
201{
203 return false;
204 }
205 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
206 TreeElement *te = get_target_element(space_outliner);
207 if (te == nullptr) {
208 return false;
209 }
210
211 return true;
212}
213
215 ReportList *reports,
216 Scene * /*scene*/,
217 TreeElement * /*te*/,
218 TreeStoreElem *tsep,
219 TreeStoreElem *tselem)
220{
221 if (!tsep || !TSE_IS_REAL_ID(tsep)) {
222 /* Valid case, no parent element of the action or it is not an ID (could be a #TSE_ID_BASE
223 * for example) so there's no data to unlink from. */
224 BKE_reportf(reports,
226 "Cannot unlink action '%s'. It's not clear which object or object-data it "
227 "should be unlinked from, there's no object or object-data as parent in the "
228 "Outliner tree",
229 tselem->id->name + 2);
230 return;
231 }
232
233 /* just set action to nullptr */
234 BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, nullptr);
236}
237
238static void unlink_material_fn(bContext * /*C*/,
239 ReportList *reports,
240 Scene * /*scene*/,
241 TreeElement *te,
242 TreeStoreElem *tsep,
243 TreeStoreElem *tselem)
244{
245 const bool te_is_material = TSE_IS_REAL_ID(tselem) && (GS(tselem->id->name) == ID_MA);
246
247 if (!te_is_material) {
248 /* Just fail silently. Another element may be selected that is a material, we don't want to
249 * confuse users with an error in that case. */
250 return;
251 }
252
253 if (!tsep || !TSE_IS_REAL_ID(tsep)) {
254 /* Valid case, no parent element of the material or it is not an ID (could be a #TSE_ID_BASE
255 * for example) so there's no data to unlink from. */
256 BKE_reportf(reports,
258 "Cannot unlink material '%s'. It's not clear which object or object-data it "
259 "should be unlinked from, there's no object or object-data as parent in the "
260 "Outliner tree",
261 tselem->id->name + 2);
262 return;
263 }
264
265 if (!ID_IS_EDITABLE(tsep->id) || ID_IS_OVERRIDE_LIBRARY(tsep->id)) {
266 BKE_reportf(reports,
268 "Cannot unlink the material '%s' from linked object data",
269 tselem->id->name + 2);
270 return;
271 }
272
273 Material **matar = nullptr;
274 int a, totcol = 0;
275
276 switch (GS(tsep->id->name)) {
277 case ID_OB: {
278 Object *ob = (Object *)tsep->id;
279 totcol = ob->totcol;
280 matar = ob->mat;
281 break;
282 }
283 case ID_ME: {
284 Mesh *mesh = (Mesh *)tsep->id;
285 totcol = mesh->totcol;
286 matar = mesh->mat;
287 break;
288 }
289 case ID_CU_LEGACY: {
290 Curve *cu = (Curve *)tsep->id;
291 totcol = cu->totcol;
292 matar = cu->mat;
293 break;
294 }
295 case ID_MB: {
296 MetaBall *mb = (MetaBall *)tsep->id;
297 totcol = mb->totcol;
298 matar = mb->mat;
299 break;
300 }
301 case ID_CV: {
302 Curves *curves = (Curves *)tsep->id;
303 totcol = curves->totcol;
304 matar = curves->mat;
305 break;
306 }
307 case ID_PT: {
308 PointCloud *pointcloud = (PointCloud *)tsep->id;
309 totcol = pointcloud->totcol;
310 matar = pointcloud->mat;
311 break;
312 }
313 case ID_VO: {
314 Volume *volume = (Volume *)tsep->id;
315 totcol = volume->totcol;
316 matar = volume->mat;
317 break;
318 }
319 default:
321 }
322
323 if (LIKELY(matar != nullptr)) {
324 for (a = 0; a < totcol; a++) {
325 if (a == te->index && matar[a]) {
326 id_us_min(&matar[a]->id);
327 matar[a] = nullptr;
328 }
329 }
330 }
331}
332
333static void unlink_texture_fn(bContext * /*C*/,
334 ReportList *reports,
335 Scene * /*scene*/,
336 TreeElement *te,
337 TreeStoreElem *tsep,
338 TreeStoreElem *tselem)
339{
340 if (!tsep || !TSE_IS_REAL_ID(tsep)) {
341 /* Valid case, no parent element of the texture or it is not an ID (could be a #TSE_ID_BASE
342 * for example) so there's no data to unlink from. */
343 BKE_reportf(reports,
345 "Cannot unlink texture '%s'. It's not clear which freestyle line style it should "
346 "be unlinked from, there's no freestyle line style as parent in the Outliner tree",
347 tselem->id->name + 2);
348 return;
349 }
350
351 MTex **mtex = nullptr;
352 int a;
353
354 if (GS(tsep->id->name) == ID_LS) {
356 mtex = ls->mtex;
357 }
358 else {
359 return;
360 }
361
362 for (a = 0; a < MAX_MTEX; a++) {
363 if (a == te->index && mtex[a]) {
364 if (mtex[a]->tex) {
365 id_us_min(&mtex[a]->tex->id);
366 mtex[a]->tex = nullptr;
367 }
368 }
369 }
370}
371
373 ReportList *reports,
374 Scene * /*scene*/,
375 TreeElement * /*te*/,
376 TreeStoreElem *tsep,
377 TreeStoreElem *tselem)
378{
379 Main *bmain = CTX_data_main(C);
380 Collection *collection = (Collection *)tselem->id;
381
382 if (!tsep || !TSE_IS_REAL_ID(tsep)) {
383 /* Valid case, no parent element of the collection or it is not an ID (could be a #TSE_ID_BASE
384 * for example) so there's no data to unlink from. */
385 BKE_reportf(reports,
387 "Cannot unlink collection '%s'. It's not clear which scene, collection or "
388 "instance empties it should be unlinked from, there's no scene, collection or "
389 "instance empties as parent in the Outliner tree",
390 tselem->id->name + 2);
391 return;
392 }
393
394 if (tsep && (!ID_IS_EDITABLE(tsep->id) || ID_IS_OVERRIDE_LIBRARY(tsep->id))) {
395 BKE_reportf(reports,
397 "Cannot unlink collection '%s' parented to another linked collection '%s'",
398 collection->id.name + 2,
399 tsep->id->name + 2);
400 return;
401 }
402
403 if (tsep) {
404 if (GS(tsep->id->name) == ID_OB) {
405 Object *ob = (Object *)tsep->id;
406 ob->instance_collection = nullptr;
409 }
410 else if (GS(tsep->id->name) == ID_GR) {
411 Collection *parent = (Collection *)tsep->id;
412 id_fake_user_set(&collection->id);
413 BKE_collection_child_remove(bmain, parent, collection);
416 }
417 else if (GS(tsep->id->name) == ID_SCE) {
418 Scene *scene = (Scene *)tsep->id;
419 Collection *parent = scene->master_collection;
420 id_fake_user_set(&collection->id);
421 BKE_collection_child_remove(bmain, parent, collection);
424 }
425 }
426}
427
429 ReportList *reports,
430 Scene * /*scene*/,
431 TreeElement *te,
432 TreeStoreElem *tsep,
433 TreeStoreElem *tselem)
434{
435 if (tsep && tsep->id) {
436 Main *bmain = CTX_data_main(C);
437 Object *ob = (Object *)tselem->id;
438 const eSpaceOutliner_Mode outliner_mode = eSpaceOutliner_Mode(
439 CTX_wm_space_outliner(C)->outlinevis);
440
441 if (GS(tsep->id->name) == ID_OB) {
442 /* Parented objects need to find which collection to unlink from. */
443 TreeElement *te_parent = te->parent;
444 while (tsep && GS(tsep->id->name) == ID_OB) {
445 if (!ID_IS_EDITABLE(tsep->id)) {
446 BKE_reportf(reports,
448 "Cannot unlink object '%s' parented to another linked object '%s'",
449 ob->id.name + 2,
450 tsep->id->name + 2);
451 return;
452 }
453 te_parent = te_parent->parent;
454 tsep = te_parent ? TREESTORE(te_parent) : nullptr;
455 }
456 }
457
458 if (tsep && tsep->id) {
459 if (!ID_IS_EDITABLE(tsep->id) || ID_IS_OVERRIDE_LIBRARY(tsep->id)) {
460 BKE_reportf(reports,
462 "Cannot unlink object '%s' from linked collection or scene '%s'",
463 ob->id.name + 2,
464 tsep->id->name + 2);
465 return;
466 }
467 switch (GS(tsep->id->name)) {
468 case ID_GR: {
469 Collection *parent = (Collection *)tsep->id;
470 BKE_collection_object_remove(bmain, parent, ob, true);
472 break;
473 }
474 case ID_SCE: {
475 Scene *scene = reinterpret_cast<Scene *>(tsep->id);
476 /* In Scene view, remove the object from all collections in the scene. */
477 if (outliner_mode == SO_SCENES) {
478 FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
479 if (BKE_collection_has_object(collection, ob)) {
480 BKE_collection_object_remove(bmain, collection, ob, true);
481 DEG_id_tag_update(&collection->id, ID_RECALC_HIERARCHY);
483 }
484 }
486 }
487 /* Otherwise, remove the object from the scene's main collection. */
488 else {
489 Collection *parent = scene->master_collection;
490 BKE_collection_object_remove(bmain, parent, ob, true);
492 }
493 break;
494 }
495 default: {
496 /* Un-handled case, should never be reached. */
498 return;
499 }
500 }
501 /* NOTE: Cannot risk tagging the object here, as it may have been deleted if its last usage
502 * was removed by above code. */
505 }
506 }
507}
508
509static void unlink_world_fn(bContext * /*C*/,
510 ReportList *reports,
511 Scene * /*scene*/,
512 TreeElement * /*te*/,
513 TreeStoreElem *tsep,
514 TreeStoreElem *tselem)
515{
516 if (!tsep || !TSE_IS_REAL_ID(tsep)) {
517 /* Valid case, no parent element of the world or it is not an ID (could be a #TSE_ID_BASE
518 * for example) so there's no data to unlink from. */
519 BKE_reportf(reports,
521 "Cannot unlink world '%s'. It's not clear which scene it should be unlinked from, "
522 "there's no scene as parent in the Outliner tree",
523 tselem->id->name + 2);
524 return;
525 }
526
527 Scene *parscene = (Scene *)tsep->id;
528 World *wo = (World *)tselem->id;
529
530 /* need to use parent scene not just scene, otherwise may end up getting wrong one */
531 id_us_min(&wo->id);
532 parscene->world = nullptr;
533}
534
536 ReportList *reports,
537 Scene *scene,
538 SpaceOutliner *space_outliner,
539 outliner_operation_fn operation_fn)
540{
541 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
542 TreeStoreElem *tselem = TREESTORE(te);
543 if (tselem->flag & TSE_SELECTED) {
544 if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
545 tselem->type == TSE_LAYER_COLLECTION)
546 {
547 TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr;
548 operation_fn(C, reports, scene, te, tsep, tselem);
549 }
550 }
551 });
552}
553
555 /* Only selected items. */
557 /* Only content 'inside' selected items (their sub-tree). */
559 /* Combining both options above. */
561};
562
565 "SELECTED",
566 0,
567 "Selected",
568 "Apply the operation over selected data-blocks only"},
570 "CONTENT",
571 0,
572 "Content",
573 "Apply the operation over content of the selected items only (the data-blocks in their "
574 "sub-tree)"},
576 "SELECTED_AND_CONTENT",
577 0,
578 "Selected & Content",
579 "Apply the operation over selected data-blocks and all their dependencies"},
580 {0, nullptr, 0, nullptr, nullptr},
581};
582
584 bContext *C,
585 ReportList *reports,
586 Scene *scene,
587 TreeElement *element,
588 TreeStoreElem *tselem,
589 const bool has_parent_selected,
590 outliner_operation_fn operation_fn,
591 eOutlinerLibOpSelectionSet selection_set)
592{
593 const bool do_selected = ELEM(selection_set,
596 const bool do_content = ELEM(selection_set,
599
600 const bool is_selected = tselem->flag & TSE_SELECTED;
601 if ((is_selected && do_selected) || (has_parent_selected && do_content)) {
602 if (((tselem->type == TSE_SOME_ID) && (element->idcode != 0)) ||
603 tselem->type == TSE_LAYER_COLLECTION)
604 {
605 TreeStoreElem *tsep = element->parent ? TREESTORE(element->parent) : nullptr;
606 operation_fn(C, reports, scene, element, tsep, tselem);
607 }
608 }
609 return is_selected;
610}
611
613 ReportList *reports,
614 Scene *scene,
615 SpaceOutliner *space_outliner,
616 const ListBase &subtree,
617 const bool has_parent_selected,
618 outliner_operation_fn operation_fn,
619 eOutlinerLibOpSelectionSet selection_set)
620{
621 LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) {
622 /* Get needed data out in case element gets freed. */
623 TreeStoreElem *tselem = TREESTORE(element);
624 const ListBase subtree = element->subtree;
625
627 C, reports, scene, element, tselem, has_parent_selected, operation_fn, selection_set);
628
629 /* Don't access element from now on, it may be freed. Note that the open/collapsed state may
630 * also have been changed in the visitor callback. */
632 reports,
633 scene,
634 space_outliner,
635 subtree,
636 is_selected || has_parent_selected,
637 operation_fn,
638 selection_set);
639 }
640}
641
643 ReportList *reports,
644 Scene *scene,
645 SpaceOutliner *space_outliner,
646 outliner_operation_fn operation_fn,
647 eOutlinerLibOpSelectionSet selection_set,
648 const bool do_active_element_first)
649{
650 if (do_active_element_first) {
651 TreeElement *active_element = outliner_find_element_with_flag(&space_outliner->tree,
652 TSE_ACTIVE);
653 if (active_element != nullptr) {
654 TreeStoreElem *tselem = TREESTORE(active_element);
655 const ListBase subtree = active_element->subtree;
656
658 C, reports, scene, active_element, tselem, false, operation_fn, selection_set);
659
660 /* Don't access element from now on, it may be freed. Note that the open/collapsed state may
661 * also have been changed in the visitor callback. */
663 C, reports, scene, space_outliner, subtree, is_selected, operation_fn, selection_set);
664 }
665 }
666
668 C, reports, scene, space_outliner, space_outliner->tree, false, operation_fn, selection_set);
669}
670
673/* -------------------------------------------------------------------- */
680
682 {OL_SCENE_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
683 {0, nullptr, 0, nullptr, nullptr},
684};
685
687 bContext *C,
688 SpaceOutliner *space_outliner,
690 bool (*operation_fn)(bContext *, eOutliner_PropSceneOps, TreeElement *, TreeStoreElem *))
691{
692 bool success = false;
693
694 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
695 TreeStoreElem *tselem = TREESTORE(te);
696 if (tselem->flag & TSE_SELECTED) {
697 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) {
698 if (operation_fn(C, event, te, tselem)) {
699 success = true;
700 }
701 }
702 }
703 });
704
705 return success;
706}
707
708static bool scene_fn(bContext *C,
710 TreeElement * /*te*/,
711 TreeStoreElem *tselem)
712{
713 Scene *scene = (Scene *)tselem->id;
714
715 if (event == OL_SCENE_OP_DELETE) {
716 if (ED_scene_delete(C, CTX_data_main(C), scene)) {
718 }
719 else {
720 return false;
721 }
722 }
723
724 return true;
725}
726
728{
729 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
731
732 if (outliner_do_scene_operation(C, space_outliner, event, scene_fn) == false) {
733 return OPERATOR_CANCELLED;
734 }
735
736 if (event == OL_SCENE_OP_DELETE) {
737 outliner_cleanup_tree(space_outliner);
738 ED_undo_push(C, "Delete Scene(s)");
739 }
740 else {
742 return OPERATOR_CANCELLED;
743 }
744
745 return OPERATOR_FINISHED;
746}
747
749{
750 /* identifiers */
751 ot->name = "Outliner Scene Operation";
752 ot->idname = "OUTLINER_OT_scene_operation";
753 ot->description = "Context menu for scene operations";
754
755 /* callbacks */
759
760 ot->flag = 0;
761
762 ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", "");
763}
764
767/* -------------------------------------------------------------------- */
780
782 const ListBase *tree, short tselem_type, short type, const char *str, uiSearchItems *items)
783{
784 char name[64];
785 int iconid;
786
788 TreeStoreElem *tselem = TREESTORE(te);
789
790 if (tree_element_id_type_to_index(te) == type && tselem_type == tselem->type) {
791 if (BLI_strcasestr(te->name, str)) {
792 STRNCPY(name, te->name);
793
794 iconid = tree_element_get_icon(tselem, te).icon;
795
796 /* Don't allow duplicate named items */
797 if (UI_search_items_find_index(items, name) == -1) {
798 if (!UI_search_item_add(items, name, te, iconid, 0, 0)) {
799 break;
800 }
801 }
802 }
803 }
804
805 merged_element_search_fn_recursive(&te->subtree, tselem_type, type, str, items);
806 }
807}
808
809/* Get a list of elements that match the search string */
811 void *data,
812 const char *str,
813 uiSearchItems *items,
814 const bool /*is_first*/)
815{
816 MergedSearchData *search_data = (MergedSearchData *)data;
817 TreeElement *parent = search_data->parent_element;
818 TreeElement *te = search_data->select_element;
819
820 int type = tree_element_id_type_to_index(te);
821
822 merged_element_search_fn_recursive(&parent->subtree, TREESTORE(te)->type, type, str, items);
823}
824
825/* Activate an element from the merged element search menu */
826static void merged_element_search_exec_fn(bContext *C, void * /*arg1*/, void *element)
827{
828 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
829 TreeElement *te = (TreeElement *)element;
830
831 outliner_item_select(C, space_outliner, te, OL_ITEM_SELECT | OL_ITEM_ACTIVATE);
832
833 ED_outliner_select_sync_from_outliner(C, space_outliner);
834}
835
840static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *data)
841{
842 static char search[64] = "";
843 uiBlock *block;
844 uiBut *but;
845
846 /* Clear search on each menu creation */
847 *search = '\0';
848
849 block = UI_block_begin(C, region, __func__, UI_EMBOSS);
852
853 short menu_width = 10 * UI_UNIT_X;
854 but = uiDefSearchBut(
855 block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, "");
857 nullptr,
859 data,
860 false,
861 nullptr,
863 nullptr);
865
866 /* Fake button to hold space for search items */
867 uiDefBut(block,
869 0,
870 "",
871 10,
872 10 - UI_searchbox_size_y(),
873 menu_width,
875 nullptr,
876 0,
877 0,
878 nullptr);
879
880 /* Center the menu on the cursor */
881 const int offset[2] = {-(menu_width / 2), 0};
882 UI_block_bounds_set_popup(block, 6, offset);
883
884 return block;
885}
886
888 TreeElement *parent_te,
889 TreeElement *activate_te)
890{
891 MergedSearchData *select_data = MEM_cnew<MergedSearchData>("merge_search_data");
892 select_data->parent_element = parent_te;
893 select_data->select_element = activate_te;
894
896}
897
899 ReportList * /*reports*/,
900 Scene * /*scene*/,
901 TreeElement * /*te*/,
902 TreeStoreElem * /*tsep*/,
903 TreeStoreElem *tselem)
904{
905 const Scene *scene = CTX_data_scene(C);
906 ViewLayer *view_layer = CTX_data_view_layer(C);
907 Object *ob = (Object *)tselem->id;
908 BKE_view_layer_synced_ensure(scene, view_layer);
909 Base *base = BKE_view_layer_base_find(view_layer, ob);
910
911 if (base) {
913 }
914}
915
918/* -------------------------------------------------------------------- */
923 ReportList * /*reports*/,
924 Scene * /*scene*/,
925 TreeElement *te,
926 TreeStoreElem * /*tsep*/,
927 TreeStoreElem * /*tselem*/)
928{
929 /* Don't extend because this toggles, which is nice for Ctrl-Click but not for a menu item.
930 * it's especially confusing when multiple items are selected since some toggle on/off. */
931 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
933 C, space_outliner, te, OL_ITEM_SELECT | OL_ITEM_ACTIVATE | OL_ITEM_RECURSIVE);
934}
935
937 ReportList * /*reports*/,
938 Scene * /*scene*/,
939 TreeElement * /*te*/,
940 TreeStoreElem * /*tsep*/,
941 TreeStoreElem *tselem)
942{
943 const Scene *scene = CTX_data_scene(C);
944 ViewLayer *view_layer = CTX_data_view_layer(C);
945 Object *ob = (Object *)tselem->id;
946 BKE_view_layer_synced_ensure(scene, view_layer);
947 Base *base = BKE_view_layer_base_find(view_layer, ob);
948
949 if (base) {
950 base->flag &= ~BASE_SELECTED;
951 }
952}
953
954static void outliner_object_delete_fn(bContext *C, ReportList *reports, Scene *scene, Object *ob)
955{
956 if (ob) {
957 Main *bmain = CTX_data_main(C);
958 if (ob->id.tag & ID_TAG_INDIRECT) {
960 reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2);
961 return;
962 }
963 if (ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0 &&
965 {
966 BKE_reportf(reports,
968 "Cannot delete object '%s' from scene '%s', indirectly used objects need at "
969 "least one user",
970 ob->id.name + 2,
971 scene->id.name + 2);
972 return;
973 }
974
975 /* Check also library later. */
976 if ((ob->mode & OB_MODE_EDIT) && BKE_object_is_in_editmode(ob)) {
978 }
979 BKE_id_delete(bmain, ob);
980 }
981}
982
983static void id_local_fn(bContext *C,
984 ReportList * /*reports*/,
985 Scene * /*scene*/,
986 TreeElement * /*te*/,
987 TreeStoreElem * /*tsep*/,
988 TreeStoreElem *tselem)
989{
990 if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & ID_TAG_EXTERN)) {
991 Main *bmain = CTX_data_main(C);
994 }
995 }
996 else if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id)) {
998 }
999}
1000
1019
1022
1025
1031
1035
1042
1045
1046 void id_root_add(ID *id_hierarchy_root_reference,
1047 ID *id_root_reference,
1048 ID *id_instance_hint,
1049 const bool is_override_instancing_object)
1050 {
1051 OutlinerLiboverrideDataIDRoot id_root_data;
1052 id_root_data.id_root_reference = id_root_reference;
1053 id_root_data.id_hierarchy_root_override = nullptr;
1054 id_root_data.id_instance_hint = id_instance_hint;
1055 id_root_data.is_override_instancing_object = is_override_instancing_object;
1056
1057 Vector<OutlinerLiboverrideDataIDRoot> &value = id_hierarchy_roots.lookup_or_add_default(
1058 id_hierarchy_root_reference);
1059 value.append(id_root_data);
1060 }
1061 void id_root_set(ID *id_hierarchy_root_reference)
1062 {
1063 OutlinerLiboverrideDataIDRoot id_root_data;
1064 id_root_data.id_root_reference = nullptr;
1065 id_root_data.id_hierarchy_root_override = nullptr;
1066 id_root_data.id_instance_hint = nullptr;
1067 id_root_data.is_override_instancing_object = false;
1068
1069 Vector<OutlinerLiboverrideDataIDRoot> &value = id_hierarchy_roots.lookup_or_add_default(
1070 id_hierarchy_root_reference);
1071 if (value.is_empty()) {
1072 value.append(id_root_data);
1073 }
1074 }
1075};
1076
1077/* Store 'UUID' of IDs of selected elements in the Outliner tree, before generating the override
1078 * hierarchy. */
1081 ReportList *reports,
1082 TreeElement *te,
1083 TreeStoreElem *tsep,
1084 TreeStoreElem *tselem)
1085{
1086 BLI_assert(TSE_IS_REAL_ID(tselem));
1087
1088 const bool do_hierarchy = data->do_hierarchy;
1089 ID *id_root_reference = tselem->id;
1090
1091 if (!BKE_idtype_idcode_is_linkable(GS(id_root_reference->name)) ||
1093 0)
1094 {
1095 return;
1096 }
1097
1098 /* Only process a given ID once. Otherwise, all kind of weird things can happen if e.g. a
1099 * selected sub-collection is part of more than one override hierarchies. */
1100 if (data->selected_id_uid.contains(id_root_reference->session_uid)) {
1101 return;
1102 }
1103 data->selected_id_uid.add(id_root_reference->session_uid);
1104
1105 if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root_reference) && !ID_IS_LINKED(id_root_reference)) {
1106 id_root_reference->override_library->flag &= ~LIBOVERRIDE_FLAG_SYSTEM_DEFINED;
1107 return;
1108 }
1109
1110 if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id_root_reference)) {
1111 if (ID_IS_LINKED(id_root_reference)) {
1113 reports,
1115 "Could not create library override from data-block '%s', as it is not overridable",
1116 id_root_reference->name);
1117 }
1118 /* Else it's a local ID, do not bother reporting this, as it gets annoyingly noisy then when
1119 * operated e.g. on a hierarchy of liboverrides. */
1120 return;
1121 }
1122
1123 BLI_assert(do_hierarchy);
1124 UNUSED_VARS_NDEBUG(do_hierarchy);
1125
1126 if (GS(id_root_reference->name) == ID_GR && (tselem->flag & TSE_CLOSED) != 0) {
1127 /* If selected element is a (closed) collection, check all of its objects recursively, and also
1128 * consider the armature ones as 'selected' (i.e. to not become system overrides). */
1129 Collection *root_collection = reinterpret_cast<Collection *>(id_root_reference);
1130 FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (root_collection, object_iter) {
1131 if (id_root_reference->lib == object_iter->id.lib && object_iter->type == OB_ARMATURE) {
1132 data->selected_id_uid.add(object_iter->id.session_uid);
1133 }
1134 }
1136 }
1137
1138 ID *id_instance_hint = nullptr;
1139 bool is_override_instancing_object = false;
1140 if (tsep != nullptr && tsep->type == TSE_SOME_ID && tsep->id != nullptr &&
1141 GS(tsep->id->name) == ID_OB && !ID_IS_OVERRIDE_LIBRARY(tsep->id))
1142 {
1143 Object *ob = reinterpret_cast<Object *>(tsep->id);
1144 if (ob->type == OB_EMPTY && &ob->instance_collection->id == id_root_reference) {
1145 BLI_assert(GS(id_root_reference->name) == ID_GR);
1146 /* Empty instantiating the collection we override, we need to pass it to BKE overriding code
1147 * for proper handling. */
1148 id_instance_hint = tsep->id;
1149 is_override_instancing_object = true;
1150 }
1151 }
1152
1153 if (!ID_IS_OVERRIDABLE_LIBRARY(id_root_reference) &&
1154 !(ID_IS_LINKED(id_root_reference) && do_hierarchy))
1155 {
1156 return;
1157 }
1158
1159 Main *bmain = CTX_data_main(C);
1160
1161 if (do_hierarchy) {
1162 /* Tag all linked parents in tree hierarchy to be also overridden. */
1163 ID *id_hierarchy_root_reference = id_root_reference;
1164 while ((te = te->parent) != nullptr) {
1165 if (!TSE_IS_REAL_ID(te->store_elem)) {
1166 continue;
1167 }
1168
1169 /* Tentative hierarchy root. */
1170 ID *id_current_hierarchy_root = te->store_elem->id;
1171
1172 /* If the parent ID is from a different library than the reference root one, we are done
1173 * with upwards tree processing in any case. */
1174 if (id_current_hierarchy_root->lib != id_root_reference->lib) {
1175 if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id_current_hierarchy_root)) {
1176 /* Virtual overrides (i.e. embedded IDs), we can simply keep processing their parent to
1177 * get an actual real override. */
1178 continue;
1179 }
1180
1181 /* If the parent ID is already an override, and is valid (i.e. local override), we can
1182 * access its hierarchy root directly. */
1183 if (!ID_IS_LINKED(id_current_hierarchy_root) &&
1184 ID_IS_OVERRIDE_LIBRARY_REAL(id_current_hierarchy_root) &&
1185 id_current_hierarchy_root->override_library->reference->lib == id_root_reference->lib)
1186 {
1187 id_hierarchy_root_reference =
1188 id_current_hierarchy_root->override_library->hierarchy_root;
1189 BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
1190 break;
1191 }
1192
1193 if (ID_IS_LINKED(id_current_hierarchy_root)) {
1194 /* No local 'anchor' was found for the hierarchy to override, do not proceed, as this
1195 * would most likely generate invisible/confusing/hard to use and manage overrides. */
1196 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
1197 BKE_reportf(reports,
1199 "Invalid anchor ('%s') found, needed to create library override from "
1200 "data-block '%s'",
1201 id_current_hierarchy_root->name,
1202 id_root_reference->name);
1203 return;
1204 }
1205
1206 /* In all other cases, `id_current_hierarchy_root` cannot be a valid hierarchy root, so
1207 * current `id_hierarchy_root_reference` is our best candidate. */
1208
1209 break;
1210 }
1211
1212 /* If some element in the tree needs to be overridden, but its ID is not overridable,
1213 * abort. */
1214 if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id_current_hierarchy_root)) {
1215 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
1216 BKE_reportf(reports,
1218 "Could not create library override from data-block '%s', one of its parents "
1219 "is not overridable ('%s')",
1220 id_root_reference->name,
1221 id_current_hierarchy_root->name);
1222 return;
1223 }
1224 id_current_hierarchy_root->tag |= ID_TAG_DOIT;
1225 id_hierarchy_root_reference = id_current_hierarchy_root;
1226 }
1227
1228 /* That case can happen when linked data is a complex mix involving several libraries and/or
1229 * linked overrides. E.g. a mix of overrides from one library, and indirectly linked data
1230 * from another library. Do not try to support such cases for now. */
1231 if (!((id_hierarchy_root_reference->lib == id_root_reference->lib) ||
1232 (!ID_IS_LINKED(id_hierarchy_root_reference) &&
1233 ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference) &&
1234 id_hierarchy_root_reference->override_library->reference->lib ==
1235 id_root_reference->lib)))
1236 {
1237 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
1238 BKE_reportf(reports,
1240 "Invalid hierarchy root ('%s') found, needed to create library override from "
1241 "data-block '%s'",
1242 id_hierarchy_root_reference->name,
1243 id_root_reference->name);
1244 return;
1245 }
1246
1247 /* While ideally this should not be needed, in practice user almost _never_ wants to actually
1248 * create liboverrides for all data under a selected hierarchy node, and this has currently a
1249 * dreadful consequences over performances (since it would call
1250 * #BKE_lib_override_library_create over _all_ items in the hierarchy). So only the clearing of
1251 * the system override flag is supported for non-selected items for now.
1252 */
1253 const bool is_selected = tselem->flag & TSE_SELECTED;
1254 if (!is_selected && data->id_hierarchy_roots.contains(id_hierarchy_root_reference)) {
1255 return;
1256 }
1257
1258 data->id_root_add(id_hierarchy_root_reference,
1259 id_root_reference,
1260 id_instance_hint,
1261 is_override_instancing_object);
1262 }
1263 else if (ID_IS_OVERRIDABLE_LIBRARY(id_root_reference)) {
1264 data->id_root_add(
1265 id_root_reference, id_root_reference, id_instance_hint, is_override_instancing_object);
1266 }
1267}
1268
1270 Main &bmain,
1271 Scene *scene,
1272 ViewLayer *view_layer,
1274 ID *id_hierarchy_root_reference,
1276 bool &r_aggregated_success)
1277{
1278 BLI_assert(ID_IS_LINKED(id_hierarchy_root_reference) ||
1279 ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
1280
1281 const bool do_hierarchy = data.do_hierarchy;
1282
1283 /* NOTE: This process is not the most efficient, but allows to re-use existing code.
1284 * If this becomes a bottle-neck at some point, we need to implement a new
1285 * `BKE_lib_override_library_hierarchy_create()` function able to process several roots inside of
1286 * a same hierarchy in a single call. */
1287 for (OutlinerLiboverrideDataIDRoot &data_idroot : data_idroots) {
1288 /* For now, remap all local usages of linked ID to local override one here. */
1289 ID *id_iter;
1290 FOREACH_MAIN_ID_BEGIN (&bmain, id_iter) {
1291 if (ID_IS_LINKED(id_iter) || ID_IS_OVERRIDE_LIBRARY(id_iter)) {
1292 id_iter->tag &= ~ID_TAG_DOIT;
1293 }
1294 else {
1295 id_iter->tag |= ID_TAG_DOIT;
1296 }
1297 }
1299
1300 bool success = false;
1301 if (do_hierarchy) {
1302 ID *id_root_override = nullptr;
1303 success = BKE_lib_override_library_create(&bmain,
1304 scene,
1305 view_layer,
1306 nullptr,
1307 data_idroot.id_root_reference,
1308 id_hierarchy_root_reference,
1309 data_idroot.id_instance_hint,
1310 &id_root_override,
1311 data.do_fully_editable);
1312
1313 if (success) {
1314 BLI_assert(id_root_override != nullptr);
1315 BLI_assert(!ID_IS_LINKED(id_root_override));
1316 BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root_override));
1317
1318 ID *id_hierarchy_root_override = id_root_override->override_library->hierarchy_root;
1319 BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_override));
1320 if (ID_IS_LINKED(id_hierarchy_root_reference)) {
1321 BLI_assert(id_hierarchy_root_override->override_library->reference ==
1322 id_hierarchy_root_reference);
1323 /* If the hierarchy root reference was a linked data, after the first iteration there is
1324 * now a matching override, which shall be used for all further partial overrides with
1325 * this same hierarchy. */
1326 id_hierarchy_root_reference = id_hierarchy_root_override;
1327 }
1328 else {
1329 BLI_assert(id_hierarchy_root_override == id_hierarchy_root_reference);
1330 }
1331 data_idroot.id_hierarchy_root_override = id_hierarchy_root_override;
1332 data.id_hierarchy_roots_uid.add(id_hierarchy_root_override->session_uid);
1333 }
1334 }
1335 else if (ID_IS_OVERRIDABLE_LIBRARY(data_idroot.id_root_reference)) {
1336 ID *id_root_override = BKE_lib_override_library_create_from_id(
1337 &bmain, data_idroot.id_root_reference, true);
1338
1339 success = id_root_override != nullptr;
1340 if (success) {
1341 BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root_override));
1342 id_root_override->override_library->flag &= ~LIBOVERRIDE_FLAG_SYSTEM_DEFINED;
1343 }
1344 /* Cleanup. */
1346 BKE_main_id_tag_all(&bmain, ID_TAG_DOIT, false);
1347 }
1348 else {
1350 }
1351
1352 /* Remove the instance empty from this scene, the items now have an overridden collection
1353 * instead. */
1354 if (success && data_idroot.is_override_instancing_object) {
1355 BLI_assert(GS(data_idroot.id_instance_hint->name) == ID_OB);
1357 &bmain, scene, reinterpret_cast<Object *>(data_idroot.id_instance_hint));
1358 }
1359
1360 r_aggregated_success = r_aggregated_success && success;
1361 }
1362}
1363
1364/* Clear system override flag from newly created overrides which linked reference were previously
1365 * selected in the Outliner tree. */
1367 ReportList *reports,
1369{
1370 Main *bmain = CTX_data_main(C);
1371 Scene *scene = CTX_data_scene(C);
1372 ViewLayer *view_layer = CTX_data_view_layer(C);
1373 const bool do_hierarchy = data.do_hierarchy;
1374
1375 bool success = true;
1376 for (auto &&[id_hierarchy_root_reference, data_idroots] : data.id_hierarchy_roots.items()) {
1378 *bmain, scene, view_layer, data, id_hierarchy_root_reference, data_idroots, success);
1379 }
1380
1381 if (!success) {
1382 BKE_reportf(reports,
1384 "Could not create library override from one or more of the selected data-blocks");
1385 }
1386
1387 if (!do_hierarchy) {
1388 return;
1389 }
1390
1391 ID *id_iter;
1392 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
1393 if (ID_IS_LINKED(id_iter) || !ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) {
1394 continue;
1395 }
1396 if (id_iter->override_library->hierarchy_root != nullptr &&
1397 !data.id_hierarchy_roots_uid.contains(
1399 {
1400 continue;
1401 }
1402 if (data.selected_id_uid.contains(id_iter->override_library->reference->session_uid) ||
1403 data.selected_id_uid.contains(id_iter->session_uid))
1404 {
1405 id_iter->override_library->flag &= ~LIBOVERRIDE_FLAG_SYSTEM_DEFINED;
1406 }
1407 }
1409}
1410
1413 TreeStoreElem *tselem)
1414{
1415 BLI_assert(TSE_IS_REAL_ID(tselem));
1416 ID *id_root = tselem->id;
1417 const bool do_hierarchy = data->do_hierarchy;
1418
1419 if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) {
1420 CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name);
1421 return;
1422 }
1423
1424 Main *bmain = CTX_data_main(C);
1425
1426 if (do_hierarchy) {
1427 BKE_lib_override_library_id_hierarchy_reset(bmain, id_root, false);
1428 }
1429 else {
1430 BKE_lib_override_library_id_reset(bmain, id_root, false);
1431 }
1432}
1433
1435 ReportList * /*reports*/,
1437{
1438 Main *bmain = CTX_data_main(C);
1439 ViewLayer *view_layer = CTX_data_view_layer(C);
1440 Scene *scene = CTX_data_scene(C);
1441
1442 /* TODO: At some point this likely needs to be re-written as a BKE function instead, with better
1443 * handling of hierarchies among other things. */
1444
1445 /* Try to process all potential leaves first (deleting some liboverride leaves will turn other
1446 * liboverrides into leaves as well). */
1447 bool do_process_leaves = true;
1448 while (!data.id_hierarchy_roots.is_empty()) {
1449 bool has_found_leaves = false;
1450
1451 for (auto &&id : data.id_hierarchy_roots.keys()) {
1452 if (do_process_leaves) {
1454 /* If given ID is not using any other override (it's a 'leaf' in the override hierarchy),
1455 * delete it and remap its usages to its linked reference. Otherwise, keep it as a reset
1456 * system override. */
1457 bool do_remap_active = false;
1458 BKE_view_layer_synced_ensure(scene, view_layer);
1459 if (BKE_view_layer_active_object_get(view_layer) == reinterpret_cast<Object *>(id)) {
1460 BLI_assert(GS(id->name) == ID_OB);
1461 do_remap_active = true;
1462 }
1464 bmain, id, id->override_library->reference, ID_REMAP_SKIP_INDIRECT_USAGE);
1465 if (do_remap_active) {
1466 BKE_view_layer_synced_ensure(scene, view_layer);
1467 Object *ref_object = reinterpret_cast<Object *>(id->override_library->reference);
1468 Base *basact = BKE_view_layer_base_find(view_layer, ref_object);
1469 if (basact != nullptr) {
1470 view_layer->basact = basact;
1471 }
1473 }
1474
1475 BKE_id_delete(bmain, id);
1476 data.id_hierarchy_roots.remove(id);
1477 has_found_leaves = true;
1478 }
1479 }
1480 else {
1482 BKE_lib_override_library_id_reset(bmain, id, true);
1483 data.id_hierarchy_roots.remove(id);
1484 }
1485 }
1486
1487 do_process_leaves = has_found_leaves;
1488 }
1490}
1491
1493 ReportList *reports,
1494 TreeStoreElem *tselem)
1495{
1496 BLI_assert(TSE_IS_REAL_ID(tselem));
1497 ID *id = tselem->id;
1498
1499 if (!ID_IS_OVERRIDE_LIBRARY(id)) {
1500 return;
1501 }
1502 if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
1503 BKE_reportf(reports,
1505 "Cannot clear embedded library override '%s', only overrides of real data-blocks "
1506 "can be directly cleared",
1507 id->name);
1508 return;
1509 }
1510 if (ID_IS_LINKED(id)) {
1512 reports,
1514 "Cannot clear linked library override '%s', only local overrides can be directly cleared",
1515 id->name);
1516 return;
1517 }
1518
1519 data->id_root_set(id);
1520}
1521
1523{
1524 BLI_assert(TSE_IS_REAL_ID(tselem));
1525 ID *id_root = tselem->id;
1526
1527 if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) {
1528 CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name);
1529 return;
1530 }
1531
1532 if (id_root->override_library->hierarchy_root != nullptr) {
1533 id_root = id_root->override_library->hierarchy_root;
1534 }
1535
1536 data->id_root_set(id_root);
1537}
1538
1539/* Resync a hierarchy of library overrides. */
1541 ReportList *reports,
1543{
1544 Main *bmain = CTX_data_main(C);
1545 Scene *scene = CTX_data_scene(C);
1546 const bool do_hierarchy_enforce = data.do_resync_hierarchy_enforce;
1547
1548 BlendFileReadReport report{};
1549 report.reports = reports;
1550
1551 for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) {
1553 scene,
1555 id_hierarchy_root,
1556 nullptr,
1557 do_hierarchy_enforce,
1558 &report);
1559 }
1560
1561 WM_event_add_notifier(C, NC_WINDOW, nullptr);
1562}
1563
1565 TreeStoreElem *tselem)
1566{
1567 BLI_assert(TSE_IS_REAL_ID(tselem));
1568 ID *id_root = tselem->id;
1569
1570 if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) {
1571 CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name);
1572 return;
1573 }
1574
1575 if (id_root->override_library->hierarchy_root != nullptr) {
1576 id_root = id_root->override_library->hierarchy_root;
1577 }
1578
1579 data->id_root_set(id_root);
1580}
1581
1582/* Clear (delete) a hierarchy of library overrides. */
1584 ReportList * /*reports*/,
1586{
1587 Main *bmain = CTX_data_main(C);
1588
1589 for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) {
1590 BKE_lib_override_library_delete(bmain, id_hierarchy_root);
1591 }
1592}
1593
1594static void id_fake_user_set_fn(bContext * /*C*/,
1595 ReportList * /*reports*/,
1596 Scene * /*scene*/,
1597 TreeElement * /*te*/,
1598 TreeStoreElem * /*tsep*/,
1599 TreeStoreElem *tselem)
1600{
1601 ID *id = tselem->id;
1602
1603 id_fake_user_set(id);
1604}
1605
1607 ReportList * /*reports*/,
1608 Scene * /*scene*/,
1609 TreeElement * /*te*/,
1610 TreeStoreElem * /*tsep*/,
1611 TreeStoreElem *tselem)
1612{
1613 ID *id = tselem->id;
1614
1616}
1617
1619 ReportList * /*reports*/,
1620 Scene * /*scene*/,
1621 TreeElement * /*te*/,
1622 TreeStoreElem * /*tsep*/,
1623 TreeStoreElem *tselem)
1624{
1625 ID *id = tselem->id;
1626
1628}
1629
1631 ReportList * /*reports*/,
1632 Scene * /*scene*/,
1633 TreeElement *te,
1634 TreeStoreElem *tsep,
1635 TreeStoreElem *tselem)
1636{
1637 /* This callback runs for all selected elements, some of which may not be actions which results
1638 * in a crash. */
1639 if (te->idcode != ID_AC) {
1640 return;
1641 }
1642
1643 ID *id = tselem->id;
1644
1645 if (id) {
1646 IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id;
1647 PropertyRNA *prop;
1648
1649 PointerRNA ptr = RNA_pointer_create(&iat->id, &RNA_AnimData, iat->adt);
1650 prop = RNA_struct_find_property(&ptr, "action");
1651
1652 id_single_user(C, id, &ptr, prop);
1653 }
1654}
1655
1657 ReportList * /*reports*/,
1658 Scene * /*scene*/,
1659 TreeElement * /*te*/,
1660 TreeStoreElem *tsep,
1661 TreeStoreElem *tselem)
1662{
1663 ID *id = tselem->id;
1664
1665 /* need to use parent scene not just scene, otherwise may end up getting wrong one */
1666 if (id) {
1667 Scene *parscene = (Scene *)tsep->id;
1668 PropertyRNA *prop;
1669
1670 PointerRNA ptr = RNA_id_pointer_create(&parscene->id);
1671 prop = RNA_struct_find_property(&ptr, "world");
1672
1673 id_single_user(C, id, &ptr, prop);
1674 }
1675}
1676
1678 ReportList *reports,
1679 Scene *scene_act,
1680 SpaceOutliner *space_outliner,
1681 ListBase *lb,
1682 outliner_operation_fn operation_fn,
1683 bool recurse_selected)
1684{
1685 LISTBASE_FOREACH (TreeElement *, te, lb) {
1686 TreeStoreElem *tselem = TREESTORE(te);
1687 bool select_handled = false;
1688 if (tselem->flag & TSE_SELECTED) {
1689 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1690 /* When objects selected in other scenes, don't know if that should be allowed. */
1691 Scene *scene_owner = (Scene *)outliner_search_back(te, ID_SCE);
1692 if (scene_owner && scene_act != scene_owner) {
1694 }
1695 /* Important to use 'scene_owner' not scene_act else deleting objects can crash.
1696 * only use 'scene_act' when 'scene_owner' is nullptr, which can happen when the
1697 * outliner isn't showing scenes: Visible Layer draw mode for eg. */
1698 operation_fn(C, reports, scene_owner ? scene_owner : scene_act, te, nullptr, tselem);
1699 select_handled = true;
1700 }
1701 }
1702 if (TSELEM_OPEN(tselem, space_outliner)) {
1703 if ((select_handled == false) || recurse_selected) {
1705 C, reports, scene_act, space_outliner, &te->subtree, operation_fn, recurse_selected);
1706 }
1707 }
1708 }
1709}
1710
1712 ReportList *reports,
1713 Scene *scene_act,
1714 SpaceOutliner *space_outliner,
1715 ListBase *lb,
1716 outliner_operation_fn operation_fn)
1717{
1718 outliner_do_object_operation_ex(C, reports, scene_act, space_outliner, lb, operation_fn, true);
1719}
1720
1723/* -------------------------------------------------------------------- */
1727static void clear_animdata_fn(int /*event*/,
1728 TreeElement * /*te*/,
1729 TreeStoreElem *tselem,
1730 void * /*arg*/)
1731{
1732 BKE_animdata_free(tselem->id, true);
1734}
1735
1736static void unlinkact_animdata_fn(int /*event*/,
1737 TreeElement * /*te*/,
1738 TreeStoreElem *tselem,
1739 void * /*arg*/)
1740{
1741 /* just set action to nullptr */
1742 BKE_animdata_set_action(nullptr, tselem->id, nullptr);
1744}
1745
1746static void cleardrivers_animdata_fn(int /*event*/,
1747 TreeElement * /*te*/,
1748 TreeStoreElem *tselem,
1749 void * /*arg*/)
1750{
1751 IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id;
1752
1753 /* just free drivers - stored as a list of F-Curves */
1756}
1757
1758static void refreshdrivers_animdata_fn(int /*event*/,
1759 TreeElement * /*te*/,
1760 TreeStoreElem *tselem,
1761 void * /*arg*/)
1762{
1763 IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id;
1764
1765 /* Loop over drivers, performing refresh
1766 * (i.e. check `graph_buttons.cc` and `rna_fcurve.cc` for details). */
1767 LISTBASE_FOREACH (FCurve *, fcu, &iat->adt->drivers) {
1768 fcu->flag &= ~FCURVE_DISABLED;
1769
1770 if (fcu->driver) {
1771 fcu->driver->flag &= ~DRIVER_FLAG_INVALID;
1772 }
1773 }
1774}
1775
1778/* -------------------------------------------------------------------- */
1793
1796 "OVERRIDE_LIBRARY_CREATE_HIERARCHY",
1797 0,
1798 "Make",
1799 "Create a local override of the selected linked data-blocks, and their hierarchy of "
1800 "dependencies"},
1802 "OVERRIDE_LIBRARY_RESET",
1803 0,
1804 "Reset",
1805 "Reset the selected local overrides to their linked references values"},
1807 "OVERRIDE_LIBRARY_CLEAR_SINGLE",
1808 0,
1809 "Clear",
1810 "Delete the selected local overrides and relink their usages to the linked data-blocks if "
1811 "possible, else reset them and mark them as non editable"},
1812 {0, nullptr, 0, nullptr, nullptr},
1813};
1814
1817 "OVERRIDE_LIBRARY_RESYNC_HIERARCHY",
1818 0,
1819 "Resync",
1820 "Rebuild the selected local overrides from their linked references, as well as their "
1821 "hierarchies of dependencies"},
1823 "OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE",
1824 0,
1825 "Resync Enforce",
1826 "Rebuild the selected local overrides from their linked references, as well as their "
1827 "hierarchies of dependencies, enforcing these hierarchies to match the linked data (i.e. "
1828 "ignoring existing overrides on data-blocks pointer properties)"},
1831 "OVERRIDE_LIBRARY_DELETE_HIERARCHY",
1832 0,
1833 "Delete",
1834 "Delete the selected local overrides (including their hierarchies of override dependencies) "
1835 "and relink their usages to the linked data-blocks"},
1836 {0, nullptr, 0, nullptr, nullptr},
1837};
1838
1840{
1842 return false;
1843 }
1844 return true;
1845}
1846
1848{
1849 Scene *scene = CTX_data_scene(C);
1850 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1851
1852 /* check for invalid states */
1853 if (space_outliner == nullptr) {
1854 return OPERATOR_CANCELLED;
1855 }
1856
1857 const eOutlinerLibOpSelectionSet selection_set = static_cast<eOutlinerLibOpSelectionSet>(
1858 RNA_enum_get(op->ptr, "selection_set"));
1860 RNA_enum_get(op->ptr, "type"));
1861 switch (event) {
1863 OutlinerLibOverrideData override_data{};
1864 override_data.do_hierarchy = true;
1865 override_data.do_fully_editable = false;
1866
1868 C,
1869 op->reports,
1870 scene,
1871 space_outliner,
1872 [&](bContext *C,
1873 ReportList *reports,
1874 Scene * /*scene*/,
1875 TreeElement *te,
1876 TreeStoreElem *tsep,
1877 TreeStoreElem *tselem) {
1878 id_override_library_create_hierarchy_pre_process(
1879 C, &override_data, reports, te, tsep, tselem);
1880 },
1881 selection_set,
1882 true);
1883
1885
1886 ED_undo_push(C, "Overridden Data Hierarchy");
1887 break;
1888 }
1890 OutlinerLibOverrideData override_data{};
1892 C,
1893 op->reports,
1894 scene,
1895 space_outliner,
1896 [&](bContext *C,
1897 ReportList * /*reports*/,
1898 Scene * /*scene*/,
1899 TreeElement * /*te*/,
1900 TreeStoreElem * /*tsep*/,
1901 TreeStoreElem *tselem) { id_override_library_reset(C, &override_data, tselem); },
1902 selection_set,
1903 false);
1904 ED_undo_push(C, "Reset Overridden Data");
1905 break;
1906 }
1908 OutlinerLibOverrideData override_data{};
1909 override_data.do_hierarchy = false;
1910 override_data.do_fully_editable = false;
1911
1913 C,
1914 op->reports,
1915 scene,
1916 space_outliner,
1917 [&](bContext * /*C*/,
1918 ReportList *reports,
1919 Scene * /*scene*/,
1920 TreeElement * /*te*/,
1921 TreeStoreElem * /*tsep*/,
1922 TreeStoreElem *tselem) {
1923 id_override_library_clear_single(&override_data, reports, tselem);
1924 },
1925 selection_set,
1926 false);
1927
1929
1930 ED_undo_push(C, "Clear Overridden Data");
1931 break;
1932 }
1933
1935 OutlinerLibOverrideData override_data{};
1936 override_data.do_hierarchy = true;
1938 C,
1939 op->reports,
1940 scene,
1941 space_outliner,
1942 [&](bContext * /*C*/,
1943 ReportList * /*reports*/,
1944 Scene * /*scene*/,
1945 TreeElement * /*te*/,
1946 TreeStoreElem * /*tsep*/,
1947 TreeStoreElem *tselem) { id_override_library_resync(&override_data, tselem); },
1949 false);
1950
1952
1953 ED_undo_push(C, "Resync Overridden Data Hierarchy");
1954 break;
1955 }
1957 OutlinerLibOverrideData override_data{};
1958 override_data.do_hierarchy = true;
1959 override_data.do_resync_hierarchy_enforce = true;
1961 C,
1962 op->reports,
1963 scene,
1964 space_outliner,
1965 [&](bContext * /*C*/,
1966 ReportList * /*reports*/,
1967 Scene * /*scene*/,
1968 TreeElement * /*te*/,
1969 TreeStoreElem * /*tsep*/,
1970 TreeStoreElem *tselem) { id_override_library_resync(&override_data, tselem); },
1972 false);
1973
1975
1976 ED_undo_push(C, "Resync Overridden Data Hierarchy Enforce");
1977 break;
1978 }
1980 OutlinerLibOverrideData override_data{};
1981 override_data.do_hierarchy = true;
1983 C,
1984 op->reports,
1985 scene,
1986 space_outliner,
1987 [&](bContext * /*C*/,
1988 ReportList * /*reports*/,
1989 Scene * /*scene*/,
1990 TreeElement * /*te*/,
1991 TreeStoreElem * /*tsep*/,
1992 TreeStoreElem *tselem) {
1993 id_override_library_delete_hierarchy(&override_data, tselem);
1994 },
1996 false);
1997
1999
2000 ED_undo_push(C, "Delete Overridden Data Hierarchy");
2001 break;
2002 }
2003 default:
2004 /* Invalid - unhandled. */
2005 break;
2006 }
2007
2008 WM_event_add_notifier(C, NC_WINDOW, nullptr);
2011
2012 return OPERATOR_FINISHED;
2013}
2014
2016{
2017 /* identifiers */
2018 ot->name = "Outliner Library Override Operation";
2019 ot->idname = "OUTLINER_OT_liboverride_operation";
2020 ot->description = "Create, reset or clear library override hierarchies";
2021
2022 /* callbacks */
2026
2027 ot->flag = 0;
2028
2029 RNA_def_enum(ot->srna, "type", prop_liboverride_op_types, 0, "Library Override Operation", "");
2031 "selection_set",
2033 0,
2034 "Selection Set",
2035 "Over which part of the tree items to apply the operation");
2036}
2037
2039{
2040 /* identifiers */
2041 ot->name = "Outliner Library Override Troubleshoot Operation";
2042 ot->idname = "OUTLINER_OT_liboverride_troubleshoot_operation";
2043 ot->description = "Advanced operations over library override to help fix broken hierarchies";
2044
2045 /* callbacks */
2049
2050 ot->flag = 0;
2051
2053 "type",
2055 0,
2056 "Library Override Troubleshoot Operation",
2057 "");
2059 "selection_set",
2061 0,
2062 "Selection Set",
2063 "Over which part of the tree items to apply the operation");
2064}
2065
2068/* -------------------------------------------------------------------- */
2079
2085
2092
2093static void pchan_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, void * /*arg*/)
2094{
2095 bPoseChannel *pchan = (bPoseChannel *)te->directdata;
2096
2097 if (event == OL_DOP_SELECT) {
2098 pchan->bone->flag |= BONE_SELECTED;
2099 }
2100 else if (event == OL_DOP_DESELECT) {
2101 pchan->bone->flag &= ~BONE_SELECTED;
2102 }
2103 else if (event == OL_DOP_HIDE) {
2104 pchan->bone->flag |= BONE_HIDDEN_P;
2105 pchan->bone->flag &= ~BONE_SELECTED;
2106 }
2107 else if (event == OL_DOP_UNHIDE) {
2108 pchan->bone->flag &= ~BONE_HIDDEN_P;
2109 }
2110}
2111
2112static void bone_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, void * /*arg*/)
2113{
2114 Bone *bone = (Bone *)te->directdata;
2115
2116 if (event == OL_DOP_SELECT) {
2117 bone->flag |= BONE_SELECTED;
2118 }
2119 else if (event == OL_DOP_DESELECT) {
2120 bone->flag &= ~BONE_SELECTED;
2121 }
2122 else if (event == OL_DOP_HIDE) {
2123 bone->flag |= BONE_HIDDEN_P;
2124 bone->flag &= ~BONE_SELECTED;
2125 }
2126 else if (event == OL_DOP_UNHIDE) {
2127 bone->flag &= ~BONE_HIDDEN_P;
2128 }
2129}
2130
2131static void ebone_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, void * /*arg*/)
2132{
2133 EditBone *ebone = (EditBone *)te->directdata;
2134
2135 if (event == OL_DOP_SELECT) {
2136 ebone->flag |= BONE_SELECTED;
2137 }
2138 else if (event == OL_DOP_DESELECT) {
2139 ebone->flag &= ~BONE_SELECTED;
2140 }
2141 else if (event == OL_DOP_HIDE) {
2142 ebone->flag |= BONE_HIDDEN_A;
2143 ebone->flag &= ~BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
2144 }
2145 else if (event == OL_DOP_UNHIDE) {
2146 ebone->flag &= ~BONE_HIDDEN_A;
2147 }
2148}
2149
2150static void sequence_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, void *scene_ptr)
2151{
2153 Sequence *seq = &te_seq->get_sequence();
2154 Scene *scene = (Scene *)scene_ptr;
2155 Editing *ed = SEQ_editing_get(scene);
2156 if (BLI_findindex(ed->seqbasep, seq) != -1) {
2157 if (event == OL_DOP_SELECT) {
2158 ED_sequencer_select_sequence_single(scene, seq, true);
2159 }
2160 else if (event == OL_DOP_DESELECT) {
2161 seq->flag &= ~SELECT;
2162 }
2163 else if (event == OL_DOP_HIDE) {
2164 if (!(seq->flag & SEQ_MUTE)) {
2165 seq->flag |= SEQ_MUTE;
2167 }
2168 }
2169 else if (event == OL_DOP_UNHIDE) {
2170 if (seq->flag & SEQ_MUTE) {
2171 seq->flag &= ~SEQ_MUTE;
2173 }
2174 }
2175 }
2176}
2177
2178static void gpencil_layer_fn(int event,
2179 TreeElement *te,
2180 TreeStoreElem * /*tselem*/,
2181 void * /*arg*/)
2182{
2183 bGPDlayer *gpl = (bGPDlayer *)te->directdata;
2184
2185 if (event == OL_DOP_SELECT) {
2186 gpl->flag |= GP_LAYER_SELECT;
2187 }
2188 else if (event == OL_DOP_DESELECT) {
2189 gpl->flag &= ~GP_LAYER_SELECT;
2190 }
2191 else if (event == OL_DOP_HIDE) {
2192 gpl->flag |= GP_LAYER_HIDE;
2193 }
2194 else if (event == OL_DOP_UNHIDE) {
2195 gpl->flag &= ~GP_LAYER_HIDE;
2196 }
2197}
2198
2199static void grease_pencil_node_fn(int event,
2200 TreeElement *te,
2201 TreeStoreElem * /*tselem*/,
2202 void * /*arg*/)
2203{
2205
2206 if (event == OL_DOP_SELECT) {
2207 node.set_selected(true);
2208 }
2209 else if (event == OL_DOP_DESELECT) {
2210 node.set_selected(false);
2211 }
2212 else if (event == OL_DOP_HIDE) {
2213 node.set_visible(false);
2214 }
2215 else if (event == OL_DOP_UNHIDE) {
2216 node.set_visible(true);
2217 }
2218}
2219
2220static void data_select_linked_fn(int event,
2221 TreeElement *te,
2222 TreeStoreElem * /*tselem*/,
2223 void *C_v)
2224{
2226 if (!te_rna_struct) {
2227 return;
2228 }
2229
2230 if (event == OL_DOP_SELECT_LINKED) {
2231 const PointerRNA &ptr = te_rna_struct->get_pointer_rna();
2232 if (RNA_struct_is_ID(ptr.type)) {
2233 bContext *C = (bContext *)C_v;
2234 ID *id = static_cast<ID *>(ptr.data);
2235
2237 }
2238 }
2239}
2240
2241static void constraint_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, void *C_v)
2242{
2243 bContext *C = static_cast<bContext *>(C_v);
2244 Main *bmain = CTX_data_main(C);
2245 bConstraint *constraint = (bConstraint *)te->directdata;
2247
2248 if (event == OL_CONSTRAINTOP_ENABLE) {
2249 constraint->flag &= ~CONSTRAINT_OFF;
2250 object::constraint_update(bmain, ob);
2252 }
2253 else if (event == OL_CONSTRAINTOP_DISABLE) {
2254 constraint->flag |= CONSTRAINT_OFF;
2255 object::constraint_update(bmain, ob);
2257 }
2258 else if (event == OL_CONSTRAINTOP_DELETE) {
2259 ListBase *lb = nullptr;
2260
2261 if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) {
2262 lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints;
2263 }
2264 else {
2265 lb = &ob->constraints;
2266 }
2267
2268 if (BKE_constraint_remove_ex(lb, ob, constraint)) {
2269 /* there's no active constraint now, so make sure this is the case */
2271
2272 /* Needed to set the flags on pose-bones correctly. */
2273 object::constraint_update(bmain, ob);
2274
2276 te->store_elem->flag &= ~TSE_SELECTED;
2277 }
2278 }
2279}
2280
2285
2286static void modifier_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, void *arg)
2287{
2288 ModifierFnArgs *data = static_cast<ModifierFnArgs *>(arg);
2289 bContext *C = data->C;
2290 Main *bmain = CTX_data_main(C);
2291 Scene *scene = CTX_data_scene(C);
2295
2296 if (event == OL_MODIFIER_OP_TOGVIS) {
2300 }
2301 else if (event == OL_MODIFIER_OP_TOGREN) {
2305 }
2306 else if (event == OL_MODIFIER_OP_DELETE) {
2307 object::modifier_remove(data->reports, bmain, scene, ob, md);
2309 te->store_elem->flag &= ~TSE_SELECTED;
2310 }
2311 else if (event == OL_MODIFIER_OP_APPLY) {
2313 bmain, data->reports, depsgraph, scene, ob, md, object::MODIFIER_APPLY_DATA, false, false);
2317 te->store_elem->flag &= ~TSE_SELECTED;
2318 }
2319}
2320
2322 SpaceOutliner *space_outliner,
2323 int type,
2324 int event,
2325 void (*operation_fn)(int, TreeElement *, TreeStoreElem *, void *),
2326 void *arg)
2327{
2328 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2329 TreeStoreElem *tselem = TREESTORE(te);
2330 if (tselem->flag & TSE_SELECTED) {
2331 if (tselem->type == type) {
2332 operation_fn(event, te, tselem, arg);
2333 }
2334 }
2335 });
2336}
2337
2339 Main *bmain,
2340 Scene *scene,
2341 Object *object)
2342{
2343 if (object->id.tag & ID_TAG_INDIRECT) {
2345 reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", object->id.name + 2);
2346 BLI_assert((object->id.tag & ID_TAG_DOIT) == 0);
2347 }
2348 /* FIXME: This code checking object user-count won't work as expected if a same object belongs to
2349 * more than one collection in the scene. */
2350 if (ID_REAL_USERS(object) <= 1 && ID_EXTRA_USERS(object) == 0 &&
2351 BKE_library_ID_is_indirectly_used(bmain, object))
2352 {
2353 BKE_reportf(reports,
2355 "Cannot delete object '%s' from scene '%s', indirectly used objects need at least "
2356 "one user",
2357 object->id.name + 2,
2358 scene->id.name + 2);
2359 BLI_assert((object->id.tag & ID_TAG_DOIT) == 0);
2360 }
2361
2362 object->id.tag |= ID_TAG_DOIT;
2363}
2364
2366 ReportList *reports, Main *bmain, ViewLayer *view_layer, Scene *scene, Base *base)
2367{
2368 Object *object = base->object;
2369 BLI_assert(object != nullptr);
2370
2371 outliner_batch_delete_object_tag(reports, bmain, scene, object);
2372
2373 /* Even though the object itself may not be deletable, some of its children may still be
2374 * deletable. */
2375 for (Base *base_iter = static_cast<Base *>(BKE_view_layer_object_bases_get(view_layer)->first);
2376 base_iter != nullptr;
2377 base_iter = base_iter->next)
2378 {
2379 Object *parent_ob_iter;
2380 for (parent_ob_iter = base_iter->object->parent;
2381 (parent_ob_iter != nullptr && parent_ob_iter != object &&
2382 (parent_ob_iter->id.tag & ID_TAG_DOIT) == 0);
2383 parent_ob_iter = parent_ob_iter->parent)
2384 {
2385 /* pass */
2386 }
2387 if (parent_ob_iter != nullptr) {
2388 /* There is one or more parents to current iterated object that also need to be deleted,
2389 * process the parenting chain again to tag them as such.
2390 *
2391 * NOTE: Since objects that cannot be deleted are not tagged, the relevant 'parenting'
2392 * branches may be looped over more than once. Would not expect this to be a real issue in
2393 * practice though. */
2394 for (parent_ob_iter = base_iter->object;
2395 (parent_ob_iter != nullptr && parent_ob_iter != object &&
2396 (parent_ob_iter->id.tag & ID_TAG_DOIT) == 0);
2397 parent_ob_iter = parent_ob_iter->parent)
2398 {
2399 outliner_batch_delete_object_tag(reports, bmain, scene, parent_ob_iter);
2400 }
2401 }
2402 }
2403}
2404
2406 ReportList *reports,
2407 Scene *scene,
2408 Object *ob)
2409{
2410 if (ob->id.tag & ID_TAG_DOIT) {
2411 /* Object has already been processed and tagged for removal as part of another parenting
2412 * hierarchy. */
2413#ifndef NDEBUG
2414 ViewLayer *view_layer = CTX_data_view_layer(C);
2415 BKE_view_layer_synced_ensure(scene, view_layer);
2416 BLI_assert(BKE_view_layer_base_find(view_layer, ob) == nullptr);
2417#endif
2418 return;
2419 }
2420
2421 ViewLayer *view_layer = CTX_data_view_layer(C);
2422 Object *obedit = CTX_data_edit_object(C);
2423
2424 Base *base = BKE_view_layer_base_find(view_layer, ob);
2425
2426 if (base == nullptr) {
2427 return;
2428 }
2429
2430 /* Exit Edit mode if the active object or one of its children are being edited. */
2431 for (; obedit && (obedit != base->object); obedit = obedit->parent) {
2432 /* pass */
2433 }
2434 if (obedit == base->object) {
2436 }
2437
2438 Main *bmain = CTX_data_main(C);
2439 outliner_batch_delete_object_hierarchy_tag(reports, bmain, view_layer, scene, base);
2440}
2441
2443{
2444 LISTBASE_FOREACH (Object *, ob_iter, &bmain->objects) {
2445 if ((ob_iter->id.tag & ID_TAG_DOIT) == 0) {
2446 continue;
2447 }
2448
2449 BKE_scene_collections_object_remove(bmain, scene, ob_iter, false);
2450
2451 /* Check on all objects tagged for deletion, these that are still in use (e.g. in collections
2452 * from another scene) should not be deleted. They also need to be tagged for depsgraph update.
2453 */
2454 if (ob_iter->id.us != 0) {
2455 ob_iter->id.tag &= ~ID_TAG_DOIT;
2456 DEG_id_tag_update_ex(bmain, &ob_iter->id, ID_RECALC_BASE_FLAGS);
2457 }
2458 }
2459
2461}
2462
2465/* -------------------------------------------------------------------- */
2469enum {
2475};
2476
2478 {OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""},
2479 {OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
2480 {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
2481 {OL_OP_REMAP,
2482 "REMAP",
2483 0,
2484 "Remap Users",
2485 "Make all users of selected data-blocks to use instead a new chosen one"},
2486 {OL_OP_RENAME, "RENAME", 0, "Rename", ""},
2487 {0, nullptr, 0, nullptr, nullptr},
2488};
2489
2491{
2492 Main *bmain = CTX_data_main(C);
2493 Scene *scene = CTX_data_scene(C);
2494 wmWindow *win = CTX_wm_window(C);
2495 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2496 int event;
2497 const char *str = nullptr;
2498 bool selection_changed = false;
2499
2500 /* check for invalid states */
2501 if (space_outliner == nullptr) {
2502 return OPERATOR_CANCELLED;
2503 }
2504
2505 event = RNA_enum_get(op->ptr, "type");
2506
2507 switch (event) {
2508 case OL_OP_SELECT: {
2509 Scene *sce = scene; /* To be able to delete, scenes are set... */
2511 C, op->reports, scene, space_outliner, &space_outliner->tree, object_select_fn);
2512 /* FIXME: This is most certainly broken, maybe check should rather be
2513 * `if (CTX_data_scene(C) != scene)` ? */
2514 if (scene != sce) {
2515 WM_window_set_active_scene(bmain, C, win, sce);
2516 }
2517
2518 str = "Select Objects";
2519 selection_changed = true;
2520 break;
2521 }
2523 Scene *sce = scene; /* To be able to delete, scenes are set... */
2525 op->reports,
2526 scene,
2527 space_outliner,
2528 &space_outliner->tree,
2530 false);
2531 /* FIXME: This is most certainly broken, maybe check should rather be
2532 * `if (CTX_data_scene(C) != scene)` ? */
2533 if (scene != sce) {
2534 WM_window_set_active_scene(bmain, C, win, sce);
2535 }
2536 str = "Select Object Hierarchy";
2537 selection_changed = true;
2538 break;
2539 }
2540 case OL_OP_DESELECT:
2542 C, op->reports, scene, space_outliner, &space_outliner->tree, object_deselect_fn);
2543 str = "Deselect Objects";
2544 selection_changed = true;
2545 break;
2546 case OL_OP_REMAP:
2547 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_remap_fn);
2548 /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
2549 * trick does not work here). */
2550 break;
2551 case OL_OP_RENAME:
2553 C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn);
2554 str = "Rename Object";
2555 break;
2556 default:
2558 return OPERATOR_CANCELLED;
2559 }
2560
2561 if (selection_changed) {
2565 }
2566
2567 if (str != nullptr) {
2568 ED_undo_push(C, str);
2569 }
2570
2571 return OPERATOR_FINISHED;
2572}
2573
2575{
2576 /* identifiers */
2577 ot->name = "Outliner Object Operation";
2578 ot->idname = "OUTLINER_OT_object_operation";
2579
2580 /* callbacks */
2584
2585 ot->flag = 0;
2586
2587 ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", "");
2588}
2589
2592/* -------------------------------------------------------------------- */
2596using OutlinerDeleteFn = void (*)(bContext *C, ReportList *reports, Scene *scene, Object *ob);
2597
2603
2605 ReportList *reports,
2606 Scene *scene,
2607 GSet *objects_to_delete,
2608 OutlinerDeleteFn delete_fn)
2609{
2610 GSetIterator objects_to_delete_iter;
2611 GSET_ITER (objects_to_delete_iter, objects_to_delete) {
2612 Object *ob = (Object *)BLI_gsetIterator_getKey(&objects_to_delete_iter);
2613
2614 delete_fn(C, reports, scene, ob);
2615 }
2616}
2617
2619{
2620 ObjectEditData *data = static_cast<ObjectEditData *>(customdata);
2621 GSet *objects_to_delete = data->objects_set;
2622 TreeStoreElem *tselem = TREESTORE(te);
2623
2625 return TRAVERSE_CONTINUE;
2626 }
2627
2628 if ((tselem->type != TSE_SOME_ID) || (tselem->id == nullptr) || (GS(tselem->id->name) != ID_OB))
2629 {
2630 return TRAVERSE_SKIP_CHILDS;
2631 }
2632
2633 /* Do not allow to delete children objects of an override collection. */
2634 TreeElement *te_parent = te->parent;
2635 if (te_parent != nullptr && outliner_is_collection_tree_element(te_parent)) {
2636 TreeStoreElem *tselem_parent = TREESTORE(te_parent);
2637 ID *id_parent = tselem_parent->id;
2638 /* It's not possible to remove an object from an overridden collection (and potentially scene,
2639 * through the master collection). */
2640 if (ELEM(GS(id_parent->name), ID_GR, ID_SCE)) {
2641 if (ID_IS_OVERRIDE_LIBRARY_REAL(id_parent)) {
2642 return TRAVERSE_SKIP_CHILDS;
2643 }
2644 }
2645 }
2646
2647 ID *id = tselem->id;
2648
2651 if (!(data->is_liboverride_hierarchy_root_allowed || data->is_liboverride_allowed)) {
2652 return TRAVERSE_SKIP_CHILDS;
2653 }
2654 }
2655 else {
2656 if (!data->is_liboverride_allowed) {
2657 return TRAVERSE_SKIP_CHILDS;
2658 }
2659 }
2660 }
2661
2662 BLI_gset_add(objects_to_delete, id);
2663
2664 return TRAVERSE_CONTINUE;
2665}
2666
2668{
2669 Main *bmain = CTX_data_main(C);
2670 Scene *scene = CTX_data_scene(C);
2671 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2672 wmMsgBus *mbus = CTX_wm_message_bus(C);
2673 ViewLayer *view_layer = CTX_data_view_layer(C);
2674 BKE_view_layer_synced_ensure(scene, view_layer);
2675 const Base *basact_prev = BKE_view_layer_active_base_get(view_layer);
2676
2677 const bool delete_hierarchy = RNA_boolean_get(op->ptr, "hierarchy");
2678
2679 /* Get selected objects skipping duplicates to prevent deleting objects linked to multiple
2680 * collections twice */
2681 ObjectEditData object_delete_data = {};
2682 object_delete_data.objects_set = BLI_gset_ptr_new(__func__);
2683 object_delete_data.is_liboverride_allowed = false;
2684 object_delete_data.is_liboverride_hierarchy_root_allowed = delete_hierarchy;
2685 outliner_tree_traverse(space_outliner,
2686 &space_outliner->tree,
2687 0,
2690 &object_delete_data);
2691
2692 if (delete_hierarchy) {
2693 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
2694
2695 BKE_view_layer_synced_ensure(scene, view_layer);
2696
2697 /* #object_batch_delete_hierarchy_fn callback will only remove objects from collections and tag
2698 * them for deletion. */
2700 op->reports,
2701 scene,
2702 object_delete_data.objects_set,
2704
2706 }
2707 else {
2709 C, op->reports, scene, object_delete_data.objects_set, outliner_object_delete_fn);
2710 }
2711
2712 BLI_gset_free(object_delete_data.objects_set, nullptr);
2713
2714 outliner_collection_delete(C, bmain, scene, op->reports, delete_hierarchy);
2715
2716 /* Tree management normally happens from draw_outliner(), but when
2717 * you're clicking too fast on Delete object from context menu in
2718 * outliner several mouse events can be handled in one cycle without
2719 * handling notifiers/redraw which leads to deleting the same object twice.
2720 * cleanup tree here to prevent such cases. */
2721 outliner_cleanup_tree(space_outliner);
2722
2725
2726 BKE_view_layer_synced_ensure(scene, view_layer);
2727 if (basact_prev != BKE_view_layer_active_base_get(view_layer)) {
2729 WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
2730 }
2731
2732 ED_node_tree_propagate_change(C, bmain, nullptr);
2733
2738
2739 return OPERATOR_FINISHED;
2740}
2741
2743{
2744 /* identifiers */
2745 ot->name = "Delete";
2746 ot->idname = "OUTLINER_OT_delete";
2747 ot->description = "Delete selected objects and collections";
2748
2749 /* callbacks */
2752
2753 /* flags */
2755
2756 /* properties */
2758 ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections");
2760}
2761
2764/* -------------------------------------------------------------------- */
2786
2787/* TODO: implement support for changing the ID-block used. */
2789 {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
2790 {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
2791 {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
2792 {OUTLINER_IDOP_DELETE, "DELETE", ICON_X, "Delete", ""},
2794 "REMAP",
2795 0,
2796 "Remap Users",
2797 "Make all users of selected data-blocks to use instead current (clicked) one"},
2799 {OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""},
2800 {OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""},
2803 "ADD_FAKE",
2804 0,
2805 "Add Fake User",
2806 "Ensure data-block gets saved even if it isn't in use (e.g. for motion and material "
2807 "libraries)"},
2808 {OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
2809 {OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""},
2810 {OUTLINER_IDOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
2811 {0, nullptr, 0, nullptr, nullptr},
2812};
2813
2815 PointerRNA * /*ptr*/,
2816 PropertyRNA * /*prop*/,
2817 const int enum_value)
2818{
2820 return false;
2821 }
2822
2823 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2824 TreeElement *te = get_target_element(space_outliner);
2825 TreeStoreElem *tselem = TREESTORE(te);
2826 if (!TSE_IS_REAL_ID(tselem)) {
2827 return false;
2828 }
2829
2830 switch (enum_value) {
2832 if (ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
2833 return true;
2834 }
2835 /* TODO(dalai): enable in the few cases where this can be supported
2836 * (i.e., when we have a valid parent for the tselem). */
2837 return false;
2838 }
2839
2840 return true;
2841}
2842
2844 PointerRNA *ptr,
2845 PropertyRNA *prop,
2846 bool *r_free)
2847{
2848 EnumPropertyItem *items = nullptr;
2849 int totitem = 0;
2850
2851 if ((C == nullptr) || (ED_operator_outliner_active(C) == false)) {
2852 return prop_id_op_types;
2853 }
2854 for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != nullptr; it++) {
2855 if (!outliner_id_operation_item_poll(C, ptr, prop, it->value)) {
2856 continue;
2857 }
2858 RNA_enum_item_add(&items, &totitem, it);
2859 }
2860 RNA_enum_item_end(&items, &totitem);
2861 *r_free = true;
2862
2863 return items;
2864}
2865
2867{
2868 Main *bmain = CTX_data_main(C);
2870 Scene *scene = CTX_data_scene(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 OUTLINER_IDOP_UNLINK: {
2885 /* unlink datablock from its parent */
2886 if (objectlevel) {
2887 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, unlink_object_fn);
2888
2890 ED_undo_push(C, "Unlink Object");
2891 break;
2892 }
2893
2894 switch (idlevel) {
2895 case ID_AC:
2896 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, unlink_action_fn);
2897
2899 ED_undo_push(C, "Unlink action");
2900 break;
2901 case ID_MA:
2902 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, unlink_material_fn);
2903
2905 ED_undo_push(C, "Unlink material");
2906 break;
2907 case ID_TE:
2908 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, unlink_texture_fn);
2909
2911 ED_undo_push(C, "Unlink texture");
2912 break;
2913 case ID_WO:
2914 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, unlink_world_fn);
2915
2917 ED_undo_push(C, "Unlink world");
2918 break;
2919 case ID_GR:
2921 C, op->reports, scene, space_outliner, unlink_collection_fn);
2922
2924 ED_undo_push(C, "Unlink Collection");
2925 break;
2926 default:
2927 BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
2928 break;
2929 }
2930 break;
2931 }
2932 case OUTLINER_IDOP_LOCAL: {
2933 /* make local */
2934 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_local_fn);
2935 ED_undo_push(C, "Localized Data");
2936 break;
2937 }
2938 case OUTLINER_IDOP_SINGLE: {
2939 /* make single user */
2940 switch (idlevel) {
2941 case ID_AC:
2943 C, op->reports, scene, space_outliner, singleuser_action_fn);
2944
2946 ED_undo_push(C, "Single-User Action");
2947 break;
2948
2949 case ID_WO:
2951 C, op->reports, scene, space_outliner, singleuser_world_fn);
2952
2954 ED_undo_push(C, "Single-User World");
2955 break;
2956
2957 default:
2958 BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
2959 break;
2960 }
2961 break;
2962 }
2963 case OUTLINER_IDOP_DELETE: {
2964 if (idlevel > 0) {
2965 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
2966 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_delete_tag_fn);
2968 WM_event_add_notifier(C, NC_OBJECT, nullptr);
2969 ED_undo_push(C, "Delete");
2970 }
2971 break;
2972 }
2973 case OUTLINER_IDOP_REMAP: {
2974 if (idlevel > 0 || objectlevel) {
2975 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_remap_fn);
2976 /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
2977 * trick does not work here). */
2978 }
2979 break;
2980 }
2981 case OUTLINER_IDOP_COPY: {
2982 wm->op_undo_depth++;
2983 WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
2984 wm->op_undo_depth--;
2985 /* No need for undo, this operation does not change anything... */
2986 break;
2987 }
2988 case OUTLINER_IDOP_PASTE: {
2989 wm->op_undo_depth++;
2990 WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
2991 wm->op_undo_depth--;
2993 ED_undo_push(C, "Paste");
2994 break;
2995 }
2997 /* set fake user */
2998 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_fake_user_set_fn);
2999
3000 WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
3001 ED_undo_push(C, "Add Fake User");
3002 break;
3003 }
3005 /* clear fake user */
3006 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_fake_user_clear_fn);
3007
3008 WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
3009 ED_undo_push(C, "Clear Fake User");
3010 break;
3011 }
3012 case OUTLINER_IDOP_RENAME: {
3013 /* rename */
3014 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, item_rename_fn);
3015
3016 WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
3017 ED_undo_push(C, "Rename");
3018 break;
3019 }
3021 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_select_linked_fn);
3023 ED_undo_push(C, "Select");
3024 break;
3025
3026 default:
3027 /* Invalid - unhandled. */
3028 break;
3029 }
3030
3031 ED_node_tree_propagate_change(C, bmain, nullptr);
3032
3033 /* wrong notifier still... */
3034 WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
3035
3036 /* XXX: this is just so that outliner is always up to date. */
3038
3039 return OPERATOR_FINISHED;
3040}
3041
3043{
3044 /* identifiers */
3045 ot->name = "Outliner ID Data Operation";
3046 ot->idname = "OUTLINER_OT_id_operation";
3047 ot->description = "General data-block management operations";
3048
3049 /* callbacks */
3053
3054 ot->flag = 0;
3055
3056 ot->prop = RNA_def_enum(ot->srna, "type", prop_id_op_types, 0, "ID Data Operation", "");
3058}
3059
3062/* -------------------------------------------------------------------- */
3073
3075 {OL_LIB_DELETE, "DELETE", ICON_X, "Delete", "Delete this library and all its items"},
3077 "RELOCATE",
3078 0,
3079 "Relocate",
3080 "Select a new path for this library, and reload all its data"},
3081 {OL_LIB_RELOAD, "RELOAD", ICON_FILE_REFRESH, "Reload", "Reload all data from this library"},
3082 {0, nullptr, 0, nullptr, nullptr},
3083};
3084
3086{
3087 Main *bmain = CTX_data_main(C);
3088 Scene *scene = CTX_data_scene(C);
3089 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3090
3091 /* check for invalid states */
3092 if (space_outliner == nullptr) {
3093 return OPERATOR_CANCELLED;
3094 }
3095
3097 switch (event) {
3098 case OL_LIB_DELETE: {
3099 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
3100 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_delete_tag_fn);
3102 ED_undo_push(C, "Delete Library");
3103 break;
3104 }
3105 case OL_LIB_RELOCATE: {
3106 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, lib_relocate_fn);
3107 /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
3108 * trick does not work here). */
3109 break;
3110 }
3111 case OL_LIB_RELOAD: {
3112 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, lib_reload_fn);
3113 /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
3114 * trick does not work here). */
3115 break;
3116 }
3117 default:
3118 /* invalid - unhandled */
3119 break;
3120 }
3121
3122 ED_node_tree_propagate_change(C, bmain, nullptr);
3123
3124 /* wrong notifier still... */
3125 WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr);
3126
3127 /* XXX: this is just so that outliner is always up to date */
3129
3130 return OPERATOR_FINISHED;
3131}
3132
3134{
3135 /* identifiers */
3136 ot->name = "Outliner Library Operation";
3137 ot->idname = "OUTLINER_OT_lib_operation";
3138
3139 /* callbacks */
3143
3144 ot->prop = RNA_def_enum(
3145 ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", "");
3146}
3147
3150/* -------------------------------------------------------------------- */
3155 SpaceOutliner *space_outliner,
3156 int type,
3157 ID *newid,
3158 void (*operation_fn)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *))
3159{
3160 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
3161 TreeStoreElem *tselem = TREESTORE(te);
3162 if (tselem->flag & TSE_SELECTED) {
3163 if (tselem->type == type) {
3164 TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr;
3165 operation_fn(te, tselem, tsep, newid);
3166 }
3167 }
3168 });
3169}
3170
3171static void actionset_id_fn(TreeElement * /*te*/,
3172 TreeStoreElem *tselem,
3173 TreeStoreElem *tsep,
3174 ID *actId)
3175{
3176 bAction *act = (bAction *)actId;
3177
3178 if (tselem->type == TSE_ANIM_DATA) {
3179 /* "animation" entries - action is child of this */
3180 BKE_animdata_set_action(nullptr, tselem->id, act);
3181 }
3182 /* TODO: if any other "expander" channels which own actions need to support this menu,
3183 * add: tselem->type = ...
3184 */
3185 else if (tsep && (tsep->type == TSE_ANIM_DATA)) {
3186 /* "animation" entries case again */
3187 BKE_animdata_set_action(nullptr, tsep->id, act);
3188 }
3189 /* TODO: other cases not supported yet. */
3190}
3191
3193{
3194 Main *bmain = CTX_data_main(C);
3195 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3196 int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3197 bAction *act;
3198
3199 TreeElement *te = get_target_element(space_outliner);
3200 get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3201
3202 /* get action to use */
3203 act = static_cast<bAction *>(BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action")));
3204
3205 if (act == nullptr) {
3206 BKE_report(op->reports, RPT_ERROR, "No valid action to add");
3207 return OPERATOR_CANCELLED;
3208 }
3209 if (act->idroot == 0) {
3210 /* Hopefully in this case (i.e. library of userless actions),
3211 * the user knows what they're doing. */
3212 BKE_reportf(op->reports,
3214 "Action '%s' does not specify what data-blocks it can be used on "
3215 "(try setting the 'ID Root Type' setting from the data-blocks editor "
3216 "for this action to avoid future problems)",
3217 act->id.name + 2);
3218 }
3219
3220 /* perform action if valid channel */
3221 if (datalevel == TSE_ANIM_DATA) {
3222 outliner_do_id_set_operation(space_outliner, datalevel, (ID *)act, actionset_id_fn);
3223 }
3224 else if (idlevel == ID_AC) {
3225 outliner_do_id_set_operation(space_outliner, idlevel, (ID *)act, actionset_id_fn);
3226 }
3227 else {
3228 return OPERATOR_CANCELLED;
3229 }
3230
3231 /* set notifier that things have changed */
3234 ED_undo_push(C, "Set action");
3235
3236 /* done */
3237 return OPERATOR_FINISHED;
3238}
3239
3241{
3242 PropertyRNA *prop;
3243
3244 /* identifiers */
3245 ot->name = "Outliner Set Action";
3246 ot->idname = "OUTLINER_OT_action_set";
3247 ot->description = "Change the active action used";
3248
3249 /* api callbacks */
3253
3254 /* flags */
3256
3257 /* props */
3258 /* TODO: this would be nicer as an ID-pointer... */
3259 prop = RNA_def_enum(ot->srna, "action", rna_enum_dummy_NULL_items, 0, "Action", "");
3262 ot->prop = prop;
3263}
3264
3267/* -------------------------------------------------------------------- */
3282
3285 "CLEAR_ANIMDATA",
3286 0,
3287 "Clear Animation Data",
3288 "Remove this animation data container"},
3289 {OUTLINER_ANIMOP_SET_ACT, "SET_ACT", 0, "Set Action", ""},
3290 {OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""},
3291 {OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""},
3292 {OUTLINER_ANIMOP_CLEAR_DRV, "CLEAR_DRIVERS", 0, "Clear Drivers", ""},
3293 {0, nullptr, 0, nullptr, nullptr},
3294};
3295
3297{
3299 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3300 int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3301 TreeElement *te = get_target_element(space_outliner);
3302 get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3303
3304 if (datalevel != TSE_ANIM_DATA) {
3305 return OPERATOR_CANCELLED;
3306 }
3307
3308 /* perform the core operation */
3310 switch (event) {
3312 /* Remove Animation Data - this may remove the active action, in some cases... */
3313 outliner_do_data_operation(space_outliner, datalevel, event, clear_animdata_fn, nullptr);
3314
3316 ED_undo_push(C, "Clear Animation Data");
3317 break;
3318
3320 /* delegate once again... */
3321 wm->op_undo_depth++;
3323 C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, nullptr, nullptr);
3324 wm->op_undo_depth--;
3325 ED_undo_push(C, "Set active action");
3326 break;
3327
3329 /* clear active action - using standard rules */
3330 outliner_do_data_operation(space_outliner, datalevel, event, unlinkact_animdata_fn, nullptr);
3331
3333 ED_undo_push(C, "Unlink action");
3334 break;
3335
3338 space_outliner, datalevel, event, refreshdrivers_animdata_fn, nullptr);
3339
3341 // ED_undo_push(C, "Refresh Drivers"); /* No undo needed - shouldn't have any impact? */
3342 break;
3343
3346 space_outliner, datalevel, event, cleardrivers_animdata_fn, nullptr);
3347
3349 ED_undo_push(C, "Clear Drivers");
3350 break;
3351
3352 default: /* Invalid. */
3353 break;
3354 }
3355
3356 /* update dependencies */
3358
3359 return OPERATOR_FINISHED;
3360}
3361
3363{
3364 /* identifiers */
3365 ot->name = "Outliner Animation Data Operation";
3366 ot->idname = "OUTLINER_OT_animdata_operation";
3367
3368 /* callbacks */
3372
3373 ot->flag = 0;
3374
3375 ot->prop = RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", "");
3376}
3377
3380/* -------------------------------------------------------------------- */
3385 {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""},
3386 {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_HIDE_ON, "Disable", ""},
3387 {OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""},
3388 {0, nullptr, 0, nullptr, nullptr},
3389};
3390
3392{
3393 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3395
3396 outliner_do_data_operation(space_outliner, TSE_CONSTRAINT, event, constraint_fn, C);
3397
3398 if (event == OL_CONSTRAINTOP_DELETE) {
3399 outliner_cleanup_tree(space_outliner);
3400 }
3401
3402 ED_undo_push(C, "Constraint operation");
3403
3404 return OPERATOR_FINISHED;
3405}
3406
3408{
3409 /* identifiers */
3410 ot->name = "Outliner Constraint Operation";
3411 ot->idname = "OUTLINER_OT_constraint_operation";
3412
3413 /* callbacks */
3417
3418 ot->flag = 0;
3419
3420 ot->prop = RNA_def_enum(
3421 ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", "");
3422}
3423
3426/* -------------------------------------------------------------------- */
3431 {OL_MODIFIER_OP_APPLY, "APPLY", ICON_CHECKMARK, "Apply", ""},
3432 {OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
3434 {OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle Viewport Use", ""},
3435 {OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle Render Use", ""},
3436 {0, nullptr, 0, nullptr, nullptr},
3437};
3438
3440{
3441 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3443
3444 ModifierFnArgs args{};
3445 args.C = C;
3446 args.reports = op->reports;
3447
3448 outliner_do_data_operation(space_outliner, TSE_MODIFIER, event, modifier_fn, &args);
3449
3451 outliner_cleanup_tree(space_outliner);
3452 }
3453
3454 ED_undo_push(C, "Modifier operation");
3455
3456 return OPERATOR_FINISHED;
3457}
3458
3460{
3461 /* identifiers */
3462 ot->name = "Outliner Modifier Operation";
3463 ot->idname = "OUTLINER_OT_modifier_operation";
3464
3465 /* callbacks */
3469
3470 ot->flag = 0;
3471
3472 ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", "");
3473}
3474
3477/* -------------------------------------------------------------------- */
3482{
3484 return false;
3485 }
3486 const SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3487 const TreeElement *te = get_target_element(space_outliner);
3488
3489 if (te == nullptr) {
3490 return false;
3491 }
3492
3493 int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3494 get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3495 return ELEM(datalevel,
3497 TSE_BONE,
3498 TSE_EBONE,
3502}
3503
3505{
3506 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3507 int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3508 TreeElement *te = get_target_element(space_outliner);
3509 get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3510
3512 switch (datalevel) {
3513 case TSE_POSE_CHANNEL: {
3514 outliner_do_data_operation(space_outliner, datalevel, event, pchan_fn, nullptr);
3516 ED_undo_push(C, "PoseChannel operation");
3517
3518 break;
3519 }
3520 case TSE_BONE: {
3521 outliner_do_data_operation(space_outliner, datalevel, event, bone_fn, nullptr);
3523 ED_undo_push(C, "Bone operation");
3524
3525 break;
3526 }
3527 case TSE_EBONE: {
3528 outliner_do_data_operation(space_outliner, datalevel, event, ebone_fn, nullptr);
3530 ED_undo_push(C, "EditBone operation");
3531
3532 break;
3533 }
3534 case TSE_SEQUENCE: {
3535 Scene *scene = CTX_data_scene(C);
3536 outliner_do_data_operation(space_outliner, datalevel, event, sequence_fn, scene);
3538 ED_undo_push(C, "Sequencer operation");
3539
3540 break;
3541 }
3542 case TSE_GP_LAYER: {
3543 outliner_do_data_operation(space_outliner, datalevel, event, gpencil_layer_fn, nullptr);
3545 ED_undo_push(C, "Grease Pencil Layer operation");
3546
3547 break;
3548 }
3550 outliner_do_data_operation(space_outliner, datalevel, event, grease_pencil_node_fn, nullptr);
3552 ED_undo_push(C, "Grease Pencil Node operation");
3553 break;
3554 }
3555 case TSE_RNA_STRUCT:
3556 if (event == OL_DOP_SELECT_LINKED) {
3557 outliner_do_data_operation(space_outliner, datalevel, event, data_select_linked_fn, C);
3558 }
3559
3560 break;
3561
3562 default:
3563 BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
3564 break;
3565 }
3566
3567 return OPERATOR_FINISHED;
3568}
3569
3570/* Dynamically populate an enum of Keying Sets */
3572 PointerRNA * /*ptr*/,
3573 PropertyRNA * /*prop*/,
3574 bool * /*r_free*/)
3575{
3576 /* Check for invalid states. */
3577 if (C == nullptr) {
3579 }
3580
3581 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3582 if (space_outliner == nullptr) {
3584 }
3585
3586 TreeElement *te = get_target_element(space_outliner);
3587 if (te == nullptr) {
3589 }
3590
3591 TreeStoreElem *tselem = TREESTORE(te);
3592
3593 static const EnumPropertyItem optype_sel_and_hide[] = {
3594 {OL_DOP_SELECT, "SELECT", 0, "Select", ""},
3595 {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""},
3596 {OL_DOP_HIDE, "HIDE", 0, "Hide", ""},
3597 {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""},
3598 {0, nullptr, 0, nullptr, nullptr}};
3599
3600 static const EnumPropertyItem optype_sel_linked[] = {
3601 {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
3602 {0, nullptr, 0, nullptr, nullptr}};
3603
3604 if (tselem->type == TSE_RNA_STRUCT) {
3605 return optype_sel_linked;
3606 }
3607
3608 return optype_sel_and_hide;
3609}
3610
3612{
3613 /* identifiers */
3614 ot->name = "Outliner Data Operation";
3615 ot->idname = "OUTLINER_OT_data_operation";
3616
3617 /* callbacks */
3621
3622 ot->flag = 0;
3623
3624 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_dummy_DEFAULT_items, 0, "Data Operation", "");
3626}
3627
3630/* -------------------------------------------------------------------- */
3634static int outliner_operator_menu(bContext *C, const char *opname)
3635{
3636 wmOperatorType *ot = WM_operatortype_find(opname, false);
3637 uiPopupMenu *pup = UI_popup_menu_begin(C, WM_operatortype_name(ot, nullptr).c_str(), ICON_NONE);
3638 uiLayout *layout = UI_popup_menu_layout(pup);
3639
3640 /* Set this so the default execution context is the same as sub-menus. */
3642
3643 if (WM_operator_poll(C, ot)) {
3645
3646 uiItemS(layout);
3647 }
3648
3649 uiItemMContents(layout, "OUTLINER_MT_context_menu");
3650
3651 UI_popup_menu_end(C, pup);
3652
3653 return OPERATOR_INTERFACE;
3654}
3655
3657 ARegion *region,
3658 SpaceOutliner *space_outliner,
3659 TreeElement *te)
3660{
3661 int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3662 TreeStoreElem *tselem = TREESTORE(te);
3663
3664 int select_flag = OL_ITEM_ACTIVATE | OL_ITEM_SELECT;
3665 if (tselem->flag & TSE_SELECTED) {
3666 select_flag |= OL_ITEM_EXTEND;
3667 }
3668
3669 outliner_item_select(C, space_outliner, te, select_flag);
3670
3671 /* Only redraw, don't rebuild here because TreeElement pointers will
3672 * become invalid and operations will crash. */
3674 ED_outliner_select_sync_from_outliner(C, space_outliner);
3675
3676 get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3677
3678 if (scenelevel) {
3679 return outliner_operator_menu(C, "OUTLINER_OT_scene_operation");
3680 }
3681 if (objectlevel) {
3682 WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN);
3683 return OPERATOR_FINISHED;
3684 }
3685 if (idlevel) {
3686 switch (idlevel) {
3687 case ID_GR:
3688 WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
3689 return OPERATOR_FINISHED;
3690 break;
3691 case ID_LI:
3692 return outliner_operator_menu(C, "OUTLINER_OT_lib_operation");
3693 break;
3694 default:
3695 return outliner_operator_menu(C, "OUTLINER_OT_id_operation");
3696 break;
3697 }
3698 }
3699 else if (datalevel) {
3700 if (datalevel == TSE_ANIM_DATA) {
3701 return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation");
3702 }
3703 if (datalevel == TSE_DRIVER_BASE) {
3704 /* do nothing... no special ops needed yet */
3705 return OPERATOR_CANCELLED;
3706 }
3707 if (datalevel == TSE_LAYER_COLLECTION) {
3708 WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
3709 return OPERATOR_FINISHED;
3710 }
3712 WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
3713 return OPERATOR_FINISHED;
3714 }
3715 if (datalevel == TSE_ID_BASE) {
3716 /* do nothing... there are no ops needed here yet */
3717 return OPERATOR_CANCELLED;
3718 }
3719 if (datalevel == TSE_CONSTRAINT) {
3720 return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation");
3721 }
3722 if (datalevel == TSE_MODIFIER) {
3723 return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation");
3724 }
3725 return outliner_operator_menu(C, "OUTLINER_OT_data_operation");
3726 }
3727
3728 return OPERATOR_CANCELLED;
3729}
3730
3731static int outliner_operation_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
3732{
3733 ARegion *region = CTX_wm_region(C);
3734 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3736 float view_mval[2];
3737
3738 if (but) {
3740 }
3741
3743 &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
3744
3746 space_outliner, &space_outliner->tree, view_mval[1]);
3747 if (!hovered_te) {
3748 /* Let this fall through to 'OUTLINER_MT_context_menu'. */
3749 return OPERATOR_PASS_THROUGH;
3750 }
3751
3752 return do_outliner_operation_event(C, region, space_outliner, hovered_te);
3753}
3754
3756{
3757 ot->name = "Context Menu";
3758 ot->idname = "OUTLINER_OT_operation";
3759 ot->description = "Context menu for item operations";
3760
3762
3764}
3765
3768} // namespace blender::ed::outliner
bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
Definition anim_data.cc:194
void BKE_animdata_free(ID *id, bool do_id_user)
Definition anim_data.cc:263
bool BKE_collection_object_remove(Main *bmain, Collection *collection, Object *ob, bool free_us)
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END
#define FOREACH_SCENE_COLLECTION_END
bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, bool free_us)
bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child)
bool BKE_collection_has_object(Collection *collection, const Object *ob)
#define FOREACH_SCENE_COLLECTION_BEGIN(scene, _instance)
#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object)
bool BKE_constraint_remove_ex(ListBase *list, struct Object *ob, struct bConstraint *con)
void BKE_constraints_active_set(ListBase *list, struct bConstraint *con)
ReportList * CTX_wm_reports(const bContext *C)
SpaceOutliner * CTX_wm_space_outliner(const bContext *C)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
wmMsgBus * CTX_wm_message_bus(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
void BKE_fcurves_free(ListBase *list)
Low-level operations for grease pencil.
bool BKE_idtype_idcode_is_linkable(short idcode)
Definition idtype.cc:201
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Base * BKE_view_layer_active_base_get(ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
void BKE_id_newptr_and_tag_clear(ID *id)
Definition lib_id.cc:405
void BKE_id_delete(Main *bmain, void *idv) ATTR_NONNULL()
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
Definition lib_id.cc:1034
void size_t BKE_id_multi_tagged_delete(Main *bmain) ATTR_NONNULL()
void id_fake_user_set(ID *id)
Definition lib_id.cc:389
void BKE_main_id_newptr_and_tag_clear(Main *bmain)
Definition lib_id.cc:1947
bool BKE_lib_id_make_local(Main *bmain, ID *id, int flags)
Definition lib_id.cc:584
void id_fake_user_clear(ID *id)
Definition lib_id.cc:397
@ LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR
void id_us_min(ID *id)
Definition lib_id.cc:359
void BKE_main_id_tag_all(Main *mainvar, int tag, bool value)
Definition lib_id.cc:1198
ID * BKE_lib_override_library_create_from_id(Main *bmain, ID *reference_id, bool do_tagged_remap)
void BKE_lib_override_library_id_reset(Main *bmain, ID *id_root, bool do_reset_system_override)
bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root, Collection *override_resync_residual_storage, bool do_hierarchy_enforce, BlendFileReadReport *reports)
bool BKE_lib_override_library_create(Main *bmain, Scene *scene, ViewLayer *view_layer, Library *owner_library, ID *id_root_reference, ID *id_hierarchy_root_reference, ID *id_instance_hint, ID **r_id_root_override, const bool do_fully_editable)
void BKE_lib_override_library_id_hierarchy_reset(Main *bmain, ID *id_root, bool do_reset_system_override)
void BKE_lib_override_library_make_local(Main *bmain, ID *id)
void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
bool BKE_lib_override_library_is_hierarchy_leaf(Main *bmain, ID *id)
bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
Definition lib_query.cc:613
@ ID_REMAP_SKIP_INDIRECT_USAGE
void void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, int remap_flags) ATTR_NONNULL(1
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:500
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:494
General operations, lookup, etc. for blender objects.
bool BKE_object_is_in_editmode(const 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.cc:125
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
struct GSet GSet
Definition BLI_ghash.h:341
GSet * BLI_gset_ptr_new(const char *info)
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition BLI_ghash.h:459
#define GSET_ITER(gs_iter_, gset_)
Definition BLI_ghash.h:472
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.c:966
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
int char * BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
#define LIKELY(x)
external readfile function prototypes.
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_id_tag_update_ex(Main *bmain, ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
#define ID_IS_OVERRIDE_LIBRARY_VIRTUAL(_id)
Definition DNA_ID.h:680
#define ID_EXTRA_USERS(id)
Definition DNA_ID.h:623
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_SELECT
Definition DNA_ID.h:1068
@ ID_RECALC_HIERARCHY
Definition DNA_ID.h:1125
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:1044
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1071
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:676
#define ID_IS_OVERRIDABLE_LIBRARY(_id)
Definition DNA_ID.h:669
#define ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(_id)
Definition DNA_ID.h:665
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
@ ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE
Definition DNA_ID.h:736
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:725
@ ID_TAG_INDIRECT
Definition DNA_ID.h:794
@ ID_TAG_EXTERN
Definition DNA_ID.h:788
@ ID_TAG_DOIT
Definition DNA_ID.h:1003
#define ID_REAL_USERS(id)
Definition DNA_ID.h:637
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
#define ID_IS_OVERRIDE_LIBRARY_HIERARCHY_ROOT(_id)
Definition DNA_ID.h:686
ID_Type
@ ID_WM
@ ID_CA
@ ID_AR
@ ID_MC
@ ID_CF
@ ID_LI
@ ID_TE
@ ID_IM
@ ID_VO
@ ID_WS
@ ID_NT
@ ID_LA
@ ID_KE
@ ID_TXT
@ ID_SO
@ ID_SCE
@ ID_LS
@ ID_MSK
@ ID_CV
@ ID_PAL
@ ID_BR
@ ID_LP
@ ID_WO
@ ID_MA
@ ID_AC
@ ID_SCR
@ ID_CU_LEGACY
@ ID_GD_LEGACY
@ ID_VF
@ ID_ME
@ ID_IP
@ ID_GR
@ ID_SPK
@ ID_MB
@ ID_LT
@ ID_OB
@ ID_GP
@ ID_PA
@ ID_PT
@ ID_PC
#define ID_NLA
@ 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
@ 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_GREASE_PENCIL_NODE
@ TSE_ID_BASE
@ TSE_SOME_ID
@ TSE_DRIVER_BASE
@ TSE_MODIFIER
@ TSE_RNA_STRUCT
@ TSE_SELECTED
@ TSE_CLOSED
@ TSE_ACTIVE
eSpaceOutliner_Mode
@ SO_VIEW_LAYER
@ SO_SCENES
@ OPERATOR_PASS_THROUGH
void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *ntree)
Definition node_edit.cc:492
void ED_outliner_select_sync_from_object_tag(bContext *C)
void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_outliner)
void ED_outliner_select_sync_from_all_tag(bContext *C)
bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene) ATTR_NONNULL()
bool ED_operator_region_outliner_active(bContext *C)
void ED_region_tag_redraw_no_rebuild(ARegion *region)
Definition area.cc:653
bool ED_operator_outliner_active(bContext *C)
void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool deselect_all)
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:104
Read Guarded memory(de)allocation.
const EnumPropertyItem * RNA_action_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
#define RNA_ENUM_ITEM_SEPR
Definition RNA_types.hh:528
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:321
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
#define C
Definition RandGen.cpp:29
#define MAX_MTEX
Definition Stroke.h:33
#define UI_UNIT_Y
@ UI_EMBOSS
void UI_block_theme_style_set(uiBlock *block, char theme_style)
@ UI_BLOCK_SEARCH_MENU
@ UI_BLOCK_LOOP
@ UI_BLOCK_MOVEMOUSE_QUIT
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2])
Definition interface.cc:590
uiBut * uiDefBut(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, const char *tip)
void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg, uiFreeArgFunc arg_free)
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)
bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid, int but_flag, uint8_t name_prefix_offset)
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, eUIEmbossType emboss)
void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
void uiItemS(uiLayout *layout)
uiBut * UI_context_active_but_get(const bContext *C)
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void uiItemMContents(uiLayout *layout, const char *menuname)
int UI_search_items_find_index(const uiSearchItems *items, const char *name)
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
int UI_searchbox_size_y()
uiBut * uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxncpy, int x, int y, short width, short height, const char *tip)
@ UI_BLOCK_THEME_STYLE_POPUP
#define UI_UNIT_X
void UI_block_flag_enable(uiBlock *block, int flag)
@ UI_BTYPE_LABEL
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
void UI_but_flag_enable(uiBut *but, int flag)
@ UI_BUT_ACTIVATE_ON_INIT
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1663
#define ND_SEQUENCER
Definition WM_types.hh:404
#define ND_WORLD
Definition WM_types.hh:419
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_WINDOW
Definition WM_types.hh:342
#define NC_ID
Definition WM_types.hh:362
#define ND_NLA_ACTCHANGE
Definition WM_types.hh:465
#define ND_OB_ACTIVE
Definition WM_types.hh:407
#define NC_WM
Definition WM_types.hh:341
#define ND_DATA
Definition WM_types.hh:475
#define NC_ANIMATION
Definition WM_types.hh:355
#define ND_LIB_OVERRIDE_CHANGED
Definition WM_types.hh:386
#define ND_OB_SELECT
Definition WM_types.hh:409
#define NC_SCENE
Definition WM_types.hh:345
#define ND_LAYER_CONTENT
Definition WM_types.hh:420
#define ND_MODIFIER
Definition WM_types.hh:429
#define ND_POSE
Definition WM_types.hh:425
#define NA_EDITED
Definition WM_types.hh:550
#define ND_CONSTRAINT
Definition WM_types.hh:431
#define NA_REMOVED
Definition WM_types.hh:553
#define NC_GPENCIL
Definition WM_types.hh:366
#define ND_LAYER
Definition WM_types.hh:417
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:219
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
#define ND_OB_SHADING
Definition WM_types.hh:424
#define ND_SPACE_VIEW3D
Definition WM_types.hh:494
#define NC_OBJECT
Definition WM_types.hh:346
#define ND_ANIMCHAN
Definition WM_types.hh:463
#define NC_SPACE
Definition WM_types.hh:359
#define NA_SELECTED
Definition WM_types.hh:555
#define ND_SPACE_OUTLINER
Definition WM_types.hh:493
void append(const T &value)
const Depsgraph * depsgraph
KDTree_3d * tree
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define str(s)
#define GS(x)
Definition iris.cc:202
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
bool modifier_apply(Main *bmain, ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md, int mode, bool keep_modifier, bool do_all_keyframes)
void constraint_update(Main *bmain, Object *ob)
void base_select(Base *base, eObjectSelect_Mode mode)
bool editmode_exit(bContext *C, int flag)
void select_linked_by_id(bContext *C, ID *id)
void base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
bool editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int flag)
bool modifier_remove(ReportList *reports, Main *bmain, Scene *scene, Object *ob, ModifierData *md)
void all_open(const SpaceOutliner &space_outliner, const VisitorFn visitor)
static bool outliner_liboverride_operation_poll(bContext *C)
void OUTLINER_OT_delete(wmOperatorType *ot)
static void unlink_texture_fn(bContext *, ReportList *reports, Scene *, TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
static void ebone_fn(int event, TreeElement *te, TreeStoreElem *, void *)
static const EnumPropertyItem outliner_lib_op_type_items[]
static void object_deselect_fn(bContext *C, ReportList *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *tselem)
static bool outliner_do_libdata_operation_selection_set_element(bContext *C, ReportList *reports, Scene *scene, TreeElement *element, TreeStoreElem *tselem, const bool has_parent_selected, outliner_operation_fn operation_fn, eOutlinerLibOpSelectionSet selection_set)
static int outliner_data_operation_exec(bContext *C, wmOperator *op)
static void id_override_library_create_hierarchy_process(bContext *C, ReportList *reports, OutlinerLibOverrideData &data)
void OUTLINER_OT_scene_operation(wmOperatorType *ot)
static const EnumPropertyItem * outliner_data_op_sets_enum_item_fn(bContext *C, PointerRNA *, PropertyRNA *, bool *)
static void object_select_hierarchy_fn(bContext *C, ReportList *, Scene *, TreeElement *te, TreeStoreElem *, TreeStoreElem *)
static void unlink_action_fn(bContext *C, ReportList *reports, Scene *, TreeElement *, TreeStoreElem *tsep, TreeStoreElem *tselem)
static void unlink_object_fn(bContext *C, ReportList *reports, Scene *, TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
static TreeTraversalAction outliner_collect_objects_to_delete(TreeElement *te, void *customdata)
static bool scene_fn(bContext *C, eOutliner_PropSceneOps event, TreeElement *, TreeStoreElem *tselem)
static int outliner_operation_invoke(bContext *C, wmOperator *, const wmEvent *event)
bool outliner_is_collection_tree_element(const TreeElement *te)
static void get_element_operation_type(const TreeElement *te, int *scenelevel, int *objectlevel, int *idlevel, int *datalevel)
static void clear_animdata_fn(int, TreeElement *, TreeStoreElem *tselem, void *)
void OUTLINER_OT_data_operation(wmOperatorType *ot)
void OUTLINER_OT_lib_operation(wmOperatorType *ot)
static CLG_LogRef LOG
void OUTLINER_OT_constraint_operation(wmOperatorType *ot)
static const EnumPropertyItem prop_constraint_op_types[]
static const EnumPropertyItem prop_lib_op_selection_set[]
static void id_fake_user_set_fn(bContext *, ReportList *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *tselem)
static int outliner_action_set_exec(bContext *C, wmOperator *op)
static void modifier_fn(int event, TreeElement *te, TreeStoreElem *, void *arg)
static void object_select_fn(bContext *C, ReportList *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *tselem)
static int outliner_modifier_operation_exec(bContext *C, wmOperator *op)
static void id_override_library_clear_single_process(bContext *C, ReportList *, OutlinerLibOverrideData &data)
static void outliner_batch_delete_object_hierarchy(Main *bmain, Scene *scene)
static void refreshdrivers_animdata_fn(int, TreeElement *, TreeStoreElem *tselem, void *)
static int outliner_liboverride_operation_exec(bContext *C, wmOperator *op)
void id_delete_tag_fn(bContext *C, ReportList *reports, Scene *, TreeElement *te, TreeStoreElem *, TreeStoreElem *tselem)
static void id_override_library_reset(bContext *C, OutlinerLibOverrideData *data, TreeStoreElem *tselem)
static void merged_element_search_fn_recursive(const ListBase *tree, short tselem_type, short type, const char *str, uiSearchItems *items)
static int outliner_object_operation_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_scene_op_types[]
static void pchan_fn(int event, TreeElement *te, TreeStoreElem *, void *)
static void outliner_batch_delete_object_hierarchy_tag(ReportList *reports, Main *bmain, ViewLayer *view_layer, Scene *scene, Base *base)
void OUTLINER_OT_modifier_operation(wmOperatorType *ot)
static void unlinkact_animdata_fn(int, TreeElement *, TreeStoreElem *tselem, void *)
static int outliner_operator_menu(bContext *C, const char *opname)
void outliner_collection_delete(bContext *C, Main *bmain, Scene *scene, ReportList *reports, bool do_hierarchy)
TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
static void object_batch_delete_hierarchy_tag_fn(bContext *C, ReportList *reports, Scene *scene, Object *ob)
TreeElement * outliner_find_item_at_y(const SpaceOutliner *space_outliner, const ListBase *tree, float view_co_y)
static int outliner_delete_exec(bContext *C, wmOperator *op)
static void outliner_object_delete_fn(bContext *C, ReportList *reports, Scene *scene, Object *ob)
static const EnumPropertyItem prop_animdata_op_types[]
static void merged_element_search_update_fn(const bContext *, void *data, const char *str, uiSearchItems *items, const bool)
static void data_select_linked_fn(int event, TreeElement *te, TreeStoreElem *, void *C_v)
static void merged_element_search_exec_fn(bContext *C, void *, void *element)
static bool outliner_data_operation_poll(bContext *C)
static void id_override_library_resync(OutlinerLibOverrideData *data, TreeStoreElem *tselem)
void outliner_do_object_operation_ex(bContext *C, ReportList *reports, Scene *scene, SpaceOutliner *space_outliner, ListBase *lb, outliner_operation_fn operation_fn, bool recurse_selected)
static void singleuser_action_fn(bContext *C, ReportList *, Scene *, TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
void OUTLINER_OT_object_operation(wmOperatorType *ot)
static void id_fake_user_clear_fn(bContext *, ReportList *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *tselem)
static void id_select_linked_fn(bContext *C, ReportList *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *tselem)
static void id_local_fn(bContext *C, ReportList *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *tselem)
static void bone_fn(int event, TreeElement *te, TreeStoreElem *, void *)
void OUTLINER_OT_animdata_operation(wmOperatorType *ot)
static void unlink_world_fn(bContext *, ReportList *reports, Scene *, TreeElement *, TreeStoreElem *tsep, TreeStoreElem *tselem)
void lib_relocate_fn(bContext *C, ReportList *, Scene *, TreeElement *te, TreeStoreElem *, TreeStoreElem *tselem)
int tree_element_id_type_to_index(TreeElement *te)
static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
static void id_override_library_clear_single(OutlinerLibOverrideData *data, ReportList *reports, TreeStoreElem *tselem)
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)
static void unlink_collection_fn(bContext *C, ReportList *reports, Scene *, TreeElement *, TreeStoreElem *tsep, TreeStoreElem *tselem)
static void outliner_do_data_operation(SpaceOutliner *space_outliner, int type, int event, void(*operation_fn)(int, TreeElement *, TreeStoreElem *, void *), void *arg)
static const EnumPropertyItem prop_liboverride_op_types[]
static void id_override_library_delete_hierarchy(OutlinerLibOverrideData *data, TreeStoreElem *tselem)
void OUTLINER_OT_action_set(wmOperatorType *ot)
static bool outliner_id_operation_item_poll(bContext *C, PointerRNA *, PropertyRNA *, const int enum_value)
bool outliner_tree_traverse(const SpaceOutliner *space_outliner, ListBase *tree, int filter_te_flag, int filter_tselem_flag, TreeTraversalFunc func, void *customdata)
static const EnumPropertyItem prop_id_op_types[]
static void id_override_library_resync_hierarchy_process(bContext *C, ReportList *reports, OutlinerLibOverrideData &data)
TreeElementT * tree_element_cast(const TreeElement *te)
ID * outliner_search_back(TreeElement *te, short idcode)
static void cleardrivers_animdata_fn(int, TreeElement *, TreeStoreElem *tselem, void *)
void merged_element_search_menu_invoke(bContext *C, TreeElement *parent_te, TreeElement *activate_te)
static uiBlock * merged_element_search_menu(bContext *C, ARegion *region, void *data)
static TreeElement * get_target_element(const SpaceOutliner *space_outliner)
static void unlink_material_fn(bContext *, ReportList *reports, Scene *, TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
static void constraint_fn(int event, TreeElement *te, TreeStoreElem *, void *C_v)
static void actionset_id_fn(TreeElement *, TreeStoreElem *tselem, TreeStoreElem *tsep, ID *actId)
@ OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT
static void outliner_batch_delete_object_tag(ReportList *reports, Main *bmain, Scene *scene, Object *object)
void id_remap_fn(bContext *C, ReportList *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *tselem)
void lib_reload_fn(bContext *C, ReportList *, Scene *, TreeElement *te, TreeStoreElem *, TreeStoreElem *tselem)
void outliner_cleanup_tree(SpaceOutliner *space_outliner)
static void outliner_do_object_delete(bContext *C, ReportList *reports, Scene *scene, GSet *objects_to_delete, OutlinerDeleteFn delete_fn)
static void singleuser_world_fn(bContext *C, ReportList *, Scene *, TreeElement *, TreeStoreElem *tsep, TreeStoreElem *tselem)
void outliner_do_object_operation(bContext *C, ReportList *reports, Scene *scene, SpaceOutliner *space_outliner, ListBase *lb, outliner_operation_fn operation_fn)
TreeElement * outliner_find_element_with_flag(const ListBase *lb, short flag)
static void outliner_do_libdata_operation(bContext *C, ReportList *reports, Scene *scene, SpaceOutliner *space_outliner, outliner_operation_fn operation_fn)
void OUTLINER_OT_liboverride_troubleshoot_operation(wmOperatorType *ot)
static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
static int outliner_constraint_operation_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_operation(wmOperatorType *ot)
static const EnumPropertyItem * outliner_id_operation_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
static const EnumPropertyItem prop_modifier_op_types[]
void item_rename_fn(bContext *C, ReportList *reports, Scene *, TreeElement *te, TreeStoreElem *, TreeStoreElem *tselem)
static bool outliner_do_scene_operation(bContext *C, SpaceOutliner *space_outliner, eOutliner_PropSceneOps event, bool(*operation_fn)(bContext *, eOutliner_PropSceneOps, TreeElement *, TreeStoreElem *))
static void sequence_fn(int event, TreeElement *te, TreeStoreElem *, void *scene_ptr)
static void outliner_do_id_set_operation(SpaceOutliner *space_outliner, int type, ID *newid, void(*operation_fn)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *))
static void gpencil_layer_fn(int event, TreeElement *te, TreeStoreElem *, void *)
void(*)(bContext *C, ReportList *reports, Scene *scene, Object *ob) OutlinerDeleteFn
static const EnumPropertyItem prop_liboverride_troubleshoot_op_types[]
void OUTLINER_OT_id_operation(wmOperatorType *ot)
static int do_outliner_operation_event(bContext *C, ARegion *region, SpaceOutliner *space_outliner, TreeElement *te)
void OUTLINER_OT_liboverride_operation(wmOperatorType *ot)
static void id_override_library_delete_hierarchy_process(bContext *C, ReportList *, OutlinerLibOverrideData &data)
void outliner_item_select(bContext *C, SpaceOutliner *space_outliner, TreeElement *te, short select_flag)
static void id_override_library_create_hierarchy_pre_process(bContext *C, OutlinerLibOverrideData *data, ReportList *reports, TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
static int outliner_id_operation_exec(bContext *C, wmOperator *op)
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)
static int outliner_scene_operation_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_object_op_types[]
static void grease_pencil_node_fn(int event, TreeElement *te, TreeStoreElem *, void *)
static bool outliner_operation_tree_element_poll(bContext *C)
#define TREESTORE(a)
#define TSELEM_OPEN(telm, sv)
bool RNA_struct_is_ID(const StructRNA *type)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
const char * RNA_property_identifier(const PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
const EnumPropertyItem rna_enum_dummy_NULL_items[]
Definition rna_rna.cc:29
const EnumPropertyItem rna_enum_dummy_DEFAULT_items[]
Definition rna_rna.cc:35
Editing * SEQ_editing_get(const Scene *scene)
Definition sequencer.cc:262
void SEQ_relations_invalidate_dependent(Scene *scene, Sequence *seq)
ListBase drivers
struct Base * next
short flag
struct Object * object
struct Material ** mat
short totcol
ListBase * seqbasep
const char * identifier
Definition RNA_types.hh:506
struct MTex * mtex[18]
unsigned int flag
Definition DNA_ID.h:352
struct ID * hierarchy_root
Definition DNA_ID.h:343
struct ID * reference
Definition DNA_ID.h:333
Definition DNA_ID.h:413
int tag
Definition DNA_ID.h:434
struct Library * lib
Definition DNA_ID.h:419
IDOverrideLibrary * override_library
Definition DNA_ID.h:459
short flag
Definition DNA_ID.h:430
char name[66]
Definition DNA_ID.h:425
unsigned int session_uid
Definition DNA_ID.h:454
ID id
Definition DNA_ID.h:529
struct Tex * tex
ListBase actions
Definition BKE_main.hh:233
ListBase objects
Definition BKE_main.hh:212
struct Material ** mat
ListBase constraints
struct Collection * instance_collection
struct Material ** mat
struct Object * parent
struct Material ** mat
StructRNA * type
Definition RNA_types.hh:41
void * data
Definition RNA_types.hh:42
struct World * world
struct Base * basact
struct Bone * bone
Map< ID *, Vector< OutlinerLiboverrideDataIDRoot > > id_hierarchy_roots
void id_root_add(ID *id_hierarchy_root_reference, ID *id_root_reference, ID *id_instance_hint, const bool is_override_instancing_object)
void id_root_set(ID *id_hierarchy_root_reference)
int mval[2]
Definition WM_types.hh:728
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct PointerRNA * ptr
void WM_menu_name_call(bContext *C, const char *menu_name, short context)
bool WM_operator_poll(bContext *C, wmOperatorType *ot)
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.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *)
void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)