Blender V4.5
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"
63#include "UI_view2d.hh"
64
65#include "RNA_access.hh"
66#include "RNA_define.hh"
67#include "RNA_enum_types.hh"
68#include "RNA_path.hh"
69#include "RNA_prototypes.hh"
70
71#include "GPU_material.hh"
72
73#include "outliner_intern.hh"
75#include "tree/tree_iterator.hh"
76
77#include "wm_window.hh"
78
79using namespace blender::ed::outliner;
80
81namespace blender::ed::outliner {
82
83static void outliner_show_active(SpaceOutliner *space_outliner,
84 ARegion *region,
85 TreeElement *te,
86 ID *id);
87
88/* -------------------------------------------------------------------- */
91
92static void outliner_copybuffer_filepath_get(char filepath[FILE_MAX], size_t filepath_maxncpy)
93{
94 /* NOTE: this uses the same path as the 3D viewport. */
95 BLI_path_join(filepath, filepath_maxncpy, BKE_tempdir_base(), "copybuffer.blend");
96}
97
99
100/* -------------------------------------------------------------------- */
103
105 wmOperator * /*op*/,
106 const wmEvent *event)
107{
108 /* stop highlighting if out of area */
109 if (!ED_screen_area_active(C)) {
111 }
112
113 /* Drag and drop does its own highlighting. */
115 if (wm->drags.first) {
117 }
118
119 ARegion *region = CTX_wm_region(C);
120 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
121
122 float view_mval[2];
124 &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
125
127 space_outliner, &space_outliner->tree, view_mval[1]);
128
129 TreeElement *icon_te = nullptr;
130 bool is_over_icon = false;
131 if (hovered_te) {
133 space_outliner, hovered_te, view_mval[0], nullptr, &is_over_icon);
134 }
135
136 bool changed = false;
137
138 if (!hovered_te || !is_over_icon || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED) ||
139 !(icon_te->store_elem->flag & TSE_HIGHLIGHTED_ICON))
140 {
141 /* Clear highlights when nothing is hovered or when a new item is hovered. */
142 changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
143 if (hovered_te) {
144 hovered_te->store_elem->flag |= TSE_HIGHLIGHTED;
145 changed = true;
146 }
147 if (is_over_icon) {
149 changed = true;
150 }
151 }
152
153 if (changed) {
155 }
156
158}
159
161{
162 ot->name = "Update Highlight";
163 ot->idname = "OUTLINER_OT_highlight_update";
164 ot->description = "Update the item highlight based on the current mouse position";
165
167
169}
170
172
173/* -------------------------------------------------------------------- */
176
177void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all)
178{
179 /* Only allow opening elements with children. */
181 return;
182 }
183
184 /* Don't allow collapsing the scene collection. */
185 TreeStoreElem *tselem = TREESTORE(te);
186 if (tselem->type == TSE_VIEW_COLLECTION_BASE) {
187 return;
188 }
189
190 if (open) {
191 tselem->flag &= ~TSE_CLOSED;
192 }
193 else {
194 tselem->flag |= TSE_CLOSED;
195 }
196
197 if (toggle_all) {
199 }
200}
201
207
209 wmOperator *op,
210 const wmEvent *event)
211{
212 ARegion *region = CTX_wm_region(C);
213 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
215
216 float view_mval[2];
218 &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
219
220 if (event->type == MOUSEMOVE) {
221 TreeElement *te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
222
223 /* Only openclose if mouse is not over the previously toggled element */
224 if (te && TREESTORE(te) != data->prev_tselem) {
225
226 /* Only toggle openclose on the same level as the first clicked element */
227 if (te->xs == data->x_location) {
228 outliner_item_openclose(te, data->open, false);
229
231 }
232 }
233
234 if (te) {
235 data->prev_tselem = TREESTORE(te);
236 }
237 else {
238 data->prev_tselem = nullptr;
239 }
240 }
241 else if (event->val == KM_RELEASE) {
243
244 return OPERATOR_FINISHED;
245 }
246
248}
249
251 wmOperator *op,
252 const wmEvent *event)
253{
254 ARegion *region = CTX_wm_region(C);
255 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
256
257 const bool toggle_all = RNA_boolean_get(op->ptr, "all");
258
259 float view_mval[2];
260
261 int mval[2];
262 WM_event_drag_start_mval(event, region, mval);
263
264 UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
265
266 TreeElement *te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
267
268 if (te && outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
269 TreeStoreElem *tselem = TREESTORE(te);
270
271 const bool open = (tselem->flag & TSE_CLOSED) ||
272 (toggle_all && outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1));
273
274 outliner_item_openclose(te, open, toggle_all);
276
277 /* Only toggle once for single click toggling */
278 if ((event->type == LEFTMOUSE) && (event->val != KM_CLICK_DRAG)) {
279 return OPERATOR_FINISHED;
280 }
281
282 /* Store last expanded tselem and x coordinate of disclosure triangle */
283 OpenCloseData *toggle_data = MEM_callocN<OpenCloseData>("open_close_data");
284 toggle_data->prev_tselem = tselem;
285 toggle_data->open = open;
286 toggle_data->x_location = te->xs;
287
288 /* Store the first clicked on element */
289 op->customdata = toggle_data;
290
293 }
294
296}
297
299{
300 ot->name = "Open/Close";
301 ot->idname = "OUTLINER_OT_item_openclose";
302 ot->description = "Toggle whether item under cursor is enabled or closed";
303
306
308
309 RNA_def_boolean(ot->srna, "all", false, "All", "Close or open all items");
310}
311
313
314/* -------------------------------------------------------------------- */
317
318static void do_item_rename(ARegion *region,
319 TreeElement *te,
320 TreeStoreElem *tselem,
322{
323 bool add_textbut = false;
324
325 /* FIXME: These info messages are often useless, they should be either reworded to be more
326 * informative for the user, or purely removed? */
327
328 /* Can't rename rna datablocks entries or listbases. */
329 if (ELEM(tselem->type,
331 TSE_NLA,
345 TSE_ID_BASE) ||
347 {
348 BKE_report(reports, RPT_INFO, "Not an editable name");
349 }
350 else if (ELEM(tselem->type, TSE_STRIP, TSE_STRIP_DATA, TSE_STRIP_DUP)) {
351 BKE_report(reports, RPT_INFO, "Strip names are not editable from the Outliner");
352 }
353 else if (TSE_IS_REAL_ID(tselem) && !ID_IS_EDITABLE(tselem->id)) {
354 BKE_report(reports, RPT_INFO, "External library data is not editable");
355 }
356 else if (TSE_IS_REAL_ID(tselem) && ID_IS_OVERRIDE_LIBRARY(tselem->id)) {
357 BKE_report(reports, RPT_INFO, "Overridden data-blocks names are not editable");
358 }
361
362 if (collection->flag & COLLECTION_IS_MASTER) {
363 BKE_report(reports, RPT_INFO, "Not an editable name");
364 }
365 else {
366 add_textbut = true;
367 }
368 }
369 else if (te->idcode == ID_LI) {
370 BKE_report(reports, RPT_INFO, "Library path is not editable, use the Relocate operation");
371 }
372 else {
373 add_textbut = true;
374 }
375
376 if (add_textbut) {
377 tselem->flag |= TSE_TEXTBUT;
378 ED_region_tag_redraw(region);
379 }
380}
381
384 Scene * /*scene*/,
385 TreeElement *te,
386 TreeStoreElem * /*tsep*/,
387 TreeStoreElem *tselem)
388{
389 ARegion *region = CTX_wm_region(C);
390 do_item_rename(region, te, tselem, reports);
391}
392
395{
396 TreeElement *active_element = outliner_find_element_with_flag(&space_outliner->tree, TSE_ACTIVE);
397
398 if (!active_element) {
399 BKE_report(reports, RPT_WARNING, "No active item to rename");
400 return nullptr;
401 }
402
403 return active_element;
404}
405
407 ARegion *region,
408 const wmEvent *event)
409{
410 float fmval[2];
411 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
412
413 TreeElement *hovered = outliner_find_item_at_y(space_outliner, &space_outliner->tree, fmval[1]);
414 if (hovered && outliner_item_is_co_over_name(hovered, fmval[0])) {
415 return hovered;
416 }
417
418 return nullptr;
419}
420
422 wmOperator *op,
423 const wmEvent *event)
424{
425 ARegion *region = CTX_wm_region(C);
426 View2D *v2d = &region->v2d;
427 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
428 const bool use_active = RNA_boolean_get(op->ptr, "use_active");
429
430 TreeElement *te = use_active ? outliner_item_rename_find_active(space_outliner, op->reports) :
431 outliner_item_rename_find_hovered(space_outliner, region, event);
432 if (!te) {
434 }
435
436 /* Force element into view. */
437 outliner_show_active(space_outliner, region, te, TREESTORE(te)->id);
438 int size_y = BLI_rcti_size_y(&v2d->mask) + 1;
439 int ytop = (te->ys + (size_y / 2));
440 int delta_y = ytop - v2d->cur.ymax;
441 outliner_scroll_view(space_outliner, region, delta_y);
442
443 do_item_rename(region, te, TREESTORE(te), op->reports);
444
445 return OPERATOR_FINISHED;
446}
447
449{
450 PropertyRNA *prop;
451
452 ot->name = "Rename";
453 ot->idname = "OUTLINER_OT_item_rename";
454 ot->description = "Rename the active element";
455
457
459
460 /* Flags. No undo, since this operator only activate the name editing text field in the Outliner,
461 * but does not actually change anything. */
462 ot->flag = OPTYPE_REGISTER;
463
464 prop = RNA_def_boolean(ot->srna,
465 "use_active",
466 false,
467 "Use Active",
468 "Rename the active item, rather than the one the mouse is over");
470}
471
473
474/* -------------------------------------------------------------------- */
477
479{
480 Main *bmain = CTX_data_main(C);
481 ID *id = tselem->id;
482
483 BLI_assert(id != nullptr);
484 BLI_assert(((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) ||
485 (tselem->type == TSE_LAYER_COLLECTION));
487
488 if (ID_IS_OVERRIDE_LIBRARY(id)) {
491 {
494 "Cannot delete library override id '%s', it is part of an override hierarchy",
495 id->name);
496 return;
497 }
498 }
499
500 if (te->idcode == ID_LI) {
501 Library *lib = blender::id_cast<Library *>(id);
502 if (lib->runtime->parent != nullptr) {
503 BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked library '%s'", id->name);
504 return;
505 }
506 if (CTX_data_scene(C)->id.lib == lib) {
509 "Cannot delete library '%s', as it contains the currently active Scene",
510 id->name);
511 return;
512 }
513 }
514 if (id->tag & ID_TAG_INDIRECT) {
515 BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name);
516 return;
517 }
518 if (ID_REAL_USERS(id) <= 1 && BKE_library_ID_is_indirectly_used(bmain, id)) {
521 "Cannot delete id '%s', indirectly used data-blocks need at least one user",
522 id->name);
523 return;
524 }
525 if (te->idcode == ID_WS) {
527 if (id->tag & ID_TAG_PRE_EXISTING) {
529 reports, RPT_WARNING, "Cannot delete currently visible workspace id '%s'", id->name);
531 return;
532 }
534 }
535
536 id->tag |= ID_TAG_DOIT;
537
538 WM_event_add_notifier(C, NC_WINDOW, nullptr);
539}
540
543 Scene * /*scene*/,
544 TreeElement *te,
545 TreeStoreElem * /*tsep*/,
546 TreeStoreElem *tselem)
547{
548 id_delete_tag(C, reports, te, tselem);
549}
550
553 TreeElement *te,
554 const float mval[2])
555{
556 int id_tagged_num = 0;
557
558 if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
559 TreeStoreElem *tselem = TREESTORE(te);
560
561 if (te->idcode != 0 && tselem->id) {
562 if (te->idcode == ID_LI && ((Library *)tselem->id)->runtime->parent) {
565 "Cannot delete indirectly linked library '%s'",
566 ((Library *)tselem->id)->runtime->filepath_abs);
567 }
568 else {
569 id_delete_tag(C, reports, te, tselem);
570 id_tagged_num++;
571 }
572 }
573 }
574 else {
575 LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) {
576 if ((id_tagged_num += outliner_id_delete_tag(C, reports, te_sub, mval)) != 0) {
577 break;
578 }
579 }
580 }
581
582 return id_tagged_num;
583}
584
586 wmOperator *op,
587 const wmEvent *event)
588{
589 Main *bmain = CTX_data_main(C);
590 ARegion *region = CTX_wm_region(C);
591 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
592 float fmval[2];
593
594 BLI_assert(region && space_outliner);
595
596 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
597
598 int id_tagged_num = 0;
599 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
600 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
601 if ((id_tagged_num += outliner_id_delete_tag(C, op->reports, te, fmval)) != 0) {
602 break;
603 }
604 }
605 if (id_tagged_num == 0) {
606 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
607 return OPERATOR_CANCELLED;
608 }
609
611 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
612 return OPERATOR_FINISHED;
613}
614
616{
617 ot->name = "Delete Data-Block";
618 ot->idname = "OUTLINER_OT_id_delete";
619 ot->description = "Delete the ID under cursor";
620
623
624 /* Flags. */
626}
627
629
630/* -------------------------------------------------------------------- */
633
635{
636 Main *bmain = CTX_data_main(C);
637 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
638
639 const short id_type = short(RNA_enum_get(op->ptr, "id_type"));
640 ID *old_id = static_cast<ID *>(
641 BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id")));
642 ID *new_id = static_cast<ID *>(
643 BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")));
644
645 /* check for invalid states */
646 if (space_outliner == nullptr) {
647 return OPERATOR_CANCELLED;
648 }
649
650 if (!(old_id && new_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
653 "Invalid old/new ID pair ('%s' / '%s')",
654 old_id ? old_id->name : "Invalid ID",
655 new_id ? new_id->name : "Invalid ID");
656 return OPERATOR_CANCELLED;
657 }
658
659 if (!ID_IS_EDITABLE(old_id)) {
662 "Old ID '%s' is linked from a library, indirect usages of this data-block will "
663 "not be remapped",
664 old_id->name);
665 }
666
669
671
672 /* recreate dependency graph to include new objects */
674
675 /* Free gpu materials, some materials depend on existing objects,
676 * such as lights so freeing correctly refreshes. */
677 GPU_materials_free(bmain);
678
679 WM_event_add_notifier(C, NC_WINDOW, nullptr);
680
681 return OPERATOR_FINISHED;
682}
683
685 wmOperator *op,
686 ListBase *tree,
687 const float y)
688{
690 if (y > te->ys && y < te->ys + UI_UNIT_Y) {
691 TreeStoreElem *tselem = TREESTORE(te);
692
693 if ((tselem->type == TSE_SOME_ID) && tselem->id) {
694 RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
695 RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2);
696 RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2);
697 return true;
698 }
699 }
700 if (outliner_id_remap_find_tree_element(C, op, &te->subtree, y)) {
701 return true;
702 }
703 }
704 return false;
705}
706
708{
709 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
710 ARegion *region = CTX_wm_region(C);
711 float fmval[2];
712
713 if (!RNA_property_is_set(op->ptr, RNA_struct_find_property(op->ptr, "id_type"))) {
714 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
715
716 outliner_id_remap_find_tree_element(C, op, &space_outliner->tree, fmval[1]);
717 }
718
719 return WM_operator_props_dialog_popup(C, op, 400, IFACE_("Remap Data ID"), IFACE_("Remap"));
720}
721
724 PropertyRNA * /*prop*/,
725 bool *r_free)
726{
727 if (C == nullptr) {
729 }
730
731 EnumPropertyItem item_tmp = {0}, *item = nullptr;
732 int totitem = 0;
733 int i = 0;
734
735 short id_type = short(RNA_enum_get(ptr, "id_type"));
736 ID *id = static_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first);
737
738 for (; id; id = static_cast<ID *>(id->next)) {
739 item_tmp.identifier = item_tmp.name = id->name + 2;
740 item_tmp.value = i++;
741 RNA_enum_item_add(&item, &totitem, &item_tmp);
742 }
743
744 RNA_enum_item_end(&item, &totitem);
745 *r_free = true;
746
747 return item;
748}
749
751{
752 PropertyRNA *prop;
753
754 /* identifiers */
755 ot->name = "Outliner ID Data Remap";
756 ot->idname = "OUTLINER_OT_id_remap";
757
758 /* callbacks */
762
763 /* Flags. */
765
766 prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
768 /* Changing ID type wont make sense, would return early with "Invalid old/new ID pair" anyways.
769 */
771
772 prop = RNA_def_enum(
773 ot->srna, "old_id", rna_enum_dummy_NULL_items, 0, "Old ID", "Old ID to replace");
776
777 ot->prop = RNA_def_enum(ot->srna,
778 "new_id",
780 0,
781 "New ID",
782 "New ID to remap all selected IDs' users to");
785}
786
788{
789 wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
790 PointerRNA op_props;
791
792 BLI_assert(tselem->id != nullptr);
793
795
796 RNA_enum_set(&op_props, "id_type", GS(tselem->id->name));
797 RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2);
798
799 WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
800
802}
803
805
806/* -------------------------------------------------------------------- */
809
810static int outliner_id_copy_tag(SpaceOutliner *space_outliner,
811 ListBase *tree,
813{
814 using namespace blender::bke::blendfile;
815
816 int num_ids = 0;
817
819 TreeStoreElem *tselem = TREESTORE(te);
820
821 /* Add selected item and all of its dependencies to the copy buffer. */
822 if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) {
823 copybuffer.id_add(tselem->id,
825 (PartialWriteContext::IDAddOperations::SET_FAKE_USER |
826 PartialWriteContext::IDAddOperations::SET_CLIPBOARD_MARK |
827 PartialWriteContext::IDAddOperations::ADD_DEPENDENCIES)},
828 nullptr);
829 num_ids++;
830 }
831
832 /* go over sub-tree */
833 num_ids += outliner_id_copy_tag(space_outliner, &te->subtree, copybuffer);
834 }
835
836 return num_ids;
837}
838
840{
841 using namespace blender::bke::blendfile;
842
843 Main *bmain = CTX_data_main(C);
844 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
846
847 const int num_ids = outliner_id_copy_tag(space_outliner, &space_outliner->tree, copybuffer);
848 if (num_ids == 0) {
849 BKE_report(op->reports, RPT_INFO, "No selected data-blocks to copy");
850 return OPERATOR_CANCELLED;
851 }
852
853 char filepath[FILE_MAX];
854 outliner_copybuffer_filepath_get(filepath, sizeof(filepath));
855 copybuffer.write(filepath, *op->reports);
856
857 BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids);
858
859 return OPERATOR_FINISHED;
860}
861
863{
864 /* identifiers */
865 ot->name = "Outliner ID Data Copy";
866 ot->idname = "OUTLINER_OT_id_copy";
867 ot->description = "Copy the selected data-blocks to the internal clipboard";
868
869 /* callbacks */
872
873 /* Flags, don't need any undo here (this operator does not change anything in Blender data). */
874 ot->flag = 0;
875}
876
878
879/* -------------------------------------------------------------------- */
882
884{
885 char filepath[FILE_MAX];
887
888 outliner_copybuffer_filepath_get(filepath, sizeof(filepath));
889
890 const int num_pasted = BKE_copybuffer_paste(C, filepath, flag, op->reports, 0);
891 if (num_pasted == 0) {
892 BKE_report(op->reports, RPT_INFO, "No data to paste");
893 return OPERATOR_CANCELLED;
894 }
895
896 WM_event_add_notifier(C, NC_WINDOW, nullptr);
897
898 BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted);
899
900 return OPERATOR_FINISHED;
901}
902
904{
905 /* identifiers */
906 ot->name = "Outliner ID Data Paste";
907 ot->idname = "OUTLINER_OT_id_paste";
908 ot->description = "Paste data-blocks from the internal clipboard";
909
910 /* callbacks */
913
914 /* flags */
916}
917
919
920/* -------------------------------------------------------------------- */
923
925 wmOperator *op,
926 const wmEvent * /*event*/)
927{
928 PointerRNA id_linked_ptr = CTX_data_pointer_get_type(C, "id", &RNA_ID);
929 ID *id_linked = static_cast<ID *>(id_linked_ptr.data);
930
931 if (!id_linked) {
932 BKE_report(op->reports, RPT_ERROR_INVALID_INPUT, "There is no active data-block");
933 return OPERATOR_CANCELLED;
934 }
935 if (!ID_IS_LINKED(id_linked) || !BKE_idtype_idcode_is_linkable(GS(id_linked->name))) {
938 "The active data-block '%s' is not a valid linked one",
939 BKE_id_name(*id_linked));
940 return OPERATOR_CANCELLED;
941 }
945 "The active data-block '%s' is used by other linked data",
946 BKE_id_name(*id_linked));
947 return OPERATOR_CANCELLED;
948 }
949
950 wmOperatorType *ot = WM_operatortype_find("WM_OT_id_linked_relocate", false);
951 PointerRNA op_props;
952
954 RNA_int_set(&op_props, "id_session_uid", *reinterpret_cast<int *>(&id_linked->session_uid));
955
957 C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
958
960
961 /* If the matching WM operator invoke was successful, it was added to modal handlers. This
962 * operator however is _not_ modal, and will leak memory if it returns this status. */
964}
965
967{
968 ot->name = "Relocate Linked ID";
969 ot->idname = "OUTLINER_OT_id_linked_relocate";
970 ot->description =
971 "Replace the active linked ID (and its dependencies if any) by another one, from the same "
972 "or a different library";
973
976
977 /* Flags. No undo, no registering, all the actual work/changes is done by the matching WM
978 * operator. */
979 ot->flag = 0;
980}
981
983
984/* -------------------------------------------------------------------- */
987
989 bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload)
990{
991 PointerRNA op_props;
993
994 BLI_assert(te->idcode == ID_LI && tselem->id != nullptr);
996
998
999 RNA_string_set(&op_props, "library", tselem->id->name + 2);
1000
1001 if (reload) {
1002 Library *lib = (Library *)tselem->id;
1003 char dir[FILE_MAXDIR], filename[FILE_MAX];
1004
1006 lib->runtime->filepath_abs, dir, sizeof(dir), filename, sizeof(filename));
1007
1008 printf("%s, %s\n", tselem->id->name, lib->runtime->filepath_abs);
1009
1010 /* We assume if both paths in lib are not the same then `lib->filepath` was relative. */
1012 &op_props, "relative_path", BLI_path_cmp(lib->runtime->filepath_abs, lib->filepath) != 0);
1013
1014 RNA_string_set(&op_props, "directory", dir);
1015 RNA_string_set(&op_props, "filename", filename);
1016
1017 ret = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props, nullptr);
1018 }
1019 else {
1020 ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
1021 }
1022
1023 WM_operator_properties_free(&op_props);
1024
1025 return ret;
1026}
1027
1029 bContext *C, ReportList *reports, TreeElement *te, const float mval[2], const bool reload)
1030{
1031 if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
1032 TreeStoreElem *tselem = TREESTORE(te);
1033
1034 if (te->idcode == ID_LI && tselem->id) {
1035 if (((Library *)tselem->id)->runtime->parent && !reload) {
1038 "Cannot relocate indirectly linked library '%s'",
1039 ((Library *)tselem->id)->runtime->filepath_abs);
1040 return OPERATOR_CANCELLED;
1041 }
1042
1043 wmOperatorType *ot = WM_operatortype_find(reload ? "WM_OT_lib_reload" : "WM_OT_lib_relocate",
1044 false);
1045 return lib_relocate(C, te, tselem, ot, reload);
1046 }
1047 }
1048 else {
1049 LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) {
1051 if ((ret = outliner_lib_relocate_invoke_do(C, reports, te_sub, mval, reload))) {
1052 return ret;
1053 }
1054 }
1055 }
1056
1057 return wmOperatorStatus(0);
1058}
1059
1061 wmOperator *op,
1062 const wmEvent *event)
1063{
1064 ARegion *region = CTX_wm_region(C);
1065 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1066 float fmval[2];
1067
1068 BLI_assert(region && space_outliner);
1069
1070 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
1071
1072 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
1074
1075 if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, false))) {
1076 return ret;
1077 }
1078 }
1079
1080 return OPERATOR_CANCELLED;
1081}
1082
1084{
1085 ot->name = "Relocate Library";
1086 ot->idname = "OUTLINER_OT_lib_relocate";
1087 ot->description = "Relocate the library under cursor";
1088
1091
1092 /* Flags. */
1093 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1094}
1095
1097 ReportList * /*reports*/,
1098 Scene * /*scene*/,
1099 TreeElement *te,
1100 TreeStoreElem * /*tsep*/,
1101 TreeStoreElem *tselem)
1102{
1103 /* XXX: This does not work with several items
1104 * (it is only called once in the end, due to the 'deferred'
1105 * file-browser invocation through event system...). */
1106
1107 wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false);
1108
1109 lib_relocate(C, te, tselem, ot, false);
1110}
1111
1113 wmOperator *op,
1114 const wmEvent *event)
1115{
1116 ARegion *region = CTX_wm_region(C);
1117 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1118 float fmval[2];
1119
1120 BLI_assert(region && space_outliner);
1121
1122 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
1123
1124 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
1126
1127 if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, true))) {
1128 return ret;
1129 }
1130 }
1131
1132 return OPERATOR_CANCELLED;
1133}
1134
1136
1137/* -------------------------------------------------------------------- */
1140
1142{
1143 ot->name = "Reload Library";
1144 ot->idname = "OUTLINER_OT_lib_reload";
1145 ot->description = "Reload the library under cursor";
1146
1149
1150 /* Flags. */
1151 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1152}
1153
1155 ReportList * /*reports*/,
1156 Scene * /*scene*/,
1157 TreeElement *te,
1158 TreeStoreElem * /*tsep*/,
1159 TreeStoreElem *tselem)
1160{
1161 wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_reload", false);
1162
1163 lib_relocate(C, te, tselem, ot, true);
1164}
1165
1167
1168/* -------------------------------------------------------------------- */
1171
1172static int outliner_count_levels(ListBase *lb, const int curlevel)
1173{
1174 int level = curlevel;
1175
1176 LISTBASE_FOREACH (TreeElement *, te, lb) {
1177 int lev = outliner_count_levels(&te->subtree, curlevel + 1);
1178 level = std::max(lev, level);
1179 }
1180 return level;
1181}
1182
1183int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel)
1184{
1185 LISTBASE_FOREACH (TreeElement *, te, lb) {
1186 TreeStoreElem *tselem = TREESTORE(te);
1187 if (tselem->flag & flag) {
1188 return curlevel;
1189 }
1190
1191 int level = outliner_flag_is_any_test(&te->subtree, flag, curlevel + 1);
1192 if (level) {
1193 return level;
1194 }
1195 }
1196 return 0;
1197}
1198
1199bool outliner_flag_set(const SpaceOutliner &space_outliner, const short flag, const short set)
1200{
1201 return outliner_flag_set(space_outliner.tree, flag, set);
1202}
1203
1204bool outliner_flag_set(const ListBase &lb, const short flag, const short set)
1205{
1206 bool changed = false;
1207
1208 tree_iterator::all(lb, [&](TreeElement *te) {
1209 TreeStoreElem *tselem = TREESTORE(te);
1210 bool has_flag = (tselem->flag & flag);
1211 if (set == 0) {
1212 if (has_flag) {
1213 tselem->flag &= ~flag;
1214 changed = true;
1215 }
1216 }
1217 else if (!has_flag) {
1218 tselem->flag |= flag;
1219 changed = true;
1220 }
1221 });
1222
1223 return changed;
1224}
1225
1226bool outliner_flag_flip(const SpaceOutliner &space_outliner, const short flag)
1227{
1228 return outliner_flag_flip(space_outliner.tree, flag);
1229}
1230
1231bool outliner_flag_flip(const ListBase &lb, const short flag)
1232{
1233 bool changed = false;
1234
1235 tree_iterator::all(lb, [&](TreeElement *te) {
1236 TreeStoreElem *tselem = TREESTORE(te);
1237 tselem->flag ^= flag;
1238 });
1239
1240 return changed;
1241}
1242
1244
1245/* -------------------------------------------------------------------- */
1248
1250{
1251 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1252 ARegion *region = CTX_wm_region(C);
1253
1254 if (outliner_flag_is_any_test(&space_outliner->tree, TSE_CLOSED, 1)) {
1255 outliner_flag_set(*space_outliner, TSE_CLOSED, 0);
1256 }
1257 else {
1258 outliner_flag_set(*space_outliner, TSE_CLOSED, 1);
1259 }
1260
1261 ED_region_tag_redraw(region);
1262
1263 return OPERATOR_FINISHED;
1264}
1265
1267{
1268 /* identifiers */
1269 ot->name = "Expand/Collapse All";
1270 ot->idname = "OUTLINER_OT_expanded_toggle";
1271 ot->description = "Expand/Collapse all items";
1272
1273 /* callbacks */
1276
1277 /* no undo or registry, UI option */
1278}
1279
1281
1282/* -------------------------------------------------------------------- */
1285
1287{
1288 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1289 ARegion *region = CTX_wm_region(C);
1290 Scene *scene = CTX_data_scene(C);
1291 int action = RNA_enum_get(op->ptr, "action");
1292 if (action == SEL_TOGGLE) {
1293 action = outliner_flag_is_any_test(&space_outliner->tree, TSE_SELECTED, 1) ? SEL_DESELECT :
1294 SEL_SELECT;
1295 }
1296
1297 switch (action) {
1298 case SEL_SELECT:
1299 outliner_flag_set(*space_outliner, TSE_SELECTED, 1);
1300 break;
1301 case SEL_DESELECT:
1302 outliner_flag_set(*space_outliner, TSE_SELECTED, 0);
1303 break;
1304 case SEL_INVERT:
1305 outliner_flag_flip(*space_outliner, TSE_SELECTED);
1306 break;
1307 }
1308
1309 ED_outliner_select_sync_from_outliner(C, space_outliner);
1310
1314
1315 return OPERATOR_FINISHED;
1316}
1317
1319{
1320 /* identifiers */
1321 ot->name = "Toggle Selected";
1322 ot->idname = "OUTLINER_OT_select_all";
1323 ot->description = "Toggle the Outliner selection of items";
1324
1325 /* callbacks */
1328
1329 /* no undo or registry */
1330
1331 /* rna */
1333}
1334
1336
1337/* -------------------------------------------------------------------- */
1340
1342{
1343 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1344 ScrArea *area = CTX_wm_area(C);
1346 UI_textbutton_activate_rna(C, region, space_outliner, "filter_text");
1347
1348 return OPERATOR_FINISHED;
1349}
1350
1352{
1353 /* Identifiers. */
1354 ot->name = "Filter";
1355 ot->description = "Start entering filter text";
1356 ot->idname = "OUTLINER_OT_start_filter";
1357
1358 /* Callbacks. */
1361}
1362
1364{
1365 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1366 space_outliner->search_string[0] = '\0';
1368 return OPERATOR_FINISHED;
1369}
1370
1372{
1373 /* Identifiers. */
1374 ot->name = "Clear Filter";
1375 ot->description = "Clear the search filter";
1376 ot->idname = "OUTLINER_OT_clear_filter";
1377
1378 /* Callbacks. */
1381}
1382
1384
1385/* -------------------------------------------------------------------- */
1388
1389void outliner_set_coordinates(const ARegion *region, const SpaceOutliner *space_outliner)
1390{
1391 int starty = int(region->v2d.tot.ymax) - UI_UNIT_Y;
1392
1393 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
1394 /* store coord and continue, we need coordinates for elements outside view too */
1395 te->xs = 0;
1396 te->ys = float(starty);
1397 starty -= UI_UNIT_Y;
1398 });
1399}
1400
1403{
1404 TreeStoreElem *tselem;
1405 bool retval = false;
1406
1407 for (te = te->parent; te; te = te->parent) {
1408 tselem = TREESTORE(te);
1409 if (tselem->flag & TSE_CLOSED) {
1410 tselem->flag &= ~TSE_CLOSED;
1411 retval = true;
1412 }
1413 }
1414 return retval;
1415}
1416
1421 SpaceOutliner *space_outliner,
1422 const Scene *scene,
1423 ViewLayer *view_layer)
1424{
1425 TreeElement *te;
1426
1427 BKE_view_layer_synced_ensure(scene, view_layer);
1428 Object *obact = BKE_view_layer_active_object_get(view_layer);
1429
1430 if (!obact) {
1431 return nullptr;
1432 }
1433
1434 te = outliner_find_id(space_outliner, &space_outliner->tree, &obact->id);
1435
1436 if (te != nullptr && obact->type == OB_ARMATURE) {
1437 /* traverse down the bone hierarchy in case of armature */
1438 TreeElement *te_obact = te;
1439
1440 if (obact->mode & OB_MODE_POSE) {
1441 Object *obpose = BKE_object_pose_armature_get(obact);
1442 bPoseChannel *pchan = BKE_pose_channel_active(obpose, false);
1443 if (pchan) {
1444 te = outliner_find_posechannel(&te_obact->subtree, pchan);
1445 }
1446 }
1447 else if (obact->mode & OB_MODE_EDIT) {
1448 EditBone *ebone = CTX_data_active_bone(C);
1449 if (ebone) {
1450 te = outliner_find_editbone(&te_obact->subtree, ebone);
1451 }
1452 }
1453 }
1454
1455 return te;
1456}
1457
1458static void outliner_show_active(SpaceOutliner *space_outliner,
1459 ARegion *region,
1460 TreeElement *te,
1461 ID *id)
1462{
1463 /* open up tree to active object/bone */
1464 if (TREESTORE(te)->id == id) {
1465 if (outliner_open_back(te)) {
1466 outliner_set_coordinates(region, space_outliner);
1467 }
1468 return;
1469 }
1470
1471 LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
1472 outliner_show_active(space_outliner, region, ten, id);
1473 }
1474}
1475
1477{
1478 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1479 const Scene *scene = CTX_data_scene(C);
1480 ViewLayer *view_layer = CTX_data_view_layer(C);
1481 ARegion *region = CTX_wm_region(C);
1482 View2D *v2d = &region->v2d;
1483
1485 C, space_outliner, scene, view_layer);
1486
1487 if (active_element) {
1488 ID *id = TREESTORE(active_element)->id;
1489
1490 /* Expand all elements in the outliner with matching ID */
1491 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
1492 outliner_show_active(space_outliner, region, te, id);
1493 }
1494
1495 /* Also open back from the active_element (only done for the first found occurrence of ID
1496 * though). */
1497 outliner_show_active(space_outliner, region, active_element, id);
1498
1499 /* Center view on first element found */
1500 int size_y = BLI_rcti_size_y(&v2d->mask) + 1;
1501 int ytop = (active_element->ys + (size_y / 2));
1502 int delta_y = ytop - v2d->cur.ymax;
1503
1504 outliner_scroll_view(space_outliner, region, delta_y);
1505 }
1506 else {
1507 return OPERATOR_CANCELLED;
1508 }
1509
1511
1512 return OPERATOR_FINISHED;
1513}
1514
1516{
1517 /* identifiers */
1518 ot->name = "Show Active";
1519 ot->idname = "OUTLINER_OT_show_active";
1520 ot->description =
1521 "Open up the tree and adjust the view so that the active object is shown centered";
1522
1523 /* callbacks */
1526}
1527
1529
1530/* -------------------------------------------------------------------- */
1533
1535{
1536 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1537 ARegion *region = CTX_wm_region(C);
1538 int size_y = BLI_rcti_size_y(&region->v2d.mask) + 1;
1539
1540 bool up = RNA_boolean_get(op->ptr, "up");
1541
1542 if (!up) {
1543 size_y = -size_y;
1544 }
1545
1546 outliner_scroll_view(space_outliner, region, size_y);
1547
1549
1550 return OPERATOR_FINISHED;
1551}
1552
1554{
1555 PropertyRNA *prop;
1556
1557 /* identifiers */
1558 ot->name = "Scroll Page";
1559 ot->idname = "OUTLINER_OT_scroll_page";
1560 ot->description = "Scroll page up or down";
1561
1562 /* callbacks */
1565
1566 /* properties */
1567 prop = RNA_def_boolean(ot->srna, "up", false, "Up", "Scroll up one page");
1569}
1570
1572
1573/* -------------------------------------------------------------------- */
1576
1577/* helper function for Show/Hide one level operator */
1578static void outliner_openclose_level(ListBase *lb, int curlevel, int level, int open)
1579{
1580 LISTBASE_FOREACH (TreeElement *, te, lb) {
1581 TreeStoreElem *tselem = TREESTORE(te);
1582
1583 if (open) {
1584 if (curlevel <= level) {
1585 tselem->flag &= ~TSE_CLOSED;
1586 }
1587 }
1588 else {
1589 if (curlevel >= level) {
1590 tselem->flag |= TSE_CLOSED;
1591 }
1592 }
1593
1594 outliner_openclose_level(&te->subtree, curlevel + 1, level, open);
1595 }
1596}
1597
1599{
1600 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1601 ARegion *region = CTX_wm_region(C);
1602 const bool add = RNA_boolean_get(op->ptr, "open");
1603 int level;
1604
1605 level = outliner_flag_is_any_test(&space_outliner->tree, TSE_CLOSED, 1);
1606 if (add == 1) {
1607 if (level) {
1608 outliner_openclose_level(&space_outliner->tree, 1, level, 1);
1609 }
1610 }
1611 else {
1612 if (level == 0) {
1613 level = outliner_count_levels(&space_outliner->tree, 0);
1614 }
1615 if (level) {
1616 outliner_openclose_level(&space_outliner->tree, 1, level - 1, 0);
1617 }
1618 }
1619
1620 ED_region_tag_redraw(region);
1621
1622 return OPERATOR_FINISHED;
1623}
1624
1626{
1627 PropertyRNA *prop;
1628
1629 /* identifiers */
1630 ot->name = "Show/Hide One Level";
1631 ot->idname = "OUTLINER_OT_show_one_level";
1632 ot->description = "Expand/collapse all entries by one level";
1633
1634 /* callbacks */
1637
1638 /* no undo or registry, UI option */
1639
1640 /* properties */
1641 prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Expand all entries one level deep");
1643}
1644
1646
1647/* -------------------------------------------------------------------- */
1650
1656{
1657 LISTBASE_FOREACH (TreeElement *, te, lb) {
1658 TreeStoreElem *tselem = TREESTORE(te);
1659 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1660 return 1;
1661 }
1662 if (subtree_has_objects(&te->subtree)) {
1663 return 1;
1664 }
1665 }
1666 return 0;
1667}
1668
1669/* Helper function for Show Hierarchy operator */
1670static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outliner)
1671{
1672 /* open all object elems, close others */
1673 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
1674 TreeStoreElem *tselem = TREESTORE(te);
1675
1676 if (ELEM(tselem->type,
1681 {
1682 if (te->idcode == ID_SCE) {
1683 if (tselem->id != (ID *)scene) {
1684 tselem->flag |= TSE_CLOSED;
1685 }
1686 else {
1687 tselem->flag &= ~TSE_CLOSED;
1688 }
1689 }
1690 else if (te->idcode == ID_OB) {
1691 if (subtree_has_objects(&te->subtree)) {
1692 tselem->flag &= ~TSE_CLOSED;
1693 }
1694 else {
1695 tselem->flag |= TSE_CLOSED;
1696 }
1697 }
1698 }
1699 else {
1700 tselem->flag |= TSE_CLOSED;
1701 }
1702 });
1703}
1704
1705/* show entire object level hierarchy */
1707{
1708 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1709 ARegion *region = CTX_wm_region(C);
1710 Scene *scene = CTX_data_scene(C);
1711
1712 /* recursively open/close levels */
1713 tree_element_show_hierarchy(scene, space_outliner);
1714
1715 ED_region_tag_redraw(region);
1716
1717 return OPERATOR_FINISHED;
1718}
1719
1721{
1722 /* identifiers */
1723 ot->name = "Show Hierarchy";
1724 ot->idname = "OUTLINER_OT_show_hierarchy";
1725 ot->description = "Open all object entries and close all others";
1726
1727 /* callbacks */
1729 /* TODO: shouldn't be allowed in RNA views... */
1731
1732 /* no undo or registry, UI option */
1733}
1734
1736
1737/* -------------------------------------------------------------------- */
1740
1745{
1746 ScrArea *area = CTX_wm_area(C);
1747 if ((area) && (area->spacetype == SPACE_OUTLINER)) {
1748 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1749 return (space_outliner->outlinevis == SO_DATA_API);
1750 }
1751 return false;
1752}
1753
1754/* Helper func to extract an RNA path from selected tree element
1755 * NOTE: the caller must zero-out all values of the pointers that it passes here first, as
1756 * this function does not do that yet
1757 */
1759 TreeStoreElem *tselem,
1760 ID **id,
1761 char **path,
1762 int *array_index,
1763 short *flag,
1764 short * /*groupmode*/)
1765{
1766 ListBase hierarchy = {nullptr, nullptr};
1767 char *newpath = nullptr;
1768
1769 /* optimize tricks:
1770 * - Don't do anything if the selected item is a 'struct', but arrays are allowed
1771 */
1772 if (tselem->type == TSE_RNA_STRUCT) {
1773 return;
1774 }
1775
1776 /* Overview of Algorithm:
1777 * 1. Go up the chain of parents until we find the 'root', taking note of the
1778 * levels encountered in reverse-order (i.e. items are added to the start of the list
1779 * for more convenient looping later)
1780 * 2. Walk down the chain, adding from the first ID encountered
1781 * (which will become the 'ID' for the KeyingSet Path), and build a
1782 * path as we step through the chain
1783 */
1784
1785 /* step 1: flatten out hierarchy of parents into a flat chain */
1786 for (TreeElement *tem = te->parent; tem; tem = tem->parent) {
1787 LinkData *ld = MEM_callocN<LinkData>("LinkData for tree_element_to_path()");
1788 ld->data = tem;
1789 BLI_addhead(&hierarchy, ld);
1790 }
1791
1792 /* step 2: step down hierarchy building the path
1793 * (NOTE: addhead in previous loop was needed so that we can loop like this) */
1794 LISTBASE_FOREACH (LinkData *, ld, &hierarchy) {
1795 /* get data */
1796 TreeElement *tem = (TreeElement *)ld->data;
1798 PointerRNA ptr = tem_rna->get_pointer_rna();
1799
1800 /* check if we're looking for first ID, or appending to path */
1801 if (*id) {
1802 /* just 'append' property to path
1803 * - to prevent memory leaks, we must write to newpath not path,
1804 * then free old path + swap them.
1805 */
1807 PropertyRNA *prop = tem_rna_prop->get_property_rna();
1808
1809 if (RNA_property_type(prop) == PROP_POINTER) {
1810 /* for pointer we just append property name */
1811 newpath = RNA_path_append(*path, &ptr, prop, 0, nullptr);
1812 }
1813 else if (RNA_property_type(prop) == PROP_COLLECTION) {
1814 char buf[128], *name;
1815
1816 TreeElement *temnext = (TreeElement *)(ld->next->data);
1817 PointerRNA nextptr = tree_element_cast<TreeElementRNACommon>(temnext)->get_pointer_rna();
1818 name = RNA_struct_name_get_alloc(&nextptr, buf, sizeof(buf), nullptr);
1819
1820 if (name) {
1821 /* if possible, use name as a key in the path */
1822 newpath = RNA_path_append(*path, nullptr, prop, 0, name);
1823
1824 if (name != buf) {
1825 MEM_freeN(name);
1826 }
1827 }
1828 else {
1829 /* otherwise use index */
1830 int index = 0;
1831
1832 LISTBASE_FOREACH (TreeElement *, temsub, &tem->subtree) {
1833 if (temsub == temnext) {
1834 break;
1835 }
1836 index++;
1837 }
1838 newpath = RNA_path_append(*path, nullptr, prop, index, nullptr);
1839 }
1840
1841 ld = ld->next;
1842 }
1843 }
1844
1845 if (newpath) {
1846 if (*path) {
1847 MEM_freeN(*path);
1848 }
1849 *path = newpath;
1850 newpath = nullptr;
1851 }
1852 }
1853 else {
1854 /* no ID, so check if entry is RNA-struct,
1855 * and if that RNA-struct is an ID datablock to extract info from. */
1857 /* ptr->data not ptr->owner_id seems to be the one we want,
1858 * since ptr->data is sometimes the owner of this ID? */
1859 if (RNA_struct_is_ID(ptr.type)) {
1860 *id = static_cast<ID *>(ptr.data);
1861
1862 /* clear path */
1863 if (*path) {
1864 MEM_freeN(*path);
1865 path = nullptr;
1866 }
1867 }
1868 }
1869 }
1870 }
1871
1872 /* step 3: if we've got an ID, add the current item to the path */
1873 if (*id) {
1874 /* add the active property to the path */
1875 PropertyRNA *prop = tree_element_cast<TreeElementRNACommon>(te)->get_property_rna();
1876
1877 /* array checks */
1878 if (tselem->type == TSE_RNA_ARRAY_ELEM) {
1879 /* item is part of an array, so must set the array_index */
1880 *array_index = te->index;
1881 }
1882 else if (RNA_property_array_check(prop)) {
1883 /* entire array was selected, so keyframe all */
1885 }
1886
1887 /* path */
1888 newpath = RNA_path_append(*path, nullptr, prop, 0, nullptr);
1889 if (*path) {
1890 MEM_freeN(*path);
1891 }
1892 *path = newpath;
1893 }
1894
1895 /* free temp data */
1896 BLI_freelistN(&hierarchy);
1897}
1898
1900
1901/* -------------------------------------------------------------------- */
1904
1911enum {
1914} /*eDrivers_EditModes*/;
1915
1916/* Iterate over tree, finding and working on selected items */
1917static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
1919 short mode)
1920{
1921 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
1922 TreeStoreElem *tselem = TREESTORE(te);
1923
1924 /* if item is selected, perform operation */
1925 if (!(tselem->flag & TSE_SELECTED)) {
1926 return;
1927 }
1928
1929 ID *id = nullptr;
1930 char *path = nullptr;
1931 int array_index = 0;
1932 short flag = 0;
1933 short groupmode = KSP_GROUP_KSNAME;
1934
1936 PointerRNA ptr = te_rna ? te_rna->get_pointer_rna() : PointerRNA_NULL;
1937 PropertyRNA *prop = te_rna ? te_rna->get_property_rna() : nullptr;
1938
1939 /* check if RNA-property described by this selected element is an animatable prop */
1940 if (prop && RNA_property_anim_editable(&ptr, prop)) {
1941 /* get id + path + index info from the selected element */
1942 tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
1943 }
1944
1945 /* only if ID and path were set, should we perform any actions */
1946 if (id && path) {
1947 short dflags = CREATEDRIVER_WITH_DEFAULT_DVAR;
1948 int arraylen = 1;
1949
1950 /* array checks */
1951 if (flag & KSP_FLAG_WHOLE_ARRAY) {
1952 /* entire array was selected, so add drivers for all */
1953 arraylen = RNA_property_array_length(&ptr, prop);
1954 }
1955 else {
1956 arraylen = array_index;
1957 }
1958
1959 /* we should do at least one step */
1960 if (arraylen == array_index) {
1961 arraylen++;
1962 }
1963
1964 /* for each array element we should affect, add driver */
1965 for (; array_index < arraylen; array_index++) {
1966 /* action depends on mode */
1967 switch (mode) {
1968 case DRIVERS_EDITMODE_ADD: {
1969 /* add a new driver with the information obtained (only if valid) */
1970 ANIM_add_driver(reports, id, path, array_index, dflags, DRIVER_TYPE_PYTHON);
1971 break;
1972 }
1974 ANIM_remove_driver(id, path, array_index);
1975 break;
1976 }
1977 }
1978 }
1979
1980 /* free path, since it had to be generated */
1981 MEM_freeN(path);
1982 }
1983 });
1984}
1985
1987
1988/* -------------------------------------------------------------------- */
1991
1993{
1994 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1995
1996 /* check for invalid states */
1997 if (space_outliner == nullptr) {
1998 return OPERATOR_CANCELLED;
1999 }
2000
2001 /* recursively go into tree, adding selected items */
2003
2004 /* send notifiers */
2005 WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, nullptr); /* XXX */
2006
2007 return OPERATOR_FINISHED;
2008}
2009
2011{
2012 /* API callbacks. */
2013 ot->idname = "OUTLINER_OT_drivers_add_selected";
2014 ot->name = "Add Drivers for Selected";
2015 ot->description = "Add drivers to selected items";
2016
2017 /* API callbacks. */
2020
2021 /* flags */
2022 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2023}
2024
2026
2027/* -------------------------------------------------------------------- */
2030
2032{
2033 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2034
2035 /* check for invalid states */
2036 if (space_outliner == nullptr) {
2037 return OPERATOR_CANCELLED;
2038 }
2039
2040 /* recursively go into tree, adding selected items */
2042
2043 /* send notifiers */
2044 WM_event_add_notifier(C, ND_KEYS, nullptr); /* XXX */
2045
2046 return OPERATOR_FINISHED;
2047}
2048
2050{
2051 /* identifiers */
2052 ot->idname = "OUTLINER_OT_drivers_delete_selected";
2053 ot->name = "Delete Drivers for Selected";
2054 ot->description = "Delete drivers assigned to selected items";
2055
2056 /* API callbacks. */
2059
2060 /* flags */
2061 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2062}
2063
2065
2066/* -------------------------------------------------------------------- */
2069
2076enum {
2079} /*eKeyingSet_EditModes*/;
2080
2081/* Find the 'active' KeyingSet, and add if not found (if adding is allowed). */
2082/* TODO: should this be an API func? */
2084{
2085 KeyingSet *ks = nullptr;
2086
2087 /* sanity check */
2088 if (scene == nullptr) {
2089 return nullptr;
2090 }
2091
2092 /* try to find one from scene */
2093 if (scene->active_keyingset > 0) {
2094 ks = static_cast<KeyingSet *>(BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1));
2095 }
2096
2097 /* Add if none found */
2098 /* XXX the default settings have yet to evolve. */
2099 if ((add) && (ks == nullptr)) {
2100 ks = BKE_keyingset_add(&scene->keyingsets, nullptr, nullptr, KEYINGSET_ABSOLUTE, 0);
2102 }
2103
2104 return ks;
2105}
2106
2107/* Iterate over tree, finding and working on selected items */
2109 KeyingSet *ks,
2110 const short mode)
2111{
2112 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2113 TreeStoreElem *tselem = TREESTORE(te);
2114
2115 /* if item is selected, perform operation */
2116 if (!(tselem->flag & TSE_SELECTED)) {
2117 return;
2118 }
2119
2120 ID *id = nullptr;
2121 char *path = nullptr;
2122 int array_index = 0;
2123 short flag = 0;
2124 short groupmode = KSP_GROUP_KSNAME;
2125
2126 /* check if RNA-property described by this selected element is an animatable prop */
2128 if (te_rna) {
2129 PointerRNA ptr = te_rna->get_pointer_rna();
2130 if (PropertyRNA *prop = te_rna->get_property_rna()) {
2131 if (RNA_property_anim_editable(&ptr, prop)) {
2132 /* get id + path + index info from the selected element */
2133 tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
2134 }
2135 }
2136 }
2137
2138 /* only if ID and path were set, should we perform any actions */
2139 if (id && path) {
2140 /* action depends on mode */
2141 switch (mode) {
2143 /* add a new path with the information obtained (only if valid) */
2144 /* TODO: what do we do with group name?
2145 * for now, we don't supply one, and just let this use the KeyingSet name */
2146 BKE_keyingset_add_path(ks, id, nullptr, path, array_index, flag, groupmode);
2148 break;
2149 }
2151 /* find the relevant path, then remove it from the KeyingSet */
2152 KS_Path *ksp = BKE_keyingset_find_path(ks, id, nullptr, path, array_index, groupmode);
2153
2154 if (ksp) {
2155 /* free path's data */
2156 BKE_keyingset_free_path(ks, ksp);
2157
2158 ks->active_path = 0;
2159 }
2160 break;
2161 }
2162 }
2163
2164 /* free path, since it had to be generated */
2165 MEM_freeN(path);
2166 }
2167 });
2168}
2169
2171
2172/* -------------------------------------------------------------------- */
2175
2177{
2178 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2179 Scene *scene = CTX_data_scene(C);
2180 KeyingSet *ks = verify_active_keyingset(scene, 1);
2181
2182 /* check for invalid states */
2183 if (ks == nullptr) {
2184 BKE_report(op->reports, RPT_ERROR, "Operation requires an active keying set");
2185 return OPERATOR_CANCELLED;
2186 }
2187 if (space_outliner == nullptr) {
2188 return OPERATOR_CANCELLED;
2189 }
2190
2191 /* recursively go into tree, adding selected items */
2193
2194 /* send notifiers */
2196
2197 return OPERATOR_FINISHED;
2198}
2199
2201{
2202 /* identifiers */
2203 ot->idname = "OUTLINER_OT_keyingset_add_selected";
2204 ot->name = "Keying Set Add Selected";
2205 ot->description = "Add selected items (blue-gray rows) to active Keying Set";
2206
2207 /* API callbacks. */
2210
2211 /* flags */
2212 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2213}
2214
2216
2217/* -------------------------------------------------------------------- */
2220
2222{
2223 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2224 Scene *scene = CTX_data_scene(C);
2225 KeyingSet *ks = verify_active_keyingset(scene, 1);
2226
2227 /* check for invalid states */
2228 if (space_outliner == nullptr) {
2229 return OPERATOR_CANCELLED;
2230 }
2231
2232 /* recursively go into tree, adding selected items */
2234
2235 /* send notifiers */
2237
2238 return OPERATOR_FINISHED;
2239}
2240
2242{
2243 /* identifiers */
2244 ot->idname = "OUTLINER_OT_keyingset_remove_selected";
2245 ot->name = "Keying Set Remove Selected";
2246 ot->description = "Remove selected items (blue-gray rows) from active Keying Set";
2247
2248 /* API callbacks. */
2251
2252 /* flags */
2253 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2254}
2255
2257
2258/* -------------------------------------------------------------------- */
2261
2263{
2264 ScrArea *area = CTX_wm_area(C);
2265 if (area != nullptr && area->spacetype == SPACE_OUTLINER) {
2266 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2267 return (space_outliner->outlinevis == SO_ID_ORPHANS);
2268 }
2269 return true;
2270}
2271
2272static void unused_message_gen(std::string &message,
2273 const std::array<int, INDEX_ID_MAX> &num_tagged)
2274{
2275 bool is_first = true;
2276 if (num_tagged[INDEX_ID_NULL] == 0) {
2277 message += IFACE_("None");
2278 return;
2279 }
2280
2281 /* NOTE: Index is looped in reversed order, since typically 'higher level' IDs (like Collections
2282 * or Objects) have a higher index than 'lower level' ones like object data, materials, etc.
2283 *
2284 * It makes more sense to present to the user the deleted numbers of Collections or Objects
2285 * before the ones for object data or Materials. */
2286 for (int i = INDEX_ID_MAX - 2; i >= 0; i--) {
2287 if (num_tagged[i] != 0) {
2288 message += fmt::format(
2289 "{}{} {}",
2290 (is_first) ? "" : ", ",
2291 num_tagged[i],
2292 (num_tagged[i] > 1) ?
2295 is_first = false;
2296 }
2297 }
2298}
2299
2301{
2302 /* Computation of unused data amounts, with all options ON.
2303 * Used to estimate the maximum required width for the dialog. */
2304 Main *bmain = CTX_data_main(C);
2306 data.do_local_ids = true;
2307 data.do_linked_ids = true;
2308 data.do_recursive = true;
2310
2311 std::string unused_message;
2312 const uiStyle *style = UI_style_get_dpi();
2313 unused_message_gen(unused_message, data.num_local);
2314 float max_messages_width = BLF_width(
2315 style->widget.uifont_id, unused_message.c_str(), BLF_DRAW_STR_DUMMY_MAX);
2316
2317 unused_message = "";
2318 unused_message_gen(unused_message, data.num_linked);
2319 max_messages_width = std::max(
2320 max_messages_width,
2321 BLF_width(style->widget.uifont_id, unused_message.c_str(), BLF_DRAW_STR_DUMMY_MAX));
2322
2323 return int(std::max(max_messages_width, 300.0f));
2324}
2325
2327{
2328 if (op->customdata) {
2329 MEM_delete(static_cast<LibQueryUnusedIDsData *>(op->customdata));
2330 op->customdata = nullptr;
2331 }
2332}
2333
2335{
2336 Main *bmain = CTX_data_main(C);
2338
2339 data.do_local_ids = RNA_boolean_get(op->ptr, "do_local_ids");
2340 data.do_linked_ids = RNA_boolean_get(op->ptr, "do_linked_ids");
2341 data.do_recursive = RNA_boolean_get(op->ptr, "do_recursive");
2342
2344
2345 /* Always assume count changed, and request a redraw. */
2346 return true;
2347}
2348
2350 wmOperator *op,
2351 const wmEvent * /*event*/)
2352{
2353 op->customdata = MEM_new<LibQueryUnusedIDsData>(__func__);
2354
2355 /* Compute expected amounts of deleted IDs and store them in 'cached' operator properties. */
2357
2359 op,
2361 IFACE_("Purge Unused Data from This File"),
2362 IFACE_("Delete"));
2363}
2364
2366{
2367 Main *bmain = CTX_data_main(C);
2368 ScrArea *area = CTX_wm_area(C);
2369 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2370
2371 if (!op->customdata) {
2372 op->customdata = MEM_new<LibQueryUnusedIDsData>(__func__);
2373 }
2375
2376 data.do_local_ids = RNA_boolean_get(op->ptr, "do_local_ids");
2377 data.do_linked_ids = RNA_boolean_get(op->ptr, "do_linked_ids");
2378 data.do_recursive = RNA_boolean_get(op->ptr, "do_recursive");
2379
2380 /* Tag all IDs to delete. */
2382
2383 if (data.num_total[INDEX_ID_NULL] == 0) {
2384 BKE_report(op->reports, RPT_INFO, "No orphaned data-blocks to purge");
2385 MEM_delete(static_cast<LibQueryUnusedIDsData *>(op->customdata));
2386 op->customdata = nullptr;
2387 return OPERATOR_CANCELLED;
2388 }
2389
2391
2392 BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-block(s)", data.num_total[INDEX_ID_NULL]);
2393
2394 /* XXX: tree management normally happens from draw_outliner(), but when
2395 * you're clicking to fast on Delete object from context menu in
2396 * outliner several mouse events can be handled in one cycle without
2397 * handling notifiers/redraw which leads to deleting the same object twice.
2398 * cleanup tree here to prevent such cases. */
2399 if ((area != nullptr) && (area->spacetype == SPACE_OUTLINER)) {
2400 outliner_cleanup_tree(space_outliner);
2401 }
2402
2404 WM_event_add_notifier(C, NC_ID | NA_REMOVED, nullptr);
2405 /* Force full redraw of the UI. */
2407
2409
2410 return OPERATOR_FINISHED;
2411}
2412
2417
2419{
2420 uiLayout *layout = op->layout;
2421 PointerRNA *ptr = op->ptr;
2422 if (!op->customdata) {
2423 /* This should only happen on 'adjust last operation' case, since `invoke` will not have been
2424 * called then before showing the UI (the 'redo panel' UI uses WM-stored operator properties
2425 * and a newly-created operator).
2426 *
2427 * Since that operator is not 'registered' for adjusting from undo stack, this should never
2428 * happen currently. */
2430 op->customdata = MEM_new<LibQueryUnusedIDsData>(__func__);
2431 }
2433
2434 std::string unused_message;
2435 unused_message_gen(unused_message, data.num_local);
2436 uiLayout *column = &layout->column(true);
2437 column->prop(ptr, "do_local_ids", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2438 uiLayout *row = &column->row(true);
2439 row->separator(2.67f);
2440 row->label(unused_message, ICON_NONE);
2441
2442 unused_message = "";
2443 unused_message_gen(unused_message, data.num_linked);
2444 column = &layout->column(true);
2445 column->prop(ptr, "do_linked_ids", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2446 row = &column->row(true);
2447 row->separator(2.67f);
2448 row->label(unused_message, ICON_NONE);
2449
2450 layout->prop(ptr, "do_recursive", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2451}
2452
2454{
2455 /* identifiers */
2456 ot->idname = "OUTLINER_OT_orphans_purge";
2457 ot->name = "Purge All";
2458 ot->description = "Clear all orphaned data-blocks without any users from the file";
2459
2460 /* callbacks */
2464
2468
2469 /* flags */
2470 /* NOTE: No #OPTYPE_REGISTER, since this operator should not be 'adjustable'. */
2471 ot->flag = OPTYPE_UNDO;
2472
2473 /* Actual user-visible settings. */
2474 RNA_def_boolean(ot->srna,
2475 "do_local_ids",
2476 true,
2477 "Local Data-blocks",
2478 "Include unused local data-blocks into deletion");
2479 RNA_def_boolean(ot->srna,
2480 "do_linked_ids",
2481 true,
2482 "Linked Data-blocks",
2483 "Include unused linked data-blocks into deletion");
2484
2485 RNA_def_boolean(ot->srna,
2486 "do_recursive",
2487 true,
2488 "Recursive Delete",
2489 "Recursively check for indirectly unused data-blocks, ensuring that no orphaned "
2490 "data-blocks remain after execution");
2491}
2492
2494
2495/* -------------------------------------------------------------------- */
2498
2500 wmOperator * /*op*/,
2501 const wmEvent *event)
2502{
2503 const int sizex = int(450.0f * UI_SCALE_FAC);
2504 const int sizey = int(450.0f * UI_SCALE_FAC);
2505 const rcti window_rect = {
2506 /*xmin*/ event->xy[0],
2507 /*xmax*/ event->xy[0] + sizex,
2508 /*ymin*/ event->xy[1],
2509 /*ymax*/ event->xy[1] + sizey,
2510 };
2511
2512 if (WM_window_open(C,
2513 IFACE_("Manage Unused Data"),
2514 &window_rect,
2516 false,
2517 false,
2518 true,
2520 nullptr,
2521 nullptr) != nullptr)
2522 {
2523 SpaceOutliner *soutline = CTX_wm_space_outliner(C);
2524 soutline->outlinevis = SO_ID_ORPHANS;
2525 return OPERATOR_FINISHED;
2526 }
2527 return OPERATOR_CANCELLED;
2528}
2529
2531{
2532 /* identifiers */
2533 ot->idname = "OUTLINER_OT_orphans_manage";
2534 ot->name = "Manage Unused Data";
2535 ot->description = "Open a window to manage unused data";
2536
2537 /* callbacks */
2539
2540 /* flags */
2541 ot->flag = OPTYPE_REGISTER;
2542}
2543
2545
2546} // 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:81
struct KeyingSet * BKE_keyingset_add(struct ListBase *list, const char idname[], const char name[], short flag, short keyingflag)
Definition anim_sys.cc:131
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:161
void BKE_keyingset_free_path(struct KeyingSet *ks, struct KS_Path *ksp)
Definition anim_sys.cc:224
const char * BKE_tempdir_base() ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition appdir.cc:1249
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)
short BKE_idtype_index_to_idcode(int idtype_index)
Definition idtype.cc:344
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:165
bool BKE_idtype_idcode_is_linkable(short idcode)
Definition idtype.cc:198
const char * BKE_idtype_idcode_to_name_plural(short idcode)
Definition idtype.cc:172
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:1207
void BKE_main_lib_objects_recalc_all(Main *bmain)
Definition lib_id.cc:1280
const char * BKE_id_name(const ID &id)
void BKE_main_id_tag_all(Main *mainvar, int tag, bool value)
Definition lib_id.cc:1214
bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
Definition lib_query.cc:628
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:887
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:877
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
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:840
void BKE_workspace_id_tag_all_visible(Main *bmain, int tag) ATTR_NONNULL()
Definition workspace.cc:545
#define BLF_DRAW_STR_DUMMY_MAX
Definition BLF_api.hh:468
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:805
#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.
@ ID_RECALC_SELECT
Definition DNA_ID.h:1009
struct ID ID
@ ID_TAG_INDIRECT
Definition DNA_ID.h:756
@ ID_TAG_PRE_EXISTING
Definition DNA_ID.h:834
@ ID_TAG_DOIT
Definition DNA_ID.h:944
@ INDEX_ID_NULL
Definition DNA_ID.h:1266
@ LIBOVERRIDE_FLAG_NO_HIERARCHY
Definition DNA_ID.h:348
@ 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
#define UI_SCALE_FAC
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
@ RPT_ERROR_INVALID_INPUT
@ 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:714
int ED_screen_area_active(const bContext *C)
void ED_region_tag_redraw_no_rebuild(ARegion *region)
Definition area.cc:659
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
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:155
@ PROP_COLLECTION
Definition RNA_types.hh:156
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:406
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
#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:1667
@ WIN_ALIGN_LOCATION_CENTER
Definition WM_api.hh:362
#define NC_WINDOW
Definition WM_types.hh:372
#define NC_ID
Definition WM_types.hh:392
#define NC_ANIMATION
Definition WM_types.hh:385
@ KM_CLICK_DRAG
Definition WM_types.hh:316
@ KM_RELEASE
Definition WM_types.hh:309
#define ND_OB_SELECT
Definition WM_types.hh:439
#define ND_KEYINGSET
Definition WM_types.hh:445
#define NC_SCENE
Definition WM_types.hh:375
ReportList * reports
Definition WM_types.hh:1025
#define ND_FCURVES_ORDER
Definition WM_types.hh:496
#define NA_REMOVED
Definition WM_types.hh:584
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:238
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:245
#define ND_KEYS
Definition WM_types.hh:460
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
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
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:398
bool ANIM_remove_driver(ID *id, const char rna_path[], int array_index)
Main Driver Management API calls.
Definition drivers.cc:522
KDTree_3d * tree
#define printf(...)
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
#define ID_IS_LINKED(_id)
#define ID_IS_EDITABLE(_id)
#define INDEX_ID_MAX
#define ID_REAL_USERS(id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
#define GS(a)
void BKE_lib_query_unused_ids_amounts(Main *bmain, LibQueryUnusedIDsData &parameters)
void BKE_lib_query_unused_ids_tag(Main *bmain, const int tag, LibQueryUnusedIDsData &parameters)
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 wmOperatorStatus outliner_orphans_manage_invoke(bContext *C, wmOperator *, const wmEvent *event)
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)
void OUTLINER_OT_show_hierarchy(wmOperatorType *ot)
TreeElement * outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
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 int outliner_id_copy_tag(SpaceOutliner *space_outliner, ListBase *tree, blender::bke::blendfile::PartialWriteContext &copybuffer)
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)
static void outliner_orphans_purge_cancel(bContext *, 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)
void id_remap_fn(bContext *C, TreeStoreElem *tselem)
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)
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)
static void outliner_orphans_purge_cleanup(wmOperator *op)
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)
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)
void RNA_def_property_enum_funcs_runtime(PropertyRNA *prop, EnumPropertyGetFunc getfunc, EnumPropertySetFunc setfunc, EnumPropertyItemFunc itemfunc)
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_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:623
const char * name
Definition RNA_types.hh:627
unsigned int flag
Definition DNA_ID.h:338
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
IDOverrideLibrary * override_library
Definition DNA_ID.h:459
char name[66]
Definition DNA_ID.h:415
unsigned int session_uid
Definition DNA_ID.h:444
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:754
short val
Definition WM_types.hh:756
int mval[2]
Definition WM_types.hh:760
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])
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
wmOperatorStatus WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ MOUSEMOVE
@ LEFTMOUSE
PointerRNA * ptr
Definition wm_files.cc:4227
wmOperatorType * ot
Definition wm_files.cc:4226
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)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
wmWindow * WM_window_open(bContext *C, const char *title, const rcti *rect_unscaled, int space_type, bool toplevel, bool dialog, bool temp, eWindowAlignment alignment, void(*area_setup_fn)(bScreen *screen, ScrArea *area, void *user_data), void *area_setup_user_data)
uint8_t flag
Definition wm_window.cc:139