Blender V4.5
interface_template_id.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BKE_anim_data.hh"
10#include "BKE_collection.hh"
11#include "BKE_context.hh"
12#include "BKE_idtype.hh"
13#include "BKE_layer.hh"
14#include "BKE_lib_id.hh"
15#include "BKE_lib_override.hh"
16#include "BKE_library.hh"
17#include "BKE_main.hh"
19#include "BKE_packedFile.hh"
20
21#include "BLI_listbase.h"
22#include "BLI_string.h"
23#include "BLI_string_search.hh"
24
25#include "BLT_translation.hh"
26
28
30#include "DNA_scene_types.h"
31#include "DNA_workspace_types.h"
32
33#include "ED_id_management.hh"
34#include "ED_node.hh"
35#include "ED_object.hh"
36#include "ED_undo.hh"
37
38#include "RNA_access.hh"
39#include "RNA_prototypes.hh"
40
41#include "WM_api.hh"
42
43#include "UI_interface.hh"
44#include "UI_string_search.hh"
45#include "interface_intern.hh"
47
50
51struct TemplateID {
53 PropertyRNA *prop = nullptr;
54
55 ListBase *idlb = nullptr;
56 short idcode = 0;
57 short filter = 0;
58 int prv_rows = 0;
59 int prv_cols = 0;
60 bool preview = false;
61 float scale = 0.0f;
62};
63
64/* Search browse menu, assign. */
65static void template_ID_set_property_exec_fn(bContext *C, void *arg_template, void *item)
66{
67 TemplateID *template_ui = (TemplateID *)arg_template;
68
69 /* ID */
70 if (item) {
71 PointerRNA idptr = RNA_id_pointer_create(static_cast<ID *>(item));
72 RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, nullptr);
73 RNA_property_update(C, &template_ui->ptr, template_ui->prop);
74 }
75}
76
77static bool id_search_allows_id(TemplateID *template_ui, const int flag, ID *id, const char *query)
78{
79 ID *id_from = template_ui->ptr.owner_id;
80
81 /* Do self check. */
82 if ((flag & PROP_ID_SELF_CHECK) && id == id_from) {
83 return false;
84 }
85
86 /* Use filter. */
87 if (RNA_property_type(template_ui->prop) == PROP_POINTER) {
89 if (RNA_property_pointer_poll(&template_ui->ptr, template_ui->prop, &ptr) == 0) {
90 return false;
91 }
92 }
93
94 /* Hide dot prefixed data-blocks, but only if filter does not force them visible. */
95 if (U.uiflag & USER_HIDE_DOT) {
96 if ((id->name[2] == '.') && (query[0] != '.')) {
97 return false;
98 }
99 }
100
101 return true;
102}
103
104static bool id_search_add(const bContext *C, TemplateID *template_ui, uiSearchItems *items, ID *id)
105{
106 /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix
107 * followed by ID_NAME-2 characters from id->name
108 */
109 char name_ui[MAX_ID_FULL_NAME_UI];
110 int iconid = ui_id_icon_get(C, id, template_ui->preview);
111 const bool use_lib_prefix = template_ui->preview || iconid;
112 const bool has_sep_char = ID_IS_LINKED(id);
113
114 /* When using previews, the library hint (linked, overridden, missing) is added with a
115 * character prefix, otherwise we can use a icon. */
116 int name_prefix_offset;
117 BKE_id_full_name_ui_prefix_get(name_ui, id, use_lib_prefix, UI_SEP_CHAR, &name_prefix_offset);
118 if (!use_lib_prefix) {
119 iconid = UI_icon_from_library(id);
120 }
121
122 if (!UI_search_item_add(items,
123 name_ui,
124 id,
125 iconid,
126 has_sep_char ? int(UI_BUT_HAS_SEP_CHAR) : 0,
127 name_prefix_offset))
128 {
129 return false;
130 }
131
132 return true;
133}
134
135/* ID Search browse menu, do the search */
136static void id_search_cb(const bContext *C,
137 void *arg_template,
138 const char *str,
139 uiSearchItems *items,
140 const bool /*is_first*/)
141{
142 TemplateID *template_ui = (TemplateID *)arg_template;
143 ListBase *lb = template_ui->idlb;
144 const int flag = RNA_property_flag(template_ui->prop);
145
147
148 /* ID listbase */
149 LISTBASE_FOREACH (ID *, id, lb) {
150 if (id_search_allows_id(template_ui, flag, id, str)) {
151 search.add(id->name + 2, id);
152 }
153 }
154
155 const blender::Vector<ID *> filtered_ids = search.query(str);
156
157 for (ID *id : filtered_ids) {
158 if (!id_search_add(C, template_ui, items, id)) {
159 break;
160 }
161 }
162}
163
167static void id_search_cb_tagged(const bContext *C,
168 void *arg_template,
169 const char *str,
170 uiSearchItems *items)
171{
172 TemplateID *template_ui = (TemplateID *)arg_template;
173 ListBase *lb = template_ui->idlb;
174 const int flag = RNA_property_flag(template_ui->prop);
175
178
179 /* ID listbase */
180 LISTBASE_FOREACH (ID *, id, lb) {
181 if (id->tag & ID_TAG_DOIT) {
182 if (id_search_allows_id(template_ui, flag, id, str)) {
183 search.add(id->name + 2, id);
184 }
185 id->tag &= ~ID_TAG_DOIT;
186 }
187 }
188
189 blender::Vector<ID *> filtered_ids = search.query(str);
190
191 for (ID *id : filtered_ids) {
192 if (!id_search_add(C, template_ui, items, id)) {
193 break;
194 }
195 }
196}
197
202 void *arg_template,
203 const char *str,
204 uiSearchItems *items,
205 const bool /*is_first*/)
206{
207 TemplateID *template_ui = (TemplateID *)arg_template;
208 ListBase *lb = template_ui->idlb;
209 Scene *scene = nullptr;
210 ID *id_from = template_ui->ptr.owner_id;
211
212 if (id_from && GS(id_from->name) == ID_SCE) {
213 scene = (Scene *)id_from;
214 }
215 else {
216 scene = CTX_data_scene(C);
217 }
218
220
221 FOREACH_SCENE_OBJECT_BEGIN (scene, ob_iter) {
222 ob_iter->id.tag |= ID_TAG_DOIT;
223 }
225 id_search_cb_tagged(C, arg_template, str, items);
226}
227
229 bContext *C, ARegion *region, const rcti *item_rect, void * /*arg*/, void *active)
230{
231 ID *active_id = static_cast<ID *>(active);
232 return UI_tooltip_create_from_search_item_generic(C, region, item_rect, active_id);
233}
234
235/* ID Search browse menu, open */
236static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
237{
238 static TemplateID template_ui;
239 PointerRNA active_item_ptr;
240 void (*id_search_update_fn)(
241 const bContext *, void *, const char *, uiSearchItems *, const bool) = id_search_cb;
242
243 /* arg_litem is malloced, can be freed by parent button */
244 template_ui = *((TemplateID *)arg_litem);
245 active_item_ptr = RNA_property_pointer_get(&template_ui.ptr, template_ui.prop);
246
247 if (template_ui.filter) {
248 /* Currently only used for objects. */
249 if (template_ui.idcode == ID_OB) {
250 if (template_ui.filter == UI_TEMPLATE_ID_FILTER_AVAILABLE) {
251 id_search_update_fn = id_search_cb_objects_from_scene;
252 }
253 }
254 }
255
257 region,
258 id_search_update_fn,
259 &template_ui,
261 active_item_ptr.data,
263 template_ui.prv_rows,
264 template_ui.prv_cols,
265 template_ui.scale);
266}
267
268static void template_id_cb(bContext *C, void *arg_litem, void *arg_event);
269
271 PointerRNA *r_ptr,
272 PropertyRNA **r_prop)
273{
275
276 *r_ptr = {};
277 *r_prop = nullptr;
278
279 if (but && (but->funcN == template_id_cb) && but->func_argN) {
280 TemplateID *template_ui = static_cast<TemplateID *>(but->func_argN);
281 *r_ptr = template_ui->ptr;
282 *r_prop = template_ui->prop;
283 }
284}
285
287 Collection *collection,
288 const int parent_level,
289 Collection **r_collection_parent_best,
290 int *r_parent_level_best)
291{
292 if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY_REAL(collection)) {
293 return;
294 }
295 if (ID_IS_OVERRIDABLE_LIBRARY(collection) || ID_IS_OVERRIDE_LIBRARY_REAL(collection)) {
296 if (parent_level > *r_parent_level_best) {
297 *r_parent_level_best = parent_level;
298 *r_collection_parent_best = collection;
299 }
300 }
301 for (CollectionParent *iter = static_cast<CollectionParent *>(collection->runtime.parents.first);
302 iter != nullptr;
303 iter = iter->next)
304 {
305 if (iter->collection->id.lib != collection->id.lib && ID_IS_LINKED(iter->collection)) {
306 continue;
307 }
309 iter->collection, parent_level + 1, r_collection_parent_best, r_parent_level_best);
310 }
311}
312
314 Collection *root_collection, ID *target_id, const bool do_parents)
315{
316 root_collection->id.tag |= ID_TAG_DOIT;
317
318 /* Tag all local parents of the root collection, so that usages of the root collection and other
319 * linked ones can be replaced by the local overrides in those parents too. */
320 if (do_parents) {
321 for (CollectionParent *iter =
322 static_cast<CollectionParent *>(root_collection->runtime.parents.first);
323 iter != nullptr;
324 iter = iter->next)
325 {
326 if (ID_IS_LINKED(iter->collection)) {
327 continue;
328 }
329 iter->collection->id.tag |= ID_TAG_DOIT;
330 }
331 }
332
333 for (CollectionChild *iter = static_cast<CollectionChild *>(root_collection->children.first);
334 iter != nullptr;
335 iter = iter->next)
336 {
337 if (ID_IS_LINKED(iter->collection) && iter->collection->id.lib != target_id->lib) {
338 continue;
339 }
340 if (GS(target_id->name) == ID_OB &&
341 !BKE_collection_has_object_recursive(iter->collection, (Object *)target_id))
342 {
343 continue;
344 }
345 if (GS(target_id->name) == ID_GR &&
346 !BKE_collection_has_collection(iter->collection, (Collection *)target_id))
347 {
348 continue;
349 }
351 iter->collection, target_id, false);
352 }
353}
354
356 bContext *C, Main *bmain, ID *owner_id, ID *id, const char **r_undo_push_label)
357{
358 const char *undo_push_label;
359 if (r_undo_push_label == nullptr) {
360 r_undo_push_label = &undo_push_label;
361 }
362
363 /* If this is called on an already local override, 'toggle' between user-editable state, and
364 * system override with reset. */
365 if (!ID_IS_LINKED(id) && ID_IS_OVERRIDE_LIBRARY(id)) {
367 BKE_lib_override_library_get(bmain, id, nullptr, &id);
368 }
370 id->override_library->flag &= ~LIBOVERRIDE_FLAG_SYSTEM_DEFINED;
371 *r_undo_push_label = "Make Library Override Hierarchy Editable";
372 }
373 else {
374 BKE_lib_override_library_id_reset(bmain, id, true);
375 *r_undo_push_label = "Clear Library Override Hierarchy";
376 }
377
381 return id;
382 }
383
384 /* Attempt to perform a hierarchy override, based on contextual data available.
385 * NOTE: do not attempt to perform such hierarchy override at all cost, if there is not enough
386 * context, better to abort than create random overrides all over the place. */
388 WM_global_reportf(RPT_ERROR, "The data-block %s is not overridable", id->name);
389 return nullptr;
390 }
391
392 Object *object_active = CTX_data_active_object(C);
393 if (object_active == nullptr && GS(owner_id->name) == ID_OB) {
394 object_active = (Object *)owner_id;
395 }
396 if (object_active != nullptr) {
397 if (ID_IS_LINKED(object_active)) {
398 if (object_active->id.lib != id->lib || !ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(object_active))
399 {
400 /* The active object is from a different library than the overridden ID, or otherwise
401 * cannot be used in hierarchy. */
402 object_active = nullptr;
403 }
404 }
405 else if (!ID_IS_OVERRIDE_LIBRARY_REAL(object_active)) {
406 /* Fully local object cannot be used in override hierarchy either. */
407 object_active = nullptr;
408 }
409 }
410
411 Collection *collection_active_context = CTX_data_collection(C);
412 Collection *collection_active = collection_active_context;
413 if (collection_active == nullptr && GS(owner_id->name) == ID_GR) {
414 collection_active = (Collection *)owner_id;
415 }
416 if (collection_active != nullptr) {
417 if (ID_IS_LINKED(collection_active)) {
418 if (collection_active->id.lib != id->lib ||
419 !ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(collection_active))
420 {
421 /* The active collection is from a different library than the overridden ID, or otherwise
422 * cannot be used in hierarchy. */
423 collection_active = nullptr;
424 }
425 else {
426 int parent_level_best = -1;
427 Collection *collection_parent_best = nullptr;
429 collection_active, 0, &collection_parent_best, &parent_level_best);
430 collection_active = collection_parent_best;
431 }
432 }
433 else if (!ID_IS_OVERRIDE_LIBRARY_REAL(collection_active)) {
434 /* Fully local collection cannot be used in override hierarchy either. */
435 collection_active = nullptr;
436 }
437 }
438 if (collection_active == nullptr && object_active != nullptr &&
439 (ID_IS_LINKED(object_active) || ID_IS_OVERRIDE_LIBRARY_REAL(object_active)))
440 {
441 /* If we failed to find a valid 'active' collection so far for our override hierarchy, but do
442 * have a valid 'active' object, try to find a collection from that object. */
443 LISTBASE_FOREACH (Collection *, collection_iter, &bmain->collections) {
444 if (ID_IS_LINKED(collection_iter) && collection_iter->id.lib != id->lib) {
445 continue;
446 }
447 if (!ID_IS_OVERRIDE_LIBRARY_REAL(collection_iter)) {
448 continue;
449 }
450 if (!BKE_collection_has_object_recursive(collection_iter, object_active)) {
451 continue;
452 }
453 int parent_level_best = -1;
454 Collection *collection_parent_best = nullptr;
456 collection_iter, 0, &collection_parent_best, &parent_level_best);
457 collection_active = collection_parent_best;
458 break;
459 }
460 }
461
462 ID *id_override = nullptr;
463 Scene *scene = CTX_data_scene(C);
464 ViewLayer *view_layer = CTX_data_view_layer(C);
465 switch (GS(id->name)) {
466 case ID_GR:
467 if (collection_active != nullptr &&
468 BKE_collection_has_collection(collection_active, (Collection *)id))
469 {
471 if (object_active != nullptr) {
472 object_active->id.tag |= ID_TAG_DOIT;
473 }
475 scene,
476 view_layer,
477 nullptr,
478 id,
479 &collection_active->id,
480 nullptr,
481 &id_override,
482 false);
483 }
484 else if (object_active != nullptr && !ID_IS_LINKED(object_active) &&
485 &object_active->instance_collection->id == id)
486 {
487 object_active->id.tag |= ID_TAG_DOIT;
489 scene,
490 view_layer,
491 id->lib,
492 id,
493 &object_active->id,
494 &object_active->id,
495 &id_override,
496 false);
497 }
498 break;
499 case ID_OB:
500 if (collection_active != nullptr &&
501 BKE_collection_has_object_recursive(collection_active, (Object *)id))
502 {
504 if (object_active != nullptr) {
505 object_active->id.tag |= ID_TAG_DOIT;
506 }
508 scene,
509 view_layer,
510 nullptr,
511 id,
512 &collection_active->id,
513 nullptr,
514 &id_override,
515 false);
516 }
517 else {
518 if (object_active != nullptr) {
519 object_active->id.tag |= ID_TAG_DOIT;
520 }
522 bmain, scene, view_layer, nullptr, id, nullptr, nullptr, &id_override, false);
523 BKE_scene_collections_object_remove(bmain, scene, (Object *)id, true);
525 }
526 break;
527 case ID_ME:
528 case ID_CU_LEGACY:
529 case ID_MB:
530 case ID_LT:
531 case ID_LA:
532 case ID_CA:
533 case ID_SPK:
534 case ID_AR:
535 case ID_GD_LEGACY:
536 case ID_CV:
537 case ID_PT:
538 case ID_VO:
539 case ID_NT: /* Essentially geometry nodes from modifier currently. */
540 if (object_active != nullptr) {
541 if (collection_active != nullptr &&
542 BKE_collection_has_object_recursive(collection_active, object_active))
543 {
545 object_active->id.tag |= ID_TAG_DOIT;
547 scene,
548 view_layer,
549 nullptr,
550 id,
551 &collection_active->id,
552 nullptr,
553 &id_override,
554 false);
555 }
556 else {
557 object_active->id.tag |= ID_TAG_DOIT;
559 scene,
560 view_layer,
561 nullptr,
562 id,
563 &object_active->id,
564 nullptr,
565 &id_override,
566 false);
567 }
568 }
569 else {
571 bmain, scene, view_layer, nullptr, id, id, nullptr, &id_override, false);
572 }
573 break;
574 case ID_MA:
575 case ID_TE:
576 case ID_IM:
577 WM_global_reportf(RPT_WARNING, "The type of data-block %s is not yet implemented", id->name);
578 break;
579 case ID_WO:
580 WM_global_reportf(RPT_WARNING, "The type of data-block %s is not yet implemented", id->name);
581 break;
582 case ID_PA:
583 WM_global_reportf(RPT_WARNING, "The type of data-block %s is not yet implemented", id->name);
584 break;
585 default:
586 WM_global_reportf(RPT_WARNING, "The type of data-block %s is not yet implemented", id->name);
587 break;
588 }
589
590 if (id_override != nullptr) {
592
593 /* Ensure that the hierarchy root of the newly overridden data is instantiated in the scene, in
594 * case it's a collection or object. */
595 ID *hierarchy_root = id_override->override_library->hierarchy_root;
596 if (GS(hierarchy_root->name) == ID_OB) {
597 Object *object_hierarchy_root = reinterpret_cast<Object *>(hierarchy_root);
598 if (!BKE_scene_has_object(scene, object_hierarchy_root)) {
599 if (!ID_IS_LINKED(collection_active_context)) {
600 BKE_collection_object_add(bmain, collection_active_context, object_hierarchy_root);
601 }
602 else {
603 BKE_collection_object_add(bmain, scene->master_collection, object_hierarchy_root);
604 }
605 }
606 }
607 else if (GS(hierarchy_root->name) == ID_GR) {
608 Collection *collection_hierarchy_root = reinterpret_cast<Collection *>(hierarchy_root);
609 if (!BKE_collection_has_collection(scene->master_collection, collection_hierarchy_root)) {
610 if (!ID_IS_LINKED(collection_active_context)) {
611 BKE_collection_child_add(bmain, collection_active_context, collection_hierarchy_root);
612 }
613 else {
614 BKE_collection_child_add(bmain, scene->master_collection, collection_hierarchy_root);
615 }
616 }
617 }
618
619 *r_undo_push_label = "Make Library Override Hierarchy";
620
621 /* In theory we could rely on setting/updating the RNA ID pointer property (as done by calling
622 * code) to be enough.
623 *
624 * However, some rare ID pointers properties (like the "active object in view-layer" one used
625 * for the Object templateID in the Object properties) use notifiers that do not enforce a
626 * rebuild of outliner trees, leading to crashes.
627 *
628 * So for now, add some extra notifiers here. */
631 }
632 return id_override;
633}
634
636 Main *bmain,
637 TemplateID *template_ui,
638 PointerRNA *idptr,
639 const char **r_undo_push_label)
640{
641 ID *id = static_cast<ID *>(idptr->data);
642 ID *owner_id = template_ui->ptr.owner_id;
643
645 C, bmain, owner_id, id, r_undo_push_label);
646
647 if (id_override != nullptr) {
648 /* `idptr` is re-assigned to owner property to ensure proper updates etc. Here we also use it
649 * to ensure remapping of the owner property from the linked data to the newly created
650 * liboverride (note that in theory this remapping has already been done by code above), but
651 * only in case owner ID was already local ID (override or pure local data).
652 *
653 * Otherwise, owner ID will also have been overridden, and remapped already to use it's
654 * override of the data too. */
655 if (!ID_IS_LINKED(owner_id)) {
656 *idptr = RNA_id_pointer_create(id_override);
657 }
658 }
659 else {
660 WM_global_reportf(RPT_ERROR, "The data-block %s could not be overridden", id->name);
661 }
662}
663
664static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
665{
666 TemplateID *template_ui = (TemplateID *)arg_litem;
667 PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
668 ID *id = static_cast<ID *>(idptr.data);
669 const int event = POINTER_AS_INT(arg_event);
670 const char *undo_push_label = nullptr;
671
672 switch (event) {
673 case UI_ID_NOP:
674 /* Don't do anything, typically set for buttons that execute an operator instead. They may
675 * still assign the callback so the button can be identified as part of an ID-template. See
676 * #UI_context_active_but_prop_get_templateID(). */
677 break;
678 case UI_ID_RENAME:
679 /* Only for the undo push. */
680 undo_push_label = "Rename Data-Block";
681 break;
682 case UI_ID_BROWSE:
683 case UI_ID_PIN:
684 RNA_warning("warning, id event %d shouldn't come here", event);
685 break;
686 case UI_ID_OPEN:
687 case UI_ID_ADD_NEW:
688 /* these call UI_context_active_but_prop_get_templateID */
689 break;
690 case UI_ID_DELETE:
691 idptr = {};
692 RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, nullptr);
693 RNA_property_update(C, &template_ui->ptr, template_ui->prop);
694
695 if (id && CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
696 /* only way to force-remove data (on save) */
699 id->us = 0;
700 undo_push_label = "Delete Data-Block";
701 }
702 else {
703 undo_push_label = "Unlink Data-Block";
704 }
705
706 break;
707 case UI_ID_FAKE_USER:
708 if (id) {
709 if (id->flag & ID_FLAG_FAKEUSER) {
710 id_us_plus(id);
711 }
712 else {
713 id_us_min(id);
714 }
715 undo_push_label = "Fake User";
716 }
717 else {
718 return;
719 }
720 break;
721 case UI_ID_LOCAL:
722 if (id) {
723 Main *bmain = CTX_data_main(C);
724 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
725 template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label);
726 }
727 else {
730
731 /* Reassign to get proper updates/notifiers. */
732 idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
733 undo_push_label = "Make Local";
734 }
735 }
736 if (undo_push_label != nullptr) {
737 RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, nullptr);
738 RNA_property_update(C, &template_ui->ptr, template_ui->prop);
739 }
740 }
741 break;
742 case UI_ID_OVERRIDE:
743 if (id && ID_IS_OVERRIDE_LIBRARY(id)) {
744 Main *bmain = CTX_data_main(C);
745 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
746 template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label);
747 }
748 else {
750 /* Reassign to get proper updates/notifiers. */
751 idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
752 RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, nullptr);
753 RNA_property_update(C, &template_ui->ptr, template_ui->prop);
754 undo_push_label = "Make Local";
755 }
756 }
757 break;
758 case UI_ID_ALONE:
759 if (id) {
760 const bool do_scene_obj = ((GS(id->name) == ID_OB) &&
761 (template_ui->ptr.type == &RNA_LayerObjects));
762
763 /* make copy */
764 if (do_scene_obj) {
765 Main *bmain = CTX_data_main(C);
766 Scene *scene = CTX_data_scene(C);
770 }
771 else {
772 Main *bmain = CTX_data_main(C);
773 id_single_user(C, id, &template_ui->ptr, template_ui->prop);
776 }
778 undo_push_label = "Make Single User";
779 }
780 break;
781#if 0
782 case UI_ID_AUTO_NAME:
783 break;
784#endif
785 }
786
787 if (undo_push_label != nullptr) {
788 ED_undo_push(C, undo_push_label);
790 }
791}
792
794{
795 if (type) {
796 switch ((ID_Type)RNA_type_to_ID_code(type)) {
797 case ID_SCE:
798 return N_("Browse Scene to be linked");
799 case ID_OB:
800 return N_("Browse Object to be linked");
801 case ID_ME:
802 return N_("Browse Mesh Data to be linked");
803 case ID_CU_LEGACY:
804 return N_("Browse Curve Data to be linked");
805 case ID_MB:
806 return N_("Browse Metaball Data to be linked");
807 case ID_MA:
808 return N_("Browse Material to be linked");
809 case ID_TE:
810 return N_("Browse Texture to be linked");
811 case ID_IM:
812 return N_("Browse Image to be linked");
813 case ID_LS:
814 return N_("Browse Line Style Data to be linked");
815 case ID_LT:
816 return N_("Browse Lattice Data to be linked");
817 case ID_LA:
818 return N_("Browse Light Data to be linked");
819 case ID_CA:
820 return N_("Browse Camera Data to be linked");
821 case ID_WO:
822 return N_("Browse World Settings to be linked");
823 case ID_SCR:
824 return N_("Choose Screen layout");
825 case ID_TXT:
826 return N_("Browse Text to be linked");
827 case ID_SPK:
828 return N_("Browse Speaker Data to be linked");
829 case ID_SO:
830 return N_("Browse Sound to be linked");
831 case ID_AR:
832 return N_("Browse Armature data to be linked");
833 case ID_AC:
834 return N_("Browse Action to be linked");
835 case ID_NT:
836 return N_("Browse Node Tree to be linked");
837 case ID_BR:
838 return N_("Browse Brush to be linked");
839 case ID_PA:
840 return N_("Browse Particle Settings to be linked");
841 case ID_GD_LEGACY:
842 return N_("Browse Grease Pencil Data to be linked");
843 case ID_MC:
844 return N_("Browse Movie Clip to be linked");
845 case ID_MSK:
846 return N_("Browse Mask to be linked");
847 case ID_PAL:
848 return N_("Browse Palette Data to be linked");
849 case ID_PC:
850 return N_("Browse Paint Curve Data to be linked");
851 case ID_CF:
852 return N_("Browse Cache Files to be linked");
853 case ID_WS:
854 return N_("Browse Workspace to be linked");
855 case ID_LP:
856 return N_("Browse LightProbe to be linked");
857 case ID_CV:
858 return N_("Browse Curves Data to be linked");
859 case ID_PT:
860 return N_("Browse Point Cloud Data to be linked");
861 case ID_VO:
862 return N_("Browse Volume Data to be linked");
863 case ID_GP:
864 return N_("Browse Grease Pencil Data to be linked");
865
866 /* Use generic text. */
867 case ID_LI:
868 case ID_IP:
869 case ID_KE:
870 case ID_VF:
871 case ID_GR:
872 case ID_WM:
873 break;
874 }
875 }
876 return N_("Browse ID data to be linked");
877}
878
884static void template_id_workspace_pin_extra_icon(const TemplateID &template_ui, uiBut *but)
885{
886 if ((template_ui.idcode != ID_SCE) || (template_ui.ptr.type != &RNA_Window)) {
887 return;
888 }
889
890 const wmWindow *win = static_cast<const wmWindow *>(template_ui.ptr.data);
891 const WorkSpace *workspace = WM_window_get_active_workspace(win);
893 "WORKSPACE_OT_scene_pin_toggle",
895 (workspace->flags & WORKSPACE_USE_PIN_SCENE) ? ICON_PINNED :
896 ICON_UNPINNED);
897}
898
903#ifdef WITH_INTERNATIONAL
904static const char *template_id_context(StructRNA *type)
905{
906 if (type) {
908 }
910}
911#else
912# define template_id_context(type) 0
913#endif
914
916 const ID *id,
917 const TemplateID &template_ui,
918 StructRNA *type,
919 const char *const newop,
920 const bool editable,
921 const bool id_open,
922 const bool use_tab_but,
923 int but_height)
924{
925 ID *idfrom = template_ui.ptr.owner_id;
926 uiBut *but;
927 const int but_type = use_tab_but ? UI_BTYPE_TAB : UI_BTYPE_BUT;
928
929 /* i18n markup, does nothing! */
964 /* NOTE: BLT_I18N_MSGID_MULTI_CTXT takes a maximum number of parameters,
965 * check the definition to see if a new call must be added when the limit
966 * is exceeded. */
967
968 const char *button_text = (id) ? "" : CTX_IFACE_(template_id_context(type), "New");
969 const int icon = (id && !use_tab_but) ? ICON_DUPLICATE : ICON_ADD;
970 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
971
972 int w = id ? UI_UNIT_X : id_open ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
973 if (!id) {
974 w = std::max(UI_fontstyle_string_width(fstyle, button_text) + int(UI_UNIT_X * 1.5f), w);
975 }
976
977 if (newop) {
978 but = uiDefIconTextButO(block,
979 but_type,
980 newop,
982 icon,
983 button_text,
984 0,
985 0,
986 w,
987 but_height,
988 std::nullopt);
991 MEM_new<TemplateID>(__func__, template_ui),
995 }
996 else {
997 but = uiDefIconTextBut(
998 block, but_type, 0, icon, button_text, 0, 0, w, but_height, nullptr, 0, 0, std::nullopt);
1001 MEM_new<TemplateID>(__func__, template_ui),
1005 }
1006
1007 if ((idfrom && !ID_IS_EDITABLE(idfrom)) || !editable) {
1009 }
1010
1011#ifndef WITH_INTERNATIONAL
1012 UNUSED_VARS(type);
1013#endif
1014
1015 return but;
1016}
1017
1018static void template_ID(const bContext *C,
1019 uiLayout *layout,
1020 TemplateID &template_ui,
1021 StructRNA *type,
1022 int flag,
1023 const char *newop,
1024 const char *openop,
1025 const char *unlinkop,
1026 const std::optional<StringRef> text,
1027 const bool live_icon,
1028 const bool hide_buttons)
1029{
1030 uiBut *but;
1031 const bool editable = RNA_property_editable(&template_ui.ptr, template_ui.prop);
1032 const bool use_previews = template_ui.preview = (flag & UI_ID_PREVIEWS) != 0;
1033
1034 PointerRNA idptr = RNA_property_pointer_get(&template_ui.ptr, template_ui.prop);
1035 ID *id = static_cast<ID *>(idptr.data);
1036 ID *idfrom = template_ui.ptr.owner_id;
1037 // lb = template_ui->idlb;
1038
1039 /* Allow operators to take the ID from context. */
1040 uiLayoutSetContextPointer(layout, "id", &idptr);
1041
1042 uiBlock *block = uiLayoutGetBlock(layout);
1043 UI_block_align_begin(block);
1044
1045 if (idptr.type) {
1046 type = idptr.type;
1047 }
1048
1049 if (text && !text->is_empty()) {
1050 /* Add label respecting the separated layout property split state. */
1051 uiItemL_respect_property_split(layout, *text, ICON_NONE);
1052 }
1053
1054 if (flag & UI_ID_BROWSE) {
1056 layout,
1057 block,
1058 &template_ui.ptr,
1059 template_ui.prop,
1061 MEM_new<TemplateID>(__func__, template_ui),
1063 use_previews,
1064 editable,
1065 live_icon,
1068 }
1069
1070 /* text button with name */
1071 if (id) {
1072 char name[UI_MAX_NAME_STR];
1073 const bool user_alert = (id->us <= 0);
1074
1075 int width = template_search_textbut_width(&idptr, RNA_struct_find_property(&idptr, "name"));
1076
1077 if ((template_ui.idcode == ID_SCE) && (template_ui.ptr.type == &RNA_Window)) {
1078 /* More room needed for "pin" icon. */
1079 width += UI_UNIT_X;
1080 }
1081
1082 const int height = template_search_textbut_height();
1083
1084 // text_idbutton(id, name);
1085 name[0] = '\0';
1086 but = uiDefButR(block,
1088 0,
1089 name,
1090 0,
1091 0,
1092 width,
1093 height,
1094 &idptr,
1095 "name",
1096 -1,
1097 0,
1098 0,
1100 /* Handle undo through the #template_id_cb set below. Default undo handling from the button
1101 * code (see #ui_apply_but_undo) would not work here, as the new name is not yet applied to the
1102 * ID. */
1104 Main *bmain = CTX_data_main(C);
1106 but, [bmain, id](std::string &new_name) { ED_id_rename(*bmain, *id, new_name); });
1107 UI_but_funcN_set(but,
1109 MEM_new<TemplateID>(__func__, template_ui),
1113 if (user_alert) {
1115 }
1116
1117 template_id_workspace_pin_extra_icon(template_ui, but);
1118
1119 if (!hide_buttons && !(idfrom && ID_IS_LINKED(idfrom))) {
1120 if (ID_IS_LINKED(id)) {
1121 const bool disabled = !BKE_idtype_idcode_is_localizable(GS(id->name));
1122 if (id->tag & ID_TAG_INDIRECT) {
1123 but = uiDefIconBut(block,
1125 0,
1126 ICON_LIBRARY_DATA_INDIRECT,
1127 0,
1128 0,
1129 UI_UNIT_X,
1130 UI_UNIT_Y,
1131 nullptr,
1132 0,
1133 0,
1134 TIP_("Indirect library data-block, cannot be made local, "
1135 "Shift + Click to create a library override hierarchy"));
1136 }
1137 else {
1138 but = uiDefIconBut(block,
1140 0,
1141 ICON_LIBRARY_DATA_DIRECT,
1142 0,
1143 0,
1144 UI_UNIT_X,
1145 UI_UNIT_Y,
1146 nullptr,
1147 0,
1148 0,
1149 TIP_("Direct linked library data-block, click to make local, "
1150 "Shift + Click to create a library override"));
1151 }
1152 if (disabled) {
1154 }
1155 else {
1156 UI_but_funcN_set(but,
1158 MEM_new<TemplateID>(__func__, template_ui),
1162 }
1163 }
1164 else if (ID_IS_OVERRIDE_LIBRARY(id)) {
1165 but = uiDefIconBut(
1166 block,
1168 0,
1169 ICON_LIBRARY_DATA_OVERRIDE,
1170 0,
1171 0,
1172 UI_UNIT_X,
1173 UI_UNIT_Y,
1174 nullptr,
1175 0,
1176 0,
1177 TIP_("Library override of linked data-block, click to make fully local, "
1178 "Shift + Click to clear the library override and toggle if it can be edited"));
1179 UI_but_funcN_set(but,
1181 MEM_new<TemplateID>(__func__, template_ui),
1185 }
1186 }
1187
1188 if ((ID_REAL_USERS(id) > 1) && (hide_buttons == false)) {
1189 char numstr[32];
1190 short numstr_len;
1191
1192 numstr_len = SNPRINTF_RLEN(numstr, "%d", ID_REAL_USERS(id));
1193
1194 but = uiDefBut(
1195 block,
1197 0,
1198 numstr,
1199 0,
1200 0,
1201 numstr_len * 0.2f * UI_UNIT_X + UI_UNIT_X,
1202 UI_UNIT_Y,
1203 nullptr,
1204 0,
1205 0,
1206 TIP_("Display number of users of this data (click to make a single-user copy)"));
1207 but->flag |= UI_BUT_UNDO;
1208
1209 UI_but_funcN_set(but,
1211 MEM_new<TemplateID>(__func__, template_ui),
1215 if (!BKE_id_copy_is_allowed(id) || (idfrom && !ID_IS_EDITABLE(idfrom)) || (!editable) ||
1216 /* object in editmode - don't change data */
1217 (idfrom && GS(idfrom->name) == ID_OB && (((Object *)idfrom)->mode & OB_MODE_EDIT)))
1218 {
1220 }
1221 }
1222
1223 if (user_alert) {
1225 }
1226
1227 if (!ID_IS_LINKED(id)) {
1228 if (ID_IS_ASSET(id)) {
1229 uiDefIconButO(block,
1230 /* Using `_N` version allows us to get the 'active' state by default. */
1232 "ASSET_OT_clear_single",
1234 /* 'active' state of a toggle button uses icon + 1, so to get proper asset
1235 * icon we need to pass its value - 1 here. */
1236 ICON_ASSET_MANAGER - 1,
1237 0,
1238 0,
1239 UI_UNIT_X,
1240 UI_UNIT_Y,
1241 std::nullopt);
1242 }
1243 else if (!ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_OB, ID_WS) && (hide_buttons == false))
1244 {
1245 uiDefIconButR(block,
1247 0,
1248 ICON_FAKE_USER_OFF,
1249 0,
1250 0,
1251 UI_UNIT_X,
1252 UI_UNIT_Y,
1253 &idptr,
1254 "use_fake_user",
1255 -1,
1256 0,
1257 0,
1258 std::nullopt);
1259 }
1260 }
1261 }
1262
1263 if ((flag & UI_ID_ADD_NEW) && (hide_buttons == false)) {
1265 block, id, template_ui, type, newop, editable, flag & UI_ID_OPEN, false, UI_UNIT_X);
1266 }
1267
1268 /* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack.
1269 * Only for images, sound and fonts */
1270 if (id && BKE_packedfile_id_check(id)) {
1271 but = uiDefIconButO(block,
1273 "FILE_OT_unpack_item",
1275 ICON_PACKAGE,
1276 0,
1277 0,
1278 UI_UNIT_X,
1279 UI_UNIT_Y,
1280 TIP_("Packed File, click to unpack"));
1282
1283 RNA_string_set(but->opptr, "id_name", id->name + 2);
1284 RNA_int_set(but->opptr, "id_type", GS(id->name));
1285
1286 if (!ID_IS_EDITABLE(id)) {
1288 }
1289 }
1290 else if (flag & UI_ID_OPEN) {
1291 const char *button_text = (id) ? "" : IFACE_("Open");
1292 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
1293
1294 int w = id ? UI_UNIT_X : (flag & UI_ID_ADD_NEW) ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
1295 if (!id) {
1296 w = std::max(UI_fontstyle_string_width(fstyle, button_text) + int(UI_UNIT_X * 1.5f), w);
1297 }
1298
1299 if (openop) {
1300 but = uiDefIconTextButO(block,
1302 openop,
1304 ICON_FILEBROWSER,
1305 (id) ? "" : IFACE_("Open"),
1306 0,
1307 0,
1308 w,
1309 UI_UNIT_Y,
1310 std::nullopt);
1311 UI_but_funcN_set(but,
1313 MEM_new<TemplateID>(__func__, template_ui),
1317 }
1318 else {
1319 but = uiDefIconTextBut(block,
1321 0,
1322 ICON_FILEBROWSER,
1323 (id) ? "" : IFACE_("Open"),
1324 0,
1325 0,
1326 w,
1327 UI_UNIT_Y,
1328 nullptr,
1329 0,
1330 0,
1331 std::nullopt);
1332 UI_but_funcN_set(but,
1334 MEM_new<TemplateID>(__func__, template_ui),
1338 }
1339
1340 if ((idfrom && !ID_IS_EDITABLE(idfrom)) || !editable) {
1342 }
1343 }
1344
1345 /* delete button */
1346 /* don't use RNA_property_is_unlink here */
1347 if (id && (flag & UI_ID_DELETE) && (hide_buttons == false)) {
1348 /* allow unlink if 'unlinkop' is passed, even when 'PROP_NEVER_UNLINK' is set */
1349 but = nullptr;
1350
1351 if (unlinkop) {
1352 but = uiDefIconButO(block,
1354 unlinkop,
1356 ICON_X,
1357 0,
1358 0,
1359 UI_UNIT_X,
1360 UI_UNIT_Y,
1361 std::nullopt);
1362 /* so we can access the template from operators, font unlinking needs this */
1363 UI_but_funcN_set(but,
1365 MEM_new<TemplateID>(__func__, template_ui),
1369 }
1370 else {
1371 if ((RNA_property_flag(template_ui.prop) & PROP_NEVER_UNLINK) == 0) {
1372 but = uiDefIconBut(
1373 block,
1375 0,
1376 ICON_X,
1377 0,
1378 0,
1379 UI_UNIT_X,
1380 UI_UNIT_Y,
1381 nullptr,
1382 0,
1383 0,
1384 TIP_("Unlink data-block "
1385 "(Shift + Click to set users to zero, data will then not be saved)"));
1386 UI_but_funcN_set(but,
1388 MEM_new<TemplateID>(__func__, template_ui),
1392
1393 if (RNA_property_flag(template_ui.prop) & PROP_NEVER_NULL) {
1395 }
1396 }
1397 }
1398
1399 if (but) {
1400 if ((idfrom && !ID_IS_EDITABLE(idfrom)) || !editable) {
1402 }
1403 }
1404 }
1405
1406 if (template_ui.idcode == ID_TE) {
1407 uiTemplateTextureShow(layout, C, &template_ui.ptr, template_ui.prop);
1408 }
1409 UI_block_align_end(block);
1410}
1411
1413{
1415
1416 if (but && but->type == UI_BTYPE_TAB) {
1417 return static_cast<ID *>(but->custom_data);
1418 }
1419 return nullptr;
1420}
1421
1422static void template_ID_tabs(const bContext *C,
1423 uiLayout *layout,
1424 TemplateID &template_id,
1425 StructRNA *type,
1426 int flag,
1427 const char *newop,
1428 const char *menu)
1429{
1430 const ARegion *region = CTX_wm_region(C);
1431 const PointerRNA active_ptr = RNA_property_pointer_get(&template_id.ptr, template_id.prop);
1432 MenuType *mt = menu ? WM_menutype_find(menu, false) : nullptr;
1433
1434 const int but_align = ui_but_align_opposite_to_area_align_get(region);
1435 const int but_height = UI_UNIT_Y * 1.1;
1436
1437 uiBlock *block = uiLayoutGetBlock(layout);
1438 const uiStyle *style = UI_style_get_dpi();
1439
1440 for (ID *id : BKE_id_ordered_list(template_id.idlb)) {
1441 const int name_width = UI_fontstyle_string_width(&style->widget, id->name + 2);
1442 const int but_width = name_width + UI_UNIT_X;
1443
1444 uiButTab *tab = (uiButTab *)uiDefButR_prop(block,
1446 0,
1447 id->name + 2,
1448 0,
1449 0,
1450 but_width,
1451 but_height,
1452 &template_id.ptr,
1453 template_id.prop,
1454 0,
1455 0.0f,
1456 sizeof(id->name) - 2,
1457 "");
1458 UI_but_funcN_set(tab,
1460 MEM_new<TemplateID>(__func__, template_id),
1461 id,
1464 UI_but_drag_set_id(tab, id);
1465 tab->custom_data = (void *)id;
1466 tab->menu = mt;
1467
1468 UI_but_drawflag_enable(tab, but_align);
1469 }
1470
1471 if (flag & UI_ID_ADD_NEW) {
1472 const bool editable = RNA_property_editable(&template_id.ptr, template_id.prop);
1473 uiBut *but;
1474
1475 if (active_ptr.type) {
1476 type = active_ptr.type;
1477 }
1478
1479 but = template_id_def_new_but(block,
1480 static_cast<const ID *>(active_ptr.data),
1481 template_id,
1482 type,
1483 newop,
1484 editable,
1485 flag & UI_ID_OPEN,
1486 true,
1487 but_height);
1488 UI_but_drawflag_enable(but, but_align);
1489 }
1490}
1491
1492static void ui_template_id(uiLayout *layout,
1493 const bContext *C,
1494 PointerRNA *ptr,
1495 const StringRefNull propname,
1496 const char *newop,
1497 const char *openop,
1498 const char *unlinkop,
1499 /* Only respected by tabs (use_tabs). */
1500 const char *menu,
1501 const std::optional<StringRef> text,
1502 int flag,
1503 int prv_rows,
1504 int prv_cols,
1505 int filter,
1506 bool use_tabs,
1507 float scale,
1508 const bool live_icon,
1509 const bool hide_buttons)
1510{
1511 PropertyRNA *prop = RNA_struct_find_property(ptr, propname.c_str());
1512
1513 if (!prop || RNA_property_type(prop) != PROP_POINTER) {
1515 "pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
1516 return;
1517 }
1518
1519 TemplateID template_ui = {};
1520 template_ui.ptr = *ptr;
1521 template_ui.prop = prop;
1522 template_ui.prv_rows = prv_rows;
1523 template_ui.prv_cols = prv_cols;
1524 template_ui.scale = scale;
1525
1526 if ((flag & UI_ID_PIN) == 0) {
1527 template_ui.filter = filter;
1528 }
1529 else {
1530 template_ui.filter = 0;
1531 }
1532
1533 if (newop) {
1535 }
1536 if (openop) {
1537 flag |= UI_ID_OPEN;
1538 }
1539
1541 short idcode = RNA_type_to_ID_code(type);
1542 template_ui.idcode = idcode;
1543 template_ui.idlb = which_libbase(CTX_data_main(C), idcode);
1544
1545 /* create UI elements for this template
1546 * - template_ID makes a copy of the template data and assigns it to the relevant buttons
1547 */
1548 if (template_ui.idlb) {
1549 if (use_tabs) {
1550 layout = &layout->row(true);
1551 template_ID_tabs(C, layout, template_ui, type, flag, newop, menu);
1552 }
1553 else {
1554 layout = &layout->row(true);
1555 template_ID(C,
1556 layout,
1557 template_ui,
1558 type,
1559 flag,
1560 newop,
1561 openop,
1562 unlinkop,
1563 text,
1564 live_icon,
1565 hide_buttons);
1566 }
1567 }
1568}
1569
1571 const bContext *C,
1572 PointerRNA *ptr,
1573 const StringRefNull propname,
1574 const char *newop,
1575 const char *openop,
1576 const char *unlinkop,
1577 int filter,
1578 const bool live_icon,
1579 const std::optional<StringRef> text)
1580{
1581 ui_template_id(layout,
1582 C,
1583 ptr,
1584 propname,
1585 newop,
1586 openop,
1587 unlinkop,
1588 nullptr,
1589 text,
1591 0,
1592 0,
1593 filter,
1594 false,
1595 1.0f,
1596 live_icon,
1597 false);
1598}
1599
1601 const bContext *C,
1602 ID *id,
1603 const char *newop,
1604 const char *unlinkop,
1605 const std::optional<StringRef> text)
1606{
1607 if (!id_can_have_animdata(id)) {
1608 RNA_warning("Cannot show Action selector for non-animatable ID: %s", id->name + 2);
1609 return;
1610 }
1611
1612 PropertyRNA *adt_action_prop = RNA_struct_type_find_property(&RNA_AnimData, "action");
1613 BLI_assert(adt_action_prop);
1614 BLI_assert(RNA_property_type(adt_action_prop) == PROP_POINTER);
1615
1616 /* Construct a pointer with the animated ID as owner, even when `adt` may be `nullptr`.
1617 * This way it is possible to use this RNA pointer to get/set `adt->action`, as that RNA property
1618 * has a `getter` & `setter` that only need the owner ID and are null-safe regarding the `adt`
1619 * itself.
1620 * FIXME: This is a very dirty hack, would be good to find a way to not rely on typed-but-null
1621 * PointerRNA.
1622 */
1623 AnimData *adt = BKE_animdata_from_id(id);
1624 PointerRNA adt_ptr = PointerRNA{id, &RNA_AnimData, adt, RNA_id_pointer_create(id)};
1625
1626 TemplateID template_ui = {};
1627 template_ui.ptr = adt_ptr;
1628 template_ui.prop = adt_action_prop;
1629 template_ui.prv_rows = 0;
1630 template_ui.prv_cols = 0;
1631 template_ui.scale = 1.0f;
1632 template_ui.filter = UI_TEMPLATE_ID_FILTER_ALL;
1633
1635 if (newop) {
1637 }
1638
1639 template_ui.idcode = ID_AC;
1640 template_ui.idlb = which_libbase(CTX_data_main(C), ID_AC);
1641 BLI_assert(template_ui.idlb);
1642
1643 uiLayout *row = &layout->row(true);
1645 C, row, template_ui, &RNA_Action, flag, newop, nullptr, unlinkop, text, false, false);
1646}
1647
1649 bContext *C,
1650 PointerRNA *ptr,
1651 const StringRefNull propname,
1652 const char *newop,
1653 const char *openop,
1654 const char *unlinkop,
1655 int filter,
1656 const char *text)
1657{
1658 ui_template_id(layout,
1659 C,
1660 ptr,
1661 propname,
1662 newop,
1663 openop,
1664 unlinkop,
1665 nullptr,
1666 text,
1668 0,
1669 0,
1670 filter,
1671 false,
1672 1.0f,
1673 false,
1674 false);
1675}
1676
1678 bContext *C,
1679 PointerRNA *ptr,
1680 const StringRefNull propname,
1681 const char *newop,
1682 const char *openop,
1683 const char *unlinkop,
1684 int rows,
1685 int cols,
1686 int filter,
1687 const bool hide_buttons)
1688{
1689 ui_template_id(layout,
1690 C,
1691 ptr,
1692 propname,
1693 newop,
1694 openop,
1695 unlinkop,
1696 nullptr,
1697 nullptr,
1699 rows,
1700 cols,
1701 filter,
1702 false,
1703 1.0f,
1704 false,
1705 hide_buttons);
1706}
1707
1709 bContext *C,
1710 PointerRNA *ptr,
1711 const StringRefNull propname,
1712 int rows,
1713 int cols,
1714 float scale,
1715 int filter)
1716{
1717 ui_template_id(layout,
1718 C,
1719 ptr,
1720 propname,
1721 nullptr,
1722 nullptr,
1723 nullptr,
1724 nullptr,
1725 nullptr,
1727 rows,
1728 cols,
1729 filter,
1730 false,
1731 scale < 0.5f ? 0.5f : scale,
1732 false,
1733 false);
1734}
1735
1737 bContext *C,
1738 PointerRNA *ptr,
1739 const StringRefNull propname,
1740 const char *newop,
1741 const char *menu,
1742 int filter)
1743{
1744 ui_template_id(layout,
1745 C,
1746 ptr,
1747 propname,
1748 newop,
1749 nullptr,
1750 nullptr,
1751 menu,
1752 nullptr,
1754 0,
1755 0,
1756 filter,
1757 true,
1758 1.0f,
1759 false,
1760 false);
1761}
1762
1764 PointerRNA *ptr,
1765 const StringRefNull propname,
1766 const StringRefNull proptypename,
1767 const std::optional<StringRef> text)
1768{
1769 /* get properties... */
1770 PropertyRNA *propID = RNA_struct_find_property(ptr, propname.c_str());
1771 PropertyRNA *propType = RNA_struct_find_property(ptr, proptypename.c_str());
1772
1773 if (!propID || RNA_property_type(propID) != PROP_POINTER) {
1775 "pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
1776 return;
1777 }
1778 if (!propType || RNA_property_type(propType) != PROP_ENUM) {
1779 RNA_warning("pointer-type property not found: %s.%s",
1781 proptypename.c_str());
1782 return;
1783 }
1784
1785 /* Start drawing UI Elements using standard defines */
1786
1787 /* NOTE: split amount here needs to be synced with normal labels */
1788 uiLayout *split = &layout->split(0.33f, false);
1789
1790 /* FIRST PART ................................................ */
1791 uiLayout *row = &split->row(false);
1792
1793 /* Label - either use the provided text, or will become "ID-Block:" */
1794 if (text) {
1795 if (!text->is_empty()) {
1796 row->label(*text, ICON_NONE);
1797 }
1798 }
1799 else {
1800 row->label(IFACE_("ID-Block:"), ICON_NONE);
1801 }
1802
1803 /* SECOND PART ................................................ */
1804 row = &split->row(true);
1805
1806 /* ID-Type Selector - just have a menu of icons */
1807
1808 /* HACK: special group just for the enum,
1809 * otherwise we get ugly layout with text included too... */
1810 uiLayout *sub = &row->row(true);
1812
1813 sub->prop(ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
1814
1815 /* ID-Block Selector - just use pointer widget... */
1816
1817 /* HACK: special group to counteract the effects of the previous enum,
1818 * which now pushes everything too far right. */
1819 sub = &row->row(true);
1821
1822 sub->prop(ptr, propID, 0, 0, UI_ITEM_NONE, "", ICON_NONE);
1823}
bool id_can_have_animdata(const ID *id)
Definition anim_data.cc:72
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:82
bool BKE_collection_has_object_recursive(Collection *collection, Object *ob)
#define FOREACH_SCENE_OBJECT_END
bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, bool free_us)
bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child)
#define FOREACH_SCENE_OBJECT_BEGIN(scene, _instance)
bool BKE_collection_has_collection(const Collection *parent, const Collection *collection)
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
wmWindow * CTX_wm_window(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
Collection * CTX_data_collection(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
const char * BKE_idtype_idcode_to_translation_context(short idcode)
Definition idtype.cc:179
#define BKE_idtype_idcode_is_localizable
bool BKE_scene_has_object(Scene *scene, Object *ob)
void BKE_id_newptr_and_tag_clear(ID *id)
Definition lib_id.cc:407
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
Definition lib_id.cc:1058
void id_us_plus(ID *id)
Definition lib_id.cc:353
bool BKE_id_copy_is_allowed(const ID *id)
Definition lib_id.cc:654
#define MAX_ID_FULL_NAME_UI
void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const ID *id, bool add_lib_hint, char separator_char, int *r_prefix_len)
Definition lib_id.cc:2429
blender::Vector< ID * > BKE_id_ordered_list(const ListBase *lb)
Definition lib_id.cc:2556
bool BKE_lib_id_make_local(Main *bmain, ID *id, int flags)
Definition lib_id.cc:586
void id_fake_user_clear(ID *id)
Definition lib_id.cc:399
void id_us_clear_real(ID *id)
Definition lib_id.cc:326
@ LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR
void id_us_min(ID *id)
Definition lib_id.cc:361
void BKE_main_id_flag_listbase(ListBase *lb, int flag, bool value)
Definition lib_id.cc:1223
void BKE_lib_override_library_id_reset(Main *bmain, ID *id_root, bool do_reset_system_override)
bool BKE_lib_override_library_create(Main *bmain, Scene *scene, ViewLayer *view_layer, Library *owner_library, ID *id_root_reference, ID *id_hierarchy_root_reference, ID *id_instance_hint, ID **r_id_root_override, const bool do_fully_editable)
void BKE_lib_override_library_make_local(Main *bmain, ID *id)
IDOverrideLibrary * BKE_lib_override_library_get(Main *bmain, ID *id, ID *owner_id_hint, ID **r_owner_id)
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:887
void BKE_main_ensure_invariants(Main &bmain, std::optional< blender::Span< ID * > > modified_ids=std::nullopt)
bool BKE_packedfile_id_check(const ID *id)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
#define SNPRINTF_RLEN(dst, format,...)
Definition BLI_string.h:600
#define UNUSED_VARS(...)
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
#define ELEM(...)
#define BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE
#define BLT_I18NCONTEXT_ID_WORLD
#define BLT_I18NCONTEXT_ID_ACTION
#define BLT_I18NCONTEXT_ID_TEXT
#define BLT_I18NCONTEXT_ID_VOLUME
#define BLT_I18NCONTEXT_ID_BRUSH
#define BLT_I18NCONTEXT_ID_NODETREE
#define BLT_I18NCONTEXT_ID_CURVES
#define BLT_I18NCONTEXT_ID_IMAGE
#define BLT_I18NCONTEXT_ID_SPEAKER
#define BLT_I18NCONTEXT_ID_WORKSPACE
#define BLT_I18NCONTEXT_ID_CURVE_LEGACY
#define TIP_(msgid)
#define BLT_I18NCONTEXT_ID_LATTICE
#define BLT_I18NCONTEXT_ID_GPENCIL
#define BLT_I18NCONTEXT_ID_LIGHT
#define BLT_I18NCONTEXT_ID_POINTCLOUD
#define BLT_I18NCONTEXT_ID_METABALL
#define BLT_I18NCONTEXT_ID_SOUND
#define BLT_I18NCONTEXT_ID_PARTICLESETTINGS
#define BLT_I18NCONTEXT_ID_LIGHTPROBE
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_DEFAULT
#define BLT_I18NCONTEXT_ID_SCREEN
#define BLT_I18NCONTEXT_ID_OBJECT
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_ID_PALETTE
#define BLT_I18NCONTEXT_ID_ARMATURE
#define BLT_I18N_MSGID_MULTI_CTXT(msgid,...)
#define BLT_I18NCONTEXT_ID_PAINTCURVE
#define BLT_I18NCONTEXT_ID_SCENE
#define BLT_I18NCONTEXT_ID_MATERIAL
#define BLT_I18NCONTEXT_ID_MESH
#define BLT_I18NCONTEXT_ID_CAMERA
#define BLT_I18NCONTEXT_ID_TEXTURE
#define BLT_I18NCONTEXT_ID_MASK
void DEG_relations_tag_update(Main *bmain)
@ ID_TAG_INDIRECT
Definition DNA_ID.h:756
@ ID_TAG_DOIT
Definition DNA_ID.h:944
@ ID_FLAG_FAKEUSER
Definition DNA_ID.h:682
@ LIBOVERRIDE_FLAG_SYSTEM_DEFINED
Definition DNA_ID.h:353
ID_Type
@ ID_WM
@ ID_CA
@ ID_AR
@ ID_MC
@ ID_CF
@ ID_LI
@ ID_TE
@ ID_IM
@ ID_VO
@ ID_WS
@ ID_NT
@ ID_LA
@ ID_KE
@ ID_TXT
@ ID_SO
@ ID_SCE
@ ID_LS
@ ID_MSK
@ ID_CV
@ ID_PAL
@ ID_BR
@ ID_LP
@ ID_WO
@ ID_MA
@ ID_AC
@ ID_SCR
@ ID_CU_LEGACY
@ ID_GD_LEGACY
@ ID_VF
@ ID_ME
@ ID_IP
@ ID_GR
@ ID_SPK
@ ID_MB
@ ID_LT
@ ID_OB
@ ID_GP
@ ID_PA
@ ID_PT
@ ID_PC
Object groups, one object can be in many groups at once.
@ OB_MODE_EDIT
@ USER_HIDE_DOT
@ WORKSPACE_USE_PIN_SCENE
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:99
static void split(const char *text, const char *seps, char ***str, int *count)
short RNA_type_to_ID_code(const StructRNA *type)
#define RNA_warning(format,...)
@ PROP_ENUM
Definition RNA_types.hh:154
@ PROP_POINTER
Definition RNA_types.hh:155
@ PROP_NEVER_UNLINK
Definition RNA_types.hh:358
@ PROP_NEVER_NULL
Definition RNA_types.hh:351
@ PROP_ID_SELF_CHECK
Definition RNA_types.hh:344
#define C
Definition RandGen.cpp:29
void * but_func_argN_copy(const void *argN)
void but_func_argN_free(void *argN)
void UI_but_flag_disable(uiBut *but, int flag)
#define UI_UNIT_Y
uiBut * uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, std::optional< blender::StringRef > tip)
uiBut * uiDefButR_prop(uiBlock *block, int type, int retval, std::optional< blender::StringRef > str, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, std::optional< blender::StringRef > tip)
void UI_but_func_rename_full_set(uiBut *but, std::function< void(std::string &new_name)> rename_full_func)
#define UI_SEP_CHAR
uiBut * uiDefBut(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, std::optional< blender::StringRef > tip)
const uiStyle * UI_style_get_dpi()
PointerRNA * UI_but_extra_operator_icon_add(uiBut *but, blender::StringRefNull opname, wmOperatorCallContext opcontext, int icon)
uiBut * uiDefIconButR(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, PointerRNA *ptr, blender::StringRefNull propname, int index, float min, float max, std::optional< blender::StringRef > tip)
void UI_but_drawflag_enable(uiBut *but, int flag)
uiBut * UI_context_active_but_get(const bContext *C)
@ UI_ID_BROWSE
@ UI_ID_DELETE
@ UI_ID_ADD_NEW
@ UI_ID_OPEN
@ UI_ID_PIN
@ UI_ID_RENAME
@ UI_ID_NOP
@ UI_ID_PREVIEWS
@ UI_ID_AUTO_NAME
@ UI_ID_OVERRIDE
@ UI_ID_LOCAL
@ UI_ID_FAKE_USER
@ UI_ID_ALONE
bool UI_search_item_add(uiSearchItems *items, blender::StringRef name, void *poin, int iconid, int but_flag, uint8_t name_prefix_offset)
uiBut * uiDefIconButO(uiBlock *block, int type, blender::StringRefNull opname, wmOperatorCallContext opcontext, int icon, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
PointerRNA * UI_but_operator_ptr_ensure(uiBut *but)
uiBut * uiDefIconBut(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, std::optional< blender::StringRef > tip)
void UI_block_align_begin(uiBlock *block)
int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
void uiTemplateTextureShow(uiLayout *layout, const bContext *C, PointerRNA *ptr, PropertyRNA *prop)
#define UI_FSTYLE_WIDGET
#define UI_UNIT_X
@ UI_BTYPE_BUT
@ UI_BTYPE_TAB
@ UI_BTYPE_TEXT
@ UI_BTYPE_ICON_TOGGLE_N
@ UI_BTYPE_ICON_TOGGLE
void UI_but_drag_set_id(uiBut *but, ID *id)
ARegion * UI_tooltip_create_from_search_item_generic(bContext *C, const ARegion *searchbox_region, const rcti *item_rect, ID *id)
@ UI_TEMPLATE_ID_FILTER_AVAILABLE
@ UI_TEMPLATE_ID_FILTER_ALL
@ UI_BUT_REDALERT
@ UI_BUT_UNDO
@ UI_BUT_DISABLED
@ UI_BUT_HAS_SEP_CHAR
uiBut * uiDefButR(uiBlock *block, int type, int retval, std::optional< blender::StringRef > str, int x, int y, short width, short height, PointerRNA *ptr, blender::StringRefNull propname, int index, float min, float max, std::optional< blender::StringRef > tip)
void UI_but_funcN_set(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2, uiButArgNFree func_argN_free_fn=MEM_freeN, uiButArgNCopy func_argN_copy_fn=MEM_dupallocN)
void UI_but_flag_enable(uiBut *but, int flag)
uiBut * uiDefIconTextButO(uiBlock *block, int type, blender::StringRefNull, wmOperatorCallContext opcontext, int icon, blender::StringRef str, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
void UI_block_align_end(uiBlock *block)
int UI_icon_from_library(const ID *id)
void uiLayoutSetContextPointer(uiLayout *layout, blender::StringRef name, PointerRNA *ptr)
@ UI_ITEM_R_ICON_ONLY
uiLayout * uiItemL_respect_property_split(uiLayout *layout, blender::StringRef text, int icon)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
@ UI_LAYOUT_ALIGN_LEFT
@ UI_LAYOUT_ALIGN_EXPAND
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
#define UI_ITEM_NONE
#define UI_MAX_NAME_STR
#define NC_WINDOW
Definition WM_types.hh:372
#define NC_ID
Definition WM_types.hh:392
@ KM_SHIFT
Definition WM_types.hh:275
#define NC_WM
Definition WM_types.hh:371
#define ND_DATACHANGED
Definition WM_types.hh:411
#define ND_LIB_OVERRIDE_CHANGED
Definition WM_types.hh:416
#define NA_ADDED
Definition WM_types.hh:583
#define NA_REMOVED
Definition WM_types.hh:584
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:239
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:238
#define ND_SPACE_VIEW3D
Definition WM_types.hh:525
#define NC_SPACE
Definition WM_types.hh:389
#define ND_SPACE_OUTLINER
Definition WM_types.hh:524
#define U
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
constexpr const char * c_str() const
void add(const StringRef str, T *user_data, const int weight=0)
Vector< T * > query(const StringRef query) const
bool ED_id_rename(Main &bmain, ID &id, blender::StringRefNull name)
#define str(s)
#define active
#define filter
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
#define ID_IS_OVERRIDABLE_LIBRARY(_id)
#define ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(_id)
#define ID_IS_LINKED(_id)
#define ID_IS_ASSET(_id)
#define ID_IS_EDITABLE(_id)
#define ID_REAL_USERS(id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
#define GS(a)
int ui_but_align_opposite_to_area_align_get(const ARegion *region)
int ui_id_icon_get(const bContext *C, ID *id, const bool big)
static void template_id_workspace_pin_extra_icon(const TemplateID &template_ui, uiBut *but)
void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const StringRefNull propname, const StringRefNull proptypename, const std::optional< StringRef > text)
ID * ui_template_id_liboverride_hierarchy_make(bContext *C, Main *bmain, ID *owner_id, ID *id, const char **r_undo_push_label)
void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const StringRefNull propname, const char *newop, const char *openop, const char *unlinkop, int rows, int cols, int filter, const bool hide_buttons)
#define template_id_context(type)
static bool id_search_add(const bContext *C, TemplateID *template_ui, uiSearchItems *items, ID *id)
static void id_search_cb_tagged(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
static void ui_template_id(uiLayout *layout, const bContext *C, PointerRNA *ptr, const StringRefNull propname, const char *newop, const char *openop, const char *unlinkop, const char *menu, const std::optional< StringRef > text, int flag, int prv_rows, int prv_cols, int filter, bool use_tabs, float scale, const bool live_icon, const bool hide_buttons)
static ARegion * template_ID_search_menu_item_tooltip(bContext *C, ARegion *region, const rcti *item_rect, void *, void *active)
static uiBut * template_id_def_new_but(uiBlock *block, const ID *id, const TemplateID &template_ui, StructRNA *type, const char *const newop, const bool editable, const bool id_open, const bool use_tab_but, int but_height)
void uiTemplateAction(uiLayout *layout, const bContext *C, ID *id, const char *newop, const char *unlinkop, const std::optional< StringRef > text)
static void template_ID_tabs(const bContext *C, uiLayout *layout, TemplateID &template_id, StructRNA *type, int flag, const char *newop, const char *menu)
static void id_search_cb_objects_from_scene(const bContext *C, void *arg_template, const char *str, uiSearchItems *items, const bool)
ID * UI_context_active_but_get_tab_ID(bContext *C)
static void template_id_liboverride_hierarchy_collections_tag_recursive(Collection *root_collection, ID *target_id, const bool do_parents)
static void template_ID_set_property_exec_fn(bContext *C, void *arg_template, void *item)
static void template_ID(const bContext *C, uiLayout *layout, TemplateID &template_ui, StructRNA *type, int flag, const char *newop, const char *openop, const char *unlinkop, const std::optional< StringRef > text, const bool live_icon, const bool hide_buttons)
static StringRef template_id_browse_tip(const StructRNA *type)
static bool id_search_allows_id(TemplateID *template_ui, const int flag, ID *id, const char *query)
void uiTemplateIDTabs(uiLayout *layout, bContext *C, PointerRNA *ptr, const StringRefNull propname, const char *newop, const char *menu, int filter)
void UI_context_active_but_prop_get_templateID(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop)
static uiBlock * id_search_menu(bContext *C, ARegion *region, void *arg_litem)
static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
void uiTemplateGpencilColorPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const StringRefNull propname, int rows, int cols, float scale, int filter)
void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, const StringRefNull propname, const char *newop, const char *openop, const char *unlinkop, int filter, const char *text)
void uiTemplateID(uiLayout *layout, const bContext *C, PointerRNA *ptr, const StringRefNull propname, const char *newop, const char *openop, const char *unlinkop, int filter, const bool live_icon, const std::optional< StringRef > text)
static void template_id_liboverride_hierarchy_make(bContext *C, Main *bmain, TemplateID *template_ui, PointerRNA *idptr, const char **r_undo_push_label)
static void id_search_cb(const bContext *C, void *arg_template, const char *str, uiSearchItems *items, const bool)
static void template_id_liboverride_hierarchy_collection_root_find_recursive(Collection *collection, const int parent_level, Collection **r_collection_parent_best, int *r_parent_level_best)
void template_add_button_search_menu(const bContext *C, uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, uiBlockCreateFunc block_func, void *block_argN, const std::optional< blender::StringRef > tip, const bool use_previews, const bool editable, const bool live_icon, uiButArgNFree func_argN_free_fn, uiButArgNCopy func_argN_copy_fn)
int template_search_textbut_height()
int template_search_textbut_width(PointerRNA *ptr, PropertyRNA *name_prop)
uiBlock * template_common_search_menu(const bContext *C, ARegion *region, uiButSearchUpdateFn search_update_fn, void *search_arg, uiButHandleFunc search_exec_fn, void *active_item, uiButSearchTooltipFn item_tooltip_fn, const int preview_rows, const int preview_cols, float scale)
void object_single_user_make(Main *bmain, Scene *scene, Object *ob)
PropertyRNA * RNA_struct_type_find_property(StructRNA *srna, const char *identifier)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
StructRNA * RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
PropertyType RNA_property_type(PropertyRNA *prop)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_struct_identifier(const StructRNA *type)
bool RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *value)
int RNA_property_flag(PropertyRNA *prop)
const char * RNA_struct_ui_description(const StructRNA *type)
bool RNA_property_editable(const PointerRNA *ptr, PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
struct CollectionChild * next
struct CollectionParent * next
Collection_Runtime runtime
unsigned int flag
Definition DNA_ID.h:338
struct ID * hierarchy_root
Definition DNA_ID.h:334
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
struct Library * lib
Definition DNA_ID.h:410
IDOverrideLibrary * override_library
Definition DNA_ID.h:459
short flag
Definition DNA_ID.h:420
char name[66]
Definition DNA_ID.h:415
void * first
ListBase collections
Definition BKE_main.hh:267
ustring name
Definition graph/node.h:177
struct Collection * instance_collection
ID * owner_id
Definition RNA_types.hh:51
StructRNA * type
Definition RNA_types.hh:52
void * data
Definition RNA_types.hh:53
struct Collection * master_collection
PropertyRNA * prop
MenuType * menu
void * custom_data
uiButHandleNFunc funcN
eButType type
PointerRNA * opptr
void * func_argN
void label(blender::StringRef name, int icon)
uiLayout & row(bool align)
uiLayout & split(float percentage, 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
#define N_(msgid)
void WM_global_reportf(eReportType type, const char *format,...)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4227
MenuType * WM_menutype_find(const StringRef idname, bool quiet)
WorkSpace * WM_window_get_active_workspace(const wmWindow *win)
uint8_t flag
Definition wm_window.cc:139