Blender V5.0
outliner_edit.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 <algorithm>
10#include <cstring>
11
12#include <fmt/format.h>
13
14#include "MEM_guardedalloc.h"
15
16#include "DNA_ID.h"
17#include "DNA_anim_types.h"
19#include "DNA_object_types.h"
20#include "DNA_scene_types.h"
21
22#include "BLI_listbase.h"
23#include "BLI_path_utils.hh"
24#include "BLI_string.h"
25#include "BLI_utildefines.h"
26
27#include "BLT_translation.hh"
28
29#include "BLF_api.hh"
30
31#include "BKE_action.hh"
32#include "BKE_animsys.h"
33#include "BKE_appdir.hh"
34#include "BKE_armature.hh"
36#include "BKE_blendfile.hh"
37#include "BKE_context.hh"
38#include "BKE_idtype.hh"
39#include "BKE_layer.hh"
40#include "BKE_lib_id.hh"
41#include "BKE_lib_override.hh"
42#include "BKE_lib_query.hh"
43#include "BKE_lib_remap.hh"
44#include "BKE_library.hh"
45#include "BKE_main.hh"
46#include "BKE_object.hh"
47#include "BKE_report.hh"
48#include "BKE_screen.hh"
49#include "BKE_workspace.hh"
50
51#include "DEG_depsgraph.hh"
53
54#include "ED_keyframing.hh"
55#include "ED_outliner.hh"
56#include "ED_screen.hh"
57#include "ED_select_utils.hh"
58
59#include "WM_api.hh"
60#include "WM_types.hh"
61
62#include "UI_interface.hh"
64#include "UI_view2d.hh"
65
66#include "RNA_access.hh"
67#include "RNA_define.hh"
68#include "RNA_enum_types.hh"
69#include "RNA_path.hh"
70#include "RNA_prototypes.hh"
71
72#include "GPU_material.hh"
73
74#include "outliner_intern.hh"
76#include "tree/tree_iterator.hh"
77
78#include "wm_window.hh"
79
80using namespace blender::ed::outliner;
81
82namespace blender::ed::outliner {
83
84static void outliner_show_active(SpaceOutliner *space_outliner,
85 ARegion *region,
86 TreeElement *te,
87 ID *id);
88
89/* -------------------------------------------------------------------- */
92
93static void outliner_copybuffer_filepath_get(char filepath[FILE_MAX], size_t filepath_maxncpy)
94{
95 /* NOTE: this uses the same path as the 3D viewport. */
96 BLI_path_join(filepath, filepath_maxncpy, BKE_tempdir_base(), "copybuffer.blend");
97}
98
100
101/* -------------------------------------------------------------------- */
104
106 wmOperator * /*op*/,
107 const wmEvent *event)
108{
109 /* stop highlighting if out of area */
110 if (!ED_screen_area_active(C)) {
112 }
113
114 /* Drag and drop does its own highlighting. */
116 if (wm->runtime->drags.first) {
118 }
119
120 ARegion *region = CTX_wm_region(C);
121 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
122
123 float view_mval[2];
125 &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
126
128 space_outliner, &space_outliner->tree, view_mval[1]);
129
130 TreeElement *icon_te = nullptr;
131 bool is_over_icon = false;
132 if (hovered_te) {
134 space_outliner, hovered_te, view_mval[0], nullptr, &is_over_icon);
135 }
136
137 bool changed = false;
138
139 if (!hovered_te || !is_over_icon || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED) ||
140 !(icon_te->store_elem->flag & TSE_HIGHLIGHTED_ICON))
141 {
142 /* Clear highlights when nothing is hovered or when a new item is hovered. */
143 changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
144 if (hovered_te) {
145 hovered_te->store_elem->flag |= TSE_HIGHLIGHTED;
146 changed = true;
147 }
148 if (is_over_icon) {
150 changed = true;
151 }
152 }
153
154 if (changed) {
156 }
157
159}
160
162{
163 ot->name = "Update Highlight";
164 ot->idname = "OUTLINER_OT_highlight_update";
165 ot->description = "Update the item highlight based on the current mouse position";
166
168
170}
171
173
174/* -------------------------------------------------------------------- */
177
178void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all)
179{
180 /* Only allow opening elements with children. */
182 return;
183 }
184
185 /* Don't allow collapsing the scene collection. */
186 TreeStoreElem *tselem = TREESTORE(te);
187 if (tselem->type == TSE_VIEW_COLLECTION_BASE) {
188 return;
189 }
190
191 if (open) {
192 tselem->flag &= ~TSE_CLOSED;
193 }
194 else {
195 tselem->flag |= TSE_CLOSED;
196 }
197
198 if (toggle_all) {
200 }
201}
202
208
210 wmOperator *op,
211 const wmEvent *event)
212{
213 ARegion *region = CTX_wm_region(C);
214 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
216
217 float view_mval[2];
219 &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
220
221 if (event->type == MOUSEMOVE) {
222 TreeElement *te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
223
224 /* Only openclose if mouse is not over the previously toggled element */
225 if (te && TREESTORE(te) != data->prev_tselem) {
226
227 /* Only toggle openclose on the same level as the first clicked element */
228 if (te->xs == data->x_location) {
229 outliner_item_openclose(te, data->open, false);
230
232 }
233 }
234
235 if (te) {
236 data->prev_tselem = TREESTORE(te);
237 }
238 else {
239 data->prev_tselem = nullptr;
240 }
241 }
242 else if (event->val == KM_RELEASE) {
244
245 return OPERATOR_FINISHED;
246 }
247
249}
250
252 wmOperator *op,
253 const wmEvent *event)
254{
255 ARegion *region = CTX_wm_region(C);
256 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
257
258 const bool toggle_all = RNA_boolean_get(op->ptr, "all");
259
260 float view_mval[2];
261
262 int mval[2];
263 WM_event_drag_start_mval(event, region, mval);
264
265 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
266
267 TreeElement *te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
268
269 if (te && outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
270 TreeStoreElem *tselem = TREESTORE(te);
271
272 const bool open = (tselem->flag & TSE_CLOSED) ||
273 (toggle_all && outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1));
274
275 outliner_item_openclose(te, open, toggle_all);
277
278 /* Only toggle once for single click toggling */
279 if ((event->type == LEFTMOUSE) && (event->val != KM_PRESS_DRAG)) {
280 return OPERATOR_FINISHED;
281 }
282
283 /* Store last expanded tselem and x coordinate of disclosure triangle */
284 OpenCloseData *toggle_data = MEM_callocN<OpenCloseData>("open_close_data");
285 toggle_data->prev_tselem = tselem;
286 toggle_data->open = open;
287 toggle_data->x_location = te->xs;
288
289 /* Store the first clicked on element */
290 op->customdata = toggle_data;
291
294 }
295
297}
298
300{
301 ot->name = "Open/Close";
302 ot->idname = "OUTLINER_OT_item_openclose";
303 ot->description = "Toggle whether item under cursor is enabled or closed";
304
307
309
310 RNA_def_boolean(ot->srna, "all", false, "All", "Close or open all items");
311}
312
314
315/* -------------------------------------------------------------------- */
318
319static void do_item_rename(ARegion *region,
320 TreeElement *te,
321 TreeStoreElem *tselem,
322 ReportList *reports)
323{
324 bool add_textbut = false;
325
326 /* FIXME: These info messages are often useless, they should be either reworded to be more
327 * informative for the user, or purely removed? */
328
329 /* Can't rename rna datablocks entries or listbases. */
330 if (ELEM(tselem->type,
332 TSE_NLA,
346 TSE_ID_BASE) ||
348 {
349 BKE_report(reports, RPT_INFO, "Not an editable name");
350 }
351 else if (ELEM(tselem->type, TSE_STRIP, TSE_STRIP_DATA, TSE_STRIP_DUP)) {
352 BKE_report(reports, RPT_INFO, "Strip names are not editable from the Outliner");
353 }
354 else if (TSE_IS_REAL_ID(tselem) && !ID_IS_EDITABLE(tselem->id)) {
355 BKE_report(reports, RPT_INFO, "External library data is not editable");
356 }
357 else if (TSE_IS_REAL_ID(tselem) && ID_IS_OVERRIDE_LIBRARY(tselem->id)) {
358 BKE_report(reports, RPT_INFO, "Overridden data-blocks names are not editable");
359 }
362
363 if (collection->flag & COLLECTION_IS_MASTER) {
364 BKE_report(reports, RPT_INFO, "Not an editable name");
365 }
366 else {
367 add_textbut = true;
368 }
369 }
370 else if (te->idcode == ID_LI) {
371 BKE_report(reports, RPT_INFO, "Library path is not editable, use the Relocate operation");
372 }
373 else {
374 add_textbut = true;
375 }
376
377 if (add_textbut) {
378 tselem->flag |= TSE_TEXTBUT;
379 ED_region_tag_redraw(region);
380 }
381}
382
384 ReportList *reports,
385 Scene * /*scene*/,
386 TreeElement *te,
387 TreeStoreElem * /*tsep*/,
388 TreeStoreElem *tselem)
389{
390 ARegion *region = CTX_wm_region(C);
391 do_item_rename(region, te, tselem, reports);
392}
393
395 ReportList *reports)
396{
397 TreeElement *active_element = outliner_find_element_with_flag(&space_outliner->tree, TSE_ACTIVE);
398
399 if (!active_element) {
400 BKE_report(reports, RPT_WARNING, "No active item to rename");
401 return nullptr;
402 }
403
404 return active_element;
405}
406
408 ARegion *region,
409 const wmEvent *event)
410{
411 float fmval[2];
412 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
413
414 TreeElement *hovered = outliner_find_item_at_y(space_outliner, &space_outliner->tree, fmval[1]);
415 if (hovered && outliner_item_is_co_over_name(hovered, fmval[0])) {
416 return hovered;
417 }
418
419 return nullptr;
420}
421
423 wmOperator *op,
424 const wmEvent *event)
425{
426 ARegion *region = CTX_wm_region(C);
427 View2D *v2d = &region->v2d;
428 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
429 const bool use_active = RNA_boolean_get(op->ptr, "use_active");
430
431 TreeElement *te = use_active ? outliner_item_rename_find_active(space_outliner, op->reports) :
432 outliner_item_rename_find_hovered(space_outliner, region, event);
433 if (!te) {
435 }
436
437 /* Force element into view. */
438 outliner_show_active(space_outliner, region, te, TREESTORE(te)->id);
439 int size_y = BLI_rcti_size_y(&v2d->mask) + 1;
440 int ytop = (te->ys + (size_y / 2));
441 int delta_y = ytop - v2d->cur.ymax;
442 outliner_scroll_view(space_outliner, region, delta_y);
443
444 do_item_rename(region, te, TREESTORE(te), op->reports);
445
446 return OPERATOR_FINISHED;
447}
448
450{
451 PropertyRNA *prop;
452
453 ot->name = "Rename";
454 ot->idname = "OUTLINER_OT_item_rename";
455 ot->description = "Rename the active element";
456
458
460
461 /* Flags. No undo, since this operator only activate the name editing text field in the Outliner,
462 * but does not actually change anything. */
463 ot->flag = OPTYPE_REGISTER;
464
465 prop = RNA_def_boolean(ot->srna,
466 "use_active",
467 false,
468 "Use Active",
469 "Rename the active item, rather than the one the mouse is over");
471}
472
474
475/* -------------------------------------------------------------------- */
478
479static void id_delete_tag(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
480{
481 Main *bmain = CTX_data_main(C);
482 ID *id = tselem->id;
483
484 BLI_assert(id != nullptr);
485 BLI_assert(((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
486 (tselem->type == TSE_LAYER_COLLECTION));
488
489 if (ID_IS_OVERRIDE_LIBRARY(id)) {
492 {
493 BKE_reportf(reports,
495 "Cannot delete library override id '%s', it is part of an override hierarchy",
496 id->name);
497 return;
498 }
499 }
500
501 if (te->idcode == ID_LI) {
502 Library *lib = blender::id_cast<Library *>(id);
503 if (lib->runtime->parent != nullptr) {
504 BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked library '%s'", id->name);
505 return;
506 }
507 Scene *active_scene = CTX_data_scene(C);
508 if (active_scene->id.lib == lib) {
509 BKE_reportf(reports,
511 "Cannot delete library '%s', as it contains the currently active Scene",
512 id->name);
513 return;
514 }
515 for (Library *packed_lib : lib->runtime->archived_libraries) {
516 if (active_scene->id.lib == packed_lib) {
517 BKE_reportf(reports,
519 "Cannot delete library '%s', as it contains the archive library of the "
520 "currently active packed Scene",
521 id->name);
522 return;
523 }
524 }
525 }
526 if (id->tag & ID_TAG_INDIRECT) {
527 BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name);
528 return;
529 }
530 if (ID_REAL_USERS(id) <= 1 && BKE_library_ID_is_indirectly_used(bmain, id)) {
531 BKE_reportf(reports,
533 "Cannot delete id '%s', indirectly used data-blocks need at least one user",
534 id->name);
535 return;
536 }
537 if (te->idcode == ID_WS) {
539 if (id->tag & ID_TAG_PRE_EXISTING) {
541 reports, RPT_WARNING, "Cannot delete currently visible workspace id '%s'", id->name);
543 return;
544 }
546 }
547
548 id->tag |= ID_TAG_DOIT;
549
550 WM_event_add_notifier(C, NC_WINDOW, nullptr);
551}
552
554 ReportList *reports,
555 Scene * /*scene*/,
556 TreeElement *te,
557 TreeStoreElem * /*tsep*/,
558 TreeStoreElem *tselem)
559{
560 id_delete_tag(C, reports, te, tselem);
561}
562
564 ReportList *reports,
565 TreeElement *te,
566 const float mval[2])
567{
568 int id_tagged_num = 0;
569
570 if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
571 TreeStoreElem *tselem = TREESTORE(te);
572
573 if (te->idcode != 0 && tselem->id) {
574 if (te->idcode == ID_LI && ((Library *)tselem->id)->runtime->parent) {
575 BKE_reportf(reports,
577 "Cannot delete indirectly linked library '%s'",
578 ((Library *)tselem->id)->runtime->filepath_abs);
579 }
580 else {
581 id_delete_tag(C, reports, te, tselem);
582 id_tagged_num++;
583 }
584 }
585 }
586 else {
587 LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) {
588 if ((id_tagged_num += outliner_id_delete_tag(C, reports, te_sub, mval)) != 0) {
589 break;
590 }
591 }
592 }
593
594 return id_tagged_num;
595}
596
598 wmOperator *op,
599 const wmEvent *event)
600{
601 Main *bmain = CTX_data_main(C);
602 ARegion *region = CTX_wm_region(C);
603 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
604 float fmval[2];
605
606 BLI_assert(region && space_outliner);
607
608 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
609
610 int id_tagged_num = 0;
611 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
612 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
613 if ((id_tagged_num += outliner_id_delete_tag(C, op->reports, te, fmval)) != 0) {
614 break;
615 }
616 }
617 if (id_tagged_num == 0) {
618 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
619 return OPERATOR_CANCELLED;
620 }
621
623 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
624 return OPERATOR_FINISHED;
625}
626
628{
629 ot->name = "Delete Data-Block";
630 ot->idname = "OUTLINER_OT_id_delete";
631 ot->description = "Delete the ID under cursor";
632
635
636 /* Flags. */
638}
639
641
642/* -------------------------------------------------------------------- */
645
647{
648 Main *bmain = CTX_data_main(C);
649 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
650
651 const short id_type = short(RNA_enum_get(op->ptr, "id_type"));
652 ID *old_id = static_cast<ID *>(
653 BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id")));
654 ID *new_id = static_cast<ID *>(
655 BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")));
656
657 /* check for invalid states */
658 if (space_outliner == nullptr) {
659 return OPERATOR_CANCELLED;
660 }
661
662 if (!(old_id && new_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
665 "Invalid old/new ID pair ('%s' / '%s')",
666 old_id ? old_id->name : "Invalid ID",
667 new_id ? new_id->name : "Invalid ID");
668 return OPERATOR_CANCELLED;
669 }
670
671 if (!ID_IS_EDITABLE(old_id)) {
674 "Old ID '%s' is linked from a library, indirect usages of this data-block will "
675 "not be remapped",
676 old_id->name);
677 }
678
681
683
684 /* recreate dependency graph to include new objects */
686
687 /* Free gpu materials, some materials depend on existing objects,
688 * such as lights so freeing correctly refreshes. */
689 GPU_materials_free(bmain);
690
691 WM_event_add_notifier(C, NC_WINDOW, nullptr);
692
693 return OPERATOR_FINISHED;
694}
695
697 wmOperator *op,
698 ListBase *tree,
699 const float y)
700{
702 if (y > te->ys && y < te->ys + UI_UNIT_Y) {
703 TreeStoreElem *tselem = TREESTORE(te);
704
705 if ((tselem->type == TSE_SOME_ID) && tselem->id) {
706 RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
707 RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2);
708 RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2);
709 return true;
710 }
711 }
712 if (outliner_id_remap_find_tree_element(C, op, &te->subtree, y)) {
713 return true;
714 }
715 }
716 return false;
717}
718
720{
721 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
722 ARegion *region = CTX_wm_region(C);
723 float fmval[2];
724
725 if (!RNA_property_is_set(op->ptr, RNA_struct_find_property(op->ptr, "id_type"))) {
726 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
727
728 outliner_id_remap_find_tree_element(C, op, &space_outliner->tree, fmval[1]);
729 }
730
731 return WM_operator_props_dialog_popup(C, op, 400, IFACE_("Remap Data ID"), IFACE_("Remap"));
732}
733
736 PropertyRNA * /*prop*/,
737 bool *r_free)
738{
739 if (C == nullptr) {
741 }
742
743 EnumPropertyItem item_tmp = {0}, *item = nullptr;
744 int totitem = 0;
745 int i = 0;
746
747 short id_type = short(RNA_enum_get(ptr, "id_type"));
748 ID *id = static_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first);
749
750 for (; id; id = static_cast<ID *>(id->next)) {
751 item_tmp.identifier = item_tmp.name = id->name + 2;
752 item_tmp.value = i++;
753 RNA_enum_item_add(&item, &totitem, &item_tmp);
754 }
755
756 RNA_enum_item_end(&item, &totitem);
757 *r_free = true;
758
759 return item;
760}
761
763{
764 PropertyRNA *prop;
765
766 /* identifiers */
767 ot->name = "Outliner ID Data Remap";
768 ot->idname = "OUTLINER_OT_id_remap";
769
770 /* callbacks */
774
775 /* Flags. */
777
778 prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
780 /* Changing ID type wont make sense, would return early with "Invalid old/new ID pair" anyways.
781 */
783
784 prop = RNA_def_enum(
785 ot->srna, "old_id", rna_enum_dummy_NULL_items, 0, "Old ID", "Old ID to replace");
786 RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, outliner_id_itemf, nullptr, nullptr);
788
789 ot->prop = RNA_def_enum(ot->srna,
790 "new_id",
792 0,
793 "New ID",
794 "New ID to remap all selected IDs' users to");
796 ot->prop, nullptr, nullptr, outliner_id_itemf, nullptr, nullptr);
798}
799
801 ReportList * /*reports*/,
802 Scene * /*scene*/,
803 TreeElement * /*te*/,
804 TreeStoreElem * /*tsep*/,
805 TreeStoreElem *tselem)
806{
807 wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
808 PointerRNA op_props;
809
810 BLI_assert(tselem->id != nullptr);
811
813
814 RNA_enum_set(&op_props, "id_type", GS(tselem->id->name));
815 RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2);
816
818
820}
821
823
824/* -------------------------------------------------------------------- */
827
828static int outliner_id_copy_tag(SpaceOutliner *space_outliner,
829 ListBase *tree,
831 ReportList *reports)
832{
833 using namespace blender::bke::blendfile;
834
835 int num_ids = 0;
836
838 TreeStoreElem *tselem = TREESTORE(te);
839
840 /* Add selected item and all of its dependencies to the copy buffer. */
841 if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) {
842 if (ID_IS_PACKED(tselem->id)) {
843 /* Direct link/append of packed IDs is not supported currently, so neither is their
844 * copy/pasting. */
845 continue;
846 }
847 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(tselem->id);
849 BKE_reportf(reports,
850 RPT_INFO,
851 "Copying ID '%s' is not possible, '%s' type of data-blocks is not supported",
852 tselem->id->name,
853 id_type->name);
854 }
855 if (copybuffer.id_add(tselem->id,
857 (PartialWriteContext::IDAddOperations::SET_FAKE_USER |
858 PartialWriteContext::IDAddOperations::SET_CLIPBOARD_MARK |
859 PartialWriteContext::IDAddOperations::ADD_DEPENDENCIES)},
860 nullptr))
861 {
862 num_ids++;
863 }
864 }
865
866 /* go over sub-tree */
867 num_ids += outliner_id_copy_tag(space_outliner, &te->subtree, copybuffer, reports);
868 }
869
870 return num_ids;
871}
872
874{
875 using namespace blender::bke::blendfile;
876
877 Main *bmain = CTX_data_main(C);
878 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
879 PartialWriteContext copybuffer{*bmain};
880
881 const int num_ids = outliner_id_copy_tag(
882 space_outliner, &space_outliner->tree, copybuffer, op->reports);
883 if (num_ids == 0) {
884 BKE_report(op->reports, RPT_INFO, "No selected data-blocks to copy");
885 return OPERATOR_CANCELLED;
886 }
887
888 char filepath[FILE_MAX];
889 outliner_copybuffer_filepath_get(filepath, sizeof(filepath));
890 copybuffer.write(filepath, *op->reports);
891
892 BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids);
893
894 return OPERATOR_FINISHED;
895}
896
898{
899 /* identifiers */
900 ot->name = "Outliner ID Data Copy";
901 ot->idname = "OUTLINER_OT_id_copy";
902 ot->description = "Copy the selected data-blocks to the internal clipboard";
903
904 /* callbacks */
907
908 /* Flags, don't need any undo here (this operator does not change anything in Blender data). */
909 ot->flag = 0;
910}
911
913
914/* -------------------------------------------------------------------- */
917
919{
920 char filepath[FILE_MAX];
922
923 outliner_copybuffer_filepath_get(filepath, sizeof(filepath));
924
925 const int num_pasted = BKE_copybuffer_paste(C, filepath, flag, op->reports, 0);
926 if (num_pasted == 0) {
927 BKE_report(op->reports, RPT_INFO, "No data to paste");
928 return OPERATOR_CANCELLED;
929 }
930
931 WM_event_add_notifier(C, NC_WINDOW, nullptr);
932
933 BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted);
934
935 return OPERATOR_FINISHED;
936}
937
939{
940 /* identifiers */
941 ot->name = "Outliner ID Data Paste";
942 ot->idname = "OUTLINER_OT_id_paste";
943 ot->description = "Paste data-blocks from the internal clipboard";
944
945 /* callbacks */
948
949 /* flags */
951}
952
954
955/* -------------------------------------------------------------------- */
958
960 wmOperator *op,
961 const wmEvent * /*event*/)
962{
963 PointerRNA id_linked_ptr = CTX_data_pointer_get_type(C, "id", &RNA_ID);
964 ID *id_linked = static_cast<ID *>(id_linked_ptr.data);
965
966 if (!id_linked) {
967 BKE_report(op->reports, RPT_ERROR_INVALID_INPUT, "There is no active data-block");
968 return OPERATOR_CANCELLED;
969 }
970 if (!ID_IS_LINKED(id_linked) || !BKE_idtype_idcode_is_linkable(GS(id_linked->name))) {
973 "The active data-block '%s' is not a valid linked one",
974 BKE_id_name(*id_linked));
975 return OPERATOR_CANCELLED;
976 }
980 "The active data-block '%s' is used by other linked data",
981 BKE_id_name(*id_linked));
982 return OPERATOR_CANCELLED;
983 }
984
985 wmOperatorType *ot = WM_operatortype_find("WM_OT_id_linked_relocate", false);
986 PointerRNA op_props;
987
989 RNA_int_set(&op_props, "id_session_uid", *reinterpret_cast<int *>(&id_linked->session_uid));
990
992 C, ot, wm::OpCallContext::InvokeDefault, &op_props, nullptr);
993
995
996 /* If the matching WM operator invoke was successful, it was added to modal handlers. This
997 * operator however is _not_ modal, and will leak memory if it returns this status. */
999}
1000
1002{
1003 ot->name = "Relocate Linked ID";
1004 ot->idname = "OUTLINER_OT_id_linked_relocate";
1005 ot->description =
1006 "Replace the active linked ID (and its dependencies if any) by another one, from the same "
1007 "or a different library";
1008
1011
1012 /* Flags. No undo, no registering, all the actual work/changes is done by the matching WM
1013 * operator. */
1014 ot->flag = 0;
1015}
1016
1018
1019/* -------------------------------------------------------------------- */
1022
1024 bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload)
1025{
1026 PointerRNA op_props;
1028
1029 BLI_assert(te->idcode == ID_LI && tselem->id != nullptr);
1031
1033
1034 RNA_string_set(&op_props, "library", tselem->id->name + 2);
1035
1036 if (reload) {
1037 Library *lib = (Library *)tselem->id;
1038 char dir[FILE_MAXDIR], filename[FILE_MAX];
1039
1041 lib->runtime->filepath_abs, dir, sizeof(dir), filename, sizeof(filename));
1042
1043 printf("%s, %s\n", tselem->id->name, lib->runtime->filepath_abs);
1044
1045 /* We assume if both paths in lib are not the same then `lib->filepath` was relative. */
1047 &op_props, "relative_path", BLI_path_cmp(lib->runtime->filepath_abs, lib->filepath) != 0);
1048
1049 RNA_string_set(&op_props, "directory", dir);
1050 RNA_string_set(&op_props, "filename", filename);
1051
1053 }
1054 else {
1056 }
1057
1058 WM_operator_properties_free(&op_props);
1059
1060 return ret;
1061}
1062
1064 bContext *C, ReportList *reports, TreeElement *te, const float mval[2], const bool reload)
1065{
1066 if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
1067 TreeStoreElem *tselem = TREESTORE(te);
1068
1069 if (te->idcode == ID_LI && tselem->id) {
1070 if (((Library *)tselem->id)->runtime->parent && !reload) {
1071 BKE_reportf(reports,
1073 "Cannot relocate indirectly linked library '%s'",
1074 ((Library *)tselem->id)->runtime->filepath_abs);
1075 return OPERATOR_CANCELLED;
1076 }
1077
1078 wmOperatorType *ot = WM_operatortype_find(reload ? "WM_OT_lib_reload" : "WM_OT_lib_relocate",
1079 false);
1080 return lib_relocate(C, te, tselem, ot, reload);
1081 }
1082 }
1083 else {
1084 LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) {
1086 if ((ret = outliner_lib_relocate_invoke_do(C, reports, te_sub, mval, reload))) {
1087 return ret;
1088 }
1089 }
1090 }
1091
1092 return wmOperatorStatus(0);
1093}
1094
1096 wmOperator *op,
1097 const wmEvent *event)
1098{
1099 ARegion *region = CTX_wm_region(C);
1100 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1101 float fmval[2];
1102
1103 BLI_assert(region && space_outliner);
1104
1105 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
1106
1107 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
1109
1110 if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, false))) {
1111 return ret;
1112 }
1113 }
1114
1115 return OPERATOR_CANCELLED;
1116}
1117
1119{
1120 ot->name = "Relocate Library";
1121 ot->idname = "OUTLINER_OT_lib_relocate";
1122 ot->description = "Relocate the library under cursor";
1123
1126
1127 /* Flags. */
1128 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1129}
1130
1132 ReportList * /*reports*/,
1133 Scene * /*scene*/,
1134 TreeElement *te,
1135 TreeStoreElem * /*tsep*/,
1136 TreeStoreElem *tselem)
1137{
1138 /* XXX: This does not work with several items
1139 * (it is only called once in the end, due to the 'deferred'
1140 * file-browser invocation through event system...). */
1141
1142 wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false);
1143
1144 lib_relocate(C, te, tselem, ot, false);
1145}
1146
1148 wmOperator *op,
1149 const wmEvent *event)
1150{
1151 ARegion *region = CTX_wm_region(C);
1152 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1153 float fmval[2];
1154
1155 BLI_assert(region && space_outliner);
1156
1157 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
1158
1159 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
1161
1162 if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, true))) {
1163 return ret;
1164 }
1165 }
1166
1167 return OPERATOR_CANCELLED;
1168}
1169
1171
1172/* -------------------------------------------------------------------- */
1175
1177{
1178 ot->name = "Reload Library";
1179 ot->idname = "OUTLINER_OT_lib_reload";
1180 ot->description = "Reload the library under cursor";
1181
1184
1185 /* Flags. */
1186 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1187}
1188
1190 ReportList * /*reports*/,
1191 Scene * /*scene*/,
1192 TreeElement *te,
1193 TreeStoreElem * /*tsep*/,
1194 TreeStoreElem *tselem)
1195{
1196 wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_reload", false);
1197
1198 lib_relocate(C, te, tselem, ot, true);
1199}
1200
1202
1203/* -------------------------------------------------------------------- */
1206
1207static int outliner_count_levels(ListBase *lb, const int curlevel)
1208{
1209 int level = curlevel;
1210
1211 LISTBASE_FOREACH (TreeElement *, te, lb) {
1212 int lev = outliner_count_levels(&te->subtree, curlevel + 1);
1213 level = std::max(lev, level);
1214 }
1215 return level;
1216}
1217
1218int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel)
1219{
1220 LISTBASE_FOREACH (TreeElement *, te, lb) {
1221 TreeStoreElem *tselem = TREESTORE(te);
1222 if (tselem->flag & flag) {
1223 return curlevel;
1224 }
1225
1226 int level = outliner_flag_is_any_test(&te->subtree, flag, curlevel + 1);
1227 if (level) {
1228 return level;
1229 }
1230 }
1231 return 0;
1232}
1233
1234bool outliner_flag_set(const SpaceOutliner &space_outliner, const short flag, const short set)
1235{
1236 return outliner_flag_set(space_outliner.tree, flag, set);
1237}
1238
1239bool outliner_flag_set(const ListBase &lb, const short flag, const short set)
1240{
1241 bool changed = false;
1242
1243 tree_iterator::all(lb, [&](TreeElement *te) {
1244 TreeStoreElem *tselem = TREESTORE(te);
1245 bool has_flag = (tselem->flag & flag);
1246 if (set == 0) {
1247 if (has_flag) {
1248 tselem->flag &= ~flag;
1249 changed = true;
1250 }
1251 }
1252 else if (!has_flag) {
1253 tselem->flag |= flag;
1254 changed = true;
1255 }
1256 });
1257
1258 return changed;
1259}
1260
1261bool outliner_flag_flip(const SpaceOutliner &space_outliner, const short flag)
1262{
1263 return outliner_flag_flip(space_outliner.tree, flag);
1264}
1265
1266bool outliner_flag_flip(const ListBase &lb, const short flag)
1267{
1268 bool changed = false;
1269
1270 tree_iterator::all(lb, [&](TreeElement *te) {
1271 TreeStoreElem *tselem = TREESTORE(te);
1272 tselem->flag ^= flag;
1273 });
1274
1275 return changed;
1276}
1277
1279
1280/* -------------------------------------------------------------------- */
1283
1285{
1286 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1287 ARegion *region = CTX_wm_region(C);
1288
1289 if (outliner_flag_is_any_test(&space_outliner->tree, TSE_CLOSED, 1)) {
1290 outliner_flag_set(*space_outliner, TSE_CLOSED, 0);
1291 }
1292 else {
1293 outliner_flag_set(*space_outliner, TSE_CLOSED, 1);
1294 }
1295
1296 ED_region_tag_redraw(region);
1297
1298 return OPERATOR_FINISHED;
1299}
1300
1302{
1303 /* identifiers */
1304 ot->name = "Expand/Collapse All";
1305 ot->idname = "OUTLINER_OT_expanded_toggle";
1306 ot->description = "Expand/Collapse all items";
1307
1308 /* callbacks */
1311
1312 /* no undo or registry, UI option */
1313}
1314
1316
1317/* -------------------------------------------------------------------- */
1320
1322{
1323 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1324 ARegion *region = CTX_wm_region(C);
1325 Scene *scene = CTX_data_scene(C);
1326 int action = RNA_enum_get(op->ptr, "action");
1327 if (action == SEL_TOGGLE) {
1328 action = outliner_flag_is_any_test(&space_outliner->tree, TSE_SELECTED, 1) ? SEL_DESELECT :
1329 SEL_SELECT;
1330 }
1331
1332 switch (action) {
1333 case SEL_SELECT:
1334 outliner_flag_set(*space_outliner, TSE_SELECTED, 1);
1335 break;
1336 case SEL_DESELECT:
1337 outliner_flag_set(*space_outliner, TSE_SELECTED, 0);
1338 break;
1339 case SEL_INVERT:
1340 outliner_flag_flip(*space_outliner, TSE_SELECTED);
1341 break;
1342 }
1343
1344 ED_outliner_select_sync_from_outliner(C, space_outliner);
1345
1349
1350 return OPERATOR_FINISHED;
1351}
1352
1354{
1355 /* identifiers */
1356 ot->name = "Toggle Selected";
1357 ot->idname = "OUTLINER_OT_select_all";
1358 ot->description = "Toggle the Outliner selection of items";
1359
1360 /* callbacks */
1363
1364 /* no undo or registry */
1365
1366 /* rna */
1368}
1369
1371
1372/* -------------------------------------------------------------------- */
1375
1377{
1378 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1379 ScrArea *area = CTX_wm_area(C);
1381 UI_textbutton_activate_rna(C, region, space_outliner, "filter_text");
1382
1383 return OPERATOR_FINISHED;
1384}
1385
1387{
1388 /* Identifiers. */
1389 ot->name = "Filter";
1390 ot->description = "Start entering filter text";
1391 ot->idname = "OUTLINER_OT_start_filter";
1392
1393 /* Callbacks. */
1396}
1397
1399{
1400 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1401 space_outliner->search_string[0] = '\0';
1403 return OPERATOR_FINISHED;
1404}
1405
1407{
1408 /* Identifiers. */
1409 ot->name = "Clear Filter";
1410 ot->description = "Clear the search filter";
1411 ot->idname = "OUTLINER_OT_clear_filter";
1412
1413 /* Callbacks. */
1416}
1417
1419
1420/* -------------------------------------------------------------------- */
1423
1424void outliner_set_coordinates(const ARegion *region, const SpaceOutliner *space_outliner)
1425{
1426 int starty = int(region->v2d.tot.ymax) - UI_UNIT_Y;
1427
1428 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
1429 /* store coord and continue, we need coordinates for elements outside view too */
1430 te->xs = 0;
1431 te->ys = float(starty);
1432 starty -= UI_UNIT_Y;
1433 });
1434}
1435
1438{
1439 TreeStoreElem *tselem;
1440 bool retval = false;
1441
1442 for (te = te->parent; te; te = te->parent) {
1443 tselem = TREESTORE(te);
1444 if (tselem->flag & TSE_CLOSED) {
1445 tselem->flag &= ~TSE_CLOSED;
1446 retval = true;
1447 }
1448 }
1449 return retval;
1450}
1451
1456 SpaceOutliner *space_outliner,
1457 const Scene *scene,
1458 ViewLayer *view_layer)
1459{
1460 TreeElement *te;
1461
1462 BKE_view_layer_synced_ensure(scene, view_layer);
1463 Object *obact = BKE_view_layer_active_object_get(view_layer);
1464
1465 if (!obact) {
1466 return nullptr;
1467 }
1468
1469 te = outliner_find_id(space_outliner, &space_outliner->tree, &obact->id);
1470
1471 if (te != nullptr && obact->type == OB_ARMATURE) {
1472 /* traverse down the bone hierarchy in case of armature */
1473 TreeElement *te_obact = te;
1474
1475 if (obact->mode & OB_MODE_POSE) {
1476 Object *obpose = BKE_object_pose_armature_get(obact);
1477 bPoseChannel *pchan = BKE_pose_channel_active(obpose, false);
1478 if (pchan) {
1479 te = outliner_find_posechannel(&te_obact->subtree, pchan);
1480 }
1481 }
1482 else if (obact->mode & OB_MODE_EDIT) {
1483 EditBone *ebone = CTX_data_active_bone(C);
1484 if (ebone) {
1485 te = outliner_find_editbone(&te_obact->subtree, ebone);
1486 }
1487 }
1488 }
1489
1490 return te;
1491}
1492
1493static void outliner_show_active(SpaceOutliner *space_outliner,
1494 ARegion *region,
1495 TreeElement *te,
1496 ID *id)
1497{
1498 /* open up tree to active object/bone */
1499 if (TREESTORE(te)->id == id) {
1500 if (outliner_open_back(te)) {
1501 outliner_set_coordinates(region, space_outliner);
1502 }
1503 return;
1504 }
1505
1506 LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
1507 outliner_show_active(space_outliner, region, ten, id);
1508 }
1509}
1510
1512{
1513 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1514 const Scene *scene = CTX_data_scene(C);
1515 ViewLayer *view_layer = CTX_data_view_layer(C);
1516 ARegion *region = CTX_wm_region(C);
1517 View2D *v2d = &region->v2d;
1518
1520 C, space_outliner, scene, view_layer);
1521
1522 if (active_element) {
1523 ID *id = TREESTORE(active_element)->id;
1524
1525 /* Expand all elements in the outliner with matching ID */
1526 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
1527 outliner_show_active(space_outliner, region, te, id);
1528 }
1529
1530 /* Also open back from the active_element (only done for the first found occurrence of ID
1531 * though). */
1532 outliner_show_active(space_outliner, region, active_element, id);
1533
1534 /* Center view on first element found */
1535 int size_y = BLI_rcti_size_y(&v2d->mask) + 1;
1536 int ytop = (active_element->ys + (size_y / 2));
1537 int delta_y = ytop - v2d->cur.ymax;
1538
1539 outliner_scroll_view(space_outliner, region, delta_y);
1540 }
1541 else {
1542 return OPERATOR_CANCELLED;
1543 }
1544
1546
1547 return OPERATOR_FINISHED;
1548}
1549
1551{
1552 /* identifiers */
1553 ot->name = "Show Active";
1554 ot->idname = "OUTLINER_OT_show_active";
1555 ot->description =
1556 "Open up the tree and adjust the view so that the active object is shown centered";
1557
1558 /* callbacks */
1561}
1562
1564
1565/* -------------------------------------------------------------------- */
1568
1570{
1571 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1572 ARegion *region = CTX_wm_region(C);
1573 int size_y = BLI_rcti_size_y(&region->v2d.mask) + 1;
1574
1575 bool up = RNA_boolean_get(op->ptr, "up");
1576
1577 if (!up) {
1578 size_y = -size_y;
1579 }
1580
1581 outliner_scroll_view(space_outliner, region, size_y);
1582
1584
1585 return OPERATOR_FINISHED;
1586}
1587
1589{
1590 PropertyRNA *prop;
1591
1592 /* identifiers */
1593 ot->name = "Scroll Page";
1594 ot->idname = "OUTLINER_OT_scroll_page";
1595 ot->description = "Scroll page up or down";
1596
1597 /* callbacks */
1600
1601 /* properties */
1602 prop = RNA_def_boolean(ot->srna, "up", false, "Up", "Scroll up one page");
1604}
1605
1607
1608/* -------------------------------------------------------------------- */
1611
1612/* helper function for Show/Hide one level operator */
1613static void outliner_openclose_level(ListBase *lb, int curlevel, int level, int open)
1614{
1615 LISTBASE_FOREACH (TreeElement *, te, lb) {
1616 TreeStoreElem *tselem = TREESTORE(te);
1617
1618 if (open) {
1619 if (curlevel <= level) {
1620 tselem->flag &= ~TSE_CLOSED;
1621 }
1622 }
1623 else {
1624 if (curlevel >= level) {
1625 tselem->flag |= TSE_CLOSED;
1626 }
1627 }
1628
1629 outliner_openclose_level(&te->subtree, curlevel + 1, level, open);
1630 }
1631}
1632
1634{
1635 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1636 ARegion *region = CTX_wm_region(C);
1637 const bool add = RNA_boolean_get(op->ptr, "open");
1638 int level;
1639
1640 level = outliner_flag_is_any_test(&space_outliner->tree, TSE_CLOSED, 1);
1641 if (add == 1) {
1642 if (level) {
1643 outliner_openclose_level(&space_outliner->tree, 1, level, 1);
1644 }
1645 }
1646 else {
1647 if (level == 0) {
1648 level = outliner_count_levels(&space_outliner->tree, 0);
1649 }
1650 if (level) {
1651 outliner_openclose_level(&space_outliner->tree, 1, level - 1, 0);
1652 }
1653 }
1654
1655 ED_region_tag_redraw(region);
1656
1657 return OPERATOR_FINISHED;
1658}
1659
1661{
1662 PropertyRNA *prop;
1663
1664 /* identifiers */
1665 ot->name = "Show/Hide One Level";
1666 ot->idname = "OUTLINER_OT_show_one_level";
1667 ot->description = "Expand/collapse all entries by one level";
1668
1669 /* callbacks */
1672
1673 /* no undo or registry, UI option */
1674
1675 /* properties */
1676 prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Expand all entries one level deep");
1678}
1679
1681
1682/* -------------------------------------------------------------------- */
1685
1691{
1692 LISTBASE_FOREACH (TreeElement *, te, lb) {
1693 TreeStoreElem *tselem = TREESTORE(te);
1694 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1695 return 1;
1696 }
1697 if (subtree_has_objects(&te->subtree)) {
1698 return 1;
1699 }
1700 }
1701 return 0;
1702}
1703
1704/* Helper function for Show Hierarchy operator */
1705static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outliner)
1706{
1707 /* open all object elems, close others */
1708 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
1709 TreeStoreElem *tselem = TREESTORE(te);
1710
1711 if (ELEM(tselem->type,
1716 {
1717 if (te->idcode == ID_SCE) {
1718 if (tselem->id != (ID *)scene) {
1719 tselem->flag |= TSE_CLOSED;
1720 }
1721 else {
1722 tselem->flag &= ~TSE_CLOSED;
1723 }
1724 }
1725 else if (te->idcode == ID_OB) {
1726 if (subtree_has_objects(&te->subtree)) {
1727 tselem->flag &= ~TSE_CLOSED;
1728 }
1729 else {
1730 tselem->flag |= TSE_CLOSED;
1731 }
1732 }
1733 }
1734 else {
1735 tselem->flag |= TSE_CLOSED;
1736 }
1737 });
1738}
1739
1740/* show entire object level hierarchy */
1742{
1743 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1744 ARegion *region = CTX_wm_region(C);
1745 Scene *scene = CTX_data_scene(C);
1746
1747 /* recursively open/close levels */
1748 tree_element_show_hierarchy(scene, space_outliner);
1749
1750 ED_region_tag_redraw(region);
1751
1752 return OPERATOR_FINISHED;
1753}
1754
1756{
1757 /* identifiers */
1758 ot->name = "Show Hierarchy";
1759 ot->idname = "OUTLINER_OT_show_hierarchy";
1760 ot->description = "Open all object entries and close all others";
1761
1762 /* callbacks */
1764 /* TODO: shouldn't be allowed in RNA views... */
1766
1767 /* no undo or registry, UI option */
1768}
1769
1771
1772/* -------------------------------------------------------------------- */
1775
1780{
1781 ScrArea *area = CTX_wm_area(C);
1782 if ((area) && (area->spacetype == SPACE_OUTLINER)) {
1783 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1784 return (space_outliner->outlinevis == SO_DATA_API);
1785 }
1786 return false;
1787}
1788
1789/* Helper func to extract an RNA path from selected tree element
1790 * NOTE: the caller must zero-out all values of the pointers that it passes here first, as
1791 * this function does not do that yet
1792 */
1794 TreeStoreElem *tselem,
1795 ID **id,
1796 char **path,
1797 int *array_index,
1798 short *flag,
1799 short * /*groupmode*/)
1800{
1801 ListBase hierarchy = {nullptr, nullptr};
1802 char *newpath = nullptr;
1803
1804 /* optimize tricks:
1805 * - Don't do anything if the selected item is a 'struct', but arrays are allowed
1806 */
1807 if (tselem->type == TSE_RNA_STRUCT) {
1808 return;
1809 }
1810
1811 /* Overview of Algorithm:
1812 * 1. Go up the chain of parents until we find the 'root', taking note of the
1813 * levels encountered in reverse-order (i.e. items are added to the start of the list
1814 * for more convenient looping later)
1815 * 2. Walk down the chain, adding from the first ID encountered
1816 * (which will become the 'ID' for the KeyingSet Path), and build a
1817 * path as we step through the chain
1818 */
1819
1820 /* step 1: flatten out hierarchy of parents into a flat chain */
1821 for (TreeElement *tem = te->parent; tem; tem = tem->parent) {
1822 LinkData *ld = MEM_callocN<LinkData>("LinkData for tree_element_to_path()");
1823 ld->data = tem;
1824 BLI_addhead(&hierarchy, ld);
1825 }
1826
1827 /* step 2: step down hierarchy building the path
1828 * (NOTE: addhead in previous loop was needed so that we can loop like this) */
1829 LISTBASE_FOREACH (LinkData *, ld, &hierarchy) {
1830 /* get data */
1831 TreeElement *tem = (TreeElement *)ld->data;
1833 PointerRNA ptr = tem_rna->get_pointer_rna();
1834
1835 /* check if we're looking for first ID, or appending to path */
1836 if (*id) {
1837 /* just 'append' property to path
1838 * - to prevent memory leaks, we must write to newpath not path,
1839 * then free old path + swap them.
1840 */
1842 PropertyRNA *prop = tem_rna_prop->get_property_rna();
1843
1844 if (RNA_property_type(prop) == PROP_POINTER) {
1845 /* for pointer we just append property name */
1846 newpath = RNA_path_append(*path, &ptr, prop, 0, nullptr);
1847 }
1848 else if (RNA_property_type(prop) == PROP_COLLECTION) {
1849 char buf[128], *name;
1850
1851 TreeElement *temnext = (TreeElement *)(ld->next->data);
1852 PointerRNA nextptr = tree_element_cast<TreeElementRNACommon>(temnext)->get_pointer_rna();
1853 name = RNA_struct_name_get_alloc(&nextptr, buf, sizeof(buf), nullptr);
1854
1855 if (name) {
1856 /* if possible, use name as a key in the path */
1857 newpath = RNA_path_append(*path, nullptr, prop, 0, name);
1858
1859 if (name != buf) {
1860 MEM_freeN(name);
1861 }
1862 }
1863 else {
1864 /* otherwise use index */
1865 int index = 0;
1866
1867 LISTBASE_FOREACH (TreeElement *, temsub, &tem->subtree) {
1868 if (temsub == temnext) {
1869 break;
1870 }
1871 index++;
1872 }
1873 newpath = RNA_path_append(*path, nullptr, prop, index, nullptr);
1874 }
1875
1876 ld = ld->next;
1877 }
1878 }
1879
1880 if (newpath) {
1881 if (*path) {
1882 MEM_freeN(*path);
1883 }
1884 *path = newpath;
1885 newpath = nullptr;
1886 }
1887 }
1888 else {
1889 /* no ID, so check if entry is RNA-struct,
1890 * and if that RNA-struct is an ID datablock to extract info from. */
1892 /* ptr->data not ptr->owner_id seems to be the one we want,
1893 * since ptr->data is sometimes the owner of this ID? */
1894 if (RNA_struct_is_ID(ptr.type)) {
1895 *id = static_cast<ID *>(ptr.data);
1896
1897 /* clear path */
1898 if (*path) {
1899 MEM_freeN(*path);
1900 path = nullptr;
1901 }
1902 }
1903 }
1904 }
1905 }
1906
1907 /* step 3: if we've got an ID, add the current item to the path */
1908 if (*id) {
1909 /* add the active property to the path */
1910 PropertyRNA *prop = tree_element_cast<TreeElementRNACommon>(te)->get_property_rna();
1911
1912 /* array checks */
1913 if (tselem->type == TSE_RNA_ARRAY_ELEM) {
1914 /* item is part of an array, so must set the array_index */
1915 *array_index = te->index;
1916 }
1917 else if (RNA_property_array_check(prop)) {
1918 /* entire array was selected, so keyframe all */
1920 }
1921
1922 /* path */
1923 newpath = RNA_path_append(*path, nullptr, prop, 0, nullptr);
1924 if (*path) {
1925 MEM_freeN(*path);
1926 }
1927 *path = newpath;
1928 }
1929
1930 /* free temp data */
1931 BLI_freelistN(&hierarchy);
1932}
1933
1935
1936/* -------------------------------------------------------------------- */
1939
1946enum {
1949} /*eDrivers_EditModes*/;
1950
1951/* Iterate over tree, finding and working on selected items */
1952static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
1953 ReportList *reports,
1954 short mode)
1955{
1956 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
1957 TreeStoreElem *tselem = TREESTORE(te);
1958
1959 /* if item is selected, perform operation */
1960 if (!(tselem->flag & TSE_SELECTED)) {
1961 return;
1962 }
1963
1964 ID *id = nullptr;
1965 char *path = nullptr;
1966 int array_index = 0;
1967 short flag = 0;
1968 short groupmode = KSP_GROUP_KSNAME;
1969
1971 PointerRNA ptr = te_rna ? te_rna->get_pointer_rna() : PointerRNA_NULL;
1972 PropertyRNA *prop = te_rna ? te_rna->get_property_rna() : nullptr;
1973
1974 /* check if RNA-property described by this selected element is an animatable prop */
1975 if (prop && RNA_property_anim_editable(&ptr, prop)) {
1976 /* get id + path + index info from the selected element */
1977 tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
1978 }
1979
1980 /* only if ID and path were set, should we perform any actions */
1981 if (id && path) {
1982 short dflags = CREATEDRIVER_WITH_DEFAULT_DVAR;
1983 int arraylen = 1;
1984
1985 /* array checks */
1986 if (flag & KSP_FLAG_WHOLE_ARRAY) {
1987 /* entire array was selected, so add drivers for all */
1988 arraylen = RNA_property_array_length(&ptr, prop);
1989 }
1990 else {
1991 arraylen = array_index;
1992 }
1993
1994 /* we should do at least one step */
1995 if (arraylen == array_index) {
1996 arraylen++;
1997 }
1998
1999 /* for each array element we should affect, add driver */
2000 for (; array_index < arraylen; array_index++) {
2001 /* action depends on mode */
2002 switch (mode) {
2003 case DRIVERS_EDITMODE_ADD: {
2004 /* add a new driver with the information obtained (only if valid) */
2005 ANIM_add_driver(reports, id, path, array_index, dflags, DRIVER_TYPE_PYTHON);
2006 break;
2007 }
2009 ANIM_remove_driver(id, path, array_index);
2010 break;
2011 }
2012 }
2013 }
2014
2015 /* free path, since it had to be generated */
2016 MEM_freeN(path);
2017 }
2018 });
2019}
2020
2022
2023/* -------------------------------------------------------------------- */
2026
2028{
2029 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2030
2031 /* check for invalid states */
2032 if (space_outliner == nullptr) {
2033 return OPERATOR_CANCELLED;
2034 }
2035
2036 /* recursively go into tree, adding selected items */
2038
2039 /* send notifiers */
2040 WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, nullptr); /* XXX */
2041
2042 return OPERATOR_FINISHED;
2043}
2044
2046{
2047 /* API callbacks. */
2048 ot->idname = "OUTLINER_OT_drivers_add_selected";
2049 ot->name = "Add Drivers for Selected";
2050 ot->description = "Add drivers to selected items";
2051
2052 /* API callbacks. */
2055
2056 /* flags */
2057 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2058}
2059
2061
2062/* -------------------------------------------------------------------- */
2065
2067{
2068 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2069
2070 /* check for invalid states */
2071 if (space_outliner == nullptr) {
2072 return OPERATOR_CANCELLED;
2073 }
2074
2075 /* recursively go into tree, adding selected items */
2077
2078 /* send notifiers */
2079 WM_event_add_notifier(C, ND_KEYS, nullptr); /* XXX */
2080
2081 return OPERATOR_FINISHED;
2082}
2083
2085{
2086 /* identifiers */
2087 ot->idname = "OUTLINER_OT_drivers_delete_selected";
2088 ot->name = "Delete Drivers for Selected";
2089 ot->description = "Delete drivers assigned to selected items";
2090
2091 /* API callbacks. */
2094
2095 /* flags */
2096 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2097}
2098
2100
2101/* -------------------------------------------------------------------- */
2104
2111enum {
2114} /*eKeyingSet_EditModes*/;
2115
2116/* Find the 'active' KeyingSet, and add if not found (if adding is allowed). */
2117/* TODO: should this be an API func? */
2119{
2120 KeyingSet *ks = nullptr;
2121
2122 /* sanity check */
2123 if (scene == nullptr) {
2124 return nullptr;
2125 }
2126
2127 /* try to find one from scene */
2128 if (scene->active_keyingset > 0) {
2129 ks = static_cast<KeyingSet *>(BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1));
2130 }
2131
2132 /* Add if none found */
2133 /* XXX the default settings have yet to evolve. */
2134 if ((add) && (ks == nullptr)) {
2135 ks = BKE_keyingset_add(&scene->keyingsets, nullptr, nullptr, KEYINGSET_ABSOLUTE, 0);
2137 }
2138
2139 return ks;
2140}
2141
2142/* Iterate over tree, finding and working on selected items */
2144 KeyingSet *ks,
2145 const short mode)
2146{
2147 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2148 TreeStoreElem *tselem = TREESTORE(te);
2149
2150 /* if item is selected, perform operation */
2151 if (!(tselem->flag & TSE_SELECTED)) {
2152 return;
2153 }
2154
2155 ID *id = nullptr;
2156 char *path = nullptr;
2157 int array_index = 0;
2158 short flag = 0;
2159 short groupmode = KSP_GROUP_KSNAME;
2160
2161 /* check if RNA-property described by this selected element is an animatable prop */
2163 if (te_rna) {
2164 PointerRNA ptr = te_rna->get_pointer_rna();
2165 if (PropertyRNA *prop = te_rna->get_property_rna()) {
2166 if (RNA_property_anim_editable(&ptr, prop)) {
2167 /* get id + path + index info from the selected element */
2168 tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
2169 }
2170 }
2171 }
2172
2173 /* only if ID and path were set, should we perform any actions */
2174 if (id && path) {
2175 /* action depends on mode */
2176 switch (mode) {
2178 /* add a new path with the information obtained (only if valid) */
2179 /* TODO: what do we do with group name?
2180 * for now, we don't supply one, and just let this use the KeyingSet name */
2181 BKE_keyingset_add_path(ks, id, nullptr, path, array_index, flag, groupmode);
2183 break;
2184 }
2186 /* find the relevant path, then remove it from the KeyingSet */
2187 KS_Path *ksp = BKE_keyingset_find_path(ks, id, nullptr, path, array_index, groupmode);
2188
2189 if (ksp) {
2190 /* free path's data */
2191 BKE_keyingset_free_path(ks, ksp);
2192
2193 ks->active_path = 0;
2194 }
2195 break;
2196 }
2197 }
2198
2199 /* free path, since it had to be generated */
2200 MEM_freeN(path);
2201 }
2202 });
2203}
2204
2206
2207/* -------------------------------------------------------------------- */
2210
2212{
2213 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2214 Scene *scene = CTX_data_scene(C);
2215 KeyingSet *ks = verify_active_keyingset(scene, 1);
2216
2217 /* check for invalid states */
2218 if (ks == nullptr) {
2219 BKE_report(op->reports, RPT_ERROR, "Operation requires an active keying set");
2220 return OPERATOR_CANCELLED;
2221 }
2222 if (space_outliner == nullptr) {
2223 return OPERATOR_CANCELLED;
2224 }
2225
2226 /* recursively go into tree, adding selected items */
2228
2229 /* send notifiers */
2231
2232 return OPERATOR_FINISHED;
2233}
2234
2236{
2237 /* identifiers */
2238 ot->idname = "OUTLINER_OT_keyingset_add_selected";
2239 ot->name = "Keying Set Add Selected";
2240 ot->description = "Add selected items (blue-gray rows) to active Keying Set";
2241
2242 /* API callbacks. */
2245
2246 /* flags */
2247 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2248}
2249
2251
2252/* -------------------------------------------------------------------- */
2255
2257{
2258 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2259 Scene *scene = CTX_data_scene(C);
2260 KeyingSet *ks = verify_active_keyingset(scene, 1);
2261
2262 /* check for invalid states */
2263 if (space_outliner == nullptr) {
2264 return OPERATOR_CANCELLED;
2265 }
2266
2267 /* recursively go into tree, adding selected items */
2269
2270 /* send notifiers */
2272
2273 return OPERATOR_FINISHED;
2274}
2275
2277{
2278 /* identifiers */
2279 ot->idname = "OUTLINER_OT_keyingset_remove_selected";
2280 ot->name = "Keying Set Remove Selected";
2281 ot->description = "Remove selected items (blue-gray rows) from active Keying Set";
2282
2283 /* API callbacks. */
2286
2287 /* flags */
2288 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2289}
2290
2292
2293/* -------------------------------------------------------------------- */
2296
2298{
2299 ScrArea *area = CTX_wm_area(C);
2300 if (area != nullptr && area->spacetype == SPACE_OUTLINER) {
2301 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2302 return (space_outliner->outlinevis == SO_ID_ORPHANS);
2303 }
2304 return true;
2305}
2306
2307static void unused_message_gen(std::string &message,
2308 const std::array<int, INDEX_ID_MAX> &num_tagged)
2309{
2310 bool is_first = true;
2311 if (num_tagged[INDEX_ID_NULL] == 0) {
2312 message += IFACE_("None");
2313 return;
2314 }
2315
2316 /* NOTE: Index is looped in reversed order, since typically 'higher level' IDs (like Collections
2317 * or Objects) have a higher index than 'lower level' ones like object data, materials, etc.
2318 *
2319 * It makes more sense to present to the user the deleted numbers of Collections or Objects
2320 * before the ones for object data or Materials. */
2321 for (int i = INDEX_ID_MAX - 2; i >= 0; i--) {
2322 if (num_tagged[i] != 0) {
2323 message += fmt::format(
2324 "{}{} {}",
2325 (is_first) ? "" : ", ",
2326 num_tagged[i],
2327 (num_tagged[i] > 1) ?
2330 is_first = false;
2331 }
2332 }
2333}
2334
2336{
2337 /* Computation of unused data amounts, with all options ON.
2338 * Used to estimate the maximum required width for the dialog. */
2339 Main *bmain = CTX_data_main(C);
2341 data.do_local_ids = true;
2342 data.do_linked_ids = true;
2343 data.do_recursive = true;
2345
2346 std::string unused_message;
2347 const uiStyle *style = UI_style_get_dpi();
2348 unused_message_gen(unused_message, data.num_local);
2349 float max_messages_width = BLF_width(
2350 style->widget.uifont_id, unused_message.c_str(), BLF_DRAW_STR_DUMMY_MAX);
2351
2352 unused_message = "";
2353 unused_message_gen(unused_message, data.num_linked);
2354 max_messages_width = std::max(
2355 max_messages_width,
2356 BLF_width(style->widget.uifont_id, unused_message.c_str(), BLF_DRAW_STR_DUMMY_MAX));
2357
2358 return int(std::max(max_messages_width, 300.0f));
2359}
2360
2362 wmOperator *op,
2363 const bool is_abort = false)
2364{
2365 if (is_abort) {
2366 /* In case of abort, ensure that temp tag is cleared in all IDs, since they were not deleted.
2367 */
2369 }
2370 if (op->customdata) {
2371 MEM_delete(static_cast<LibQueryUnusedIDsData *>(op->customdata));
2372 op->customdata = nullptr;
2373 }
2374}
2375
2377{
2378 Main *bmain = CTX_data_main(C);
2380
2381 data.do_local_ids = RNA_boolean_get(op->ptr, "do_local_ids");
2382 data.do_linked_ids = RNA_boolean_get(op->ptr, "do_linked_ids");
2383 data.do_recursive = RNA_boolean_get(op->ptr, "do_recursive");
2384
2386
2387 /* Always assume count changed, and request a redraw. */
2388 return true;
2389}
2390
2392 wmOperator *op,
2393 const wmEvent * /*event*/)
2394{
2395 op->customdata = MEM_new<LibQueryUnusedIDsData>(__func__);
2396
2397 /* Compute expected amounts of deleted IDs and store them in 'cached' operator properties. */
2399
2401 op,
2403 IFACE_("Purge Unused Data from This File"),
2404 IFACE_("Delete"));
2405}
2406
2408{
2409 Main *bmain = CTX_data_main(C);
2410 ScrArea *area = CTX_wm_area(C);
2411 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2412
2413 if (!op->customdata) {
2414 op->customdata = MEM_new<LibQueryUnusedIDsData>(__func__);
2415 }
2417
2418 data.do_local_ids = RNA_boolean_get(op->ptr, "do_local_ids");
2419 data.do_linked_ids = RNA_boolean_get(op->ptr, "do_linked_ids");
2420 data.do_recursive = RNA_boolean_get(op->ptr, "do_recursive");
2421
2422 /* Tag all IDs to delete. */
2424
2425 if (data.num_total[INDEX_ID_NULL] == 0) {
2426 BKE_report(op->reports, RPT_INFO, "No orphaned data-blocks to purge");
2427 outliner_orphans_purge_cleanup(C, op, true);
2428 return OPERATOR_CANCELLED;
2429 }
2430
2431 if (data.num_total[INDEX_ID_SCE] > 0) {
2432 BKE_report(op->reports,
2433 RPT_ERROR,
2434 "Attempt to delete scenes as part of a purge operation, should never happen");
2435 outliner_orphans_purge_cleanup(C, op, true);
2436 return OPERATOR_CANCELLED;
2437 }
2438
2440
2441 BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-block(s)", data.num_total[INDEX_ID_NULL]);
2442
2443 /* XXX: tree management normally happens from draw_outliner(), but when
2444 * you're clicking to fast on Delete object from context menu in
2445 * outliner several mouse events can be handled in one cycle without
2446 * handling notifiers/redraw which leads to deleting the same object twice.
2447 * cleanup tree here to prevent such cases. */
2448 if ((area != nullptr) && (area->spacetype == SPACE_OUTLINER)) {
2449 outliner_cleanup_tree(space_outliner);
2450 }
2451
2453 WM_event_add_notifier(C, NC_ID | NA_REMOVED, nullptr);
2454 /* Force full redraw of the UI. */
2456
2458
2459 return OPERATOR_FINISHED;
2460}
2461
2463{
2464 outliner_orphans_purge_cleanup(C, op, true);
2465}
2466
2468{
2469 uiLayout *layout = op->layout;
2470 PointerRNA *ptr = op->ptr;
2471 if (!op->customdata) {
2472 /* This should only happen on 'adjust last operation' case, since `invoke` will not have been
2473 * called then before showing the UI (the 'redo panel' UI uses WM-stored operator properties
2474 * and a newly-created operator).
2475 *
2476 * Since that operator is not 'registered' for adjusting from undo stack, this should never
2477 * happen currently. */
2479 op->customdata = MEM_new<LibQueryUnusedIDsData>(__func__);
2480 }
2482
2483 std::string unused_message;
2484 unused_message_gen(unused_message, data.num_local);
2485 uiLayout *column = &layout->column(true);
2486 column->prop(ptr, "do_local_ids", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2487 uiLayout *row = &column->row(true);
2488 row->separator(2.67f);
2489 row->label(unused_message, ICON_NONE);
2490
2491 unused_message = "";
2492 unused_message_gen(unused_message, data.num_linked);
2493 column = &layout->column(true);
2494 column->prop(ptr, "do_linked_ids", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2495 row = &column->row(true);
2496 row->separator(2.67f);
2497 row->label(unused_message, ICON_NONE);
2498
2499 layout->prop(ptr, "do_recursive", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2500}
2501
2503{
2504 /* identifiers */
2505 ot->idname = "OUTLINER_OT_orphans_purge";
2506 ot->name = "Purge All";
2507 ot->description = "Clear all orphaned data-blocks without any users from the file";
2508
2509 /* callbacks */
2513
2517
2518 /* flags */
2519 /* NOTE: No #OPTYPE_REGISTER, since this operator should not be 'adjustable'. */
2520 ot->flag = OPTYPE_UNDO;
2521
2522 /* Actual user-visible settings. */
2523 RNA_def_boolean(ot->srna,
2524 "do_local_ids",
2525 true,
2526 "Local Data-blocks",
2527 "Include unused local data-blocks into deletion");
2528 RNA_def_boolean(ot->srna,
2529 "do_linked_ids",
2530 true,
2531 "Linked Data-blocks",
2532 "Include unused linked data-blocks into deletion");
2533
2534 RNA_def_boolean(ot->srna,
2535 "do_recursive",
2536 true,
2537 "Recursive Delete",
2538 "Recursively check for indirectly unused data-blocks, ensuring that no orphaned "
2539 "data-blocks remain after execution");
2540}
2541
2543
2544/* -------------------------------------------------------------------- */
2547
2549 wmOperator * /*op*/,
2550 const wmEvent * /*event*/)
2551{
2552 if (WM_window_open_temp(C, IFACE_("Manage Unused Data"), SPACE_OUTLINER, false)) {
2553 SpaceOutliner *soutline = CTX_wm_space_outliner(C);
2554 soutline->outlinevis = SO_ID_ORPHANS;
2555 return OPERATOR_FINISHED;
2556 }
2557 return OPERATOR_CANCELLED;
2558}
2559
2561{
2562 /* identifiers */
2563 ot->idname = "OUTLINER_OT_orphans_manage";
2564 ot->name = "Manage Unused Data";
2565 ot->description = "Open a window to manage unused data";
2566
2567 /* callbacks */
2569
2570 /* flags */
2571 ot->flag = OPTYPE_REGISTER;
2572}
2573
2575
2576} // namespace blender::ed::outliner
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_active(Object *ob, bool check_bonecoll)
struct KS_Path * BKE_keyingset_find_path(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, int group_mode)
Definition anim_sys.cc:84
struct KeyingSet * BKE_keyingset_add(struct ListBase *list, const char idname[], const char name[], short flag, short keyingflag)
Definition anim_sys.cc:134
struct KS_Path * BKE_keyingset_add_path(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode)
Definition anim_sys.cc:164
void BKE_keyingset_free_path(struct KeyingSet *ks, struct KS_Path *ksp)
Definition anim_sys.cc:227
const char * BKE_tempdir_base() ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition appdir.cc:1243
int BKE_copybuffer_paste(bContext *C, const char *libname, int flag, ReportList *reports, uint64_t id_types_mask)
SpaceOutliner * CTX_wm_space_outliner(const bContext *C)
PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type)
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
EditBone * CTX_data_active_bone(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
const IDTypeInfo * BKE_idtype_get_info_from_id(const ID *id)
Definition idtype.cc:146
short BKE_idtype_index_to_idcode(int idtype_index)
Definition idtype.cc:341
@ IDTYPE_FLAGS_NO_COPY
Definition BKE_idtype.hh:33
@ IDTYPE_FLAGS_NO_LIBLINKING
Definition BKE_idtype.hh:35
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:164
bool BKE_idtype_idcode_is_linkable(short idcode)
Definition idtype.cc:197
const char * BKE_idtype_idcode_to_name_plural(short idcode)
Definition idtype.cc:171
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
void size_t BKE_id_multi_tagged_delete(Main *bmain) ATTR_NONNULL()
void BKE_main_id_tag_idcode(Main *mainvar, short type, int tag, bool value)
Definition lib_id.cc:1217
void BKE_main_lib_objects_recalc_all(Main *bmain)
Definition lib_id.cc:1290
const char * BKE_id_name(const ID &id)
void BKE_main_id_tag_all(Main *mainvar, int tag, bool value)
Definition lib_id.cc:1224
void BKE_lib_query_unused_ids_tag(Main *bmain, int tag, LibQueryUnusedIDsData &parameters)
bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
Definition lib_query.cc:628
void BKE_lib_query_unused_ids_amounts(Main *bmain, LibQueryUnusedIDsData &parameters)
void void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, int remap_flags) ATTR_NONNULL(1
@ ID_REMAP_SKIP_NEVER_NULL_USAGE
@ ID_REMAP_SKIP_INDIRECT_USAGE
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:902
General operations, lookup, etc. for blender objects.
Object * BKE_object_pose_armature_get(Object *ob)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR_INVALID_INPUT
Definition BKE_report.hh:40
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:846
void BKE_workspace_id_tag_all_visible(Main *bmain, int tag) ATTR_NONNULL()
Definition workspace.cc:547
#define BLF_DRAW_STR_DUMMY_MAX
Definition BLF_api.hh:440
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:802
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
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)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
#define FILE_MAX
#define BLI_path_join(...)
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
#define FILE_MAXDIR
#define BLI_path_cmp
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
#define BLT_I18NCONTEXT_ID_ID
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
ID and Library types, which are fundamental for SDNA.
#define ID_IS_PACKED(_id)
Definition DNA_ID.h:700
@ ID_TAG_INDIRECT
Definition DNA_ID.h:848
@ ID_TAG_PRE_EXISTING
Definition DNA_ID.h:926
@ ID_TAG_DOIT
Definition DNA_ID.h:1036
@ ID_RECALC_SELECT
Definition DNA_ID.h:1101
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:723
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
struct ID ID
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
#define INDEX_ID_MAX
Definition DNA_ID.h:1360
@ INDEX_ID_NULL
Definition DNA_ID.h:1357
@ INDEX_ID_SCE
Definition DNA_ID.h:1349
#define ID_REAL_USERS(id)
Definition DNA_ID.h:676
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
@ LIBOVERRIDE_FLAG_NO_HIERARCHY
Definition DNA_ID.h:358
@ ID_LI
@ ID_WS
@ ID_SCE
@ ID_OB
@ KEYINGSET_ABSOLUTE
@ DRIVER_TYPE_PYTHON
@ KSP_GROUP_KSNAME
@ KSP_FLAG_WHOLE_ARRAY
Object groups, one object can be in many groups at once.
@ COLLECTION_IS_MASTER
@ OB_MODE_EDIT
@ OB_MODE_POSE
Object is a sort of wrapper for general info.
@ OB_ARMATURE
#define TSE_IS_REAL_ID(_tse)
@ TSE_STRIP_DUP
@ TSE_CONSTRAINT_BASE
@ TSE_STRIP
@ TSE_MODIFIER_BASE
@ TSE_RNA_ARRAY_ELEM
@ TSE_STRIP_DATA
@ TSE_VIEW_COLLECTION_BASE
@ TSE_ANIM_DATA
@ TSE_RNA_PROPERTY
@ TSE_LIBRARY_OVERRIDE_BASE
@ TSE_DEFGROUP_BASE
@ TSE_SCENE_COLLECTION_BASE
@ TSE_SCENE_OBJECTS_BASE
@ TSE_R_LAYER_BASE
@ TSE_LAYER_COLLECTION
@ TSE_GENERIC_LABEL
@ TSE_GPENCIL_EFFECT_BASE
@ TSE_NLA
@ TSE_ID_BASE
@ TSE_SOME_ID
@ TSE_DRIVER_BASE
@ TSE_BONE_COLLECTION_BASE
@ TSE_RNA_STRUCT
@ TSE_POSE_BASE
@ TSE_HIGHLIGHTED_ANY
@ TSE_SELECTED
@ TSE_CLOSED
@ TSE_HIGHLIGHTED_ICON
@ TSE_HIGHLIGHTED
@ TSE_DRAG_ANY
@ TSE_ACTIVE
@ TSE_TEXTBUT
@ RGN_TYPE_HEADER
struct ARegion ARegion
@ SPACE_OUTLINER
@ FILE_ACTIVE_COLLECTION
@ FILE_AUTOSELECT
@ SO_DATA_API
@ SO_ID_ORPHANS
struct SpaceOutliner SpaceOutliner
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
@ CREATEDRIVER_WITH_DEFAULT_DVAR
void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_outliner)
bool ED_operator_region_outliner_active(bContext *C)
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
int ED_screen_area_active(const bContext *C)
void ED_region_tag_redraw_no_rebuild(ARegion *region)
Definition area.cc:638
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
bool ED_operator_outliner_active(bContext *C)
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
void GPU_materials_free(Main *bmain)
Read Guarded memory(de)allocation.
@ PROP_POINTER
Definition RNA_types.hh:167
@ PROP_COLLECTION
Definition RNA_types.hh:168
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:432
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define UI_UNIT_Y
bool UI_textbutton_activate_rna(const bContext *C, ARegion *region, const void *rna_poin_data, const char *rna_prop_id)
const uiStyle * UI_style_get_dpi()
#define UI_ITEM_NONE
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:1668
#define NC_WINDOW
Definition WM_types.hh:375
#define NC_ID
Definition WM_types.hh:395
@ KM_PRESS_DRAG
Definition WM_types.hh:319
@ KM_RELEASE
Definition WM_types.hh:312
#define NC_ANIMATION
Definition WM_types.hh:388
#define ND_OB_SELECT
Definition WM_types.hh:442
#define ND_KEYINGSET
Definition WM_types.hh:448
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_FCURVES_ORDER
Definition WM_types.hh:499
#define NA_REMOVED
Definition WM_types.hh:587
#define ND_KEYS
Definition WM_types.hh:463
BMesh const char void * data
ID * id_add(const ID *id, IDAddOptions options, blender::FunctionRef< IDAddOperations(LibraryIDLinkCallbackData *cb_data, IDAddOptions options)> dependencies_filter_cb=nullptr)
bool write(const char *write_filepath, int write_flags, int remap_mode, ReportList &reports)
virtual PropertyRNA * get_property_rna() const
nullptr float
int ANIM_add_driver(ReportList *reports, ID *id, const char rna_path[], int array_index, short flag, int type)
Main Driver Management API calls.
Definition drivers.cc:383
bool ANIM_remove_driver(ID *id, const char rna_path[], int array_index)
Main Driver Management API calls.
Definition drivers.cc:505
KDTree_3d * tree
#define GS(x)
#define printf(...)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:222
void all_open(const SpaceOutliner &space_outliner, const VisitorFn visitor)
void all(const SpaceOutliner &space_outliner, const VisitorFn visitor)
void OUTLINER_OT_expanded_toggle(wmOperatorType *ot)
bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x)
int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel)
static void outliner_openclose_level(ListBase *lb, int curlevel, int level, int open)
static wmOperatorStatus outliner_keyingset_removeitems_exec(bContext *C, wmOperator *)
static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outliner)
void outliner_tag_redraw_avoid_rebuild_on_open_change(const SpaceOutliner *space_outliner, ARegion *region)
void OUTLINER_OT_item_rename(wmOperatorType *ot)
static wmOperatorStatus outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int outliner_id_copy_tag(SpaceOutliner *space_outliner, ListBase *tree, blender::bke::blendfile::PartialWriteContext &copybuffer, ReportList *reports)
static int subtree_has_objects(ListBase *lb)
static TreeElement * outliner_item_rename_find_hovered(const SpaceOutliner *space_outliner, ARegion *region, const wmEvent *event)
static void do_outliner_keyingset_editop(SpaceOutliner *space_outliner, KeyingSet *ks, const short mode)
static wmOperatorStatus outliner_orphans_manage_invoke(bContext *C, wmOperator *, const wmEvent *)
void OUTLINER_OT_show_hierarchy(wmOperatorType *ot)
TreeElement * outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
static void outliner_orphans_purge_cancel(bContext *C, wmOperator *op)
static wmOperatorStatus outliner_id_copy_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_highlight_update(wmOperatorType *ot)
static int outliner_id_delete_tag(bContext *C, ReportList *reports, TreeElement *te, const float mval[2])
bool outliner_is_collection_tree_element(const TreeElement *te)
static TreeElement * outliner_show_active_get_element(bContext *C, SpaceOutliner *space_outliner, const Scene *scene, ViewLayer *view_layer)
static wmOperatorStatus outliner_id_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *)
void OUTLINER_OT_drivers_add_selected(wmOperatorType *ot)
static wmOperatorStatus outliner_show_active_exec(bContext *C, wmOperator *)
void OUTLINER_OT_select_all(wmOperatorType *ot)
TreeElement * outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner, TreeElement *parent_te, float view_co_x, bool *r_is_merged_icon, bool *r_is_over_icon)
void OUTLINER_OT_id_linked_relocate(wmOperatorType *ot)
static wmOperatorStatus outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void OUTLINER_OT_lib_relocate(wmOperatorType *ot)
static void do_outliner_drivers_editop(SpaceOutliner *space_outliner, ReportList *reports, short mode)
static wmOperatorStatus lib_relocate(bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload)
TreeElement * outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const ID *id)
static wmOperatorStatus outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void outliner_orphans_purge_ui(bContext *, wmOperator *op)
static wmOperatorStatus outliner_one_level_exec(bContext *C, wmOperator *op)
static void outliner_orphans_purge_cleanup(bContext *C, wmOperator *op, const bool is_abort=false)
void id_delete_tag_fn(bContext *C, ReportList *reports, Scene *, TreeElement *te, TreeStoreElem *, TreeStoreElem *tselem)
static wmOperatorStatus outliner_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus outliner_id_remap_exec(bContext *C, wmOperator *op)
static int unused_message_popup_width_compute(bContext *C)
static wmOperatorStatus outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
bool outliner_flag_set(const SpaceOutliner &space_outliner, const short flag, const short set)
static wmOperatorStatus outliner_scroll_page_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem * outliner_id_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *, bool *r_free)
TreeElement * outliner_find_item_at_y(const SpaceOutliner *space_outliner, const ListBase *tree, float view_co_y)
void OUTLINER_OT_id_paste(wmOperatorType *ot)
void OUTLINER_OT_clear_filter(wmOperatorType *ot)
void outliner_set_coordinates(const ARegion *region, const SpaceOutliner *space_outliner)
static void id_delete_tag(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
void OUTLINER_OT_start_filter(wmOperatorType *ot)
static wmOperatorStatus outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_drivers_delete_selected(wmOperatorType *ot)
void OUTLINER_OT_show_one_level(wmOperatorType *ot)
void OUTLINER_OT_show_active(wmOperatorType *ot)
static wmOperatorStatus outliner_toggle_expanded_exec(bContext *C, wmOperator *)
static bool outliner_id_remap_find_tree_element(bContext *C, wmOperator *op, ListBase *tree, const float y)
static wmOperatorStatus outliner_orphans_purge_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_id_copy(wmOperatorType *ot)
static void outliner_show_active(SpaceOutliner *space_outliner, ARegion *region, TreeElement *te, ID *id)
void OUTLINER_OT_orphans_manage(wmOperatorType *ot)
TreeElement * outliner_find_editbone(ListBase *lb, const EditBone *ebone)
static wmOperatorStatus outliner_start_filter_exec(bContext *C, wmOperator *)
Collection * outliner_collection_from_tree_element(const TreeElement *te)
static void tree_element_to_path(TreeElement *te, TreeStoreElem *tselem, ID **id, char **path, int *array_index, short *flag, short *)
void outliner_scroll_view(SpaceOutliner *space_outliner, ARegion *region, int delta_y)
bool outliner_flag_flip(const SpaceOutliner &space_outliner, const short flag)
void lib_relocate_fn(bContext *C, ReportList *, Scene *, TreeElement *te, TreeStoreElem *, TreeStoreElem *tselem)
static wmOperatorStatus outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_lib_reload(wmOperatorType *ot)
void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all)
void OUTLINER_OT_scroll_page(wmOperatorType *ot)
void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot)
void OUTLINER_OT_id_remap(wmOperatorType *ot)
void OUTLINER_OT_id_delete(wmOperatorType *ot)
TreeElementT * tree_element_cast(const TreeElement *te)
static wmOperatorStatus outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *)
void OUTLINER_OT_keyingset_add_selected(wmOperatorType *ot)
static bool ed_operator_outliner_id_orphans_active(bContext *C)
static void do_item_rename(ARegion *region, TreeElement *te, TreeStoreElem *tselem, ReportList *reports)
static wmOperatorStatus outliner_lib_relocate_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2], const bool reload)
void id_remap_fn(bContext *C, ReportList *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *tselem)
static bool ed_operator_outliner_datablocks_active(bContext *C)
void lib_reload_fn(bContext *C, ReportList *, Scene *, TreeElement *te, TreeStoreElem *, TreeStoreElem *tselem)
void outliner_cleanup_tree(SpaceOutliner *space_outliner)
static wmOperatorStatus outliner_item_rename_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void OUTLINER_OT_item_openclose(wmOperatorType *ot)
bool outliner_item_is_co_over_name(const TreeElement *te, float view_co_x)
TreeElement * outliner_find_element_with_flag(const ListBase *lb, short flag)
static KeyingSet * verify_active_keyingset(Scene *scene, short add)
static bool outliner_open_back(TreeElement *te)
static wmOperatorStatus outliner_clear_filter_exec(bContext *C, wmOperator *)
static wmOperatorStatus outliner_id_paste_exec(bContext *C, wmOperator *op)
static int outliner_count_levels(ListBase *lb, const int curlevel)
void item_rename_fn(bContext *C, ReportList *reports, Scene *, TreeElement *te, TreeStoreElem *, TreeStoreElem *tselem)
static void outliner_copybuffer_filepath_get(char filepath[FILE_MAX], size_t filepath_maxncpy)
static void unused_message_gen(std::string &message, const std::array< int, INDEX_ID_MAX > &num_tagged)
static wmOperatorStatus outliner_highlight_update_invoke(bContext *C, wmOperator *, const wmEvent *event)
static wmOperatorStatus outliner_show_hierarchy_exec(bContext *C, wmOperator *)
static wmOperatorStatus outliner_lib_reload_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool outliner_orphans_purge_check(bContext *C, wmOperator *op)
void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
static wmOperatorStatus outliner_select_all_exec(bContext *C, wmOperator *op)
static TreeElement * outliner_item_rename_find_active(const SpaceOutliner *space_outliner, ReportList *reports)
#define TREESTORE(a)
const char * name
return ret
const EnumPropertyItem rna_enum_id_type_items[]
Definition rna_ID.cc:29
bool RNA_property_array_check(PropertyRNA *prop)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
bool RNA_struct_is_ID(const StructRNA *type)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
char * RNA_struct_name_get_alloc(PointerRNA *ptr, char *fixedbuf, int fixedlen, int *r_len)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
PropertyType RNA_property_type(PropertyRNA *prop)
const PointerRNA PointerRNA_NULL
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_enum_set_identifier(bContext *C, PointerRNA *ptr, const char *name, const char *id)
bool RNA_property_anim_editable(const PointerRNA *ptr, PropertyRNA *prop_orig)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
int RNA_enum_get(PointerRNA *ptr, const char *name)
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_def_property_enum_funcs_runtime(PropertyRNA *prop, EnumPropertyGetFunc getfunc, EnumPropertySetFunc setfunc, EnumPropertyItemFunc itemfunc, EnumPropertyGetTransformFunc get_transform_fn, EnumPropertySetTransformFunc set_transform_fn)
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_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
char * RNA_path_append(const char *path, const PointerRNA *, PropertyRNA *prop, int intkey, const char *strkey)
Definition rna_path.cc:613
const EnumPropertyItem rna_enum_dummy_NULL_items[]
Definition rna_rna.cc:26
const char * identifier
Definition RNA_types.hh:657
const char * name
Definition RNA_types.hh:661
unsigned int flag
Definition DNA_ID.h:348
const char * name
uint32_t flags
Definition DNA_ID.h:414
int tag
Definition DNA_ID.h:442
struct Library * lib
Definition DNA_ID.h:420
char name[258]
Definition DNA_ID.h:432
IDOverrideLibrary * override_library
Definition DNA_ID.h:494
unsigned int session_uid
Definition DNA_ID.h:462
ListBase paths
void * data
void * first
void * data
Definition RNA_types.hh:53
PropertyRNA * next
int active_keyingset
ListBase keyingsets
char search_string[64]
float ymax
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
uiLayout & row(bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
uiFontStyle widget
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int mval[2]
Definition WM_types.hh:763
struct ReportList * reports
struct uiLayout * layout
struct PointerRNA * ptr
i
Definition text_draw.cc:230
static DynamicLibrary lib
void WM_event_drag_start_mval(const wmEvent *event, const ARegion *region, int r_mval[2])
wmOperatorStatus WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, blender::wm::OpCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ MOUSEMOVE
@ LEFTMOUSE
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_operator_properties_select_all(wmOperatorType *ot)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
wmOperatorStatus WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, std::optional< std::string > title, std::optional< std::string > confirm_text, const bool cancel_default, std::optional< std::string > message)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
wmWindow * WM_window_open_temp(bContext *C, const char *title, int space_type, bool dialog)
uint8_t flag
Definition wm_window.cc:145