Blender V5.0
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_search.hh"
23#include "BLI_string_utf8.h"
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
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 =
302 static_cast<CollectionParent *>(collection->runtime->parents.first);
303 iter != nullptr;
304 iter = iter->next)
305 {
306 if (iter->collection->id.lib != collection->id.lib && ID_IS_LINKED(iter->collection)) {
307 continue;
308 }
310 iter->collection, parent_level + 1, r_collection_parent_best, r_parent_level_best);
311 }
312}
313
315 Collection *root_collection, ID *target_id, const bool do_parents)
316{
317 root_collection->id.tag |= ID_TAG_DOIT;
318
319 /* Tag all local parents of the root collection, so that usages of the root collection and other
320 * linked ones can be replaced by the local overrides in those parents too. */
321 if (do_parents) {
322 for (CollectionParent *iter =
323 static_cast<CollectionParent *>(root_collection->runtime->parents.first);
324 iter != nullptr;
325 iter = iter->next)
326 {
327 if (ID_IS_LINKED(iter->collection)) {
328 continue;
329 }
330 iter->collection->id.tag |= ID_TAG_DOIT;
331 }
332 }
333
334 for (CollectionChild *iter = static_cast<CollectionChild *>(root_collection->children.first);
335 iter != nullptr;
336 iter = iter->next)
337 {
338 if (ID_IS_LINKED(iter->collection) && iter->collection->id.lib != target_id->lib) {
339 continue;
340 }
341 if (GS(target_id->name) == ID_OB &&
342 !BKE_collection_has_object_recursive(iter->collection, (Object *)target_id))
343 {
344 continue;
345 }
346 if (GS(target_id->name) == ID_GR &&
347 !BKE_collection_has_collection(iter->collection, (Collection *)target_id))
348 {
349 continue;
350 }
352 iter->collection, target_id, false);
353 }
354}
355
357 bContext *C, Main *bmain, ID *owner_id, ID *id, const char **r_undo_push_label)
358{
359 const char *undo_push_label;
360 if (r_undo_push_label == nullptr) {
361 r_undo_push_label = &undo_push_label;
362 }
363
364 /* If this is called on an already local override, 'toggle' between user-editable state, and
365 * system override with reset. */
366 if (!ID_IS_LINKED(id) && ID_IS_OVERRIDE_LIBRARY(id)) {
368 BKE_lib_override_library_get(bmain, id, nullptr, &id);
369 }
371 id->override_library->flag &= ~LIBOVERRIDE_FLAG_SYSTEM_DEFINED;
372 *r_undo_push_label = "Make Library Override Hierarchy Editable";
373 }
374 else {
375 BKE_lib_override_library_id_reset(bmain, id, true);
376 *r_undo_push_label = "Clear Library Override Hierarchy";
377 }
378
382 return id;
383 }
384
385 /* Attempt to perform a hierarchy override, based on contextual data available.
386 * NOTE: do not attempt to perform such hierarchy override at all cost, if there is not enough
387 * context, better to abort than create random overrides all over the place. */
389 WM_global_reportf(RPT_ERROR, "The data-block %s is not overridable", id->name);
390 return nullptr;
391 }
392
393 Object *object_active = CTX_data_active_object(C);
394 if (object_active == nullptr && GS(owner_id->name) == ID_OB) {
395 object_active = (Object *)owner_id;
396 }
397 if (object_active != nullptr) {
398 if (ID_IS_LINKED(object_active)) {
399 if (object_active->id.lib != id->lib || !ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(object_active))
400 {
401 /* The active object is from a different library than the overridden ID, or otherwise
402 * cannot be used in hierarchy. */
403 object_active = nullptr;
404 }
405 }
406 else if (!ID_IS_OVERRIDE_LIBRARY_REAL(object_active)) {
407 /* Fully local object cannot be used in override hierarchy either. */
408 object_active = nullptr;
409 }
410 }
411
412 Collection *collection_active_context = CTX_data_collection(C);
413 Collection *collection_active = collection_active_context;
414 if (collection_active == nullptr && GS(owner_id->name) == ID_GR) {
415 collection_active = (Collection *)owner_id;
416 }
417 if (collection_active != nullptr) {
418 if (ID_IS_LINKED(collection_active)) {
419 if (collection_active->id.lib != id->lib ||
420 !ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(collection_active))
421 {
422 /* The active collection is from a different library than the overridden ID, or otherwise
423 * cannot be used in hierarchy. */
424 collection_active = nullptr;
425 }
426 else {
427 int parent_level_best = -1;
428 Collection *collection_parent_best = nullptr;
430 collection_active, 0, &collection_parent_best, &parent_level_best);
431 collection_active = collection_parent_best;
432 }
433 }
434 else if (!ID_IS_OVERRIDE_LIBRARY_REAL(collection_active)) {
435 /* Fully local collection cannot be used in override hierarchy either. */
436 collection_active = nullptr;
437 }
438 }
439 if (collection_active == nullptr && object_active != nullptr &&
440 (ID_IS_LINKED(object_active) || ID_IS_OVERRIDE_LIBRARY_REAL(object_active)))
441 {
442 /* If we failed to find a valid 'active' collection so far for our override hierarchy, but do
443 * have a valid 'active' object, try to find a collection from that object. */
444 LISTBASE_FOREACH (Collection *, collection_iter, &bmain->collections) {
445 if (ID_IS_LINKED(collection_iter) && collection_iter->id.lib != id->lib) {
446 continue;
447 }
448 if (!ID_IS_OVERRIDE_LIBRARY_REAL(collection_iter)) {
449 continue;
450 }
451 if (!BKE_collection_has_object_recursive(collection_iter, object_active)) {
452 continue;
453 }
454 int parent_level_best = -1;
455 Collection *collection_parent_best = nullptr;
457 collection_iter, 0, &collection_parent_best, &parent_level_best);
458 collection_active = collection_parent_best;
459 break;
460 }
461 }
462
463 ID *id_override = nullptr;
464 Scene *scene = CTX_data_scene(C);
465 ViewLayer *view_layer = CTX_data_view_layer(C);
466 switch (GS(id->name)) {
467 case ID_GR:
468 if (collection_active != nullptr &&
469 BKE_collection_has_collection(collection_active, (Collection *)id))
470 {
472 if (object_active != nullptr) {
473 object_active->id.tag |= ID_TAG_DOIT;
474 }
476 scene,
477 view_layer,
478 nullptr,
479 id,
480 &collection_active->id,
481 nullptr,
482 &id_override,
483 false);
484 }
485 else if (object_active != nullptr && !ID_IS_LINKED(object_active) &&
486 &object_active->instance_collection->id == id)
487 {
488 object_active->id.tag |= ID_TAG_DOIT;
490 scene,
491 view_layer,
492 id->lib,
493 id,
494 &object_active->id,
495 &object_active->id,
496 &id_override,
497 false);
498 }
499 break;
500 case ID_OB:
501 if (collection_active != nullptr &&
502 BKE_collection_has_object_recursive(collection_active, (Object *)id))
503 {
505 if (object_active != nullptr) {
506 object_active->id.tag |= ID_TAG_DOIT;
507 }
509 scene,
510 view_layer,
511 nullptr,
512 id,
513 &collection_active->id,
514 nullptr,
515 &id_override,
516 false);
517 }
518 else {
519 if (object_active != nullptr) {
520 object_active->id.tag |= ID_TAG_DOIT;
521 }
523 bmain, scene, view_layer, nullptr, id, nullptr, nullptr, &id_override, false);
524 BKE_scene_collections_object_remove(bmain, scene, (Object *)id, true);
526 }
527 break;
528 case ID_ME:
529 case ID_CU_LEGACY:
530 case ID_MB:
531 case ID_LT:
532 case ID_LA:
533 case ID_CA:
534 case ID_SPK:
535 case ID_AR:
536 case ID_GD_LEGACY:
537 case ID_CV:
538 case ID_PT:
539 case ID_VO:
540 case ID_NT: /* Essentially geometry nodes from modifier currently. */
541 if (object_active != nullptr) {
542 if (collection_active != nullptr &&
543 BKE_collection_has_object_recursive(collection_active, object_active))
544 {
546 object_active->id.tag |= ID_TAG_DOIT;
548 scene,
549 view_layer,
550 nullptr,
551 id,
552 &collection_active->id,
553 nullptr,
554 &id_override,
555 false);
556 }
557 else {
558 object_active->id.tag |= ID_TAG_DOIT;
560 scene,
561 view_layer,
562 nullptr,
563 id,
564 &object_active->id,
565 nullptr,
566 &id_override,
567 false);
568 }
569 }
570 else {
572 bmain, scene, view_layer, nullptr, id, id, nullptr, &id_override, false);
573 }
574 break;
575 case ID_MA:
576 case ID_TE:
577 case ID_IM:
578 WM_global_reportf(RPT_WARNING, "The type of data-block %s is not yet implemented", id->name);
579 break;
580 case ID_WO:
581 WM_global_reportf(RPT_WARNING, "The type of data-block %s is not yet implemented", id->name);
582 break;
583 case ID_PA:
584 WM_global_reportf(RPT_WARNING, "The type of data-block %s is not yet implemented", id->name);
585 break;
586 default:
587 WM_global_reportf(RPT_WARNING, "The type of data-block %s is not yet implemented", id->name);
588 break;
589 }
590
591 if (id_override != nullptr) {
593
594 /* Ensure that the hierarchy root of the newly overridden data is instantiated in the scene, in
595 * case it's a collection or object. */
596 ID *hierarchy_root = id_override->override_library->hierarchy_root;
597 if (GS(hierarchy_root->name) == ID_OB) {
598 Object *object_hierarchy_root = reinterpret_cast<Object *>(hierarchy_root);
599 if (!BKE_scene_has_object(scene, object_hierarchy_root)) {
600 if (!ID_IS_LINKED(collection_active_context)) {
601 BKE_collection_object_add(bmain, collection_active_context, object_hierarchy_root);
602 }
603 else {
604 BKE_collection_object_add(bmain, scene->master_collection, object_hierarchy_root);
605 }
606 }
607 }
608 else if (GS(hierarchy_root->name) == ID_GR) {
609 Collection *collection_hierarchy_root = reinterpret_cast<Collection *>(hierarchy_root);
610 if (!BKE_collection_has_collection(scene->master_collection, collection_hierarchy_root)) {
611 if (!ID_IS_LINKED(collection_active_context)) {
612 BKE_collection_child_add(bmain, collection_active_context, collection_hierarchy_root);
613 }
614 else {
615 BKE_collection_child_add(bmain, scene->master_collection, collection_hierarchy_root);
616 }
617 }
618 }
619
620 *r_undo_push_label = "Make Library Override Hierarchy";
621
622 /* In theory we could rely on setting/updating the RNA ID pointer property (as done by calling
623 * code) to be enough.
624 *
625 * However, some rare ID pointers properties (like the "active object in view-layer" one used
626 * for the Object templateID in the Object properties) use notifiers that do not enforce a
627 * rebuild of outliner trees, leading to crashes.
628 *
629 * So for now, add some extra notifiers here. */
632 }
633 return id_override;
634}
635
637 Main *bmain,
638 TemplateID *template_ui,
639 PointerRNA *idptr,
640 const char **r_undo_push_label)
641{
642 ID *id = static_cast<ID *>(idptr->data);
643 ID *owner_id = template_ui->ptr.owner_id;
644
646 C, bmain, owner_id, id, r_undo_push_label);
647
648 if (id_override != nullptr) {
649 /* `idptr` is re-assigned to owner property to ensure proper updates etc. Here we also use it
650 * to ensure remapping of the owner property from the linked data to the newly created
651 * liboverride (note that in theory this remapping has already been done by code above), but
652 * only in case owner ID was already local ID (override or pure local data).
653 *
654 * Otherwise, owner ID will also have been overridden, and remapped already to use it's
655 * override of the data too. */
656 if (!ID_IS_LINKED(owner_id)) {
657 *idptr = RNA_id_pointer_create(id_override);
658 }
659 }
660 else {
661 WM_global_reportf(RPT_ERROR, "The data-block %s could not be overridden", id->name);
662 }
663}
664
665static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
666{
667 TemplateID *template_ui = (TemplateID *)arg_litem;
668 PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
669 ID *id = static_cast<ID *>(idptr.data);
670 const int event = POINTER_AS_INT(arg_event);
671 const char *undo_push_label = nullptr;
672
673 switch (event) {
674 case UI_ID_NOP:
675 /* Don't do anything, typically set for buttons that execute an operator instead. They may
676 * still assign the callback so the button can be identified as part of an ID-template. See
677 * #UI_context_active_but_prop_get_templateID(). */
678 break;
679 case UI_ID_RENAME:
680 /* Only for the undo push. */
681 undo_push_label = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Rename Data-Block");
682 break;
683 case UI_ID_BROWSE:
684 case UI_ID_PIN:
685 RNA_warning("warning, id event %d shouldn't come here", event);
686 break;
687 case UI_ID_OPEN:
688 case UI_ID_ADD_NEW:
689 /* these call UI_context_active_but_prop_get_templateID */
690 break;
691 case UI_ID_DELETE:
692 idptr = {};
693 RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, nullptr);
694 RNA_property_update(C, &template_ui->ptr, template_ui->prop);
695
696 if (id && CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
697 /* only way to force-remove data (on save) */
700 id->us = 0;
701 undo_push_label = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Data-Block");
702 }
703 else {
704 undo_push_label = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Unlink Data-Block");
705 }
706
707 break;
708 case UI_ID_FAKE_USER:
709 if (id) {
710 if (id->flag & ID_FLAG_FAKEUSER) {
711 id_us_plus(id);
712 }
713 else {
714 id_us_min(id);
715 }
716 undo_push_label = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Fake User");
717 }
718 else {
719 return;
720 }
721 break;
722 case UI_ID_LOCAL:
723 if (id) {
724 Main *bmain = CTX_data_main(C);
725 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
726 template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label);
727 }
728 else {
731
732 /* Reassign to get proper updates/notifiers. */
733 idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
734 undo_push_label = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Local");
735 }
736 }
737 if (undo_push_label != nullptr) {
738 RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, nullptr);
739 RNA_property_update(C, &template_ui->ptr, template_ui->prop);
740 }
741 }
742 break;
743 case UI_ID_OVERRIDE:
744 if (id && ID_IS_OVERRIDE_LIBRARY(id)) {
745 Main *bmain = CTX_data_main(C);
746 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
747 template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label);
748 }
749 else {
751 /* Reassign to get proper updates/notifiers. */
752 idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
753 RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, nullptr);
754 RNA_property_update(C, &template_ui->ptr, template_ui->prop);
755 undo_push_label = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Local");
756 }
757 }
758 break;
759 case UI_ID_ALONE:
760 if (id) {
761 const bool do_scene_obj = ((GS(id->name) == ID_OB) &&
762 (template_ui->ptr.type == &RNA_LayerObjects));
763
764 /* make copy */
765 if (do_scene_obj) {
766 Main *bmain = CTX_data_main(C);
767 Scene *scene = CTX_data_scene(C);
771 }
772 else {
773 Main *bmain = CTX_data_main(C);
774 id_single_user(C, id, &template_ui->ptr, template_ui->prop);
777 }
779 undo_push_label = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Single User");
780 }
781 break;
782#if 0
783 case UI_ID_AUTO_NAME:
784 break;
785#endif
786 }
787
788 if (undo_push_label != nullptr) {
789 ED_undo_push(C, undo_push_label);
791 }
792}
793
795{
796 if (type) {
797 switch ((ID_Type)RNA_type_to_ID_code(type)) {
798 case ID_SCE:
799 return N_("Browse Scene to be linked");
800 case ID_OB:
801 return N_("Browse Object to be linked");
802 case ID_ME:
803 return N_("Browse Mesh Data to be linked");
804 case ID_CU_LEGACY:
805 return N_("Browse Curve Data to be linked");
806 case ID_MB:
807 return N_("Browse Metaball Data to be linked");
808 case ID_MA:
809 return N_("Browse Material to be linked");
810 case ID_TE:
811 return N_("Browse Texture to be linked");
812 case ID_IM:
813 return N_("Browse Image to be linked");
814 case ID_LS:
815 return N_("Browse Line Style Data to be linked");
816 case ID_LT:
817 return N_("Browse Lattice Data to be linked");
818 case ID_LA:
819 return N_("Browse Light Data to be linked");
820 case ID_CA:
821 return N_("Browse Camera Data to be linked");
822 case ID_WO:
823 return N_("Browse World Settings to be linked");
824 case ID_SCR:
825 return N_("Choose Screen layout");
826 case ID_TXT:
827 return N_("Browse Text to be linked");
828 case ID_SPK:
829 return N_("Browse Speaker Data to be linked");
830 case ID_SO:
831 return N_("Browse Sound to be linked");
832 case ID_AR:
833 return N_("Browse Armature data to be linked");
834 case ID_AC:
835 return N_("Browse Action to be linked");
836 case ID_NT:
837 return N_("Browse Node Tree to be linked");
838 case ID_BR:
839 return N_("Browse Brush to be linked");
840 case ID_PA:
841 return N_("Browse Particle Settings to be linked");
842 case ID_GD_LEGACY:
843 return N_("Browse Grease Pencil Data to be linked");
844 case ID_MC:
845 return N_("Browse Movie Clip to be linked");
846 case ID_MSK:
847 return N_("Browse Mask to be linked");
848 case ID_PAL:
849 return N_("Browse Palette Data to be linked");
850 case ID_PC:
851 return N_("Browse Paint Curve Data to be linked");
852 case ID_CF:
853 return N_("Browse Cache Files to be linked");
854 case ID_WS:
855 return N_("Browse Workspace to be linked");
856 case ID_LP:
857 return N_("Browse LightProbe to be linked");
858 case ID_CV:
859 return N_("Browse Curves Data to be linked");
860 case ID_PT:
861 return N_("Browse Point Cloud Data to be linked");
862 case ID_VO:
863 return N_("Browse Volume Data to be linked");
864 case ID_GP:
865 return N_("Browse Grease Pencil Data to be linked");
866
867 /* Use generic text. */
868 case ID_LI:
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 ButType but_type = use_tab_but ? ButType::Tab : ButType::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, 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 layout->context_ptr_set("id", &idptr);
1041
1042 uiBlock *block = layout->block();
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_IS_PACKED(id)) {
1123 but = uiDefIconBut(block,
1125 0,
1126 ICON_PACKAGE,
1127 0,
1128 0,
1129 UI_UNIT_X,
1130 UI_UNIT_Y,
1131 nullptr,
1132 0,
1133 0,
1134 TIP_("Packed library data-block, click to unpack and make local"));
1135 }
1136 else if (id->tag & ID_TAG_INDIRECT) {
1137 but = uiDefIconBut(block,
1139 0,
1140 ICON_LIBRARY_DATA_INDIRECT,
1141 0,
1142 0,
1143 UI_UNIT_X,
1144 UI_UNIT_Y,
1145 nullptr,
1146 0,
1147 0,
1148 TIP_("Indirect library data-block, cannot be made local, "
1149 "Shift + Click to create a library override hierarchy"));
1150 }
1151 else {
1152 but = uiDefIconBut(block,
1154 0,
1155 ICON_LIBRARY_DATA_DIRECT,
1156 0,
1157 0,
1158 UI_UNIT_X,
1159 UI_UNIT_Y,
1160 nullptr,
1161 0,
1162 0,
1163 TIP_("Direct linked library data-block, click to make local, "
1164 "Shift + Click to create a library override"));
1165 }
1166 if (disabled) {
1168 }
1169 else {
1170 UI_but_funcN_set(but,
1172 MEM_new<TemplateID>(__func__, template_ui),
1176 }
1177 }
1178 else if (ID_IS_OVERRIDE_LIBRARY(id)) {
1179 but = uiDefIconBut(
1180 block,
1182 0,
1183 ICON_LIBRARY_DATA_OVERRIDE,
1184 0,
1185 0,
1186 UI_UNIT_X,
1187 UI_UNIT_Y,
1188 nullptr,
1189 0,
1190 0,
1191 TIP_("Library override of linked data-block, click to make fully local, "
1192 "Shift + Click to clear the library override and toggle if it can be edited"));
1193 UI_but_funcN_set(but,
1195 MEM_new<TemplateID>(__func__, template_ui),
1199 }
1200 }
1201
1202 if ((ID_REAL_USERS(id) > 1) && (hide_buttons == false)) {
1203 char numstr[32];
1204 short numstr_len;
1205
1206 numstr_len = SNPRINTF_UTF8_RLEN(numstr, "%d", ID_REAL_USERS(id));
1207
1208 but = uiDefBut(
1209 block,
1211 0,
1212 numstr,
1213 0,
1214 0,
1215 numstr_len * 0.2f * UI_UNIT_X + UI_UNIT_X,
1216 UI_UNIT_Y,
1217 nullptr,
1218 0,
1219 0,
1220 TIP_("Display number of users of this data (click to make a single-user copy)"));
1221 but->flag |= UI_BUT_UNDO;
1222
1223 UI_but_funcN_set(but,
1225 MEM_new<TemplateID>(__func__, template_ui),
1229 if (!BKE_id_copy_is_allowed(id) || (idfrom && !ID_IS_EDITABLE(idfrom)) || (!editable) ||
1230 /* object in editmode - don't change data */
1231 (idfrom && GS(idfrom->name) == ID_OB && (((Object *)idfrom)->mode & OB_MODE_EDIT)))
1232 {
1234 }
1235 }
1236
1237 if (user_alert) {
1239 }
1240
1241 if (!ID_IS_LINKED(id)) {
1242 if (ID_IS_ASSET(id)) {
1243 uiDefIconButO(block,
1244 /* Using `_N` version allows us to get the 'active' state by default. */
1246 "ASSET_OT_clear_single",
1248 /* 'active' state of a toggle button uses icon + 1, so to get proper asset
1249 * icon we need to pass its value - 1 here. */
1250 ICON_ASSET_MANAGER - 1,
1251 0,
1252 0,
1253 UI_UNIT_X,
1254 UI_UNIT_Y,
1255 std::nullopt);
1256 }
1257 else if (!ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_OB, ID_WS) && (hide_buttons == false))
1258 {
1259 uiDefIconButR(block,
1261 0,
1262 ICON_FAKE_USER_OFF,
1263 0,
1264 0,
1265 UI_UNIT_X,
1266 UI_UNIT_Y,
1267 &idptr,
1268 "use_fake_user",
1269 -1,
1270 0,
1271 0,
1272 std::nullopt);
1273 }
1274 }
1275 }
1276
1277 if ((flag & UI_ID_ADD_NEW) && (hide_buttons == false)) {
1279 block, id, template_ui, type, newop, editable, flag & UI_ID_OPEN, false, UI_UNIT_X);
1280 }
1281
1282 /* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack.
1283 * Only for images, sound and fonts */
1284 if (id && BKE_packedfile_id_check(id)) {
1285 but = uiDefIconButO(block,
1287 "FILE_OT_unpack_item",
1289 ICON_PACKAGE,
1290 0,
1291 0,
1292 UI_UNIT_X,
1293 UI_UNIT_Y,
1294 TIP_("Packed File, click to unpack"));
1296
1297 RNA_string_set(but->opptr, "id_name", id->name + 2);
1298 RNA_int_set(but->opptr, "id_type", GS(id->name));
1299
1300 if (!ID_IS_EDITABLE(id)) {
1302 }
1303 }
1304 else if (flag & UI_ID_OPEN) {
1305 const char *button_text = (id) ? "" : IFACE_("Open");
1306 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
1307
1308 int w = id ? UI_UNIT_X : (flag & UI_ID_ADD_NEW) ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
1309 if (!id) {
1310 w = std::max(UI_fontstyle_string_width(fstyle, button_text) + int(UI_UNIT_X * 1.5f), w);
1311 }
1312
1313 if (openop) {
1314 but = uiDefIconTextButO(block,
1316 openop,
1318 ICON_FILEBROWSER,
1319 (id) ? "" : IFACE_("Open"),
1320 0,
1321 0,
1322 w,
1323 UI_UNIT_Y,
1324 std::nullopt);
1325 UI_but_funcN_set(but,
1327 MEM_new<TemplateID>(__func__, template_ui),
1331 }
1332 else {
1333 but = uiDefIconTextBut(block,
1335 0,
1336 ICON_FILEBROWSER,
1337 (id) ? "" : IFACE_("Open"),
1338 0,
1339 0,
1340 w,
1341 UI_UNIT_Y,
1342 nullptr,
1343 std::nullopt);
1344 UI_but_funcN_set(but,
1346 MEM_new<TemplateID>(__func__, template_ui),
1350 }
1351
1352 if ((idfrom && !ID_IS_EDITABLE(idfrom)) || !editable) {
1354 }
1355 }
1356
1357 /* delete button */
1358 /* don't use RNA_property_is_unlink here */
1359 if (id && (flag & UI_ID_DELETE) && (hide_buttons == false)) {
1360 /* allow unlink if 'unlinkop' is passed, even when 'PROP_NEVER_UNLINK' is set */
1361 but = nullptr;
1362
1363 if (unlinkop) {
1364 but = uiDefIconButO(block,
1366 unlinkop,
1368 ICON_X,
1369 0,
1370 0,
1371 UI_UNIT_X,
1372 UI_UNIT_Y,
1373 std::nullopt);
1374 /* so we can access the template from operators, font unlinking needs this */
1375 UI_but_funcN_set(but,
1377 MEM_new<TemplateID>(__func__, template_ui),
1381 }
1382 else {
1383 if ((RNA_property_flag(template_ui.prop) & PROP_NEVER_UNLINK) == 0) {
1384 but = uiDefIconBut(
1385 block,
1387 0,
1388 ICON_X,
1389 0,
1390 0,
1391 UI_UNIT_X,
1392 UI_UNIT_Y,
1393 nullptr,
1394 0,
1395 0,
1396 TIP_("Unlink data-block "
1397 "(Shift + Click to set users to zero, data will then not be saved)"));
1398 UI_but_funcN_set(but,
1400 MEM_new<TemplateID>(__func__, template_ui),
1404
1405 if (RNA_property_flag(template_ui.prop) & PROP_NEVER_NULL) {
1407 }
1408 }
1409 }
1410
1411 if (but) {
1412 if ((idfrom && !ID_IS_EDITABLE(idfrom)) || !editable) {
1414 }
1415 }
1416 }
1417
1418 if (template_ui.idcode == ID_TE) {
1419 uiTemplateTextureShow(layout, C, &template_ui.ptr, template_ui.prop);
1420 }
1421 UI_block_align_end(block);
1422}
1423
1425{
1427
1428 if (but && but->type == ButType::Tab) {
1429 return static_cast<ID *>(but->custom_data);
1430 }
1431 return nullptr;
1432}
1433
1434static void template_ID_tabs(const bContext *C,
1435 uiLayout *layout,
1436 TemplateID &template_id,
1437 StructRNA *type,
1438 int flag,
1439 const char *newop,
1440 const char *menu)
1441{
1442 const ARegion *region = CTX_wm_region(C);
1443 const PointerRNA active_ptr = RNA_property_pointer_get(&template_id.ptr, template_id.prop);
1444 MenuType *mt = menu ? WM_menutype_find(menu, false) : nullptr;
1445
1446 /* When horizontal show the tabs as pills, rounded on all corners. */
1447 const bool horizontal =
1448 (region->regiontype == RGN_TYPE_HEADER &&
1450 const int but_align = horizontal ? 0 : ui_but_align_opposite_to_area_align_get(region);
1451
1452 const int but_height = UI_UNIT_Y * 1.1;
1453
1454 uiBlock *block = layout->block();
1455 const uiStyle *style = UI_style_get_dpi();
1456
1457 for (ID *id : BKE_id_ordered_list(template_id.idlb)) {
1458 const int name_width = UI_fontstyle_string_width(&style->widget, id->name + 2);
1459 const int but_width = name_width + UI_UNIT_X;
1460
1461 uiButTab *tab = (uiButTab *)uiDefButR_prop(block,
1463 0,
1464 id->name + 2,
1465 0,
1466 0,
1467 but_width,
1468 but_height,
1469 &template_id.ptr,
1470 template_id.prop,
1471 0,
1472 0.0f,
1473 sizeof(id->name) - 2,
1474 "");
1475 UI_but_funcN_set(tab,
1477 MEM_new<TemplateID>(__func__, template_id),
1478 id,
1481 UI_but_drag_set_id(tab, id);
1482 tab->custom_data = (void *)id;
1483 tab->menu = mt;
1484
1485 UI_but_drawflag_enable(tab, but_align);
1486 }
1487
1488 if (flag & UI_ID_ADD_NEW) {
1489 const bool editable = RNA_property_editable(&template_id.ptr, template_id.prop);
1490 uiBut *but;
1491
1492 if (active_ptr.type) {
1493 type = active_ptr.type;
1494 }
1495
1496 but = template_id_def_new_but(block,
1497 static_cast<const ID *>(active_ptr.data),
1498 template_id,
1499 type,
1500 newop,
1501 editable,
1502 flag & UI_ID_OPEN,
1503 true,
1504 but_height);
1505 UI_but_drawflag_enable(but, but_align);
1506 }
1507}
1508
1509static void ui_template_id(uiLayout *layout,
1510 const bContext *C,
1511 PointerRNA *ptr,
1512 const StringRefNull propname,
1513 const char *newop,
1514 const char *openop,
1515 const char *unlinkop,
1516 /* Only respected by tabs (use_tabs). */
1517 const char *menu,
1518 const std::optional<StringRef> text,
1519 int flag,
1520 int prv_rows,
1521 int prv_cols,
1522 int filter,
1523 bool use_tabs,
1524 float scale,
1525 const bool live_icon,
1526 const bool hide_buttons)
1527{
1528 PropertyRNA *prop = RNA_struct_find_property(ptr, propname.c_str());
1529
1530 if (!prop || RNA_property_type(prop) != PROP_POINTER) {
1532 "pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
1533 return;
1534 }
1535
1536 TemplateID template_ui = {};
1537 template_ui.ptr = *ptr;
1538 template_ui.prop = prop;
1539 template_ui.prv_rows = prv_rows;
1540 template_ui.prv_cols = prv_cols;
1541 template_ui.scale = scale;
1542
1543 if ((flag & UI_ID_PIN) == 0) {
1544 template_ui.filter = filter;
1545 }
1546 else {
1547 template_ui.filter = 0;
1548 }
1549
1550 if (newop) {
1552 }
1553 if (openop) {
1554 flag |= UI_ID_OPEN;
1555 }
1556
1558 short idcode = RNA_type_to_ID_code(type);
1559 template_ui.idcode = idcode;
1560 template_ui.idlb = which_libbase(CTX_data_main(C), idcode);
1561
1562 /* create UI elements for this template
1563 * - template_ID makes a copy of the template data and assigns it to the relevant buttons
1564 */
1565 if (template_ui.idlb) {
1566 if (use_tabs) {
1567 layout = &layout->row(true);
1568 template_ID_tabs(C, layout, template_ui, type, flag, newop, menu);
1569 }
1570 else {
1571 layout = &layout->row(true);
1572 template_ID(C,
1573 layout,
1574 template_ui,
1575 type,
1576 flag,
1577 newop,
1578 openop,
1579 unlinkop,
1580 text,
1581 live_icon,
1582 hide_buttons);
1583 }
1584 }
1585}
1586
1588 const bContext *C,
1589 PointerRNA *ptr,
1590 const StringRefNull propname,
1591 const char *newop,
1592 const char *openop,
1593 const char *unlinkop,
1594 int filter,
1595 const bool live_icon,
1596 const std::optional<StringRef> text)
1597{
1598 ui_template_id(layout,
1599 C,
1600 ptr,
1601 propname,
1602 newop,
1603 openop,
1604 unlinkop,
1605 nullptr,
1606 text,
1608 0,
1609 0,
1610 filter,
1611 false,
1612 1.0f,
1613 live_icon,
1614 false);
1615}
1616
1618 const bContext *C,
1619 ID *id,
1620 const char *newop,
1621 const char *unlinkop,
1622 const std::optional<StringRef> text)
1623{
1624 if (!id_can_have_animdata(id)) {
1625 RNA_warning("Cannot show Action selector for non-animatable ID: %s", id->name + 2);
1626 return;
1627 }
1628
1629 PropertyRNA *adt_action_prop = RNA_struct_type_find_property(&RNA_AnimData, "action");
1630 BLI_assert(adt_action_prop);
1631 BLI_assert(RNA_property_type(adt_action_prop) == PROP_POINTER);
1632
1633 /* Construct a pointer with the animated ID as owner, even when `adt` may be `nullptr`.
1634 * This way it is possible to use this RNA pointer to get/set `adt->action`, as that RNA property
1635 * has a `getter` & `setter` that only need the owner ID and are null-safe regarding the `adt`
1636 * itself.
1637 * FIXME: This is a very dirty hack, would be good to find a way to not rely on typed-but-null
1638 * PointerRNA.
1639 */
1640 AnimData *adt = BKE_animdata_from_id(id);
1641 PointerRNA adt_ptr = PointerRNA{id, &RNA_AnimData, adt, RNA_id_pointer_create(id)};
1642
1643 TemplateID template_ui = {};
1644 template_ui.ptr = adt_ptr;
1645 template_ui.prop = adt_action_prop;
1646 template_ui.prv_rows = 0;
1647 template_ui.prv_cols = 0;
1648 template_ui.scale = 1.0f;
1649 template_ui.filter = UI_TEMPLATE_ID_FILTER_ALL;
1650
1652 if (newop) {
1654 }
1655
1656 template_ui.idcode = ID_AC;
1657 template_ui.idlb = which_libbase(CTX_data_main(C), ID_AC);
1658 BLI_assert(template_ui.idlb);
1659
1660 uiLayout *row = &layout->row(true);
1662 C, row, template_ui, &RNA_Action, flag, newop, nullptr, unlinkop, text, false, false);
1663}
1664
1666 bContext *C,
1667 PointerRNA *ptr,
1668 const StringRefNull propname,
1669 const char *newop,
1670 const char *openop,
1671 const char *unlinkop,
1672 int filter,
1673 const char *text)
1674{
1675 ui_template_id(layout,
1676 C,
1677 ptr,
1678 propname,
1679 newop,
1680 openop,
1681 unlinkop,
1682 nullptr,
1683 text,
1685 0,
1686 0,
1687 filter,
1688 false,
1689 1.0f,
1690 false,
1691 false);
1692}
1693
1695 bContext *C,
1696 PointerRNA *ptr,
1697 const StringRefNull propname,
1698 const char *newop,
1699 const char *openop,
1700 const char *unlinkop,
1701 int rows,
1702 int cols,
1703 int filter,
1704 const bool hide_buttons)
1705{
1706 ui_template_id(layout,
1707 C,
1708 ptr,
1709 propname,
1710 newop,
1711 openop,
1712 unlinkop,
1713 nullptr,
1714 nullptr,
1716 rows,
1717 cols,
1718 filter,
1719 false,
1720 1.0f,
1721 false,
1722 hide_buttons);
1723}
1724
1726 bContext *C,
1727 PointerRNA *ptr,
1728 const StringRefNull propname,
1729 int rows,
1730 int cols,
1731 float scale,
1732 int filter)
1733{
1734 ui_template_id(layout,
1735 C,
1736 ptr,
1737 propname,
1738 nullptr,
1739 nullptr,
1740 nullptr,
1741 nullptr,
1742 nullptr,
1744 rows,
1745 cols,
1746 filter,
1747 false,
1748 scale < 0.5f ? 0.5f : scale,
1749 false,
1750 false);
1751}
1752
1754 bContext *C,
1755 PointerRNA *ptr,
1756 const StringRefNull propname,
1757 const char *newop,
1758 const char *menu,
1759 int filter)
1760{
1761 ui_template_id(layout,
1762 C,
1763 ptr,
1764 propname,
1765 newop,
1766 nullptr,
1767 nullptr,
1768 menu,
1769 nullptr,
1771 0,
1772 0,
1773 filter,
1774 true,
1775 1.0f,
1776 false,
1777 false);
1778}
1779
1781 PointerRNA *ptr,
1782 const StringRefNull propname,
1783 const StringRefNull proptypename,
1784 const std::optional<StringRef> text)
1785{
1786 /* get properties... */
1787 PropertyRNA *propID = RNA_struct_find_property(ptr, propname.c_str());
1788 PropertyRNA *propType = RNA_struct_find_property(ptr, proptypename.c_str());
1789
1790 if (!propID || RNA_property_type(propID) != PROP_POINTER) {
1792 "pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname.c_str());
1793 return;
1794 }
1795 if (!propType || RNA_property_type(propType) != PROP_ENUM) {
1796 RNA_warning("pointer-type property not found: %s.%s",
1798 proptypename.c_str());
1799 return;
1800 }
1801
1802 /* Start drawing UI Elements using standard defines */
1803
1804 /* NOTE: split amount here needs to be synced with normal labels */
1805 uiLayout *split = &layout->split(0.33f, false);
1806
1807 /* FIRST PART ................................................ */
1808 uiLayout *row = &split->row(false);
1809
1810 /* Label - either use the provided text, or will become "ID-Block:" */
1811 if (text) {
1812 if (!text->is_empty()) {
1813 row->label(*text, ICON_NONE);
1814 }
1815 }
1816 else {
1817 row->label(IFACE_("ID-Block:"), ICON_NONE);
1818 }
1819
1820 /* SECOND PART ................................................ */
1821 row = &split->row(true);
1822
1823 /* ID-Type Selector - just have a menu of icons */
1824
1825 /* HACK: special group just for the enum,
1826 * otherwise we get ugly layout with text included too... */
1827 uiLayout *sub = &row->row(true);
1829
1830 sub->prop(ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
1831
1832 /* ID-Block Selector - just use pointer widget... */
1833
1834 /* HACK: special group to counteract the effects of the previous enum,
1835 * which now pushes everything too far right. */
1836 sub = &row->row(true);
1838
1839 sub->prop(ptr, propID, 0, 0, UI_ITEM_NONE, "", ICON_NONE);
1840}
bool id_can_have_animdata(const ID *id)
Definition anim_data.cc:73
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:83
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:178
#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:412
@ LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
Definition lib_id.cc:1068
void id_us_plus(ID *id)
Definition lib_id.cc:358
bool BKE_id_copy_is_allowed(const ID *id)
Definition lib_id.cc:666
#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:2449
blender::Vector< ID * > BKE_id_ordered_list(const ListBase *lb)
Definition lib_id.cc:2576
bool BKE_lib_id_make_local(Main *bmain, ID *id, int flags)
Definition lib_id.cc:598
void id_fake_user_clear(ID *id)
Definition lib_id.cc:404
void id_us_clear_real(ID *id)
Definition lib_id.cc:331
void id_us_min(ID *id)
Definition lib_id.cc:366
void BKE_main_id_flag_listbase(ListBase *lb, int flag, bool value)
Definition lib_id.cc:1233
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:902
void BKE_main_ensure_invariants(Main &bmain, std::optional< blender::Span< ID * > > modified_ids=std::nullopt)
bool BKE_packedfile_id_check(const ID *id)
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
#define SNPRINTF_UTF8_RLEN(dst, format,...)
#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 CTX_N_(context, msgid)
#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 BLT_I18NCONTEXT_OPERATOR_DEFAULT
#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)
#define ID_IS_PACKED(_id)
Definition DNA_ID.h:700
@ ID_TAG_INDIRECT
Definition DNA_ID.h:848
@ ID_TAG_DOIT
Definition DNA_ID.h:1036
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:723
#define ID_IS_OVERRIDABLE_LIBRARY(_id)
Definition DNA_ID.h:716
#define ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(_id)
Definition DNA_ID.h:712
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
#define ID_IS_ASSET(_id)
Definition DNA_ID.h:737
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
#define ID_REAL_USERS(id)
Definition DNA_ID.h:676
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
@ LIBOVERRIDE_FLAG_SYSTEM_DEFINED
Definition DNA_ID.h:363
@ ID_FLAG_FAKEUSER
Definition DNA_ID.h:769
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_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
#define RGN_ALIGN_ENUM_FROM_MASK(align)
@ RGN_ALIGN_BOTTOM
@ RGN_ALIGN_TOP
@ RGN_TYPE_HEADER
@ USER_HIDE_DOT
@ WORKSPACE_USE_PIN_SCENE
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:98
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:166
@ PROP_POINTER
Definition RNA_types.hh:167
@ PROP_NEVER_UNLINK
Definition RNA_types.hh:384
@ PROP_NEVER_NULL
Definition RNA_types.hh:377
@ PROP_ID_SELF_CHECK
Definition RNA_types.hh:370
#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)
uiBut * uiDefIconTextBut(uiBlock *block, uiButTypeWithPointerType but_and_ptr_type, int retval, int icon, blender::StringRef str, int x, int y, short width, short height, void *poin, std::optional< blender::StringRef > tip)
#define UI_UNIT_Y
uiBut * uiDefButR(uiBlock *block, ButType 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_func_rename_full_set(uiBut *but, std::function< void(std::string &new_name)> rename_full_func)
#define UI_SEP_CHAR
PointerRNA * UI_but_extra_operator_icon_add(uiBut *but, blender::StringRefNull opname, blender::wm::OpCallContext opcontext, int icon)
@ UI_BUT_REDALERT
@ UI_BUT_UNDO
@ UI_BUT_DISABLED
@ UI_BUT_HAS_SEP_CHAR
uiBut * uiDefIconBut(uiBlock *block, uiButTypeWithPointerType but_and_ptr_type, int retval, int icon, 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()
@ 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
void UI_but_drawflag_enable(uiBut *but, int flag)
uiBut * uiDefIconButR(uiBlock *block, ButType 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)
uiBut * uiDefIconTextButO(uiBlock *block, ButType type, blender::StringRefNull, blender::wm::OpCallContext opcontext, int icon, blender::StringRef str, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
uiBut * UI_context_active_but_get(const bContext *C)
uiBut * uiDefIconButO(uiBlock *block, ButType type, blender::StringRefNull opname, blender::wm::OpCallContext opcontext, int icon, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
@ UI_TEMPLATE_ID_FILTER_AVAILABLE
@ UI_TEMPLATE_ID_FILTER_ALL
uiBut * uiDefButR_prop(uiBlock *block, ButType 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)
bool UI_search_item_add(uiSearchItems *items, blender::StringRef name, void *poin, int iconid, int but_flag, uint8_t name_prefix_offset)
PointerRNA * UI_but_operator_ptr_ensure(uiBut *but)
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
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)
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)
uiBut * uiDefBut(uiBlock *block, uiButTypeWithPointerType but_and_ptr_type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, std::optional< blender::StringRef > tip)
void UI_but_flag_enable(uiBut *but, int flag)
void UI_block_align_end(uiBlock *block)
int UI_icon_from_library(const ID *id)
@ UI_ITEM_R_ICON_ONLY
uiLayout * uiItemL_respect_property_split(uiLayout *layout, blender::StringRef text, int icon)
#define UI_ITEM_NONE
#define UI_MAX_NAME_STR
#define NC_WINDOW
Definition WM_types.hh:375
#define NC_ID
Definition WM_types.hh:395
@ KM_SHIFT
Definition WM_types.hh:278
#define NC_WM
Definition WM_types.hh:374
#define ND_DATACHANGED
Definition WM_types.hh:414
#define ND_LIB_OVERRIDE_CHANGED
Definition WM_types.hh:419
#define NA_ADDED
Definition WM_types.hh:586
#define NA_REMOVED
Definition WM_types.hh:587
#define ND_SPACE_VIEW3D
Definition WM_types.hh:528
#define NC_SPACE
Definition WM_types.hh:392
#define ND_SPACE_OUTLINER
Definition WM_types.hh:527
#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 GS(x)
#define active
#define filter
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)
const char * name
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
CollectionRuntimeHandle * runtime
unsigned int flag
Definition DNA_ID.h:348
struct ID * hierarchy_root
Definition DNA_ID.h:344
Definition DNA_ID.h:414
int tag
Definition DNA_ID.h:442
struct Library * lib
Definition DNA_ID.h:420
char name[258]
Definition DNA_ID.h:432
IDOverrideLibrary * override_library
Definition DNA_ID.h:494
short flag
Definition DNA_ID.h:438
void * first
ListBase collections
Definition BKE_main.hh:298
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
ButType type
PointerRNA * opptr
void * func_argN
void alignment_set(blender::ui::LayoutAlign alignment)
uiBlock * block() const
void label(blender::StringRef name, int icon)
void context_ptr_set(blender::StringRef name, const PointerRNA *ptr)
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:4238
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:145