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 ReportList * /*reports*/,
789 Scene * /*scene*/,
790 TreeElement * /*te*/,
791 TreeStoreElem * /*tsep*/,
792 TreeStoreElem *tselem)
793{
794 wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false);
795 PointerRNA op_props;
796
797 BLI_assert(tselem->id != nullptr);
798
800
801 RNA_enum_set(&op_props, "id_type", GS(tselem->id->name));
802 RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2);
803
804 WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
805
807}
808
810
811/* -------------------------------------------------------------------- */
814
815static int outliner_id_copy_tag(SpaceOutliner *space_outliner,
816 ListBase *tree,
818{
819 using namespace blender::bke::blendfile;
820
821 int num_ids = 0;
822
824 TreeStoreElem *tselem = TREESTORE(te);
825
826 /* Add selected item and all of its dependencies to the copy buffer. */
827 if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) {
828 copybuffer.id_add(tselem->id,
830 (PartialWriteContext::IDAddOperations::SET_FAKE_USER |
831 PartialWriteContext::IDAddOperations::SET_CLIPBOARD_MARK |
832 PartialWriteContext::IDAddOperations::ADD_DEPENDENCIES)},
833 nullptr);
834 num_ids++;
835 }
836
837 /* go over sub-tree */
838 num_ids += outliner_id_copy_tag(space_outliner, &te->subtree, copybuffer);
839 }
840
841 return num_ids;
842}
843
845{
846 using namespace blender::bke::blendfile;
847
848 Main *bmain = CTX_data_main(C);
849 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
851
852 const int num_ids = outliner_id_copy_tag(space_outliner, &space_outliner->tree, copybuffer);
853 if (num_ids == 0) {
854 BKE_report(op->reports, RPT_INFO, "No selected data-blocks to copy");
855 return OPERATOR_CANCELLED;
856 }
857
858 char filepath[FILE_MAX];
859 outliner_copybuffer_filepath_get(filepath, sizeof(filepath));
860 copybuffer.write(filepath, *op->reports);
861
862 BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids);
863
864 return OPERATOR_FINISHED;
865}
866
868{
869 /* identifiers */
870 ot->name = "Outliner ID Data Copy";
871 ot->idname = "OUTLINER_OT_id_copy";
872 ot->description = "Copy the selected data-blocks to the internal clipboard";
873
874 /* callbacks */
877
878 /* Flags, don't need any undo here (this operator does not change anything in Blender data). */
879 ot->flag = 0;
880}
881
883
884/* -------------------------------------------------------------------- */
887
889{
890 char filepath[FILE_MAX];
892
893 outliner_copybuffer_filepath_get(filepath, sizeof(filepath));
894
895 const int num_pasted = BKE_copybuffer_paste(C, filepath, flag, op->reports, 0);
896 if (num_pasted == 0) {
897 BKE_report(op->reports, RPT_INFO, "No data to paste");
898 return OPERATOR_CANCELLED;
899 }
900
901 WM_event_add_notifier(C, NC_WINDOW, nullptr);
902
903 BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted);
904
905 return OPERATOR_FINISHED;
906}
907
909{
910 /* identifiers */
911 ot->name = "Outliner ID Data Paste";
912 ot->idname = "OUTLINER_OT_id_paste";
913 ot->description = "Paste data-blocks from the internal clipboard";
914
915 /* callbacks */
918
919 /* flags */
921}
922
924
925/* -------------------------------------------------------------------- */
928
930 wmOperator *op,
931 const wmEvent * /*event*/)
932{
933 PointerRNA id_linked_ptr = CTX_data_pointer_get_type(C, "id", &RNA_ID);
934 ID *id_linked = static_cast<ID *>(id_linked_ptr.data);
935
936 if (!id_linked) {
937 BKE_report(op->reports, RPT_ERROR_INVALID_INPUT, "There is no active data-block");
938 return OPERATOR_CANCELLED;
939 }
940 if (!ID_IS_LINKED(id_linked) || !BKE_idtype_idcode_is_linkable(GS(id_linked->name))) {
943 "The active data-block '%s' is not a valid linked one",
944 BKE_id_name(*id_linked));
945 return OPERATOR_CANCELLED;
946 }
950 "The active data-block '%s' is used by other linked data",
951 BKE_id_name(*id_linked));
952 return OPERATOR_CANCELLED;
953 }
954
955 wmOperatorType *ot = WM_operatortype_find("WM_OT_id_linked_relocate", false);
956 PointerRNA op_props;
957
959 RNA_int_set(&op_props, "id_session_uid", *reinterpret_cast<int *>(&id_linked->session_uid));
960
962 C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
963
965
966 /* If the matching WM operator invoke was successful, it was added to modal handlers. This
967 * operator however is _not_ modal, and will leak memory if it returns this status. */
969}
970
972{
973 ot->name = "Relocate Linked ID";
974 ot->idname = "OUTLINER_OT_id_linked_relocate";
975 ot->description =
976 "Replace the active linked ID (and its dependencies if any) by another one, from the same "
977 "or a different library";
978
981
982 /* Flags. No undo, no registering, all the actual work/changes is done by the matching WM
983 * operator. */
984 ot->flag = 0;
985}
986
988
989/* -------------------------------------------------------------------- */
992
994 bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload)
995{
996 PointerRNA op_props;
998
999 BLI_assert(te->idcode == ID_LI && tselem->id != nullptr);
1001
1003
1004 RNA_string_set(&op_props, "library", tselem->id->name + 2);
1005
1006 if (reload) {
1007 Library *lib = (Library *)tselem->id;
1008 char dir[FILE_MAXDIR], filename[FILE_MAX];
1009
1011 lib->runtime->filepath_abs, dir, sizeof(dir), filename, sizeof(filename));
1012
1013 printf("%s, %s\n", tselem->id->name, lib->runtime->filepath_abs);
1014
1015 /* We assume if both paths in lib are not the same then `lib->filepath` was relative. */
1017 &op_props, "relative_path", BLI_path_cmp(lib->runtime->filepath_abs, lib->filepath) != 0);
1018
1019 RNA_string_set(&op_props, "directory", dir);
1020 RNA_string_set(&op_props, "filename", filename);
1021
1022 ret = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props, nullptr);
1023 }
1024 else {
1025 ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props, nullptr);
1026 }
1027
1028 WM_operator_properties_free(&op_props);
1029
1030 return ret;
1031}
1032
1034 bContext *C, ReportList *reports, TreeElement *te, const float mval[2], const bool reload)
1035{
1036 if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
1037 TreeStoreElem *tselem = TREESTORE(te);
1038
1039 if (te->idcode == ID_LI && tselem->id) {
1040 if (((Library *)tselem->id)->runtime->parent && !reload) {
1043 "Cannot relocate indirectly linked library '%s'",
1044 ((Library *)tselem->id)->runtime->filepath_abs);
1045 return OPERATOR_CANCELLED;
1046 }
1047
1048 wmOperatorType *ot = WM_operatortype_find(reload ? "WM_OT_lib_reload" : "WM_OT_lib_relocate",
1049 false);
1050 return lib_relocate(C, te, tselem, ot, reload);
1051 }
1052 }
1053 else {
1054 LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) {
1056 if ((ret = outliner_lib_relocate_invoke_do(C, reports, te_sub, mval, reload))) {
1057 return ret;
1058 }
1059 }
1060 }
1061
1062 return wmOperatorStatus(0);
1063}
1064
1066 wmOperator *op,
1067 const wmEvent *event)
1068{
1069 ARegion *region = CTX_wm_region(C);
1070 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1071 float fmval[2];
1072
1073 BLI_assert(region && space_outliner);
1074
1075 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
1076
1077 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
1079
1080 if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, false))) {
1081 return ret;
1082 }
1083 }
1084
1085 return OPERATOR_CANCELLED;
1086}
1087
1089{
1090 ot->name = "Relocate Library";
1091 ot->idname = "OUTLINER_OT_lib_relocate";
1092 ot->description = "Relocate the library under cursor";
1093
1096
1097 /* Flags. */
1098 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1099}
1100
1102 ReportList * /*reports*/,
1103 Scene * /*scene*/,
1104 TreeElement *te,
1105 TreeStoreElem * /*tsep*/,
1106 TreeStoreElem *tselem)
1107{
1108 /* XXX: This does not work with several items
1109 * (it is only called once in the end, due to the 'deferred'
1110 * file-browser invocation through event system...). */
1111
1112 wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false);
1113
1114 lib_relocate(C, te, tselem, ot, false);
1115}
1116
1118 wmOperator *op,
1119 const wmEvent *event)
1120{
1121 ARegion *region = CTX_wm_region(C);
1122 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1123 float fmval[2];
1124
1125 BLI_assert(region && space_outliner);
1126
1127 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
1128
1129 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
1131
1132 if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, true))) {
1133 return ret;
1134 }
1135 }
1136
1137 return OPERATOR_CANCELLED;
1138}
1139
1141
1142/* -------------------------------------------------------------------- */
1145
1147{
1148 ot->name = "Reload Library";
1149 ot->idname = "OUTLINER_OT_lib_reload";
1150 ot->description = "Reload the library under cursor";
1151
1154
1155 /* Flags. */
1156 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1157}
1158
1160 ReportList * /*reports*/,
1161 Scene * /*scene*/,
1162 TreeElement *te,
1163 TreeStoreElem * /*tsep*/,
1164 TreeStoreElem *tselem)
1165{
1166 wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_reload", false);
1167
1168 lib_relocate(C, te, tselem, ot, true);
1169}
1170
1172
1173/* -------------------------------------------------------------------- */
1176
1177static int outliner_count_levels(ListBase *lb, const int curlevel)
1178{
1179 int level = curlevel;
1180
1181 LISTBASE_FOREACH (TreeElement *, te, lb) {
1182 int lev = outliner_count_levels(&te->subtree, curlevel + 1);
1183 level = std::max(lev, level);
1184 }
1185 return level;
1186}
1187
1188int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel)
1189{
1190 LISTBASE_FOREACH (TreeElement *, te, lb) {
1191 TreeStoreElem *tselem = TREESTORE(te);
1192 if (tselem->flag & flag) {
1193 return curlevel;
1194 }
1195
1196 int level = outliner_flag_is_any_test(&te->subtree, flag, curlevel + 1);
1197 if (level) {
1198 return level;
1199 }
1200 }
1201 return 0;
1202}
1203
1204bool outliner_flag_set(const SpaceOutliner &space_outliner, const short flag, const short set)
1205{
1206 return outliner_flag_set(space_outliner.tree, flag, set);
1207}
1208
1209bool outliner_flag_set(const ListBase &lb, const short flag, const short set)
1210{
1211 bool changed = false;
1212
1213 tree_iterator::all(lb, [&](TreeElement *te) {
1214 TreeStoreElem *tselem = TREESTORE(te);
1215 bool has_flag = (tselem->flag & flag);
1216 if (set == 0) {
1217 if (has_flag) {
1218 tselem->flag &= ~flag;
1219 changed = true;
1220 }
1221 }
1222 else if (!has_flag) {
1223 tselem->flag |= flag;
1224 changed = true;
1225 }
1226 });
1227
1228 return changed;
1229}
1230
1231bool outliner_flag_flip(const SpaceOutliner &space_outliner, const short flag)
1232{
1233 return outliner_flag_flip(space_outliner.tree, flag);
1234}
1235
1236bool outliner_flag_flip(const ListBase &lb, const short flag)
1237{
1238 bool changed = false;
1239
1240 tree_iterator::all(lb, [&](TreeElement *te) {
1241 TreeStoreElem *tselem = TREESTORE(te);
1242 tselem->flag ^= flag;
1243 });
1244
1245 return changed;
1246}
1247
1249
1250/* -------------------------------------------------------------------- */
1253
1255{
1256 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1257 ARegion *region = CTX_wm_region(C);
1258
1259 if (outliner_flag_is_any_test(&space_outliner->tree, TSE_CLOSED, 1)) {
1260 outliner_flag_set(*space_outliner, TSE_CLOSED, 0);
1261 }
1262 else {
1263 outliner_flag_set(*space_outliner, TSE_CLOSED, 1);
1264 }
1265
1266 ED_region_tag_redraw(region);
1267
1268 return OPERATOR_FINISHED;
1269}
1270
1272{
1273 /* identifiers */
1274 ot->name = "Expand/Collapse All";
1275 ot->idname = "OUTLINER_OT_expanded_toggle";
1276 ot->description = "Expand/Collapse all items";
1277
1278 /* callbacks */
1281
1282 /* no undo or registry, UI option */
1283}
1284
1286
1287/* -------------------------------------------------------------------- */
1290
1292{
1293 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1294 ARegion *region = CTX_wm_region(C);
1295 Scene *scene = CTX_data_scene(C);
1296 int action = RNA_enum_get(op->ptr, "action");
1297 if (action == SEL_TOGGLE) {
1298 action = outliner_flag_is_any_test(&space_outliner->tree, TSE_SELECTED, 1) ? SEL_DESELECT :
1299 SEL_SELECT;
1300 }
1301
1302 switch (action) {
1303 case SEL_SELECT:
1304 outliner_flag_set(*space_outliner, TSE_SELECTED, 1);
1305 break;
1306 case SEL_DESELECT:
1307 outliner_flag_set(*space_outliner, TSE_SELECTED, 0);
1308 break;
1309 case SEL_INVERT:
1310 outliner_flag_flip(*space_outliner, TSE_SELECTED);
1311 break;
1312 }
1313
1314 ED_outliner_select_sync_from_outliner(C, space_outliner);
1315
1319
1320 return OPERATOR_FINISHED;
1321}
1322
1324{
1325 /* identifiers */
1326 ot->name = "Toggle Selected";
1327 ot->idname = "OUTLINER_OT_select_all";
1328 ot->description = "Toggle the Outliner selection of items";
1329
1330 /* callbacks */
1333
1334 /* no undo or registry */
1335
1336 /* rna */
1338}
1339
1341
1342/* -------------------------------------------------------------------- */
1345
1347{
1348 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1349 ScrArea *area = CTX_wm_area(C);
1351 UI_textbutton_activate_rna(C, region, space_outliner, "filter_text");
1352
1353 return OPERATOR_FINISHED;
1354}
1355
1357{
1358 /* Identifiers. */
1359 ot->name = "Filter";
1360 ot->description = "Start entering filter text";
1361 ot->idname = "OUTLINER_OT_start_filter";
1362
1363 /* Callbacks. */
1366}
1367
1369{
1370 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1371 space_outliner->search_string[0] = '\0';
1373 return OPERATOR_FINISHED;
1374}
1375
1377{
1378 /* Identifiers. */
1379 ot->name = "Clear Filter";
1380 ot->description = "Clear the search filter";
1381 ot->idname = "OUTLINER_OT_clear_filter";
1382
1383 /* Callbacks. */
1386}
1387
1389
1390/* -------------------------------------------------------------------- */
1393
1394void outliner_set_coordinates(const ARegion *region, const SpaceOutliner *space_outliner)
1395{
1396 int starty = int(region->v2d.tot.ymax) - UI_UNIT_Y;
1397
1398 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
1399 /* store coord and continue, we need coordinates for elements outside view too */
1400 te->xs = 0;
1401 te->ys = float(starty);
1402 starty -= UI_UNIT_Y;
1403 });
1404}
1405
1408{
1409 TreeStoreElem *tselem;
1410 bool retval = false;
1411
1412 for (te = te->parent; te; te = te->parent) {
1413 tselem = TREESTORE(te);
1414 if (tselem->flag & TSE_CLOSED) {
1415 tselem->flag &= ~TSE_CLOSED;
1416 retval = true;
1417 }
1418 }
1419 return retval;
1420}
1421
1426 SpaceOutliner *space_outliner,
1427 const Scene *scene,
1428 ViewLayer *view_layer)
1429{
1430 TreeElement *te;
1431
1432 BKE_view_layer_synced_ensure(scene, view_layer);
1433 Object *obact = BKE_view_layer_active_object_get(view_layer);
1434
1435 if (!obact) {
1436 return nullptr;
1437 }
1438
1439 te = outliner_find_id(space_outliner, &space_outliner->tree, &obact->id);
1440
1441 if (te != nullptr && obact->type == OB_ARMATURE) {
1442 /* traverse down the bone hierarchy in case of armature */
1443 TreeElement *te_obact = te;
1444
1445 if (obact->mode & OB_MODE_POSE) {
1446 Object *obpose = BKE_object_pose_armature_get(obact);
1447 bPoseChannel *pchan = BKE_pose_channel_active(obpose, false);
1448 if (pchan) {
1449 te = outliner_find_posechannel(&te_obact->subtree, pchan);
1450 }
1451 }
1452 else if (obact->mode & OB_MODE_EDIT) {
1453 EditBone *ebone = CTX_data_active_bone(C);
1454 if (ebone) {
1455 te = outliner_find_editbone(&te_obact->subtree, ebone);
1456 }
1457 }
1458 }
1459
1460 return te;
1461}
1462
1463static void outliner_show_active(SpaceOutliner *space_outliner,
1464 ARegion *region,
1465 TreeElement *te,
1466 ID *id)
1467{
1468 /* open up tree to active object/bone */
1469 if (TREESTORE(te)->id == id) {
1470 if (outliner_open_back(te)) {
1471 outliner_set_coordinates(region, space_outliner);
1472 }
1473 return;
1474 }
1475
1476 LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
1477 outliner_show_active(space_outliner, region, ten, id);
1478 }
1479}
1480
1482{
1483 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1484 const Scene *scene = CTX_data_scene(C);
1485 ViewLayer *view_layer = CTX_data_view_layer(C);
1486 ARegion *region = CTX_wm_region(C);
1487 View2D *v2d = &region->v2d;
1488
1490 C, space_outliner, scene, view_layer);
1491
1492 if (active_element) {
1493 ID *id = TREESTORE(active_element)->id;
1494
1495 /* Expand all elements in the outliner with matching ID */
1496 LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
1497 outliner_show_active(space_outliner, region, te, id);
1498 }
1499
1500 /* Also open back from the active_element (only done for the first found occurrence of ID
1501 * though). */
1502 outliner_show_active(space_outliner, region, active_element, id);
1503
1504 /* Center view on first element found */
1505 int size_y = BLI_rcti_size_y(&v2d->mask) + 1;
1506 int ytop = (active_element->ys + (size_y / 2));
1507 int delta_y = ytop - v2d->cur.ymax;
1508
1509 outliner_scroll_view(space_outliner, region, delta_y);
1510 }
1511 else {
1512 return OPERATOR_CANCELLED;
1513 }
1514
1516
1517 return OPERATOR_FINISHED;
1518}
1519
1521{
1522 /* identifiers */
1523 ot->name = "Show Active";
1524 ot->idname = "OUTLINER_OT_show_active";
1525 ot->description =
1526 "Open up the tree and adjust the view so that the active object is shown centered";
1527
1528 /* callbacks */
1531}
1532
1534
1535/* -------------------------------------------------------------------- */
1538
1540{
1541 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1542 ARegion *region = CTX_wm_region(C);
1543 int size_y = BLI_rcti_size_y(&region->v2d.mask) + 1;
1544
1545 bool up = RNA_boolean_get(op->ptr, "up");
1546
1547 if (!up) {
1548 size_y = -size_y;
1549 }
1550
1551 outliner_scroll_view(space_outliner, region, size_y);
1552
1554
1555 return OPERATOR_FINISHED;
1556}
1557
1559{
1560 PropertyRNA *prop;
1561
1562 /* identifiers */
1563 ot->name = "Scroll Page";
1564 ot->idname = "OUTLINER_OT_scroll_page";
1565 ot->description = "Scroll page up or down";
1566
1567 /* callbacks */
1570
1571 /* properties */
1572 prop = RNA_def_boolean(ot->srna, "up", false, "Up", "Scroll up one page");
1574}
1575
1577
1578/* -------------------------------------------------------------------- */
1581
1582/* helper function for Show/Hide one level operator */
1583static void outliner_openclose_level(ListBase *lb, int curlevel, int level, int open)
1584{
1585 LISTBASE_FOREACH (TreeElement *, te, lb) {
1586 TreeStoreElem *tselem = TREESTORE(te);
1587
1588 if (open) {
1589 if (curlevel <= level) {
1590 tselem->flag &= ~TSE_CLOSED;
1591 }
1592 }
1593 else {
1594 if (curlevel >= level) {
1595 tselem->flag |= TSE_CLOSED;
1596 }
1597 }
1598
1599 outliner_openclose_level(&te->subtree, curlevel + 1, level, open);
1600 }
1601}
1602
1604{
1605 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1606 ARegion *region = CTX_wm_region(C);
1607 const bool add = RNA_boolean_get(op->ptr, "open");
1608 int level;
1609
1610 level = outliner_flag_is_any_test(&space_outliner->tree, TSE_CLOSED, 1);
1611 if (add == 1) {
1612 if (level) {
1613 outliner_openclose_level(&space_outliner->tree, 1, level, 1);
1614 }
1615 }
1616 else {
1617 if (level == 0) {
1618 level = outliner_count_levels(&space_outliner->tree, 0);
1619 }
1620 if (level) {
1621 outliner_openclose_level(&space_outliner->tree, 1, level - 1, 0);
1622 }
1623 }
1624
1625 ED_region_tag_redraw(region);
1626
1627 return OPERATOR_FINISHED;
1628}
1629
1631{
1632 PropertyRNA *prop;
1633
1634 /* identifiers */
1635 ot->name = "Show/Hide One Level";
1636 ot->idname = "OUTLINER_OT_show_one_level";
1637 ot->description = "Expand/collapse all entries by one level";
1638
1639 /* callbacks */
1642
1643 /* no undo or registry, UI option */
1644
1645 /* properties */
1646 prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Expand all entries one level deep");
1648}
1649
1651
1652/* -------------------------------------------------------------------- */
1655
1661{
1662 LISTBASE_FOREACH (TreeElement *, te, lb) {
1663 TreeStoreElem *tselem = TREESTORE(te);
1664 if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) {
1665 return 1;
1666 }
1667 if (subtree_has_objects(&te->subtree)) {
1668 return 1;
1669 }
1670 }
1671 return 0;
1672}
1673
1674/* Helper function for Show Hierarchy operator */
1675static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outliner)
1676{
1677 /* open all object elems, close others */
1678 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
1679 TreeStoreElem *tselem = TREESTORE(te);
1680
1681 if (ELEM(tselem->type,
1686 {
1687 if (te->idcode == ID_SCE) {
1688 if (tselem->id != (ID *)scene) {
1689 tselem->flag |= TSE_CLOSED;
1690 }
1691 else {
1692 tselem->flag &= ~TSE_CLOSED;
1693 }
1694 }
1695 else if (te->idcode == ID_OB) {
1696 if (subtree_has_objects(&te->subtree)) {
1697 tselem->flag &= ~TSE_CLOSED;
1698 }
1699 else {
1700 tselem->flag |= TSE_CLOSED;
1701 }
1702 }
1703 }
1704 else {
1705 tselem->flag |= TSE_CLOSED;
1706 }
1707 });
1708}
1709
1710/* show entire object level hierarchy */
1712{
1713 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1714 ARegion *region = CTX_wm_region(C);
1715 Scene *scene = CTX_data_scene(C);
1716
1717 /* recursively open/close levels */
1718 tree_element_show_hierarchy(scene, space_outliner);
1719
1720 ED_region_tag_redraw(region);
1721
1722 return OPERATOR_FINISHED;
1723}
1724
1726{
1727 /* identifiers */
1728 ot->name = "Show Hierarchy";
1729 ot->idname = "OUTLINER_OT_show_hierarchy";
1730 ot->description = "Open all object entries and close all others";
1731
1732 /* callbacks */
1734 /* TODO: shouldn't be allowed in RNA views... */
1736
1737 /* no undo or registry, UI option */
1738}
1739
1741
1742/* -------------------------------------------------------------------- */
1745
1750{
1751 ScrArea *area = CTX_wm_area(C);
1752 if ((area) && (area->spacetype == SPACE_OUTLINER)) {
1753 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
1754 return (space_outliner->outlinevis == SO_DATA_API);
1755 }
1756 return false;
1757}
1758
1759/* Helper func to extract an RNA path from selected tree element
1760 * NOTE: the caller must zero-out all values of the pointers that it passes here first, as
1761 * this function does not do that yet
1762 */
1764 TreeStoreElem *tselem,
1765 ID **id,
1766 char **path,
1767 int *array_index,
1768 short *flag,
1769 short * /*groupmode*/)
1770{
1771 ListBase hierarchy = {nullptr, nullptr};
1772 char *newpath = nullptr;
1773
1774 /* optimize tricks:
1775 * - Don't do anything if the selected item is a 'struct', but arrays are allowed
1776 */
1777 if (tselem->type == TSE_RNA_STRUCT) {
1778 return;
1779 }
1780
1781 /* Overview of Algorithm:
1782 * 1. Go up the chain of parents until we find the 'root', taking note of the
1783 * levels encountered in reverse-order (i.e. items are added to the start of the list
1784 * for more convenient looping later)
1785 * 2. Walk down the chain, adding from the first ID encountered
1786 * (which will become the 'ID' for the KeyingSet Path), and build a
1787 * path as we step through the chain
1788 */
1789
1790 /* step 1: flatten out hierarchy of parents into a flat chain */
1791 for (TreeElement *tem = te->parent; tem; tem = tem->parent) {
1792 LinkData *ld = MEM_callocN<LinkData>("LinkData for tree_element_to_path()");
1793 ld->data = tem;
1794 BLI_addhead(&hierarchy, ld);
1795 }
1796
1797 /* step 2: step down hierarchy building the path
1798 * (NOTE: addhead in previous loop was needed so that we can loop like this) */
1799 LISTBASE_FOREACH (LinkData *, ld, &hierarchy) {
1800 /* get data */
1801 TreeElement *tem = (TreeElement *)ld->data;
1803 PointerRNA ptr = tem_rna->get_pointer_rna();
1804
1805 /* check if we're looking for first ID, or appending to path */
1806 if (*id) {
1807 /* just 'append' property to path
1808 * - to prevent memory leaks, we must write to newpath not path,
1809 * then free old path + swap them.
1810 */
1812 PropertyRNA *prop = tem_rna_prop->get_property_rna();
1813
1814 if (RNA_property_type(prop) == PROP_POINTER) {
1815 /* for pointer we just append property name */
1816 newpath = RNA_path_append(*path, &ptr, prop, 0, nullptr);
1817 }
1818 else if (RNA_property_type(prop) == PROP_COLLECTION) {
1819 char buf[128], *name;
1820
1821 TreeElement *temnext = (TreeElement *)(ld->next->data);
1822 PointerRNA nextptr = tree_element_cast<TreeElementRNACommon>(temnext)->get_pointer_rna();
1823 name = RNA_struct_name_get_alloc(&nextptr, buf, sizeof(buf), nullptr);
1824
1825 if (name) {
1826 /* if possible, use name as a key in the path */
1827 newpath = RNA_path_append(*path, nullptr, prop, 0, name);
1828
1829 if (name != buf) {
1830 MEM_freeN(name);
1831 }
1832 }
1833 else {
1834 /* otherwise use index */
1835 int index = 0;
1836
1837 LISTBASE_FOREACH (TreeElement *, temsub, &tem->subtree) {
1838 if (temsub == temnext) {
1839 break;
1840 }
1841 index++;
1842 }
1843 newpath = RNA_path_append(*path, nullptr, prop, index, nullptr);
1844 }
1845
1846 ld = ld->next;
1847 }
1848 }
1849
1850 if (newpath) {
1851 if (*path) {
1852 MEM_freeN(*path);
1853 }
1854 *path = newpath;
1855 newpath = nullptr;
1856 }
1857 }
1858 else {
1859 /* no ID, so check if entry is RNA-struct,
1860 * and if that RNA-struct is an ID datablock to extract info from. */
1862 /* ptr->data not ptr->owner_id seems to be the one we want,
1863 * since ptr->data is sometimes the owner of this ID? */
1864 if (RNA_struct_is_ID(ptr.type)) {
1865 *id = static_cast<ID *>(ptr.data);
1866
1867 /* clear path */
1868 if (*path) {
1869 MEM_freeN(*path);
1870 path = nullptr;
1871 }
1872 }
1873 }
1874 }
1875 }
1876
1877 /* step 3: if we've got an ID, add the current item to the path */
1878 if (*id) {
1879 /* add the active property to the path */
1880 PropertyRNA *prop = tree_element_cast<TreeElementRNACommon>(te)->get_property_rna();
1881
1882 /* array checks */
1883 if (tselem->type == TSE_RNA_ARRAY_ELEM) {
1884 /* item is part of an array, so must set the array_index */
1885 *array_index = te->index;
1886 }
1887 else if (RNA_property_array_check(prop)) {
1888 /* entire array was selected, so keyframe all */
1890 }
1891
1892 /* path */
1893 newpath = RNA_path_append(*path, nullptr, prop, 0, nullptr);
1894 if (*path) {
1895 MEM_freeN(*path);
1896 }
1897 *path = newpath;
1898 }
1899
1900 /* free temp data */
1901 BLI_freelistN(&hierarchy);
1902}
1903
1905
1906/* -------------------------------------------------------------------- */
1909
1916enum {
1919} /*eDrivers_EditModes*/;
1920
1921/* Iterate over tree, finding and working on selected items */
1922static void do_outliner_drivers_editop(SpaceOutliner *space_outliner,
1924 short mode)
1925{
1926 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
1927 TreeStoreElem *tselem = TREESTORE(te);
1928
1929 /* if item is selected, perform operation */
1930 if (!(tselem->flag & TSE_SELECTED)) {
1931 return;
1932 }
1933
1934 ID *id = nullptr;
1935 char *path = nullptr;
1936 int array_index = 0;
1937 short flag = 0;
1938 short groupmode = KSP_GROUP_KSNAME;
1939
1941 PointerRNA ptr = te_rna ? te_rna->get_pointer_rna() : PointerRNA_NULL;
1942 PropertyRNA *prop = te_rna ? te_rna->get_property_rna() : nullptr;
1943
1944 /* check if RNA-property described by this selected element is an animatable prop */
1945 if (prop && RNA_property_anim_editable(&ptr, prop)) {
1946 /* get id + path + index info from the selected element */
1947 tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
1948 }
1949
1950 /* only if ID and path were set, should we perform any actions */
1951 if (id && path) {
1952 short dflags = CREATEDRIVER_WITH_DEFAULT_DVAR;
1953 int arraylen = 1;
1954
1955 /* array checks */
1956 if (flag & KSP_FLAG_WHOLE_ARRAY) {
1957 /* entire array was selected, so add drivers for all */
1958 arraylen = RNA_property_array_length(&ptr, prop);
1959 }
1960 else {
1961 arraylen = array_index;
1962 }
1963
1964 /* we should do at least one step */
1965 if (arraylen == array_index) {
1966 arraylen++;
1967 }
1968
1969 /* for each array element we should affect, add driver */
1970 for (; array_index < arraylen; array_index++) {
1971 /* action depends on mode */
1972 switch (mode) {
1973 case DRIVERS_EDITMODE_ADD: {
1974 /* add a new driver with the information obtained (only if valid) */
1975 ANIM_add_driver(reports, id, path, array_index, dflags, DRIVER_TYPE_PYTHON);
1976 break;
1977 }
1979 ANIM_remove_driver(id, path, array_index);
1980 break;
1981 }
1982 }
1983 }
1984
1985 /* free path, since it had to be generated */
1986 MEM_freeN(path);
1987 }
1988 });
1989}
1990
1992
1993/* -------------------------------------------------------------------- */
1996
1998{
1999 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2000
2001 /* check for invalid states */
2002 if (space_outliner == nullptr) {
2003 return OPERATOR_CANCELLED;
2004 }
2005
2006 /* recursively go into tree, adding selected items */
2008
2009 /* send notifiers */
2010 WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, nullptr); /* XXX */
2011
2012 return OPERATOR_FINISHED;
2013}
2014
2016{
2017 /* API callbacks. */
2018 ot->idname = "OUTLINER_OT_drivers_add_selected";
2019 ot->name = "Add Drivers for Selected";
2020 ot->description = "Add drivers to selected items";
2021
2022 /* API callbacks. */
2025
2026 /* flags */
2027 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2028}
2029
2031
2032/* -------------------------------------------------------------------- */
2035
2037{
2038 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2039
2040 /* check for invalid states */
2041 if (space_outliner == nullptr) {
2042 return OPERATOR_CANCELLED;
2043 }
2044
2045 /* recursively go into tree, adding selected items */
2047
2048 /* send notifiers */
2049 WM_event_add_notifier(C, ND_KEYS, nullptr); /* XXX */
2050
2051 return OPERATOR_FINISHED;
2052}
2053
2055{
2056 /* identifiers */
2057 ot->idname = "OUTLINER_OT_drivers_delete_selected";
2058 ot->name = "Delete Drivers for Selected";
2059 ot->description = "Delete drivers assigned to selected items";
2060
2061 /* API callbacks. */
2064
2065 /* flags */
2066 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2067}
2068
2070
2071/* -------------------------------------------------------------------- */
2074
2081enum {
2084} /*eKeyingSet_EditModes*/;
2085
2086/* Find the 'active' KeyingSet, and add if not found (if adding is allowed). */
2087/* TODO: should this be an API func? */
2089{
2090 KeyingSet *ks = nullptr;
2091
2092 /* sanity check */
2093 if (scene == nullptr) {
2094 return nullptr;
2095 }
2096
2097 /* try to find one from scene */
2098 if (scene->active_keyingset > 0) {
2099 ks = static_cast<KeyingSet *>(BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1));
2100 }
2101
2102 /* Add if none found */
2103 /* XXX the default settings have yet to evolve. */
2104 if ((add) && (ks == nullptr)) {
2105 ks = BKE_keyingset_add(&scene->keyingsets, nullptr, nullptr, KEYINGSET_ABSOLUTE, 0);
2107 }
2108
2109 return ks;
2110}
2111
2112/* Iterate over tree, finding and working on selected items */
2114 KeyingSet *ks,
2115 const short mode)
2116{
2117 tree_iterator::all_open(*space_outliner, [&](TreeElement *te) {
2118 TreeStoreElem *tselem = TREESTORE(te);
2119
2120 /* if item is selected, perform operation */
2121 if (!(tselem->flag & TSE_SELECTED)) {
2122 return;
2123 }
2124
2125 ID *id = nullptr;
2126 char *path = nullptr;
2127 int array_index = 0;
2128 short flag = 0;
2129 short groupmode = KSP_GROUP_KSNAME;
2130
2131 /* check if RNA-property described by this selected element is an animatable prop */
2133 if (te_rna) {
2134 PointerRNA ptr = te_rna->get_pointer_rna();
2135 if (PropertyRNA *prop = te_rna->get_property_rna()) {
2136 if (RNA_property_anim_editable(&ptr, prop)) {
2137 /* get id + path + index info from the selected element */
2138 tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode);
2139 }
2140 }
2141 }
2142
2143 /* only if ID and path were set, should we perform any actions */
2144 if (id && path) {
2145 /* action depends on mode */
2146 switch (mode) {
2148 /* add a new path with the information obtained (only if valid) */
2149 /* TODO: what do we do with group name?
2150 * for now, we don't supply one, and just let this use the KeyingSet name */
2151 BKE_keyingset_add_path(ks, id, nullptr, path, array_index, flag, groupmode);
2153 break;
2154 }
2156 /* find the relevant path, then remove it from the KeyingSet */
2157 KS_Path *ksp = BKE_keyingset_find_path(ks, id, nullptr, path, array_index, groupmode);
2158
2159 if (ksp) {
2160 /* free path's data */
2161 BKE_keyingset_free_path(ks, ksp);
2162
2163 ks->active_path = 0;
2164 }
2165 break;
2166 }
2167 }
2168
2169 /* free path, since it had to be generated */
2170 MEM_freeN(path);
2171 }
2172 });
2173}
2174
2176
2177/* -------------------------------------------------------------------- */
2180
2182{
2183 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2184 Scene *scene = CTX_data_scene(C);
2185 KeyingSet *ks = verify_active_keyingset(scene, 1);
2186
2187 /* check for invalid states */
2188 if (ks == nullptr) {
2189 BKE_report(op->reports, RPT_ERROR, "Operation requires an active keying set");
2190 return OPERATOR_CANCELLED;
2191 }
2192 if (space_outliner == nullptr) {
2193 return OPERATOR_CANCELLED;
2194 }
2195
2196 /* recursively go into tree, adding selected items */
2198
2199 /* send notifiers */
2201
2202 return OPERATOR_FINISHED;
2203}
2204
2206{
2207 /* identifiers */
2208 ot->idname = "OUTLINER_OT_keyingset_add_selected";
2209 ot->name = "Keying Set Add Selected";
2210 ot->description = "Add selected items (blue-gray rows) to active Keying Set";
2211
2212 /* API callbacks. */
2215
2216 /* flags */
2217 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2218}
2219
2221
2222/* -------------------------------------------------------------------- */
2225
2227{
2228 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2229 Scene *scene = CTX_data_scene(C);
2230 KeyingSet *ks = verify_active_keyingset(scene, 1);
2231
2232 /* check for invalid states */
2233 if (space_outliner == nullptr) {
2234 return OPERATOR_CANCELLED;
2235 }
2236
2237 /* recursively go into tree, adding selected items */
2239
2240 /* send notifiers */
2242
2243 return OPERATOR_FINISHED;
2244}
2245
2247{
2248 /* identifiers */
2249 ot->idname = "OUTLINER_OT_keyingset_remove_selected";
2250 ot->name = "Keying Set Remove Selected";
2251 ot->description = "Remove selected items (blue-gray rows) from active Keying Set";
2252
2253 /* API callbacks. */
2256
2257 /* flags */
2258 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2259}
2260
2262
2263/* -------------------------------------------------------------------- */
2266
2268{
2269 ScrArea *area = CTX_wm_area(C);
2270 if (area != nullptr && area->spacetype == SPACE_OUTLINER) {
2271 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2272 return (space_outliner->outlinevis == SO_ID_ORPHANS);
2273 }
2274 return true;
2275}
2276
2277static void unused_message_gen(std::string &message,
2278 const std::array<int, INDEX_ID_MAX> &num_tagged)
2279{
2280 bool is_first = true;
2281 if (num_tagged[INDEX_ID_NULL] == 0) {
2282 message += IFACE_("None");
2283 return;
2284 }
2285
2286 /* NOTE: Index is looped in reversed order, since typically 'higher level' IDs (like Collections
2287 * or Objects) have a higher index than 'lower level' ones like object data, materials, etc.
2288 *
2289 * It makes more sense to present to the user the deleted numbers of Collections or Objects
2290 * before the ones for object data or Materials. */
2291 for (int i = INDEX_ID_MAX - 2; i >= 0; i--) {
2292 if (num_tagged[i] != 0) {
2293 message += fmt::format(
2294 "{}{} {}",
2295 (is_first) ? "" : ", ",
2296 num_tagged[i],
2297 (num_tagged[i] > 1) ?
2300 is_first = false;
2301 }
2302 }
2303}
2304
2306{
2307 /* Computation of unused data amounts, with all options ON.
2308 * Used to estimate the maximum required width for the dialog. */
2309 Main *bmain = CTX_data_main(C);
2311 data.do_local_ids = true;
2312 data.do_linked_ids = true;
2313 data.do_recursive = true;
2315
2316 std::string unused_message;
2317 const uiStyle *style = UI_style_get_dpi();
2318 unused_message_gen(unused_message, data.num_local);
2319 float max_messages_width = BLF_width(
2320 style->widget.uifont_id, unused_message.c_str(), BLF_DRAW_STR_DUMMY_MAX);
2321
2322 unused_message = "";
2323 unused_message_gen(unused_message, data.num_linked);
2324 max_messages_width = std::max(
2325 max_messages_width,
2326 BLF_width(style->widget.uifont_id, unused_message.c_str(), BLF_DRAW_STR_DUMMY_MAX));
2327
2328 return int(std::max(max_messages_width, 300.0f));
2329}
2330
2332{
2333 if (op->customdata) {
2334 MEM_delete(static_cast<LibQueryUnusedIDsData *>(op->customdata));
2335 op->customdata = nullptr;
2336 }
2337}
2338
2340{
2341 Main *bmain = CTX_data_main(C);
2343
2344 data.do_local_ids = RNA_boolean_get(op->ptr, "do_local_ids");
2345 data.do_linked_ids = RNA_boolean_get(op->ptr, "do_linked_ids");
2346 data.do_recursive = RNA_boolean_get(op->ptr, "do_recursive");
2347
2349
2350 /* Always assume count changed, and request a redraw. */
2351 return true;
2352}
2353
2355 wmOperator *op,
2356 const wmEvent * /*event*/)
2357{
2358 op->customdata = MEM_new<LibQueryUnusedIDsData>(__func__);
2359
2360 /* Compute expected amounts of deleted IDs and store them in 'cached' operator properties. */
2362
2364 op,
2366 IFACE_("Purge Unused Data from This File"),
2367 IFACE_("Delete"));
2368}
2369
2371{
2372 Main *bmain = CTX_data_main(C);
2373 ScrArea *area = CTX_wm_area(C);
2374 SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
2375
2376 if (!op->customdata) {
2377 op->customdata = MEM_new<LibQueryUnusedIDsData>(__func__);
2378 }
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
2385 /* Tag all IDs to delete. */
2387
2388 if (data.num_total[INDEX_ID_NULL] == 0) {
2389 BKE_report(op->reports, RPT_INFO, "No orphaned data-blocks to purge");
2390 MEM_delete(static_cast<LibQueryUnusedIDsData *>(op->customdata));
2391 op->customdata = nullptr;
2392 return OPERATOR_CANCELLED;
2393 }
2394
2396
2397 BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-block(s)", data.num_total[INDEX_ID_NULL]);
2398
2399 /* XXX: tree management normally happens from draw_outliner(), but when
2400 * you're clicking to fast on Delete object from context menu in
2401 * outliner several mouse events can be handled in one cycle without
2402 * handling notifiers/redraw which leads to deleting the same object twice.
2403 * cleanup tree here to prevent such cases. */
2404 if ((area != nullptr) && (area->spacetype == SPACE_OUTLINER)) {
2405 outliner_cleanup_tree(space_outliner);
2406 }
2407
2409 WM_event_add_notifier(C, NC_ID | NA_REMOVED, nullptr);
2410 /* Force full redraw of the UI. */
2412
2414
2415 return OPERATOR_FINISHED;
2416}
2417
2422
2424{
2425 uiLayout *layout = op->layout;
2426 PointerRNA *ptr = op->ptr;
2427 if (!op->customdata) {
2428 /* This should only happen on 'adjust last operation' case, since `invoke` will not have been
2429 * called then before showing the UI (the 'redo panel' UI uses WM-stored operator properties
2430 * and a newly-created operator).
2431 *
2432 * Since that operator is not 'registered' for adjusting from undo stack, this should never
2433 * happen currently. */
2435 op->customdata = MEM_new<LibQueryUnusedIDsData>(__func__);
2436 }
2438
2439 std::string unused_message;
2440 unused_message_gen(unused_message, data.num_local);
2441 uiLayout *column = &layout->column(true);
2442 column->prop(ptr, "do_local_ids", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2443 uiLayout *row = &column->row(true);
2444 row->separator(2.67f);
2445 row->label(unused_message, ICON_NONE);
2446
2447 unused_message = "";
2448 unused_message_gen(unused_message, data.num_linked);
2449 column = &layout->column(true);
2450 column->prop(ptr, "do_linked_ids", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2451 row = &column->row(true);
2452 row->separator(2.67f);
2453 row->label(unused_message, ICON_NONE);
2454
2455 layout->prop(ptr, "do_recursive", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2456}
2457
2459{
2460 /* identifiers */
2461 ot->idname = "OUTLINER_OT_orphans_purge";
2462 ot->name = "Purge All";
2463 ot->description = "Clear all orphaned data-blocks without any users from the file";
2464
2465 /* callbacks */
2469
2473
2474 /* flags */
2475 /* NOTE: No #OPTYPE_REGISTER, since this operator should not be 'adjustable'. */
2476 ot->flag = OPTYPE_UNDO;
2477
2478 /* Actual user-visible settings. */
2479 RNA_def_boolean(ot->srna,
2480 "do_local_ids",
2481 true,
2482 "Local Data-blocks",
2483 "Include unused local data-blocks into deletion");
2484 RNA_def_boolean(ot->srna,
2485 "do_linked_ids",
2486 true,
2487 "Linked Data-blocks",
2488 "Include unused linked data-blocks into deletion");
2489
2490 RNA_def_boolean(ot->srna,
2491 "do_recursive",
2492 true,
2493 "Recursive Delete",
2494 "Recursively check for indirectly unused data-blocks, ensuring that no orphaned "
2495 "data-blocks remain after execution");
2496}
2497
2499
2500/* -------------------------------------------------------------------- */
2503
2505 wmOperator * /*op*/,
2506 const wmEvent *event)
2507{
2508 const int sizex = int(450.0f * UI_SCALE_FAC);
2509 const int sizey = int(450.0f * UI_SCALE_FAC);
2510 const rcti window_rect = {
2511 /*xmin*/ event->xy[0],
2512 /*xmax*/ event->xy[0] + sizex,
2513 /*ymin*/ event->xy[1],
2514 /*ymax*/ event->xy[1] + sizey,
2515 };
2516
2517 if (WM_window_open(C,
2518 IFACE_("Manage Unused Data"),
2519 &window_rect,
2521 false,
2522 false,
2523 true,
2525 nullptr,
2526 nullptr) != nullptr)
2527 {
2528 SpaceOutliner *soutline = CTX_wm_space_outliner(C);
2529 soutline->outlinevis = SO_ID_ORPHANS;
2530 return OPERATOR_FINISHED;
2531 }
2532 return OPERATOR_CANCELLED;
2533}
2534
2536{
2537 /* identifiers */
2538 ot->idname = "OUTLINER_OT_orphans_manage";
2539 ot->name = "Manage Unused Data";
2540 ot->description = "Open a window to manage unused data";
2541
2542 /* callbacks */
2544
2545 /* flags */
2546 ot->flag = OPTYPE_REGISTER;
2547}
2548
2550
2551} // 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
@ ID_REMAP_SKIP_NEVER_NULL_USAGE
@ ID_REMAP_SKIP_INDIRECT_USAGE
void void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, int remap_flags) ATTR_NONNULL(1
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:882
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:872
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
@ LIBOVERRIDE_FLAG_NO_HIERARCHY
Definition DNA_ID.h:348
@ INDEX_ID_NULL
Definition DNA_ID.h:1266
@ 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
@ 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_HIGHLIGHTED_ANY
@ TSE_SELECTED
@ TSE_CLOSED
@ TSE_HIGHLIGHTED_ICON
@ TSE_HIGHLIGHTED
@ TSE_DRAG_ANY
@ TSE_ACTIVE
@ TSE_TEXTBUT
@ 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
@ 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
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_ANIMATION
Definition WM_types.hh:385
#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
@ KM_CLICK_DRAG
Definition WM_types.hh:316
@ KM_RELEASE
Definition WM_types.hh:309
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)
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)
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:4226
wmOperatorType * ot
Definition wm_files.cc:4225
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