Blender V4.5
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
8
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_listbase.h"
33#include "BLI_map.hh"
34#include "BLI_set.hh"
35#include "BLI_string.h"
36#include "BLI_utildefines.h"
37#include "BLI_vector.hh"
38
39#include "BKE_anim_data.hh"
40#include "BKE_animsys.h"
41#include "BKE_armature.hh"
42#include "BKE_collection.hh"
43#include "BKE_constraint.h"
44#include "BKE_context.hh"
45#include "BKE_fcurve.hh"
46#include "BKE_global.hh"
47#include "BKE_grease_pencil.hh"
48#include "BKE_idtype.hh"
49#include "BKE_layer.hh"
50#include "BKE_lib_id.hh"
51#include "BKE_lib_override.hh"
52#include "BKE_lib_query.hh"
53#include "BKE_lib_remap.hh"
54#include "BKE_library.hh"
55#include "BKE_main.hh"
57#include "BKE_object.hh"
58#include "BKE_report.hh"
59#include "BKE_scene.hh"
60#include "BKE_screen.hh"
61
62#include "DEG_depsgraph.hh"
64
65#include "ED_node.hh"
66#include "ED_object.hh"
67#include "ED_outliner.hh"
68#include "ED_scene.hh"
69#include "ED_screen.hh"
70#include "ED_sequencer.hh"
71#include "ED_undo.hh"
72
73#include "WM_api.hh"
74#include "WM_message.hh"
75#include "WM_types.hh"
76
77#include "UI_interface.hh"
78#include "UI_resources.hh"
79#include "UI_view2d.hh"
80
82
83#include "RNA_access.hh"
84#include "RNA_define.hh"
85#include "RNA_enum_types.hh"
86
87#include "ANIM_action_legacy.hh"
88
89#include "SEQ_relations.hh"
90#include "SEQ_sequencer.hh"
91
92#include "outliner_intern.hh"
96#include "tree/tree_iterator.hh"
97
98namespace blender::ed::outliner {
99
100static CLG_LogRef LOG = {"ed.outliner.tools"};
101
102/* -------------------------------------------------------------------- */
105
107 const TreeElement *te, int *scenelevel, int *objectlevel, int *idlevel, int *datalevel)
108{
109 *scenelevel = *objectlevel = *idlevel = *datalevel = 0;
110
111 const TreeStoreElem *tselem = TREESTORE(te);
112 if ((tselem->flag & TSE_SELECTED) == 0) {
113 return;
114 }
115
116 /* Layer collection points to collection ID. */
117 if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) {
118 *datalevel = tselem->type;
119 }
120 else {
121 const int idcode = int(GS(tselem->id->name));
122 bool is_standard_id = false;
123 switch ((ID_Type)idcode) {
124 case ID_SCE:
125 *scenelevel = 1;
126 break;
127 case ID_OB:
128 *objectlevel = 1;
129 break;
130
131 case ID_ME:
132 case ID_CU_LEGACY:
133 case ID_MB:
134 case ID_LT:
135 case ID_LA:
136 case ID_AR:
137 case ID_CA:
138 case ID_SPK:
139 case ID_MA:
140 case ID_TE:
141 case ID_IP:
142 case ID_IM:
143 case ID_SO:
144 case ID_KE:
145 case ID_WO:
146 case ID_AC:
147 case ID_TXT:
148 case ID_GR:
149 case ID_LS:
150 case ID_LI:
151 case ID_VF:
152 case ID_NT:
153 case ID_BR:
154 case ID_PA:
155 case ID_GD_LEGACY:
156 case ID_MC:
157 case ID_MSK:
158 case ID_PAL:
159 case ID_PC:
160 case ID_CF:
161 case ID_WS:
162 case ID_LP:
163 case ID_CV:
164 case ID_PT:
165 case ID_VO:
166 case ID_GP:
167 is_standard_id = true;
168 break;
169 case ID_WM:
170 case ID_SCR:
171 /* Those are ignored here. */
172 /* NOTE: while Screens should be manageable here, deleting a screen used by a workspace
173 * will cause crashes when trying to use that workspace, so for now let's play minimal,
174 * safe change. */
175 break;
176 }
177 if (idcode == ID_NLA) {
178 /* Fake one, not an actual ID type... */
179 is_standard_id = true;
180 }
181
182 if (is_standard_id) {
183 *idlevel = idcode;
184 }
185 }
186
187 /* Return values are exclusive, only one may be non-null. */
188 BLI_assert(((*scenelevel != 0) && (*objectlevel == 0) && (*idlevel == 0) && (*datalevel == 0)) ||
189 ((*scenelevel == 0) && (*objectlevel != 0) && (*idlevel == 0) && (*datalevel == 0)) ||
190 ((*scenelevel == 0) && (*objectlevel == 0) && (*idlevel != 0) && (*datalevel == 0)) ||
191 ((*scenelevel == 0) && (*objectlevel == 0) && (*idlevel == 0) && (*datalevel != 0)) ||
192 /* All null. */
193 ((*scenelevel == 0) && (*objectlevel == 0) && (*idlevel == 0) && (*datalevel == 0)));
194}
195
196static TreeElement *get_target_element(const SpaceOutliner *space_outliner)
197{
199
200 return te;
201}
202
204{
206 return false;
207 }
208 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
209 TreeElement *te = get_target_element(space_outliner);
210 if (te == nullptr) {
211 return false;
212 }
213
214 return true;
215}
216
219 Scene * /*scene*/,
220 TreeElement * /*te*/,
221 TreeStoreElem *tsep,
222 TreeStoreElem *tselem)
223{
224 if (!tsep || !TSE_IS_REAL_ID(tsep)) {
225 /* Valid case, no parent element of the action or it is not an ID (could be a #TSE_ID_BASE
226 * for example) so there's no data to unlink from. */
229 "Cannot unlink action '%s'. It's not clear which object or object-data it "
230 "should be unlinked from, there's no object or object-data as parent in the "
231 "Outliner tree",
232 tselem->id->name + 2);
233 return;
234 }
235
236 /* just set action to nullptr */
237 BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, nullptr);
239}
240
241static void unlink_material_fn(bContext * /*C*/,
243 Scene * /*scene*/,
244 TreeElement *te,
245 TreeStoreElem *tsep,
246 TreeStoreElem *tselem)
247{
248 const bool te_is_material = TSE_IS_REAL_ID(tselem) && (GS(tselem->id->name) == ID_MA);
249
250 if (!te_is_material) {
251 /* Just fail silently. Another element may be selected that is a material, we don't want to
252 * confuse users with an error in that case. */
253 return;
254 }
255
256 if (!tsep || !TSE_IS_REAL_ID(tsep)) {
257 /* Valid case, no parent element of the material or it is not an ID (could be a #TSE_ID_BASE
258 * for example) so there's no data to unlink from. */
261 "Cannot unlink material '%s'. It's not clear which object or object-data it "
262 "should be unlinked from, there's no object or object-data as parent in the "
263 "Outliner tree",
264 tselem->id->name + 2);
265 return;
266 }
267
268 if (!ID_IS_EDITABLE(tsep->id) || ID_IS_OVERRIDE_LIBRARY(tsep->id)) {
271 "Cannot unlink the material '%s' from linked object data",
272 tselem->id->name + 2);
273 return;
274 }
275
276 Material **matar = nullptr;
277 int a, totcol = 0;
278
279 switch (GS(tsep->id->name)) {
280 case ID_OB: {
281 Object *ob = (Object *)tsep->id;
282 totcol = ob->totcol;
283 matar = ob->mat;
284 break;
285 }
286 case ID_ME: {
287 Mesh *mesh = (Mesh *)tsep->id;
288 totcol = mesh->totcol;
289 matar = mesh->mat;
290 break;
291 }
292 case ID_CU_LEGACY: {
293 Curve *cu = (Curve *)tsep->id;
294 totcol = cu->totcol;
295 matar = cu->mat;
296 break;
297 }
298 case ID_MB: {
299 MetaBall *mb = (MetaBall *)tsep->id;
300 totcol = mb->totcol;
301 matar = mb->mat;
302 break;
303 }
304 case ID_CV: {
305 Curves *curves = (Curves *)tsep->id;
306 totcol = curves->totcol;
307 matar = curves->mat;
308 break;
309 }
310 case ID_PT: {
312 totcol = pointcloud->totcol;
313 matar = pointcloud->mat;
314 break;
315 }
316 case ID_VO: {
317 Volume *volume = (Volume *)tsep->id;
318 totcol = volume->totcol;
319 matar = volume->mat;
320 break;
321 }
322 default:
324 }
325
326 if (LIKELY(matar != nullptr)) {
327 for (a = 0; a < totcol; a++) {
328 if (a == te->index && matar[a]) {
329 id_us_min(&matar[a]->id);
330 matar[a] = nullptr;
331 }
332 }
333 }
334}
335
336static void unlink_texture_fn(bContext * /*C*/,
338 Scene * /*scene*/,
339 TreeElement *te,
340 TreeStoreElem *tsep,
341 TreeStoreElem *tselem)
342{
343 if (!tsep || !TSE_IS_REAL_ID(tsep)) {
344 /* Valid case, no parent element of the texture or it is not an ID (could be a #TSE_ID_BASE
345 * for example) so there's no data to unlink from. */
348 "Cannot unlink texture '%s'. It's not clear which Freestyle line style it should "
349 "be unlinked from, there's no Freestyle line style as parent in the Outliner tree",
350 tselem->id->name + 2);
351 return;
352 }
353
354 MTex **mtex = nullptr;
355 int a;
356
357 if (GS(tsep->id->name) == ID_LS) {
359 mtex = ls->mtex;
360 }
361 else {
362 return;
363 }
364
365 for (a = 0; a < MAX_MTEX; a++) {
366 if (a == te->index && mtex[a]) {
367 if (mtex[a]->tex) {
368 id_us_min(&mtex[a]->tex->id);
369 mtex[a]->tex = nullptr;
370 }
371 }
372 }
373}
374
377 Scene * /*scene*/,
378 TreeElement * /*te*/,
379 TreeStoreElem *tsep,
380 TreeStoreElem *tselem)
381{
382 Main *bmain = CTX_data_main(C);
383 Collection *collection = (Collection *)tselem->id;
384
385 if (!tsep || !TSE_IS_REAL_ID(tsep)) {
386 /* Valid case, no parent element of the collection or it is not an ID (could be a #TSE_ID_BASE
387 * for example) so there's no data to unlink from. */
390 "Cannot unlink collection '%s'. It's not clear which scene, collection or "
391 "instance empties it should be unlinked from, there's no scene, collection or "
392 "instance empties as parent in the Outliner tree",
393 tselem->id->name + 2);
394 return;
395 }
396
397 if (tsep && (!ID_IS_EDITABLE(tsep->id) || ID_IS_OVERRIDE_LIBRARY(tsep->id))) {
400 "Cannot unlink collection '%s' parented to another linked collection '%s'",
401 collection->id.name + 2,
402 tsep->id->name + 2);
403 return;
404 }
405
406 if (tsep) {
407 if (GS(tsep->id->name) == ID_OB) {
408 Object *ob = (Object *)tsep->id;
409 ob->instance_collection = nullptr;
412 }
413 else if (GS(tsep->id->name) == ID_GR) {
414 Collection *parent = (Collection *)tsep->id;
415 id_fake_user_set(&collection->id);
416 BKE_collection_child_remove(bmain, parent, collection);
419 }
420 else if (GS(tsep->id->name) == ID_SCE) {
421 Scene *scene = (Scene *)tsep->id;
422 Collection *parent = scene->master_collection;
423 id_fake_user_set(&collection->id);
424 BKE_collection_child_remove(bmain, parent, collection);
427 }
428 }
429}
430
433 Scene * /*scene*/,
434 TreeElement *te,
435 TreeStoreElem *tsep,
436 TreeStoreElem *tselem)
437{
438 if (tsep && tsep->id) {
439
440 if (!TSE_IS_REAL_ID(tsep)) {
441 return;
442 }
443 Main *bmain = CTX_data_main(C);
444 Object *ob = (Object *)tselem->id;
445 const eSpaceOutliner_Mode outliner_mode = eSpaceOutliner_Mode(
446 CTX_wm_space_outliner(C)->outlinevis);
447
448 if (GS(tsep->id->name) == ID_OB) {
449 /* Parented objects need to find which collection to unlink from. */
450 TreeElement *te_parent = te->parent;
451 while (tsep && GS(tsep->id->name) == ID_OB) {
452 if (!ID_IS_EDITABLE(tsep->id)) {
455 "Cannot unlink object '%s' parented to another linked object '%s'",
456 ob->id.name + 2,
457 tsep->id->name + 2);
458 return;
459 }
460 te_parent = te_parent->parent;
461 tsep = te_parent ? TREESTORE(te_parent) : nullptr;
462 }
463 }
464
465 if (tsep && tsep->id) {
466 if (!ID_IS_EDITABLE(tsep->id) || ID_IS_OVERRIDE_LIBRARY(tsep->id)) {
469 "Cannot unlink object '%s' from linked collection or scene '%s'",
470 ob->id.name + 2,
471 tsep->id->name + 2);
472 return;
473 }
474 switch (GS(tsep->id->name)) {
475 case ID_GR: {
476 Collection *parent = (Collection *)tsep->id;
477 BKE_collection_object_remove(bmain, parent, ob, true);
479 break;
480 }
481 case ID_SCE: {
482 Scene *scene = reinterpret_cast<Scene *>(tsep->id);
483 /* In Scene view, remove the object from all collections in the scene. */
484 if (outliner_mode == SO_SCENES) {
485 FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
486 if (BKE_collection_has_object(collection, ob)) {
487 BKE_collection_object_remove(bmain, collection, ob, true);
488 DEG_id_tag_update(&collection->id, ID_RECALC_HIERARCHY);
490 }
491 }
493 }
494 /* Otherwise, remove the object from the scene's main collection. */
495 else {
496 Collection *parent = scene->master_collection;
497 BKE_collection_object_remove(bmain, parent, ob, true);
499 }
500 break;
501 }
502 default: {
503 /* Un-handled case, should never be reached. */
505 return;
506 }
507 }
508 /* NOTE: Cannot risk tagging the object here, as it may have been deleted if its last usage
509 * was removed by above code. */
512 }
513 }
514}
515
516static void unlink_world_fn(bContext * /*C*/,
518 Scene * /*scene*/,
519 TreeElement * /*te*/,
520 TreeStoreElem *tsep,
521 TreeStoreElem *tselem)
522{
523 if (!tsep || !TSE_IS_REAL_ID(tsep)) {
524 /* Valid case, no parent element of the world or it is not an ID (could be a #TSE_ID_BASE
525 * for example) so there's no data to unlink from. */
528 "Cannot unlink world '%s'. It's not clear which scene it should be unlinked from, "
529 "there's no scene as parent in the Outliner tree",
530 tselem->id->name + 2);
531 return;
532 }
533
534 Scene *parscene = (Scene *)tsep->id;
535 World *wo = (World *)tselem->id;
536
537 /* need to use parent scene not just scene, otherwise may end up getting wrong one */
538 id_us_min(&wo->id);
539 parscene->world = nullptr;
540}
541
544 Scene *scene,
545 SpaceOutliner *space_outliner,
546 outliner_operation_fn operation_fn)
547{
548 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
549 TreeStoreElem *tselem = TREESTORE(te);
550 if (tselem->flag & TSE_SELECTED) {
551 if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
552 tselem->type == TSE_LAYER_COLLECTION)
553 {
554 TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr;
555 operation_fn(C, reports, scene, te, tsep, tselem);
556 }
557 }
558 });
559}
560
562 /* Only selected items. */
564 /* Only content 'inside' selected items (their sub-tree). */
566 /* Combining both options above. */
568};
569
572 "SELECTED",
573 0,
574 "Selected",
575 "Apply the operation over selected data-blocks only"},
577 "CONTENT",
578 0,
579 "Content",
580 "Apply the operation over content of the selected items only (the data-blocks in their "
581 "sub-tree)"},
583 "SELECTED_AND_CONTENT",
584 0,
585 "Selected & Content",
586 "Apply the operation over selected data-blocks and all their dependencies"},
587 {0, nullptr, 0, nullptr, nullptr},
588};
589
591 bContext *C,
593 Scene *scene,
595 TreeStoreElem *tselem,
596 const bool has_parent_selected,
597 outliner_operation_fn operation_fn,
598 eOutlinerLibOpSelectionSet selection_set)
599{
600 const bool do_selected = ELEM(selection_set,
603 const bool do_content = ELEM(selection_set,
606
607 const bool is_selected = tselem->flag & TSE_SELECTED;
608 if ((is_selected && do_selected) || (has_parent_selected && do_content)) {
609 if (((tselem->type == TSE_SOME_ID) && (element->idcode != 0)) ||
610 tselem->type == TSE_LAYER_COLLECTION)
611 {
612 TreeStoreElem *tsep = element->parent ? TREESTORE(element->parent) : nullptr;
613 operation_fn(C, reports, scene, element, tsep, tselem);
614 }
615 }
616 return is_selected;
617}
618
621 Scene *scene,
622 SpaceOutliner *space_outliner,
623 const ListBase &subtree,
624 const bool has_parent_selected,
625 outliner_operation_fn operation_fn,
626 eOutlinerLibOpSelectionSet selection_set)
627{
629 /* Get needed data out in case element gets freed. */
631 const ListBase subtree = element->subtree;
632
634 C, reports, scene, element, tselem, has_parent_selected, operation_fn, selection_set);
635
636 /* Don't access element from now on, it may be freed. Note that the open/collapsed state may
637 * also have been changed in the visitor callback. */
639 reports,
640 scene,
641 space_outliner,
642 subtree,
643 is_selected || has_parent_selected,
644 operation_fn,
645 selection_set);
646 }
647}
648
651 Scene *scene,
652 SpaceOutliner *space_outliner,
653 outliner_operation_fn operation_fn,
654 eOutlinerLibOpSelectionSet selection_set,
655 const bool do_active_element_first)
656{
657 if (do_active_element_first) {
658 TreeElement *active_element = outliner_find_element_with_flag(&space_outliner->tree,
659 TSE_ACTIVE);
660 if (active_element != nullptr) {
661 TreeStoreElem *tselem = TREESTORE(active_element);
662 const ListBase subtree = active_element->subtree;
663
665 C, reports, scene, active_element, tselem, false, operation_fn, selection_set);
666
667 /* Don't access element from now on, it may be freed. Note that the open/collapsed state may
668 * also have been changed in the visitor callback. */
670 C, reports, scene, space_outliner, subtree, is_selected, operation_fn, selection_set);
671 }
672 }
673
675 C, reports, scene, space_outliner, space_outliner->tree, false, operation_fn, selection_set);
676}
677
679
680/* -------------------------------------------------------------------- */
683
687
689 {OL_SCENE_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
690 {0, nullptr, 0, nullptr, nullptr},
691};
692
694 bContext *C,
695 SpaceOutliner *space_outliner,
697 bool (*operation_fn)(bContext *, eOutliner_PropSceneOps, TreeElement *, TreeStoreElem *))
698{
699 bool success = false;
700
701 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
702 TreeStoreElem *tselem = TREESTORE(te);
703 if (tselem->flag & TSE_SELECTED) {
704 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) {
705 if (operation_fn(C, event, te, tselem)) {
706 success = true;
707 }
708 }
709 }
710 });
711
712 return success;
713}
714
715static bool scene_fn(bContext *C,
717 TreeElement * /*te*/,
718 TreeStoreElem *tselem)
719{
720 Scene *scene = (Scene *)tselem->id;
721
722 if (event == OL_SCENE_OP_DELETE) {
723 if (ED_scene_delete(C, CTX_data_main(C), scene)) {
725 }
726 else {
727 return false;
728 }
729 }
730
731 return true;
732}
733
735{
736 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
738
739 if (outliner_do_scene_operation(C, space_outliner, event, scene_fn) == false) {
740 return OPERATOR_CANCELLED;
741 }
742
743 if (event == OL_SCENE_OP_DELETE) {
744 outliner_cleanup_tree(space_outliner);
745 ED_undo_push(C, "Delete Scene(s)");
746 }
747 else {
749 return OPERATOR_CANCELLED;
750 }
751
752 return OPERATOR_FINISHED;
753}
754
756{
757 /* identifiers */
758 ot->name = "Outliner Scene Operation";
759 ot->idname = "OUTLINER_OT_scene_operation";
760 ot->description = "Context menu for scene operations";
761
762 /* callbacks */
763 ot->invoke = WM_menu_invoke;
766
767 ot->flag = 0;
768
769 ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", "");
770}
771
773
774/* -------------------------------------------------------------------- */
777
787
789 const ListBase *tree, short tselem_type, short type, const char *str, uiSearchItems *items)
790{
791 char name[64];
792 int iconid;
793
795 TreeStoreElem *tselem = TREESTORE(te);
796
797 if (tree_element_id_type_to_index(te) == type && tselem_type == tselem->type) {
798 if (BLI_strcasestr(te->name, str)) {
799 STRNCPY(name, te->name);
800
801 iconid = tree_element_get_icon(tselem, te).icon;
802
803 /* Don't allow duplicate named items */
804 if (UI_search_items_find_index(items, name) == -1) {
805 if (!UI_search_item_add(items, name, te, iconid, 0, 0)) {
806 break;
807 }
808 }
809 }
810 }
811
812 merged_element_search_fn_recursive(&te->subtree, tselem_type, type, str, items);
813 }
814}
815
816/* Get a list of elements that match the search string */
818 void *data,
819 const char *str,
820 uiSearchItems *items,
821 const bool /*is_first*/)
822{
823 MergedSearchData *search_data = (MergedSearchData *)data;
824 TreeElement *parent = search_data->parent_element;
825 TreeElement *te = search_data->select_element;
826
827 int type = tree_element_id_type_to_index(te);
828
829 merged_element_search_fn_recursive(&parent->subtree, TREESTORE(te)->type, type, str, items);
830}
831
832/* Activate an element from the merged element search menu */
833static void merged_element_search_exec_fn(bContext *C, void * /*arg1*/, void *element)
834{
835 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
837
839
841}
842
848{
849 static char search[64] = "";
850 uiBlock *block;
851 uiBut *but;
852
853 /* Clear search on each menu creation */
854 *search = '\0';
855
856 block = UI_block_begin(C, region, __func__, blender::ui::EmbossType::Emboss);
859
860 short menu_width = 10 * UI_UNIT_X;
861 but = uiDefSearchBut(
862 block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, menu_width, UI_UNIT_Y, "");
864 nullptr,
866 data,
867 false,
868 nullptr,
870 nullptr);
872
873 /* Fake button to hold space for search items */
874 const int height = UI_searchbox_size_y() - UI_SEARCHBOX_BOUNDS;
875 uiDefBut(
876 block, UI_BTYPE_LABEL, 0, "", 0, -height, menu_width, height, nullptr, 0, 0, std::nullopt);
877
878 /* Center the menu on the cursor */
879 const int offset[2] = {-(menu_width / 2), 0};
881
882 return block;
883}
884
886 TreeElement *parent_te,
887 TreeElement *activate_te)
888{
889 MergedSearchData *select_data = MEM_callocN<MergedSearchData>("merge_search_data");
890 select_data->parent_element = parent_te;
891 select_data->select_element = activate_te;
892
894}
895
897 ReportList * /*reports*/,
898 Scene * /*scene*/,
899 TreeElement * /*te*/,
900 TreeStoreElem * /*tsep*/,
901 TreeStoreElem *tselem)
902{
903 const Scene *scene = CTX_data_scene(C);
904 ViewLayer *view_layer = CTX_data_view_layer(C);
905 Object *ob = (Object *)tselem->id;
906 BKE_view_layer_synced_ensure(scene, view_layer);
907 Base *base = BKE_view_layer_base_find(view_layer, ob);
908
909 if (base) {
911 }
912}
913
915
916/* -------------------------------------------------------------------- */
919
921 ReportList * /*reports*/,
922 Scene * /*scene*/,
923 TreeElement *te,
924 TreeStoreElem * /*tsep*/,
925 TreeStoreElem * /*tselem*/)
926{
927 /* Don't extend because this toggles, which is nice for Ctrl-Click but not for a menu item.
928 * it's especially confusing when multiple items are selected since some toggle on/off. */
929 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
931 C, space_outliner, te, OL_ITEM_SELECT | OL_ITEM_ACTIVATE | OL_ITEM_RECURSIVE);
932}
933
935 ReportList * /*reports*/,
936 Scene * /*scene*/,
937 TreeElement * /*te*/,
938 TreeStoreElem * /*tsep*/,
939 TreeStoreElem *tselem)
940{
941 const Scene *scene = CTX_data_scene(C);
942 ViewLayer *view_layer = CTX_data_view_layer(C);
943 Object *ob = (Object *)tselem->id;
944 BKE_view_layer_synced_ensure(scene, view_layer);
945 Base *base = BKE_view_layer_base_find(view_layer, ob);
946
947 if (base) {
948 base->flag &= ~BASE_SELECTED;
949 }
950}
951
953{
954 if (ob) {
955 Main *bmain = CTX_data_main(C);
956 if (ob->id.tag & ID_TAG_INDIRECT) {
958 reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2);
959 return;
960 }
961 if (ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0 &&
963 {
966 "Cannot delete object '%s' from scene '%s', indirectly used objects need at "
967 "least one user",
968 ob->id.name + 2,
969 scene->id.name + 2);
970 return;
971 }
972
973 /* Check also library later. */
974 if ((ob->mode & OB_MODE_EDIT) && BKE_object_is_in_editmode(ob)) {
976 }
977 BKE_id_delete(bmain, ob);
978 }
979}
980
981static void id_local_fn(bContext *C,
982 ReportList * /*reports*/,
983 Scene * /*scene*/,
984 TreeElement * /*te*/,
985 TreeStoreElem * /*tsep*/,
986 TreeStoreElem *tselem)
987{
988 if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & ID_TAG_EXTERN)) {
989 Main *bmain = CTX_data_main(C);
992 }
993 }
994 else if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id)) {
996 }
997}
998
1017
1020
1023
1029
1033
1040
1043
1044 void id_root_add(ID *id_hierarchy_root_reference,
1045 ID *id_root_reference,
1046 ID *id_instance_hint,
1047 const bool is_override_instancing_object)
1048 {
1049 OutlinerLiboverrideDataIDRoot id_root_data;
1050 id_root_data.id_root_reference = id_root_reference;
1051 id_root_data.id_hierarchy_root_override = nullptr;
1052 id_root_data.id_instance_hint = id_instance_hint;
1053 id_root_data.is_override_instancing_object = is_override_instancing_object;
1054
1055 Vector<OutlinerLiboverrideDataIDRoot> &value = id_hierarchy_roots.lookup_or_add_default(
1056 id_hierarchy_root_reference);
1057 value.append(id_root_data);
1058 }
1059 void id_root_set(ID *id_hierarchy_root_reference)
1060 {
1061 OutlinerLiboverrideDataIDRoot id_root_data;
1062 id_root_data.id_root_reference = nullptr;
1063 id_root_data.id_hierarchy_root_override = nullptr;
1064 id_root_data.id_instance_hint = nullptr;
1065 id_root_data.is_override_instancing_object = false;
1066
1067 Vector<OutlinerLiboverrideDataIDRoot> &value = id_hierarchy_roots.lookup_or_add_default(
1068 id_hierarchy_root_reference);
1069 if (value.is_empty()) {
1070 value.append(id_root_data);
1071 }
1072 }
1073};
1074
1075/* Store 'UUID' of IDs of selected elements in the Outliner tree, before generating the override
1076 * hierarchy. */
1080 TreeElement *te,
1081 TreeStoreElem *tsep,
1082 TreeStoreElem *tselem)
1083{
1084 BLI_assert(TSE_IS_REAL_ID(tselem));
1085
1086 const bool do_hierarchy = data->do_hierarchy;
1087 ID *id_root_reference = tselem->id;
1088
1089 if (!BKE_idtype_idcode_is_linkable(GS(id_root_reference->name)) ||
1091 0)
1092 {
1093 return;
1094 }
1095
1096 /* Only process a given ID once. Otherwise, all kind of weird things can happen if e.g. a
1097 * selected sub-collection is part of more than one override hierarchies. */
1098 if (data->selected_id_uid.contains(id_root_reference->session_uid)) {
1099 return;
1100 }
1101 data->selected_id_uid.add(id_root_reference->session_uid);
1102
1103 if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root_reference) && !ID_IS_LINKED(id_root_reference)) {
1105 return;
1106 }
1107
1108 if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id_root_reference)) {
1109 if (ID_IS_LINKED(id_root_reference)) {
1111 reports,
1113 "Could not create library override from data-block '%s', as it is not overridable",
1114 id_root_reference->name);
1115 }
1116 /* Else it's a local ID, do not bother reporting this, as it gets annoyingly noisy then when
1117 * operated e.g. on a hierarchy of liboverrides. */
1118 return;
1119 }
1120
1121 BLI_assert(do_hierarchy);
1122 UNUSED_VARS_NDEBUG(do_hierarchy);
1123
1124 if (GS(id_root_reference->name) == ID_GR && (tselem->flag & TSE_CLOSED) != 0) {
1125 /* If selected element is a (closed) collection, check all of its objects recursively, and also
1126 * consider the armature ones as 'selected' (i.e. to not become system overrides). */
1127 Collection *root_collection = reinterpret_cast<Collection *>(id_root_reference);
1128 FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (root_collection, object_iter) {
1129 if (id_root_reference->lib == object_iter->id.lib && object_iter->type == OB_ARMATURE) {
1130 data->selected_id_uid.add(object_iter->id.session_uid);
1131 }
1132 }
1134 }
1135
1136 ID *id_instance_hint = nullptr;
1137 bool is_override_instancing_object = false;
1138 if (tsep != nullptr && tsep->type == TSE_SOME_ID && tsep->id != nullptr &&
1139 GS(tsep->id->name) == ID_OB && !ID_IS_OVERRIDE_LIBRARY(tsep->id))
1140 {
1141 Object *ob = reinterpret_cast<Object *>(tsep->id);
1142 if (ob->type == OB_EMPTY && &ob->instance_collection->id == id_root_reference) {
1143 BLI_assert(GS(id_root_reference->name) == ID_GR);
1144 /* Empty instantiating the collection we override, we need to pass it to BKE overriding code
1145 * for proper handling. */
1146 id_instance_hint = tsep->id;
1147 is_override_instancing_object = true;
1148 }
1149 }
1150
1151 if (!ID_IS_OVERRIDABLE_LIBRARY(id_root_reference) &&
1152 !(ID_IS_LINKED(id_root_reference) && do_hierarchy))
1153 {
1154 return;
1155 }
1156
1157 Main *bmain = CTX_data_main(C);
1158
1159 if (do_hierarchy) {
1160 /* Tag all linked parents in tree hierarchy to be also overridden. */
1161 ID *id_hierarchy_root_reference = id_root_reference;
1162 while ((te = te->parent) != nullptr) {
1163 if (!TSE_IS_REAL_ID(te->store_elem)) {
1164 continue;
1165 }
1166
1167 /* Tentative hierarchy root. */
1168 ID *id_current_hierarchy_root = te->store_elem->id;
1169
1170 /* If the parent ID is from a different library than the reference root one, we are done
1171 * with upwards tree processing in any case. */
1172 if (id_current_hierarchy_root->lib != id_root_reference->lib) {
1173 if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id_current_hierarchy_root)) {
1174 /* Virtual overrides (i.e. embedded IDs), we can simply keep processing their parent to
1175 * get an actual real override. */
1176 continue;
1177 }
1178
1179 /* If the parent ID is already an override, and is valid (i.e. local override), we can
1180 * access its hierarchy root directly. */
1181 if (!ID_IS_LINKED(id_current_hierarchy_root) &&
1182 ID_IS_OVERRIDE_LIBRARY_REAL(id_current_hierarchy_root) &&
1183 id_current_hierarchy_root->override_library->reference->lib == id_root_reference->lib)
1184 {
1185 id_hierarchy_root_reference =
1186 id_current_hierarchy_root->override_library->hierarchy_root;
1187 BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
1188 break;
1189 }
1190
1191 if (ID_IS_LINKED(id_current_hierarchy_root)) {
1192 /* No local 'anchor' was found for the hierarchy to override, do not proceed, as this
1193 * would most likely generate invisible/confusing/hard to use and manage overrides. */
1194 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
1197 "Invalid anchor ('%s') found, needed to create library override from "
1198 "data-block '%s'",
1199 id_current_hierarchy_root->name,
1200 id_root_reference->name);
1201 return;
1202 }
1203
1204 /* In all other cases, `id_current_hierarchy_root` cannot be a valid hierarchy root, so
1205 * current `id_hierarchy_root_reference` is our best candidate. */
1206
1207 break;
1208 }
1209
1210 /* If some element in the tree needs to be overridden, but its ID is not overridable,
1211 * abort. */
1212 if (!ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id_current_hierarchy_root)) {
1213 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
1216 "Could not create library override from data-block '%s', one of its parents "
1217 "is not overridable ('%s')",
1218 id_root_reference->name,
1219 id_current_hierarchy_root->name);
1220 return;
1221 }
1222 id_current_hierarchy_root->tag |= ID_TAG_DOIT;
1223 id_hierarchy_root_reference = id_current_hierarchy_root;
1224 }
1225
1226 /* That case can happen when linked data is a complex mix involving several libraries and/or
1227 * linked overrides. E.g. a mix of overrides from one library, and indirectly linked data
1228 * from another library. Do not try to support such cases for now. */
1229 if (!((id_hierarchy_root_reference->lib == id_root_reference->lib) ||
1230 (!ID_IS_LINKED(id_hierarchy_root_reference) &&
1231 ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference) &&
1232 id_hierarchy_root_reference->override_library->reference->lib ==
1233 id_root_reference->lib)))
1234 {
1235 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
1238 "Invalid hierarchy root ('%s') found, needed to create library override from "
1239 "data-block '%s'",
1240 id_hierarchy_root_reference->name,
1241 id_root_reference->name);
1242 return;
1243 }
1244
1245 /* While ideally this should not be needed, in practice user almost _never_ wants to actually
1246 * create liboverrides for all data under a selected hierarchy node, and this has currently a
1247 * dreadful consequences over performances (since it would call
1248 * #BKE_lib_override_library_create over _all_ items in the hierarchy). So only the clearing of
1249 * the system override flag is supported for non-selected items for now.
1250 */
1251 const bool is_selected = tselem->flag & TSE_SELECTED;
1252 if (!is_selected && data->id_hierarchy_roots.contains(id_hierarchy_root_reference)) {
1253 return;
1254 }
1255
1256 data->id_root_add(id_hierarchy_root_reference,
1257 id_root_reference,
1258 id_instance_hint,
1259 is_override_instancing_object);
1260 }
1261 else if (ID_IS_OVERRIDABLE_LIBRARY(id_root_reference)) {
1262 data->id_root_add(
1263 id_root_reference, id_root_reference, id_instance_hint, is_override_instancing_object);
1264 }
1265}
1266
1268 Main &bmain,
1269 Scene *scene,
1270 ViewLayer *view_layer,
1272 ID *id_hierarchy_root_reference,
1274 bool &r_aggregated_success)
1275{
1276 BLI_assert(ID_IS_LINKED(id_hierarchy_root_reference) ||
1277 ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
1278
1279 const bool do_hierarchy = data.do_hierarchy;
1280
1281 /* NOTE: This process is not the most efficient, but allows to re-use existing code.
1282 * If this becomes a bottle-neck at some point, we need to implement a new
1283 * `BKE_lib_override_library_hierarchy_create()` function able to process several roots inside of
1284 * a same hierarchy in a single call. */
1285 for (OutlinerLiboverrideDataIDRoot &data_idroot : data_idroots) {
1286 /* For now, remap all local usages of linked ID to local override one here. */
1287 ID *id_iter;
1288 FOREACH_MAIN_ID_BEGIN (&bmain, id_iter) {
1289 if (ID_IS_LINKED(id_iter) || ID_IS_OVERRIDE_LIBRARY(id_iter)) {
1290 id_iter->tag &= ~ID_TAG_DOIT;
1291 }
1292 else {
1293 id_iter->tag |= ID_TAG_DOIT;
1294 }
1295 }
1297
1298 bool success = false;
1299 if (do_hierarchy) {
1300 ID *id_root_override = nullptr;
1301 success = BKE_lib_override_library_create(&bmain,
1302 scene,
1303 view_layer,
1304 nullptr,
1305 data_idroot.id_root_reference,
1306 id_hierarchy_root_reference,
1307 data_idroot.id_instance_hint,
1308 &id_root_override,
1309 data.do_fully_editable);
1310
1311 if (success) {
1312 BLI_assert(id_root_override != nullptr);
1313 BLI_assert(!ID_IS_LINKED(id_root_override));
1314 BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root_override));
1315
1316 ID *id_hierarchy_root_override = id_root_override->override_library->hierarchy_root;
1317 BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_override));
1318 if (ID_IS_LINKED(id_hierarchy_root_reference)) {
1319 BLI_assert(id_hierarchy_root_override->override_library->reference ==
1320 id_hierarchy_root_reference);
1321 /* If the hierarchy root reference was a linked data, after the first iteration there is
1322 * now a matching override, which shall be used for all further partial overrides with
1323 * this same hierarchy. */
1324 id_hierarchy_root_reference = id_hierarchy_root_override;
1325 }
1326 else {
1327 BLI_assert(id_hierarchy_root_override == id_hierarchy_root_reference);
1328 }
1329 data_idroot.id_hierarchy_root_override = id_hierarchy_root_override;
1330 data.id_hierarchy_roots_uid.add(id_hierarchy_root_override->session_uid);
1331 }
1332 }
1333 else if (ID_IS_OVERRIDABLE_LIBRARY(data_idroot.id_root_reference)) {
1334 ID *id_root_override = BKE_lib_override_library_create_from_id(
1335 &bmain, data_idroot.id_root_reference, true);
1336
1337 success = id_root_override != nullptr;
1338 if (success) {
1339 BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root_override));
1341 }
1342 /* Cleanup. */
1344 BKE_main_id_tag_all(&bmain, ID_TAG_DOIT, false);
1345 }
1346 else {
1348 }
1349
1350 /* Remove the instance empty from this scene, the items now have an overridden collection
1351 * instead. */
1352 if (success && data_idroot.is_override_instancing_object) {
1353 BLI_assert(GS(data_idroot.id_instance_hint->name) == ID_OB);
1355 &bmain, scene, reinterpret_cast<Object *>(data_idroot.id_instance_hint));
1356 }
1357
1358 r_aggregated_success = r_aggregated_success && success;
1359 }
1360}
1361
1362/* Clear system override flag from newly created overrides which linked reference were previously
1363 * selected in the Outliner tree. */
1367{
1368 Main *bmain = CTX_data_main(C);
1369 Scene *scene = CTX_data_scene(C);
1370 ViewLayer *view_layer = CTX_data_view_layer(C);
1371 const bool do_hierarchy = data.do_hierarchy;
1372
1373 bool success = true;
1374 for (auto &&[id_hierarchy_root_reference, data_idroots] : data.id_hierarchy_roots.items()) {
1376 *bmain, scene, view_layer, data, id_hierarchy_root_reference, data_idroots, success);
1377 }
1378
1379 if (!success) {
1382 "Could not create library override from one or more of the selected data-blocks");
1383 }
1384
1385 if (!do_hierarchy) {
1386 return;
1387 }
1388
1389 ID *id_iter;
1390 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
1391 if (ID_IS_LINKED(id_iter) || !ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) {
1392 continue;
1393 }
1394 if (id_iter->override_library->hierarchy_root != nullptr &&
1395 !data.id_hierarchy_roots_uid.contains(
1397 {
1398 continue;
1399 }
1400 if (data.selected_id_uid.contains(id_iter->override_library->reference->session_uid) ||
1401 data.selected_id_uid.contains(id_iter->session_uid))
1402 {
1404 }
1405 }
1407}
1408
1411 TreeStoreElem *tselem)
1412{
1413 BLI_assert(TSE_IS_REAL_ID(tselem));
1414 ID *id_root = tselem->id;
1415 const bool do_hierarchy = data->do_hierarchy;
1416
1417 if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) {
1418 CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name);
1419 return;
1420 }
1421
1422 Main *bmain = CTX_data_main(C);
1423
1424 if (do_hierarchy) {
1425 BKE_lib_override_library_id_hierarchy_reset(bmain, id_root, false);
1426 }
1427 else {
1428 BKE_lib_override_library_id_reset(bmain, id_root, false);
1429 }
1430}
1431
1433 ReportList * /*reports*/,
1435{
1436 Main *bmain = CTX_data_main(C);
1437 ViewLayer *view_layer = CTX_data_view_layer(C);
1438 Scene *scene = CTX_data_scene(C);
1439
1440 /* TODO: At some point this likely needs to be re-written as a BKE function instead, with better
1441 * handling of hierarchies among other things. */
1442
1443 /* Try to process all potential leaves first (deleting some liboverride leaves will turn other
1444 * liboverrides into leaves as well). */
1445 bool do_process_leaves = true;
1446 while (!data.id_hierarchy_roots.is_empty()) {
1447 bool has_found_leaves = false;
1448
1449 for (auto &&id : data.id_hierarchy_roots.keys()) {
1450 if (do_process_leaves) {
1452 /* If given ID is not using any other override (it's a 'leaf' in the override hierarchy),
1453 * delete it and remap its usages to its linked reference. Otherwise, keep it as a reset
1454 * system override. */
1455 bool do_remap_active = false;
1456 BKE_view_layer_synced_ensure(scene, view_layer);
1457 if (BKE_view_layer_active_object_get(view_layer) == reinterpret_cast<Object *>(id)) {
1458 BLI_assert(GS(id->name) == ID_OB);
1459 do_remap_active = true;
1460 }
1462 bmain, id, id->override_library->reference, ID_REMAP_SKIP_INDIRECT_USAGE);
1463 if (do_remap_active) {
1464 BKE_view_layer_synced_ensure(scene, view_layer);
1465 Object *ref_object = reinterpret_cast<Object *>(id->override_library->reference);
1466 Base *basact = BKE_view_layer_base_find(view_layer, ref_object);
1467 if (basact != nullptr) {
1468 view_layer->basact = basact;
1469 }
1471 }
1472
1473 BKE_id_delete(bmain, id);
1474 data.id_hierarchy_roots.remove(id);
1475 has_found_leaves = true;
1476 }
1477 }
1478 else {
1480 BKE_lib_override_library_id_reset(bmain, id, true);
1481 data.id_hierarchy_roots.remove(id);
1482 }
1483 }
1484
1485 do_process_leaves = has_found_leaves;
1486 }
1488}
1489
1492 TreeStoreElem *tselem)
1493{
1494 BLI_assert(TSE_IS_REAL_ID(tselem));
1495 ID *id = tselem->id;
1496
1497 if (!ID_IS_OVERRIDE_LIBRARY(id)) {
1498 return;
1499 }
1500 if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
1503 "Cannot clear embedded library override '%s', only overrides of real data-blocks "
1504 "can be directly cleared",
1505 id->name);
1506 return;
1507 }
1508 if (ID_IS_LINKED(id)) {
1510 reports,
1512 "Cannot clear linked library override '%s', only local overrides can be directly cleared",
1513 id->name);
1514 return;
1515 }
1516
1517 data->id_root_set(id);
1518}
1519
1521{
1522 BLI_assert(TSE_IS_REAL_ID(tselem));
1523 ID *id_root = tselem->id;
1524
1525 if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) {
1526 CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name);
1527 return;
1528 }
1529
1530 if (id_root->override_library->hierarchy_root != nullptr) {
1531 id_root = id_root->override_library->hierarchy_root;
1532 }
1533
1534 data->id_root_set(id_root);
1535}
1536
1537/* Resync a hierarchy of library overrides. */
1541{
1542 Main *bmain = CTX_data_main(C);
1543 Scene *scene = CTX_data_scene(C);
1544 const bool do_hierarchy_enforce = data.do_resync_hierarchy_enforce;
1545
1546 BlendFileReadReport report{};
1547 report.reports = reports;
1548
1549 for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) {
1551 scene,
1553 id_hierarchy_root,
1554 nullptr,
1555 do_hierarchy_enforce,
1556 &report);
1557 }
1558
1560}
1561
1563 TreeStoreElem *tselem)
1564{
1565 BLI_assert(TSE_IS_REAL_ID(tselem));
1566 ID *id_root = tselem->id;
1567
1568 if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root) || ID_IS_LINKED(id_root)) {
1569 CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name);
1570 return;
1571 }
1572
1573 if (id_root->override_library->hierarchy_root != nullptr) {
1574 id_root = id_root->override_library->hierarchy_root;
1575 }
1576
1577 data->id_root_set(id_root);
1578}
1579
1580/* Clear (delete) a hierarchy of library overrides. */
1582 ReportList * /*reports*/,
1584{
1585 Main *bmain = CTX_data_main(C);
1586
1587 for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) {
1588 BKE_lib_override_library_delete(bmain, id_hierarchy_root);
1589 }
1590}
1591
1592static void id_fake_user_set_fn(bContext * /*C*/,
1593 ReportList * /*reports*/,
1594 Scene * /*scene*/,
1595 TreeElement * /*te*/,
1596 TreeStoreElem * /*tsep*/,
1597 TreeStoreElem *tselem)
1598{
1599 ID *id = tselem->id;
1600
1601 id_fake_user_set(id);
1602}
1603
1605 ReportList * /*reports*/,
1606 Scene * /*scene*/,
1607 TreeElement * /*te*/,
1608 TreeStoreElem * /*tsep*/,
1609 TreeStoreElem *tselem)
1610{
1611 ID *id = tselem->id;
1612
1614}
1615
1617 ReportList * /*reports*/,
1618 Scene * /*scene*/,
1619 TreeElement * /*te*/,
1620 TreeStoreElem * /*tsep*/,
1621 TreeStoreElem *tselem)
1622{
1623 ID *id = tselem->id;
1624
1626}
1627
1629 ReportList * /*reports*/,
1630 Scene * /*scene*/,
1631 TreeElement *te,
1632 TreeStoreElem *tsep,
1633 TreeStoreElem *tselem)
1634{
1635 /* This callback runs for all selected elements, some of which may not be actions which results
1636 * in a crash. */
1637 if (te->idcode != ID_AC) {
1638 return;
1639 }
1640
1641 ID *id = tselem->id;
1642
1643 if (id) {
1644 IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id;
1645 PropertyRNA *prop;
1646
1647 PointerRNA ptr = RNA_pointer_create_discrete(&iat->id, &RNA_AnimData, iat->adt);
1648 prop = RNA_struct_find_property(&ptr, "action");
1649
1650 id_single_user(C, id, &ptr, prop);
1651 }
1652}
1653
1655 ReportList * /*reports*/,
1656 Scene * /*scene*/,
1657 TreeElement * /*te*/,
1658 TreeStoreElem *tsep,
1659 TreeStoreElem *tselem)
1660{
1661 ID *id = tselem->id;
1662
1663 /* need to use parent scene not just scene, otherwise may end up getting wrong one */
1664 if (id) {
1665 Scene *parscene = (Scene *)tsep->id;
1666 PropertyRNA *prop;
1667
1668 PointerRNA ptr = RNA_id_pointer_create(&parscene->id);
1669 prop = RNA_struct_find_property(&ptr, "world");
1670
1671 id_single_user(C, id, &ptr, prop);
1672 }
1673}
1674
1677 Scene *scene_act,
1678 SpaceOutliner *space_outliner,
1679 ListBase *lb,
1680 outliner_operation_fn operation_fn,
1681 bool recurse_selected)
1682{
1683 LISTBASE_FOREACH (TreeElement *, te, lb) {
1684 TreeStoreElem *tselem = TREESTORE(te);
1685 bool select_handled = false;
1686 if (tselem->flag & TSE_SELECTED) {
1687 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1688 /* When objects selected in other scenes, don't know if that should be allowed. */
1689 Scene *scene_owner = (Scene *)outliner_search_back(te, ID_SCE);
1690 if (scene_owner && scene_act != scene_owner) {
1692 }
1693 /* Important to use 'scene_owner' not scene_act else deleting objects can crash.
1694 * only use 'scene_act' when 'scene_owner' is nullptr, which can happen when the
1695 * outliner isn't showing scenes: Visible Layer draw mode for eg. */
1696 operation_fn(C, reports, scene_owner ? scene_owner : scene_act, te, nullptr, tselem);
1697 select_handled = true;
1698 }
1699 }
1700 if (TSELEM_OPEN(tselem, space_outliner)) {
1701 if ((select_handled == false) || recurse_selected) {
1703 C, reports, scene_act, space_outliner, &te->subtree, operation_fn, recurse_selected);
1704 }
1705 }
1706 }
1707}
1708
1711 Scene *scene_act,
1712 SpaceOutliner *space_outliner,
1713 ListBase *lb,
1714 outliner_operation_fn operation_fn)
1715{
1716 outliner_do_object_operation_ex(C, reports, scene_act, space_outliner, lb, operation_fn, true);
1717}
1718
1720
1721/* -------------------------------------------------------------------- */
1724
1725static void clear_animdata_fn(int /*event*/,
1726 TreeElement * /*te*/,
1727 TreeStoreElem *tselem,
1728 void * /*arg*/)
1729{
1730 BKE_animdata_free(tselem->id, true);
1732}
1733
1734static void unlinkact_animdata_fn(int /*event*/,
1735 TreeElement * /*te*/,
1736 TreeStoreElem *tselem,
1737 void * /*arg*/)
1738{
1739 /* just set action to nullptr */
1740 BKE_animdata_set_action(nullptr, tselem->id, nullptr);
1742}
1743
1744static void cleardrivers_animdata_fn(int /*event*/,
1745 TreeElement * /*te*/,
1746 TreeStoreElem *tselem,
1747 void * /*arg*/)
1748{
1749 IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id;
1750
1751 /* just free drivers - stored as a list of F-Curves */
1754}
1755
1756static void refreshdrivers_animdata_fn(int /*event*/,
1757 TreeElement * /*te*/,
1758 TreeStoreElem *tselem,
1759 void * /*arg*/)
1760{
1761 IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id;
1762
1763 /* Loop over drivers, performing refresh
1764 * (i.e. check `graph_buttons.cc` and `rna_fcurve.cc` for details). */
1765 LISTBASE_FOREACH (FCurve *, fcu, &iat->adt->drivers) {
1766 fcu->flag &= ~FCURVE_DISABLED;
1767
1768 if (fcu->driver) {
1769 fcu->driver->flag &= ~DRIVER_FLAG_INVALID;
1770 }
1771 }
1772}
1773
1775
1776/* -------------------------------------------------------------------- */
1779
1791
1794 "OVERRIDE_LIBRARY_CREATE_HIERARCHY",
1795 0,
1796 "Make",
1797 "Create a local override of the selected linked data-blocks, and their hierarchy of "
1798 "dependencies"},
1800 "OVERRIDE_LIBRARY_RESET",
1801 0,
1802 "Reset",
1803 "Reset the selected local overrides to their linked references values"},
1805 "OVERRIDE_LIBRARY_CLEAR_SINGLE",
1806 0,
1807 "Clear",
1808 "Delete the selected local overrides and relink their usages to the linked data-blocks if "
1809 "possible, else reset them and mark them as non editable"},
1810 {0, nullptr, 0, nullptr, nullptr},
1811};
1812
1815 "OVERRIDE_LIBRARY_RESYNC_HIERARCHY",
1816 0,
1817 "Resync",
1818 "Rebuild the selected local overrides from their linked references, as well as their "
1819 "hierarchies of dependencies"},
1821 "OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE",
1822 0,
1823 "Resync Enforce",
1824 "Rebuild the selected local overrides from their linked references, as well as their "
1825 "hierarchies of dependencies, enforcing these hierarchies to match the linked data (i.e. "
1826 "ignoring existing overrides on data-blocks pointer properties)"},
1829 "OVERRIDE_LIBRARY_DELETE_HIERARCHY",
1830 0,
1831 "Delete",
1832 "Delete the selected local overrides (including their hierarchies of override dependencies) "
1833 "and relink their usages to the linked data-blocks"},
1834 {0, nullptr, 0, nullptr, nullptr},
1835};
1836
1838{
1840 return false;
1841 }
1842 return true;
1843}
1844
1846{
1847 Scene *scene = CTX_data_scene(C);
1848 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1849
1850 /* check for invalid states */
1851 if (space_outliner == nullptr) {
1852 return OPERATOR_CANCELLED;
1853 }
1854
1855 const eOutlinerLibOpSelectionSet selection_set = static_cast<eOutlinerLibOpSelectionSet>(
1856 RNA_enum_get(op->ptr, "selection_set"));
1858 RNA_enum_get(op->ptr, "type"));
1859 switch (event) {
1861 OutlinerLibOverrideData override_data{};
1862 override_data.do_hierarchy = true;
1863 override_data.do_fully_editable = false;
1864
1866 C,
1867 op->reports,
1868 scene,
1869 space_outliner,
1870 [&](bContext *C,
1872 Scene * /*scene*/,
1873 TreeElement *te,
1874 TreeStoreElem *tsep,
1875 TreeStoreElem *tselem) {
1876 id_override_library_create_hierarchy_pre_process(
1877 C, &override_data, reports, te, tsep, tselem);
1878 },
1879 selection_set,
1880 true);
1881
1883
1884 ED_undo_push(C, "Overridden Data Hierarchy");
1885 break;
1886 }
1888 OutlinerLibOverrideData override_data{};
1890 C,
1891 op->reports,
1892 scene,
1893 space_outliner,
1894 [&](bContext *C,
1895 ReportList * /*reports*/,
1896 Scene * /*scene*/,
1897 TreeElement * /*te*/,
1898 TreeStoreElem * /*tsep*/,
1899 TreeStoreElem *tselem) { id_override_library_reset(C, &override_data, tselem); },
1900 selection_set,
1901 false);
1902 ED_undo_push(C, "Reset Overridden Data");
1903 break;
1904 }
1906 OutlinerLibOverrideData override_data{};
1907 override_data.do_hierarchy = false;
1908 override_data.do_fully_editable = false;
1909
1911 C,
1912 op->reports,
1913 scene,
1914 space_outliner,
1915 [&](bContext * /*C*/,
1917 Scene * /*scene*/,
1918 TreeElement * /*te*/,
1919 TreeStoreElem * /*tsep*/,
1920 TreeStoreElem *tselem) {
1921 id_override_library_clear_single(&override_data, reports, tselem);
1922 },
1923 selection_set,
1924 false);
1925
1927
1928 ED_undo_push(C, "Clear Overridden Data");
1929 break;
1930 }
1931
1933 OutlinerLibOverrideData override_data{};
1934 override_data.do_hierarchy = true;
1936 C,
1937 op->reports,
1938 scene,
1939 space_outliner,
1940 [&](bContext * /*C*/,
1941 ReportList * /*reports*/,
1942 Scene * /*scene*/,
1943 TreeElement * /*te*/,
1944 TreeStoreElem * /*tsep*/,
1945 TreeStoreElem *tselem) { id_override_library_resync(&override_data, tselem); },
1947 false);
1948
1950
1951 ED_undo_push(C, "Resync Overridden Data Hierarchy");
1952 break;
1953 }
1955 OutlinerLibOverrideData override_data{};
1956 override_data.do_hierarchy = true;
1957 override_data.do_resync_hierarchy_enforce = true;
1959 C,
1960 op->reports,
1961 scene,
1962 space_outliner,
1963 [&](bContext * /*C*/,
1964 ReportList * /*reports*/,
1965 Scene * /*scene*/,
1966 TreeElement * /*te*/,
1967 TreeStoreElem * /*tsep*/,
1968 TreeStoreElem *tselem) { id_override_library_resync(&override_data, tselem); },
1970 false);
1971
1973
1974 ED_undo_push(C, "Resync Overridden Data Hierarchy Enforce");
1975 break;
1976 }
1978 OutlinerLibOverrideData override_data{};
1979 override_data.do_hierarchy = true;
1981 C,
1982 op->reports,
1983 scene,
1984 space_outliner,
1985 [&](bContext * /*C*/,
1986 ReportList * /*reports*/,
1987 Scene * /*scene*/,
1988 TreeElement * /*te*/,
1989 TreeStoreElem * /*tsep*/,
1990 TreeStoreElem *tselem) {
1991 id_override_library_delete_hierarchy(&override_data, tselem);
1992 },
1994 false);
1995
1997
1998 ED_undo_push(C, "Delete Overridden Data Hierarchy");
1999 break;
2000 }
2001 default:
2002 /* Invalid - unhandled. */
2003 break;
2004 }
2005
2009
2010 return OPERATOR_FINISHED;
2011}
2012
2014{
2015 /* identifiers */
2016 ot->name = "Outliner Library Override Operation";
2017 ot->idname = "OUTLINER_OT_liboverride_operation";
2018 ot->description = "Create, reset or clear library override hierarchies";
2019
2020 /* callbacks */
2021 ot->invoke = WM_menu_invoke;
2024
2025 ot->flag = 0;
2026
2027 RNA_def_enum(ot->srna, "type", prop_liboverride_op_types, 0, "Library Override Operation", "");
2028 ot->prop = RNA_def_enum(ot->srna,
2029 "selection_set",
2031 0,
2032 "Selection Set",
2033 "Over which part of the tree items to apply the operation");
2034}
2035
2037{
2038 /* identifiers */
2039 ot->name = "Outliner Library Override Troubleshoot Operation";
2040 ot->idname = "OUTLINER_OT_liboverride_troubleshoot_operation";
2041 ot->description = "Advanced operations over library override to help fix broken hierarchies";
2042
2043 /* callbacks */
2044 ot->invoke = WM_menu_invoke;
2047
2048 ot->flag = 0;
2049
2050 ot->prop = RNA_def_enum(ot->srna,
2051 "type",
2053 0,
2054 "Library Override Troubleshoot Operation",
2055 "");
2056 RNA_def_enum(ot->srna,
2057 "selection_set",
2059 0,
2060 "Selection Set",
2061 "Over which part of the tree items to apply the operation");
2062}
2063
2065
2066/* -------------------------------------------------------------------- */
2069
2077
2083
2090
2091static void pchan_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, void * /*arg*/)
2092{
2093 bPoseChannel *pchan = (bPoseChannel *)te->directdata;
2094
2095 if (event == OL_DOP_SELECT) {
2096 pchan->bone->flag |= BONE_SELECTED;
2097 }
2098 else if (event == OL_DOP_DESELECT) {
2099 pchan->bone->flag &= ~BONE_SELECTED;
2100 }
2101 else if (event == OL_DOP_HIDE) {
2102 pchan->bone->flag |= BONE_HIDDEN_P;
2103 pchan->bone->flag &= ~BONE_SELECTED;
2104 }
2105 else if (event == OL_DOP_UNHIDE) {
2106 pchan->bone->flag &= ~BONE_HIDDEN_P;
2107 }
2108}
2109
2110static void bone_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, void * /*arg*/)
2111{
2112 Bone *bone = (Bone *)te->directdata;
2113
2114 if (event == OL_DOP_SELECT) {
2115 bone->flag |= BONE_SELECTED;
2116 }
2117 else if (event == OL_DOP_DESELECT) {
2118 bone->flag &= ~BONE_SELECTED;
2119 }
2120 else if (event == OL_DOP_HIDE) {
2121 bone->flag |= BONE_HIDDEN_P;
2122 bone->flag &= ~BONE_SELECTED;
2123 }
2124 else if (event == OL_DOP_UNHIDE) {
2125 bone->flag &= ~BONE_HIDDEN_P;
2126 }
2127}
2128
2129static void ebone_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, void * /*arg*/)
2130{
2131 EditBone *ebone = (EditBone *)te->directdata;
2132
2133 if (event == OL_DOP_SELECT) {
2134 ebone->flag |= BONE_SELECTED;
2135 }
2136 else if (event == OL_DOP_DESELECT) {
2137 ebone->flag &= ~BONE_SELECTED;
2138 }
2139 else if (event == OL_DOP_HIDE) {
2140 ebone->flag |= BONE_HIDDEN_A;
2142 }
2143 else if (event == OL_DOP_UNHIDE) {
2144 ebone->flag &= ~BONE_HIDDEN_A;
2145 }
2146}
2147
2148static void sequence_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, void *scene_ptr)
2149{
2151 Strip *strip = &te_strip->get_strip();
2152 Scene *scene = (Scene *)scene_ptr;
2153 Editing *ed = seq::editing_get(scene);
2154 if (BLI_findindex(ed->seqbasep, strip) != -1) {
2155 if (event == OL_DOP_SELECT) {
2156 vse::select_strip_single(scene, strip, true);
2157 }
2158 else if (event == OL_DOP_DESELECT) {
2159 strip->flag &= ~SELECT;
2160 }
2161 else if (event == OL_DOP_HIDE) {
2162 if (!(strip->flag & SEQ_MUTE)) {
2163 strip->flag |= SEQ_MUTE;
2164 seq::relations_invalidate_cache(scene, strip);
2165 }
2166 }
2167 else if (event == OL_DOP_UNHIDE) {
2168 if (strip->flag & SEQ_MUTE) {
2169 strip->flag &= ~SEQ_MUTE;
2170 seq::relations_invalidate_cache(scene, strip);
2171 }
2172 }
2173 }
2174}
2175
2176static void gpencil_layer_fn(int event,
2177 TreeElement *te,
2178 TreeStoreElem * /*tselem*/,
2179 void * /*arg*/)
2180{
2181 bGPDlayer *gpl = (bGPDlayer *)te->directdata;
2182
2183 if (event == OL_DOP_SELECT) {
2184 gpl->flag |= GP_LAYER_SELECT;
2185 }
2186 else if (event == OL_DOP_DESELECT) {
2187 gpl->flag &= ~GP_LAYER_SELECT;
2188 }
2189 else if (event == OL_DOP_HIDE) {
2190 gpl->flag |= GP_LAYER_HIDE;
2191 }
2192 else if (event == OL_DOP_UNHIDE) {
2193 gpl->flag &= ~GP_LAYER_HIDE;
2194 }
2195}
2196
2197static void grease_pencil_node_fn(int event,
2198 TreeElement *te,
2199 TreeStoreElem * /*tselem*/,
2200 void * /*arg*/)
2201{
2203
2204 if (event == OL_DOP_SELECT) {
2205 node.set_selected(true);
2206 }
2207 else if (event == OL_DOP_DESELECT) {
2208 node.set_selected(false);
2209 }
2210 else if (event == OL_DOP_HIDE) {
2211 node.set_visible(false);
2212 }
2213 else if (event == OL_DOP_UNHIDE) {
2214 node.set_visible(true);
2215 }
2216}
2217
2218static void data_select_linked_fn(int event,
2219 TreeElement *te,
2220 TreeStoreElem * /*tselem*/,
2221 void *C_v)
2222{
2224 if (!te_rna_struct) {
2225 return;
2226 }
2227
2228 if (event == OL_DOP_SELECT_LINKED) {
2229 const PointerRNA &ptr = te_rna_struct->get_pointer_rna();
2230 if (RNA_struct_is_ID(ptr.type)) {
2231 bContext *C = (bContext *)C_v;
2232 ID *id = static_cast<ID *>(ptr.data);
2233
2235 }
2236 }
2237}
2238
2239static void constraint_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, void *C_v)
2240{
2241 bContext *C = static_cast<bContext *>(C_v);
2242 Main *bmain = CTX_data_main(C);
2243 bConstraint *constraint = (bConstraint *)te->directdata;
2245
2246 if (event == OL_CONSTRAINTOP_ENABLE) {
2247 constraint->flag &= ~CONSTRAINT_OFF;
2248 object::constraint_update(bmain, ob);
2250 }
2251 else if (event == OL_CONSTRAINTOP_DISABLE) {
2252 constraint->flag |= CONSTRAINT_OFF;
2253 object::constraint_update(bmain, ob);
2255 }
2256 else if (event == OL_CONSTRAINTOP_DELETE) {
2257 ListBase *lb = nullptr;
2258
2259 if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) {
2260 lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints;
2261 }
2262 else {
2263 lb = &ob->constraints;
2264 }
2265
2266 if (BKE_constraint_remove_ex(lb, ob, constraint)) {
2267 /* there's no active constraint now, so make sure this is the case */
2269
2270 /* Needed to set the flags on pose-bones correctly. */
2271 object::constraint_update(bmain, ob);
2272
2275 }
2276 }
2277}
2278
2283
2284static void modifier_fn(int event, TreeElement *te, TreeStoreElem * /*tselem*/, void *arg)
2285{
2286 ModifierFnArgs *data = static_cast<ModifierFnArgs *>(arg);
2287 bContext *C = data->C;
2288 Main *bmain = CTX_data_main(C);
2289 Scene *scene = CTX_data_scene(C);
2293
2294 if (event == OL_MODIFIER_OP_TOGVIS) {
2298 }
2299 else if (event == OL_MODIFIER_OP_TOGREN) {
2303 }
2304 else if (event == OL_MODIFIER_OP_DELETE) {
2305 object::modifier_remove(data->reports, bmain, scene, ob, md);
2308 }
2309 else if (event == OL_MODIFIER_OP_APPLY) {
2311 bmain, data->reports, depsgraph, scene, ob, md, object::MODIFIER_APPLY_DATA, false, false);
2316 }
2317}
2318
2320 SpaceOutliner *space_outliner,
2321 int type,
2322 int event,
2323 void (*operation_fn)(int, TreeElement *, TreeStoreElem *, void *),
2324 void *arg)
2325{
2326 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2327 TreeStoreElem *tselem = TREESTORE(te);
2328 if (tselem->flag & TSE_SELECTED) {
2329 if (tselem->type == type) {
2330 operation_fn(event, te, tselem, arg);
2331 }
2332 }
2333 });
2334}
2335
2337 Main *bmain,
2338 Scene *scene,
2339 Object *object)
2340{
2341 if (object->id.tag & ID_TAG_INDIRECT) {
2343 reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", object->id.name + 2);
2344 BLI_assert((object->id.tag & ID_TAG_DOIT) == 0);
2345 }
2346 /* FIXME: This code checking object user-count won't work as expected if a same object belongs to
2347 * more than one collection in the scene. */
2348 if (ID_REAL_USERS(object) <= 1 && ID_EXTRA_USERS(object) == 0 &&
2349 BKE_library_ID_is_indirectly_used(bmain, object))
2350 {
2353 "Cannot delete object '%s' from scene '%s', indirectly used objects need at least "
2354 "one user",
2355 object->id.name + 2,
2356 scene->id.name + 2);
2357 BLI_assert((object->id.tag & ID_TAG_DOIT) == 0);
2358 }
2359
2360 object->id.tag |= ID_TAG_DOIT;
2361}
2362
2364 ReportList *reports, Main *bmain, ViewLayer *view_layer, Scene *scene, Base *base)
2365{
2366 Object *object = base->object;
2367 BLI_assert(object != nullptr);
2368
2369 outliner_batch_delete_object_tag(reports, bmain, scene, object);
2370
2371 /* Even though the object itself may not be deletable, some of its children may still be
2372 * deletable. */
2373 for (Base *base_iter = static_cast<Base *>(BKE_view_layer_object_bases_get(view_layer)->first);
2374 base_iter != nullptr;
2375 base_iter = base_iter->next)
2376 {
2377 Object *parent_ob_iter;
2378 for (parent_ob_iter = base_iter->object->parent;
2379 (parent_ob_iter != nullptr && parent_ob_iter != object &&
2380 (parent_ob_iter->id.tag & ID_TAG_DOIT) == 0);
2381 parent_ob_iter = parent_ob_iter->parent)
2382 {
2383 /* pass */
2384 }
2385 if (parent_ob_iter != nullptr) {
2386 /* There is one or more parents to current iterated object that also need to be deleted,
2387 * process the parenting chain again to tag them as such.
2388 *
2389 * NOTE: Since objects that cannot be deleted are not tagged, the relevant 'parenting'
2390 * branches may be looped over more than once. Would not expect this to be a real issue in
2391 * practice though. */
2392 for (parent_ob_iter = base_iter->object;
2393 (parent_ob_iter != nullptr && parent_ob_iter != object &&
2394 (parent_ob_iter->id.tag & ID_TAG_DOIT) == 0);
2395 parent_ob_iter = parent_ob_iter->parent)
2396 {
2397 outliner_batch_delete_object_tag(reports, bmain, scene, parent_ob_iter);
2398 }
2399 }
2400 }
2401}
2402
2405 Scene *scene,
2406 Object *ob)
2407{
2408 if (ob->id.tag & ID_TAG_DOIT) {
2409 /* Object has already been processed and tagged for removal as part of another parenting
2410 * hierarchy. */
2411#ifndef NDEBUG
2412 ViewLayer *view_layer = CTX_data_view_layer(C);
2413 BKE_view_layer_synced_ensure(scene, view_layer);
2414 BLI_assert(BKE_view_layer_base_find(view_layer, ob) == nullptr);
2415#endif
2416 return;
2417 }
2418
2419 ViewLayer *view_layer = CTX_data_view_layer(C);
2420 Object *obedit = CTX_data_edit_object(C);
2421
2422 Base *base = BKE_view_layer_base_find(view_layer, ob);
2423
2424 if (base == nullptr) {
2425 return;
2426 }
2427
2428 /* Exit Edit mode if the active object or one of its children are being edited. */
2429 for (; obedit && (obedit != base->object); obedit = obedit->parent) {
2430 /* pass */
2431 }
2432 if (obedit == base->object) {
2434 }
2435
2436 Main *bmain = CTX_data_main(C);
2437 outliner_batch_delete_object_hierarchy_tag(reports, bmain, view_layer, scene, base);
2438}
2439
2441{
2442 LISTBASE_FOREACH (Object *, ob_iter, &bmain->objects) {
2443 if ((ob_iter->id.tag & ID_TAG_DOIT) == 0) {
2444 continue;
2445 }
2446
2447 BKE_scene_collections_object_remove(bmain, scene, ob_iter, false);
2448
2449 /* Check on all objects tagged for deletion, these that are still in use (e.g. in collections
2450 * from another scene) should not be deleted. They also need to be tagged for depsgraph update.
2451 */
2452 if (ob_iter->id.us != 0) {
2453 ob_iter->id.tag &= ~ID_TAG_DOIT;
2454 DEG_id_tag_update_ex(bmain, &ob_iter->id, ID_RECALC_BASE_FLAGS);
2455 }
2456 }
2457
2459}
2460
2462
2463/* -------------------------------------------------------------------- */
2466
2467enum {
2473};
2474
2476 {OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""},
2477 {OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
2478 {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
2479 {OL_OP_REMAP,
2480 "REMAP",
2481 0,
2482 "Remap Users",
2483 "Make all users of selected data-blocks to use instead a new chosen one"},
2484 {OL_OP_RENAME, "RENAME", 0, "Rename", ""},
2485 {0, nullptr, 0, nullptr, nullptr},
2486};
2487
2489{
2490 Main *bmain = CTX_data_main(C);
2491 Scene *scene = CTX_data_scene(C);
2492 wmWindow *win = CTX_wm_window(C);
2493 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2494 int event;
2495 const char *str = nullptr;
2496 bool selection_changed = false;
2497
2498 /* check for invalid states */
2499 if (space_outliner == nullptr) {
2500 return OPERATOR_CANCELLED;
2501 }
2502
2503 event = RNA_enum_get(op->ptr, "type");
2504
2505 switch (event) {
2506 case OL_OP_SELECT: {
2507 Scene *sce = scene; /* To be able to delete, scenes are set... */
2509 C, op->reports, scene, space_outliner, &space_outliner->tree, object_select_fn);
2510 /* FIXME: This is most certainly broken, maybe check should rather be
2511 * `if (CTX_data_scene(C) != scene)` ? */
2512 if (scene != sce) {
2513 WM_window_set_active_scene(bmain, C, win, sce);
2514 }
2515
2516 str = "Select Objects";
2517 selection_changed = true;
2518 break;
2519 }
2521 Scene *sce = scene; /* To be able to delete, scenes are set... */
2523 op->reports,
2524 scene,
2525 space_outliner,
2526 &space_outliner->tree,
2528 false);
2529 /* FIXME: This is most certainly broken, maybe check should rather be
2530 * `if (CTX_data_scene(C) != scene)` ? */
2531 if (scene != sce) {
2532 WM_window_set_active_scene(bmain, C, win, sce);
2533 }
2534 str = "Select Object Hierarchy";
2535 selection_changed = true;
2536 break;
2537 }
2538 case OL_OP_DESELECT:
2540 C, op->reports, scene, space_outliner, &space_outliner->tree, object_deselect_fn);
2541 str = "Deselect Objects";
2542 selection_changed = true;
2543 break;
2544 case OL_OP_REMAP:
2545 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_remap_fn);
2546 /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
2547 * trick does not work here). */
2548 break;
2549 case OL_OP_RENAME:
2551 C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn);
2552 str = "Rename Object";
2553 break;
2554 default:
2556 return OPERATOR_CANCELLED;
2557 }
2558
2559 if (selection_changed) {
2563 }
2564
2565 if (str != nullptr) {
2566 ED_undo_push(C, str);
2567 }
2568
2569 return OPERATOR_FINISHED;
2570}
2571
2573{
2574 /* identifiers */
2575 ot->name = "Outliner Object Operation";
2576 ot->idname = "OUTLINER_OT_object_operation";
2577
2578 /* callbacks */
2579 ot->invoke = WM_menu_invoke;
2582
2583 ot->flag = 0;
2584
2585 ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", "");
2586}
2587
2589
2590/* -------------------------------------------------------------------- */
2593
2594using OutlinerDeleteFn = void (*)(bContext *C, ReportList *reports, Scene *scene, Object *ob);
2595
2601
2604 Scene *scene,
2605 const Set<Object *> &objects_to_delete,
2606 OutlinerDeleteFn delete_fn)
2607{
2608 for (Object *ob : objects_to_delete) {
2609 delete_fn(C, reports, scene, ob);
2610 }
2611}
2612
2614{
2615 ObjectEditData *data = static_cast<ObjectEditData *>(customdata);
2616 TreeStoreElem *tselem = TREESTORE(te);
2617
2619 return TRAVERSE_CONTINUE;
2620 }
2621
2622 if ((tselem->type != TSE_SOME_ID) || (tselem->id == nullptr) || (GS(tselem->id->name) != ID_OB))
2623 {
2624 return TRAVERSE_SKIP_CHILDS;
2625 }
2626
2627 /* Do not allow to delete children objects of an override collection. */
2628 TreeElement *te_parent = te->parent;
2629 if (te_parent != nullptr && outliner_is_collection_tree_element(te_parent)) {
2630 TreeStoreElem *tselem_parent = TREESTORE(te_parent);
2631 ID *id_parent = tselem_parent->id;
2632 /* It's not possible to remove an object from an overridden collection (and potentially scene,
2633 * through the master collection). */
2634 if (ELEM(GS(id_parent->name), ID_GR, ID_SCE)) {
2635 if (ID_IS_OVERRIDE_LIBRARY_REAL(id_parent)) {
2636 return TRAVERSE_SKIP_CHILDS;
2637 }
2638 }
2639 }
2640
2641 ID *id = tselem->id;
2642
2645 if (!(data->is_liboverride_hierarchy_root_allowed || data->is_liboverride_allowed)) {
2646 return TRAVERSE_SKIP_CHILDS;
2647 }
2648 }
2649 else {
2650 if (!data->is_liboverride_allowed) {
2651 return TRAVERSE_SKIP_CHILDS;
2652 }
2653 }
2654 }
2655
2656 data->objects_set.add(reinterpret_cast<Object *>(id));
2657
2658 return TRAVERSE_CONTINUE;
2659}
2660
2662{
2663 Main *bmain = CTX_data_main(C);
2664 Scene *scene = CTX_data_scene(C);
2665 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2666 wmMsgBus *mbus = CTX_wm_message_bus(C);
2667 ViewLayer *view_layer = CTX_data_view_layer(C);
2668 BKE_view_layer_synced_ensure(scene, view_layer);
2669 const Base *basact_prev = BKE_view_layer_active_base_get(view_layer);
2670
2671 const bool delete_hierarchy = RNA_boolean_get(op->ptr, "hierarchy");
2672
2673 /* Get selected objects skipping duplicates to prevent deleting objects linked to multiple
2674 * collections twice */
2675 ObjectEditData object_delete_data = {};
2676 object_delete_data.is_liboverride_allowed = false;
2677 object_delete_data.is_liboverride_hierarchy_root_allowed = delete_hierarchy;
2678 outliner_tree_traverse(space_outliner,
2679 &space_outliner->tree,
2680 0,
2683 &object_delete_data);
2684
2685 if (delete_hierarchy) {
2686 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
2687
2688 BKE_view_layer_synced_ensure(scene, view_layer);
2689
2690 /* #object_batch_delete_hierarchy_fn callback will only remove objects from collections and tag
2691 * them for deletion. */
2693 op->reports,
2694 scene,
2695 object_delete_data.objects_set,
2697
2699 }
2700 else {
2702 C, op->reports, scene, object_delete_data.objects_set, outliner_object_delete_fn);
2703 }
2704
2705 outliner_collection_delete(C, bmain, scene, op->reports, delete_hierarchy);
2706
2707 /* Tree management normally happens from draw_outliner(), but when
2708 * you're clicking too fast on Delete object from context menu in
2709 * outliner several mouse events can be handled in one cycle without
2710 * handling notifiers/redraw which leads to deleting the same object twice.
2711 * cleanup tree here to prevent such cases. */
2712 outliner_cleanup_tree(space_outliner);
2713
2716
2717 BKE_view_layer_synced_ensure(scene, view_layer);
2718 if (basact_prev != BKE_view_layer_active_base_get(view_layer)) {
2720 WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
2721 }
2722
2724
2729
2730 return OPERATOR_FINISHED;
2731}
2732
2734{
2735 /* identifiers */
2736 ot->name = "Delete";
2737 ot->idname = "OUTLINER_OT_delete";
2738 ot->description = "Delete selected objects and collections";
2739
2740 /* callbacks */
2741 ot->exec = outliner_delete_exec;
2743
2744 /* flags */
2745 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2746
2747 /* properties */
2749 ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections");
2751}
2752
2754
2755/* -------------------------------------------------------------------- */
2758
2777
2778/* TODO: implement support for changing the ID-block used. */
2780 {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
2781 {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
2782 {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
2783 {OUTLINER_IDOP_DELETE, "DELETE", ICON_X, "Delete", ""},
2785 "REMAP",
2786 0,
2787 "Remap Users",
2788 "Make all users of selected data-blocks to use instead current (clicked) one"},
2790 {OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""},
2791 {OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""},
2794 "ADD_FAKE",
2795 0,
2796 "Add Fake User",
2797 "Ensure data-block gets saved even if it isn't in use (e.g. for motion and material "
2798 "libraries)"},
2799 {OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""},
2800 {OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""},
2801 {OUTLINER_IDOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
2802 {0, nullptr, 0, nullptr, nullptr},
2803};
2804
2806 PointerRNA * /*ptr*/,
2807 PropertyRNA * /*prop*/,
2808 const int enum_value)
2809{
2811 return false;
2812 }
2813
2814 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2815 TreeElement *te = get_target_element(space_outliner);
2816 TreeStoreElem *tselem = TREESTORE(te);
2817 if (!TSE_IS_REAL_ID(tselem)) {
2818 return false;
2819 }
2820
2821 switch (enum_value) {
2823 if (ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) {
2824 return true;
2825 }
2826 /* TODO(dalai): enable in the few cases where this can be supported
2827 * (i.e., when we have a valid parent for the tselem). */
2828 return false;
2829 }
2830
2831 return true;
2832}
2833
2835 PointerRNA *ptr,
2836 PropertyRNA *prop,
2837 bool *r_free)
2838{
2839 EnumPropertyItem *items = nullptr;
2840 int totitem = 0;
2841
2842 if ((C == nullptr) || (ED_operator_outliner_active(C) == false)) {
2843 return prop_id_op_types;
2844 }
2845 for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != nullptr; it++) {
2846 if (!outliner_id_operation_item_poll(C, ptr, prop, it->value)) {
2847 continue;
2848 }
2849 RNA_enum_item_add(&items, &totitem, it);
2850 }
2851 RNA_enum_item_end(&items, &totitem);
2852 *r_free = true;
2853
2854 return items;
2855}
2856
2858{
2859 Main *bmain = CTX_data_main(C);
2861 Scene *scene = CTX_data_scene(C);
2862 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2863 int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
2864
2865 /* check for invalid states */
2866 if (space_outliner == nullptr) {
2867 return OPERATOR_CANCELLED;
2868 }
2869
2870 TreeElement *te = get_target_element(space_outliner);
2871 get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
2872
2874 switch (event) {
2875 case OUTLINER_IDOP_UNLINK: {
2876 /* unlink datablock from its parent */
2877 if (objectlevel) {
2878 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, unlink_object_fn);
2879
2881 ED_undo_push(C, "Unlink Object");
2882 break;
2883 }
2884
2885 switch (idlevel) {
2886 case ID_AC:
2887 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, unlink_action_fn);
2888
2890 ED_undo_push(C, "Unlink action");
2891 break;
2892 case ID_MA:
2893 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, unlink_material_fn);
2894
2896 ED_undo_push(C, "Unlink material");
2897 break;
2898 case ID_TE:
2899 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, unlink_texture_fn);
2900
2902 ED_undo_push(C, "Unlink texture");
2903 break;
2904 case ID_WO:
2905 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, unlink_world_fn);
2906
2908 ED_undo_push(C, "Unlink world");
2909 break;
2910 case ID_GR:
2912 C, op->reports, scene, space_outliner, unlink_collection_fn);
2913
2915 ED_undo_push(C, "Unlink Collection");
2916 break;
2917 default:
2918 BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
2919 break;
2920 }
2921 break;
2922 }
2923 case OUTLINER_IDOP_LOCAL: {
2924 /* make local */
2925 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_local_fn);
2926 ED_undo_push(C, "Localized Data");
2927 break;
2928 }
2929 case OUTLINER_IDOP_SINGLE: {
2930 /* make single user */
2931 switch (idlevel) {
2932 case ID_AC:
2934 C, op->reports, scene, space_outliner, singleuser_action_fn);
2935
2937 ED_undo_push(C, "Single-User Action");
2938 break;
2939
2940 case ID_WO:
2942 C, op->reports, scene, space_outliner, singleuser_world_fn);
2943
2945 ED_undo_push(C, "Single-User World");
2946 break;
2947
2948 default:
2949 BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
2950 break;
2951 }
2952 break;
2953 }
2954 case OUTLINER_IDOP_DELETE: {
2955 if (idlevel > 0) {
2956 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
2957 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_delete_tag_fn);
2960 ED_undo_push(C, "Delete");
2961 }
2962 break;
2963 }
2964 case OUTLINER_IDOP_REMAP: {
2965 if (idlevel > 0 || objectlevel) {
2966 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_remap_fn);
2967 /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
2968 * trick does not work here). */
2969 }
2970 break;
2971 }
2972 case OUTLINER_IDOP_COPY: {
2973 wm->op_undo_depth++;
2974 WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
2975 wm->op_undo_depth--;
2976 /* No need for undo, this operation does not change anything... */
2977 break;
2978 }
2979 case OUTLINER_IDOP_PASTE: {
2980 wm->op_undo_depth++;
2981 WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
2982 wm->op_undo_depth--;
2984 ED_undo_push(C, "Paste");
2985 break;
2986 }
2988 /* set fake user */
2989 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_fake_user_set_fn);
2990
2992 ED_undo_push(C, "Add Fake User");
2993 break;
2994 }
2996 /* clear fake user */
2997 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_fake_user_clear_fn);
2998
3000 ED_undo_push(C, "Clear Fake User");
3001 break;
3002 }
3003 case OUTLINER_IDOP_RENAME: {
3004 /* rename */
3005 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, item_rename_fn);
3006
3008 ED_undo_push(C, "Rename");
3009 break;
3010 }
3012 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_select_linked_fn);
3014 ED_undo_push(C, "Select");
3015 break;
3016
3017 default:
3018 /* Invalid - unhandled. */
3019 break;
3020 }
3021
3023
3024 /* wrong notifier still... */
3026
3027 /* XXX: this is just so that outliner is always up to date. */
3029
3030 return OPERATOR_FINISHED;
3031}
3032
3034{
3035 /* identifiers */
3036 ot->name = "Outliner ID Data Operation";
3037 ot->idname = "OUTLINER_OT_id_operation";
3038 ot->description = "General data-block management operations";
3039
3040 /* callbacks */
3041 ot->invoke = WM_menu_invoke;
3044
3045 ot->flag = 0;
3046
3047 ot->prop = RNA_def_enum(ot->srna, "type", prop_id_op_types, 0, "ID Data Operation", "");
3049}
3050
3052
3053/* -------------------------------------------------------------------- */
3056
3064
3066 {OL_LIB_DELETE, "DELETE", ICON_X, "Delete", "Delete this library and all its items"},
3068 "RELOCATE",
3069 0,
3070 "Relocate",
3071 "Select a new path for this library, and reload all its data"},
3072 {OL_LIB_RELOAD, "RELOAD", ICON_FILE_REFRESH, "Reload", "Reload all data from this library"},
3073 {0, nullptr, 0, nullptr, nullptr},
3074};
3075
3077{
3078 Main *bmain = CTX_data_main(C);
3079 Scene *scene = CTX_data_scene(C);
3080 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3081
3082 /* check for invalid states */
3083 if (space_outliner == nullptr) {
3084 return OPERATOR_CANCELLED;
3085 }
3086
3088 switch (event) {
3089 case OL_LIB_DELETE: {
3090 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
3091 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_delete_tag_fn);
3093 ED_undo_push(C, "Delete Library");
3094 break;
3095 }
3096 case OL_LIB_RELOCATE: {
3097 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, lib_relocate_fn);
3098 /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
3099 * trick does not work here). */
3100 break;
3101 }
3102 case OL_LIB_RELOAD: {
3103 outliner_do_libdata_operation(C, op->reports, scene, space_outliner, lib_reload_fn);
3104 /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
3105 * trick does not work here). */
3106 break;
3107 }
3108 default:
3109 /* invalid - unhandled */
3110 break;
3111 }
3112
3114
3115 /* wrong notifier still... */
3117
3118 /* XXX: this is just so that outliner is always up to date */
3120
3121 return OPERATOR_FINISHED;
3122}
3123
3125{
3126 /* identifiers */
3127 ot->name = "Outliner Library Operation";
3128 ot->idname = "OUTLINER_OT_lib_operation";
3129
3130 /* callbacks */
3131 ot->invoke = WM_menu_invoke;
3134
3135 ot->prop = RNA_def_enum(
3136 ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", "");
3137}
3138
3140
3141/* -------------------------------------------------------------------- */
3144
3146 SpaceOutliner *space_outliner,
3147 int type,
3148 ID *newid,
3149 void (*operation_fn)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *))
3150{
3151 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
3152 TreeStoreElem *tselem = TREESTORE(te);
3153 if (tselem->flag & TSE_SELECTED) {
3154 if (tselem->type == type) {
3155 TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr;
3156 operation_fn(te, tselem, tsep, newid);
3157 }
3158 }
3159 });
3160}
3161
3162static void actionset_id_fn(TreeElement * /*te*/,
3163 TreeStoreElem *tselem,
3164 TreeStoreElem *tsep,
3165 ID *actId)
3166{
3167 bAction *act = (bAction *)actId;
3168
3169 if (tselem->type == TSE_ANIM_DATA) {
3170 /* "animation" entries - action is child of this */
3171 BKE_animdata_set_action(nullptr, tselem->id, act);
3172 }
3173 /* TODO: if any other "expander" channels which own actions need to support this menu,
3174 * add: tselem->type = ...
3175 */
3176 else if (tsep && (tsep->type == TSE_ANIM_DATA)) {
3177 /* "animation" entries case again */
3178 BKE_animdata_set_action(nullptr, tsep->id, act);
3179 }
3180 /* TODO: other cases not supported yet. */
3181}
3182
3184{
3185 Main *bmain = CTX_data_main(C);
3186 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3187 int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3188 bAction *act;
3189
3190 TreeElement *te = get_target_element(space_outliner);
3191 get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3192
3193 /* get action to use */
3194 act = static_cast<bAction *>(BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action")));
3195
3196 if (act == nullptr) {
3197 BKE_report(op->reports, RPT_ERROR, "No valid action to add");
3198 return OPERATOR_CANCELLED;
3199 }
3201 /* Hopefully in this case (i.e. library of userless actions),
3202 * the user knows what they're doing. */
3203 BKE_reportf(op->reports,
3205 "Action '%s' does not specify what data-blocks it can be used on "
3206 "(try setting the 'ID Root Type' setting from the data-blocks editor "
3207 "for this action to avoid future problems)",
3208 act->id.name + 2);
3209 }
3210
3211 /* perform action if valid channel */
3212 if (datalevel == TSE_ANIM_DATA) {
3213 outliner_do_id_set_operation(space_outliner, datalevel, (ID *)act, actionset_id_fn);
3214 }
3215 else if (idlevel == ID_AC) {
3216 outliner_do_id_set_operation(space_outliner, idlevel, (ID *)act, actionset_id_fn);
3217 }
3218 else {
3219 return OPERATOR_CANCELLED;
3220 }
3221
3222 /* set notifier that things have changed */
3225 ED_undo_push(C, "Set action");
3226
3227 /* done */
3228 return OPERATOR_FINISHED;
3229}
3230
3232{
3233 PropertyRNA *prop;
3234
3235 /* identifiers */
3236 ot->name = "Outliner Set Action";
3237 ot->idname = "OUTLINER_OT_action_set";
3238 ot->description = "Change the active action used";
3239
3240 /* API callbacks. */
3241 ot->invoke = WM_enum_search_invoke;
3244
3245 /* flags */
3246 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3247
3248 /* props */
3249 /* TODO: this would be nicer as an ID-pointer... */
3250 prop = RNA_def_enum(ot->srna, "action", rna_enum_dummy_NULL_items, 0, "Action", "");
3253 ot->prop = prop;
3254}
3255
3257
3258/* -------------------------------------------------------------------- */
3261
3273
3276 "CLEAR_ANIMDATA",
3277 0,
3278 "Clear Animation Data",
3279 "Remove this animation data container"},
3280 {OUTLINER_ANIMOP_SET_ACT, "SET_ACT", 0, "Set Action", ""},
3281 {OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""},
3282 {OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""},
3283 {OUTLINER_ANIMOP_CLEAR_DRV, "CLEAR_DRIVERS", 0, "Clear Drivers", ""},
3284 {0, nullptr, 0, nullptr, nullptr},
3285};
3286
3288{
3290 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3291 int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3292 TreeElement *te = get_target_element(space_outliner);
3293 get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3294
3295 if (datalevel != TSE_ANIM_DATA) {
3296 return OPERATOR_CANCELLED;
3297 }
3298
3299 /* perform the core operation */
3301 switch (event) {
3303 /* Remove Animation Data - this may remove the active action, in some cases... */
3304 outliner_do_data_operation(space_outliner, datalevel, event, clear_animdata_fn, nullptr);
3305
3307 ED_undo_push(C, "Clear Animation Data");
3308 break;
3309
3311 /* delegate once again... */
3312 wm->op_undo_depth++;
3314 C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, nullptr, nullptr);
3315 wm->op_undo_depth--;
3316 ED_undo_push(C, "Set active action");
3317 break;
3318
3320 /* clear active action - using standard rules */
3321 outliner_do_data_operation(space_outliner, datalevel, event, unlinkact_animdata_fn, nullptr);
3322
3324 ED_undo_push(C, "Unlink action");
3325 break;
3326
3329 space_outliner, datalevel, event, refreshdrivers_animdata_fn, nullptr);
3330
3332 // ED_undo_push(C, "Refresh Drivers"); /* No undo needed - shouldn't have any impact? */
3333 break;
3334
3337 space_outliner, datalevel, event, cleardrivers_animdata_fn, nullptr);
3338
3340 ED_undo_push(C, "Clear Drivers");
3341 break;
3342
3343 default: /* Invalid. */
3344 break;
3345 }
3346
3347 /* update dependencies */
3349
3350 return OPERATOR_FINISHED;
3351}
3352
3354{
3355 /* identifiers */
3356 ot->name = "Outliner Animation Data Operation";
3357 ot->idname = "OUTLINER_OT_animdata_operation";
3358
3359 /* callbacks */
3360 ot->invoke = WM_menu_invoke;
3363
3364 ot->flag = 0;
3365
3366 ot->prop = RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", "");
3367}
3368
3370
3371/* -------------------------------------------------------------------- */
3374
3376 {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""},
3377 {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_HIDE_ON, "Disable", ""},
3378 {OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""},
3379 {0, nullptr, 0, nullptr, nullptr},
3380};
3381
3383{
3384 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3386
3387 outliner_do_data_operation(space_outliner, TSE_CONSTRAINT, event, constraint_fn, C);
3388
3389 if (event == OL_CONSTRAINTOP_DELETE) {
3390 outliner_cleanup_tree(space_outliner);
3391 }
3392
3393 ED_undo_push(C, "Constraint operation");
3394
3395 return OPERATOR_FINISHED;
3396}
3397
3399{
3400 /* identifiers */
3401 ot->name = "Outliner Constraint Operation";
3402 ot->idname = "OUTLINER_OT_constraint_operation";
3403
3404 /* callbacks */
3405 ot->invoke = WM_menu_invoke;
3408
3409 ot->flag = 0;
3410
3411 ot->prop = RNA_def_enum(
3412 ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", "");
3413}
3414
3416
3417/* -------------------------------------------------------------------- */
3420
3422 {OL_MODIFIER_OP_APPLY, "APPLY", ICON_CHECKMARK, "Apply", ""},
3423 {OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
3425 {OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle Viewport Use", ""},
3426 {OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle Render Use", ""},
3427 {0, nullptr, 0, nullptr, nullptr},
3428};
3429
3431{
3432 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3434
3435 ModifierFnArgs args{};
3436 args.C = C;
3437 args.reports = op->reports;
3438
3439 outliner_do_data_operation(space_outliner, TSE_MODIFIER, event, modifier_fn, &args);
3440
3442 outliner_cleanup_tree(space_outliner);
3443 }
3444
3445 ED_undo_push(C, "Modifier operation");
3446
3447 return OPERATOR_FINISHED;
3448}
3449
3451{
3452 /* identifiers */
3453 ot->name = "Outliner Modifier Operation";
3454 ot->idname = "OUTLINER_OT_modifier_operation";
3455
3456 /* callbacks */
3457 ot->invoke = WM_menu_invoke;
3460
3461 ot->flag = 0;
3462
3463 ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", "");
3464}
3465
3467
3468/* -------------------------------------------------------------------- */
3471
3473{
3475 return false;
3476 }
3477 const SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3478 const TreeElement *te = get_target_element(space_outliner);
3479
3480 if (te == nullptr) {
3481 return false;
3482 }
3483
3484 int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3485 get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3486 return ELEM(
3488}
3489
3491{
3492 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3493 int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3494 TreeElement *te = get_target_element(space_outliner);
3495 get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3496
3498 switch (datalevel) {
3499 case TSE_POSE_CHANNEL: {
3500 outliner_do_data_operation(space_outliner, datalevel, event, pchan_fn, nullptr);
3502 ED_undo_push(C, "PoseChannel operation");
3503
3504 break;
3505 }
3506 case TSE_BONE: {
3507 outliner_do_data_operation(space_outliner, datalevel, event, bone_fn, nullptr);
3509 ED_undo_push(C, "Bone operation");
3510
3511 break;
3512 }
3513 case TSE_EBONE: {
3514 outliner_do_data_operation(space_outliner, datalevel, event, ebone_fn, nullptr);
3516 ED_undo_push(C, "EditBone operation");
3517
3518 break;
3519 }
3520 case TSE_STRIP: {
3521 Scene *scene = CTX_data_scene(C);
3522 outliner_do_data_operation(space_outliner, datalevel, event, sequence_fn, scene);
3524 ED_undo_push(C, "Sequencer operation");
3525
3526 break;
3527 }
3528 case TSE_GP_LAYER: {
3529 outliner_do_data_operation(space_outliner, datalevel, event, gpencil_layer_fn, nullptr);
3531 ED_undo_push(C, "Grease Pencil Layer operation");
3532
3533 break;
3534 }
3536 outliner_do_data_operation(space_outliner, datalevel, event, grease_pencil_node_fn, nullptr);
3538 ED_undo_push(C, "Grease Pencil Node operation");
3539 break;
3540 }
3541 case TSE_RNA_STRUCT:
3542 if (event == OL_DOP_SELECT_LINKED) {
3543 outliner_do_data_operation(space_outliner, datalevel, event, data_select_linked_fn, C);
3544 }
3545
3546 break;
3547
3548 default:
3549 BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
3550 break;
3551 }
3552
3553 return OPERATOR_FINISHED;
3554}
3555
3556/* Dynamically populate an enum of Keying Sets */
3558 PointerRNA * /*ptr*/,
3559 PropertyRNA * /*prop*/,
3560 bool * /*r_free*/)
3561{
3562 /* Check for invalid states. */
3563 if (C == nullptr) {
3565 }
3566
3567 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3568 if (space_outliner == nullptr) {
3570 }
3571
3572 TreeElement *te = get_target_element(space_outliner);
3573 if (te == nullptr) {
3575 }
3576
3577 TreeStoreElem *tselem = TREESTORE(te);
3578
3579 static const EnumPropertyItem optype_sel_and_hide[] = {
3580 {OL_DOP_SELECT, "SELECT", 0, "Select", ""},
3581 {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""},
3582 {OL_DOP_HIDE, "HIDE", 0, "Hide", ""},
3583 {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""},
3584 {0, nullptr, 0, nullptr, nullptr}};
3585
3586 static const EnumPropertyItem optype_sel_linked[] = {
3587 {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
3588 {0, nullptr, 0, nullptr, nullptr}};
3589
3590 if (tselem->type == TSE_RNA_STRUCT) {
3591 return optype_sel_linked;
3592 }
3593
3594 return optype_sel_and_hide;
3595}
3596
3598{
3599 /* identifiers */
3600 ot->name = "Outliner Data Operation";
3601 ot->idname = "OUTLINER_OT_data_operation";
3602
3603 /* callbacks */
3604 ot->invoke = WM_menu_invoke;
3607
3608 ot->flag = 0;
3609
3610 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_dummy_DEFAULT_items, 0, "Data Operation", "");
3612}
3613
3615
3616/* -------------------------------------------------------------------- */
3619
3621{
3622 wmOperatorType *ot = WM_operatortype_find(opname, false);
3623 uiPopupMenu *pup = UI_popup_menu_begin(C, WM_operatortype_name(ot, nullptr).c_str(), ICON_NONE);
3624 uiLayout *layout = UI_popup_menu_layout(pup);
3625
3626 /* Set this so the default execution context is the same as sub-menus. */
3628
3629 if (WM_operator_poll(C, ot)) {
3630 uiItemsEnumO(layout, ot->idname, RNA_property_identifier(ot->prop));
3631
3632 layout->separator();
3633 }
3634
3635 uiItemMContents(layout, "OUTLINER_MT_context_menu");
3636
3637 UI_popup_menu_end(C, pup);
3638
3639 return OPERATOR_INTERFACE;
3640}
3641
3643 ARegion *region,
3644 SpaceOutliner *space_outliner,
3645 TreeElement *te)
3646{
3647 int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
3648 TreeStoreElem *tselem = TREESTORE(te);
3649
3650 int select_flag = OL_ITEM_ACTIVATE | OL_ITEM_SELECT;
3651 if (tselem->flag & TSE_SELECTED) {
3652 select_flag |= OL_ITEM_EXTEND;
3653 }
3654
3655 outliner_item_select(C, space_outliner, te, select_flag);
3656
3657 /* Only redraw, don't rebuild here because TreeElement pointers will
3658 * become invalid and operations will crash. */
3661
3662 get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
3663
3664 if (scenelevel) {
3665 return outliner_operator_menu(C, "OUTLINER_OT_scene_operation");
3666 }
3667 if (objectlevel) {
3668 WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN);
3669 return OPERATOR_FINISHED;
3670 }
3671 if (idlevel) {
3672 switch (idlevel) {
3673 case ID_GR:
3674 WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
3675 return OPERATOR_FINISHED;
3676 break;
3677 case ID_LI:
3678 return outliner_operator_menu(C, "OUTLINER_OT_lib_operation");
3679 break;
3680 default:
3681 return outliner_operator_menu(C, "OUTLINER_OT_id_operation");
3682 break;
3683 }
3684 }
3685 else if (datalevel) {
3686 if (datalevel == TSE_ANIM_DATA) {
3687 return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation");
3688 }
3689 if (datalevel == TSE_DRIVER_BASE) {
3690 /* do nothing... no special ops needed yet */
3691 return OPERATOR_CANCELLED;
3692 }
3693 if (datalevel == TSE_LAYER_COLLECTION) {
3694 WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
3695 return OPERATOR_FINISHED;
3696 }
3698 WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
3699 return OPERATOR_FINISHED;
3700 }
3701 if (datalevel == TSE_ID_BASE) {
3702 /* do nothing... there are no ops needed here yet */
3703 return OPERATOR_CANCELLED;
3704 }
3705 if (datalevel == TSE_CONSTRAINT) {
3706 return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation");
3707 }
3708 if (datalevel == TSE_MODIFIER) {
3709 return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation");
3710 }
3711 return outliner_operator_menu(C, "OUTLINER_OT_data_operation");
3712 }
3713
3714 return OPERATOR_CANCELLED;
3715}
3716
3718 wmOperator * /*op*/,
3719 const wmEvent *event)
3720{
3721 ARegion *region = CTX_wm_region(C);
3722 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
3724 float view_mval[2];
3725
3726 if (but) {
3728 }
3729
3731 &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
3732
3734 space_outliner, &space_outliner->tree, view_mval[1]);
3735 if (!hovered_te) {
3736 /* Let this fall through to 'OUTLINER_MT_context_menu'. */
3737 return OPERATOR_PASS_THROUGH;
3738 }
3739
3740 return do_outliner_operation_event(C, region, space_outliner, hovered_te);
3741}
3742
3744{
3745 ot->name = "Context Menu";
3746 ot->idname = "OUTLINER_OT_operation";
3747 ot->description = "Context menu for item operations";
3748
3749 ot->invoke = outliner_operation_invoke;
3750
3752}
3753
3755
3756} // namespace blender::ed::outliner
Functions for backward compatibility with the legacy Action API.
bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
Definition anim_data.cc:124
void BKE_animdata_free(ID *id, bool do_id_user)
Definition anim_data.cc:187
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:198
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:407
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:1058
void size_t BKE_id_multi_tagged_delete(Main *bmain) ATTR_NONNULL()
void id_fake_user_set(ID *id)
Definition lib_id.cc:391
@ LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR
void BKE_main_id_newptr_and_tag_clear(Main *bmain)
Definition lib_id.cc:1981
bool BKE_lib_id_make_local(Main *bmain, ID *id, int flags)
Definition lib_id.cc:586
void id_fake_user_clear(ID *id)
Definition lib_id.cc:399
void id_us_min(ID *id)
Definition lib_id.cc:361
void BKE_main_id_tag_all(Main *mainvar, int tag, bool value)
Definition lib_id.cc:1214
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:628
@ 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:563
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:557
void BKE_main_ensure_invariants(Main &bmain, std::optional< blender::Span< ID * > > modified_ids=std::nullopt)
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:126
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
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_relations_tag_update(Main *bmain)
@ ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE
Definition DNA_ID.h:698
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:687
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:962
@ ID_RECALC_SELECT
Definition DNA_ID.h:1009
@ ID_RECALC_HIERARCHY
Definition DNA_ID.h:1066
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:985
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1012
@ LIBOVERRIDE_FLAG_SYSTEM_DEFINED
Definition DNA_ID.h:353
@ ID_TAG_INDIRECT
Definition DNA_ID.h:756
@ ID_TAG_EXTERN
Definition DNA_ID.h:750
@ ID_TAG_DOIT
Definition DNA_ID.h:944
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
@ DRIVER_FLAG_INVALID
@ FCURVE_DISABLED
@ BONE_ROOTSEL
@ BONE_SELECTED
@ BONE_HIDDEN_A
@ BONE_HIDDEN_P
@ BONE_TIPSEL
Object groups, one object can be in many groups at once.
@ CONSTRAINT_OFF
@ 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_SELECTED
@ TSE_CLOSED
@ TSE_ACTIVE
@ TSE_POSE_CHANNEL
@ TSE_STRIP
@ TSE_GP_LAYER
@ 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
#define BASE_SELECTED(v3d, base)
eSpaceOutliner_Mode
@ SO_VIEW_LAYER
@ SO_SCENES
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
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:659
bool ED_operator_outliner_active(bContext *C)
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:99
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:645
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:406
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
#define C
Definition RandGen.cpp:29
#define MAX_MTEX
Definition Stroke.h:31
@ UI_BLOCK_THEME_STYLE_POPUP
#define UI_UNIT_Y
void UI_block_theme_style_set(uiBlock *block, char theme_style)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, blender::ui::EmbossType emboss)
void UI_block_bounds_set_popup(uiBlock *block, int addval, const int bounds_offset[2])
Definition interface.cc:641
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, std::optional< blender::StringRef > 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)
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
uiBut * uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxncpy, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
uiBut * UI_context_active_but_get(const bContext *C)
bool UI_search_item_add(uiSearchItems *items, blender::StringRef name, void *poin, int iconid, int but_flag, uint8_t name_prefix_offset)
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
#define UI_SEARCHBOX_BOUNDS
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
int UI_search_items_find_index(const uiSearchItems *items, const char *name)
int UI_searchbox_size_y()
@ UI_BLOCK_SEARCH_MENU
@ UI_BLOCK_LOOP
@ UI_BLOCK_MOVEMOUSE_QUIT
#define UI_UNIT_X
void UI_block_flag_enable(uiBlock *block, int flag)
@ UI_BTYPE_LABEL
@ UI_BUT_ACTIVATE_ON_INIT
void UI_but_flag_enable(uiBut *but, int flag)
void uiItemsEnumO(uiLayout *layout, blender::StringRefNull opname, blender::StringRefNull propname)
void uiItemMContents(uiLayout *layout, blender::StringRef menuname)
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
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:1667
#define ND_SEQUENCER
Definition WM_types.hh:434
#define ND_WORLD
Definition WM_types.hh:449
#define NC_WINDOW
Definition WM_types.hh:372
#define NC_ID
Definition WM_types.hh:392
#define ND_NLA_ACTCHANGE
Definition WM_types.hh:495
#define ND_OB_ACTIVE
Definition WM_types.hh:437
#define NC_WM
Definition WM_types.hh:371
#define ND_DATA
Definition WM_types.hh:506
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_ANIMATION
Definition WM_types.hh:385
#define ND_LIB_OVERRIDE_CHANGED
Definition WM_types.hh:416
#define ND_OB_SELECT
Definition WM_types.hh:439
#define NC_SCENE
Definition WM_types.hh:375
#define ND_LAYER_CONTENT
Definition WM_types.hh:450
#define ND_MODIFIER
Definition WM_types.hh:459
#define ND_POSE
Definition WM_types.hh:455
#define NA_EDITED
Definition WM_types.hh:581
ReportList * reports
Definition WM_types.hh:1025
#define ND_CONSTRAINT
Definition WM_types.hh:461
#define NA_REMOVED
Definition WM_types.hh:584
#define NC_GPENCIL
Definition WM_types.hh:396
#define ND_LAYER
Definition WM_types.hh:447
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:239
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:238
#define ND_OB_SHADING
Definition WM_types.hh:454
#define ND_SPACE_VIEW3D
Definition WM_types.hh:525
#define NC_OBJECT
Definition WM_types.hh:376
#define ND_ANIMCHAN
Definition WM_types.hh:493
#define NC_SPACE
Definition WM_types.hh:389
#define NA_SELECTED
Definition WM_types.hh:586
#define ND_SPACE_OUTLINER
Definition WM_types.hh:524
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const void * element
BPy_StructRNA * depsgraph
void append(const T &value)
bool is_empty() const
#define SELECT
KDTree_3d * tree
#define str(s)
#define active
#define ID_IS_OVERRIDE_LIBRARY_VIRTUAL(_id)
#define ID_EXTRA_USERS(id)
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
#define ID_IS_OVERRIDABLE_LIBRARY(_id)
#define ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(_id)
#define ID_IS_LINKED(_id)
#define ID_NLA
#define ID_IS_EDITABLE(_id)
#define ID_REAL_USERS(id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
#define ID_IS_OVERRIDE_LIBRARY_HIERARCHY_ROOT(_id)
#define GS(a)
DEG_id_tag_update_ex(cb_data->bmain, cb_data->owner_id, ID_RECALC_TAG_FOR_UNDO|ID_RECALC_SYNC_TO_EVAL)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
bool action_treat_as_legacy(const bAction &action)
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 void id_override_library_create_hierarchy_process(bContext *C, ReportList *reports, OutlinerLibOverrideData &data)
static wmOperatorStatus outliner_scene_operation_exec(bContext *C, wmOperator *op)
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 wmOperatorStatus outliner_animdata_operation_exec(bContext *C, wmOperator *op)
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 void modifier_fn(int event, TreeElement *te, TreeStoreElem *, void *arg)
static void object_select_fn(bContext *C, ReportList *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *tselem)
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 wmOperatorStatus outliner_object_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 wmOperatorStatus outliner_constraint_operation_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_scene_op_types[]
static void pchan_fn(int event, TreeElement *te, TreeStoreElem *, void *)
static wmOperatorStatus outliner_id_operation_exec(bContext *C, wmOperator *op)
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 *)
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 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 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 wmOperatorStatus outliner_lib_operation_exec(bContext *C, wmOperator *op)
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)
static wmOperatorStatus outliner_data_operation_exec(bContext *C, wmOperator *op)
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 *)
static wmOperatorStatus outliner_operator_menu(bContext *C, const char *opname)
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)
blender::FunctionRef< void(bContext *C, ReportList *reports, Scene *scene, TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)> outliner_operation_fn
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 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)
static wmOperatorStatus outliner_operation_invoke(bContext *C, wmOperator *, const wmEvent *event)
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)
static wmOperatorStatus outliner_delete_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_liboverride_troubleshoot_operation(wmOperatorType *ot)
static wmOperatorStatus outliner_liboverride_operation_exec(bContext *C, wmOperator *op)
static wmOperatorStatus outliner_modifier_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 *)
static wmOperatorStatus do_outliner_operation_event(bContext *C, ARegion *region, SpaceOutliner *space_outliner, TreeElement *te)
void(*)(bContext *C, ReportList *reports, Scene *scene, Object *ob) OutlinerDeleteFn
static const EnumPropertyItem prop_liboverride_troubleshoot_op_types[]
static wmOperatorStatus outliner_action_set_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_id_operation(wmOperatorType *ot)
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 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 void outliner_do_object_delete(bContext *C, ReportList *reports, Scene *scene, const Set< Object * > &objects_to_delete, OutlinerDeleteFn delete_fn)
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)
void select_strip_single(Scene *scene, Strip *strip, bool deselect_all)
void relations_invalidate_cache(Scene *scene, Strip *strip)
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:272
#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_discrete(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:26
const EnumPropertyItem rna_enum_dummy_DEFAULT_items[]
Definition rna_rna.cc:32
ListBase drivers
struct Base * next
short flag
struct Object * object
struct Material ** mat
short totcol
struct MTex * mtex[18]
unsigned int flag
Definition DNA_ID.h:338
struct ID * hierarchy_root
Definition DNA_ID.h:334
struct ID * reference
Definition DNA_ID.h:324
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
struct Library * lib
Definition DNA_ID.h:410
IDOverrideLibrary * override_library
Definition DNA_ID.h:459
short flag
Definition DNA_ID.h:420
char name[66]
Definition DNA_ID.h:415
unsigned int session_uid
Definition DNA_ID.h:444
ID id
Definition DNA_ID.h:505
struct Tex * tex
ListBase actions
Definition BKE_main.hh:269
ListBase objects
Definition BKE_main.hh:247
struct Material ** mat
ListBase constraints
struct Collection * instance_collection
struct Material ** mat
struct Object * parent
struct Collection * master_collection
struct World * world
struct Base * basact
struct Material ** mat
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)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
int mval[2]
Definition WM_types.hh:760
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)
wmOperatorStatus WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4226
wmOperatorType * ot
Definition wm_files.cc:4225
#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)
wmOperatorStatus WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
wmOperatorStatus WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *)
void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)