Blender V4.3
interface_templates.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <cctype>
11#include <cstddef>
12#include <cstdlib>
13#include <cstring>
14
15#include <fmt/format.h>
16
17#include "MEM_guardedalloc.h"
18
19#include "DNA_anim_types.h"
20#include "DNA_brush_types.h"
21#include "DNA_cachefile_types.h"
26#include "DNA_node_types.h"
27#include "DNA_object_types.h"
28#include "DNA_scene_types.h"
29#include "DNA_shader_fx_types.h"
30#include "DNA_texture_types.h"
31
32#include "BLI_fileops.h"
33#include "BLI_listbase.h"
34#include "BLI_math_color.h"
35#include "BLI_math_vector.h"
36#include "BLI_path_utils.hh"
37#include "BLI_rect.h"
38#include "BLI_string.h"
39#include "BLI_string_ref.hh"
40#include "BLI_string_utils.hh"
41#include "BLI_time.h"
42#include "BLI_timecode.h"
43#include "BLI_utildefines.h"
44
45#include "BLF_api.hh"
46#include "BLT_translation.hh"
47
48#include "BKE_anim_data.hh"
49#include "BKE_blender_version.h"
50#include "BKE_blendfile.hh"
51#include "BKE_colorband.hh"
52#include "BKE_colortools.hh"
53#include "BKE_constraint.h"
54#include "BKE_context.hh"
55#include "BKE_curveprofile.h"
56#include "BKE_file_handler.hh"
57#include "BKE_global.hh"
58#include "BKE_idprop.hh"
59#include "BKE_idtype.hh"
60#include "BKE_layer.hh"
61#include "BKE_lib_id.hh"
62#include "BKE_lib_override.hh"
63#include "BKE_linestyle.h"
64#include "BKE_main.hh"
65#include "BKE_modifier.hh"
66#include "BKE_packedFile.hh"
67#include "BKE_report.hh"
68#include "BKE_scene.hh"
69#include "BKE_screen.hh"
70#include "BKE_shader_fx.h"
71#include "BKE_workspace.hh"
72
73#include "BLO_readfile.hh"
74
75#include "DEG_depsgraph.hh"
78
79#include "ED_fileselect.hh"
80#include "ED_id_management.hh"
81#include "ED_info.hh"
82#include "ED_object.hh"
83#include "ED_render.hh"
84#include "ED_screen.hh"
85#include "ED_screen_types.hh"
86#include "ED_undo.hh"
87
88#include "IMB_imbuf.hh"
89#include "IMB_imbuf_types.hh"
90#include "IMB_metadata.hh"
91#include "IMB_thumbs.hh"
92
93#include "RE_engine.h"
94
95#include "RNA_access.hh"
96#include "RNA_prototypes.hh"
97
98#include "WM_api.hh"
99#include "WM_types.hh"
100
101#include "UI_interface.hh"
102#include "UI_interface_icons.hh"
103#include "UI_string_search.hh"
104#include "interface_intern.hh"
105
107using blender::Vector;
108
109/* we may want to make this optional, disable for now. */
110// #define USE_OP_RESET_BUT
111
112/* defines for templateID/TemplateSearch */
113#define TEMPLATE_SEARCH_TEXTBUT_MIN_WIDTH (UI_UNIT_X * 4)
114#define TEMPLATE_SEARCH_TEXTBUT_HEIGHT UI_UNIT_Y
115
116/* -------------------------------------------------------------------- */
119
121{
122 uiBlock *block = uiLayoutAbsoluteBlock(layout);
124}
125
127
128/* -------------------------------------------------------------------- */
131
133{
134 char str[UI_MAX_DRAW_STR];
135 int buf_len = 0;
136
138
139 const char *name = RNA_property_string_get_alloc(ptr, name_prop, str, sizeof(str), &buf_len);
140
141 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
142 const int margin = UI_UNIT_X * 0.75f;
143 const int estimated_width = UI_fontstyle_string_width(fstyle, name) + margin;
144
145 if (name != str) {
146 MEM_freeN((void *)name);
147 }
148
149 /* Clamp to some min/max width. */
150 return std::clamp(
152}
153
158
163 uiLayout *layout,
164 uiBlock *block,
166 PropertyRNA *prop,
167 uiBlockCreateFunc block_func,
168 void *block_argN,
169 const char *const tip,
170 const bool use_previews,
171 const bool editable,
172 const bool live_icon,
173 uiButArgNFree func_argN_free_fn = MEM_freeN,
174 uiButArgNCopy func_argN_copy_fn = MEM_dupallocN)
175{
176 const PointerRNA active_ptr = RNA_property_pointer_get(ptr, prop);
177 ID *id = (active_ptr.data && RNA_struct_is_ID(active_ptr.type)) ?
178 static_cast<ID *>(active_ptr.data) :
179 nullptr;
180 const ID *idfrom = ptr->owner_id;
181 const StructRNA *type = active_ptr.type ? active_ptr.type : RNA_property_pointer_type(ptr, prop);
182 uiBut *but;
183
184 if (use_previews) {
185 ARegion *region = CTX_wm_region(C);
186 /* Ugly tool header exception. */
187 const bool use_big_size = (region->regiontype != RGN_TYPE_TOOL_HEADER);
188 /* Ugly exception for screens here,
189 * drawing their preview in icon size looks ugly/useless */
190 const bool use_preview_icon = use_big_size || (id && (GS(id->name) != ID_SCR));
191 const short width = UI_UNIT_X * (use_big_size ? 6 : 1.6f);
192 const short height = UI_UNIT_Y * (use_big_size ? 6 : 1);
193 uiLayout *col = nullptr;
194
195 if (use_big_size) {
196 /* Assume column layout here. To be more correct, we should check if the layout passed to
197 * template_id is a column one, but this should work well in practice. */
198 col = uiLayoutColumn(layout, true);
199 }
200
201 but = uiDefBlockButN(block,
202 block_func,
203 block_argN,
204 "",
205 0,
206 0,
207 width,
208 height,
209 tip,
210 func_argN_free_fn,
211 func_argN_copy_fn);
212 if (use_preview_icon) {
213 const int icon = id ? ui_id_icon_get(C, id, use_big_size) : RNA_struct_ui_icon(type);
215 }
216 else {
219 }
220
221 if ((idfrom && !ID_IS_EDITABLE(idfrom)) || !editable) {
223 }
224 if (use_big_size) {
225 uiLayoutRow(col ? col : layout, true);
226 }
227 }
228 else {
229 but = uiDefBlockButN(block,
230 block_func,
231 block_argN,
232 "",
233 0,
234 0,
235 UI_UNIT_X * 1.6,
236 UI_UNIT_Y,
237 tip,
238 func_argN_free_fn,
239 func_argN_copy_fn);
240
241 if (live_icon) {
242 const int icon = id ? ui_id_icon_get(C, id, false) : RNA_struct_ui_icon(type);
244 }
245 else {
247 }
248 if (id) {
249 /* default dragging of icon for id browse buttons */
250 UI_but_drag_set_id(but, id);
251 }
253
254 if ((idfrom && !ID_IS_EDITABLE(idfrom)) || !editable) {
256 }
257 }
258}
259
261 ARegion *region,
262 uiButSearchUpdateFn search_update_fn,
263 void *search_arg,
264 uiButHandleFunc search_exec_fn,
265 void *active_item,
266 uiButSearchTooltipFn item_tooltip_fn,
267 const int preview_rows,
268 const int preview_cols,
269 float scale)
270{
271 static char search[256];
272 wmWindow *win = CTX_wm_window(C);
273 uiBut *but;
274
275 /* clear initial search string, then all items show */
276 search[0] = 0;
277
278 uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
281
282 /* preview thumbnails */
283 if (preview_rows > 0 && preview_cols > 0) {
284 const int w = 4 * U.widget_unit * preview_cols * scale;
285 const int h = 5 * U.widget_unit * preview_rows * scale;
286
287 /* fake button, it holds space for search items */
288 uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 26, w, h, nullptr, 0, 0, nullptr);
289
290 but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, w, UI_UNIT_Y, "");
291 UI_but_search_preview_grid_size_set(but, preview_rows, preview_cols);
292 }
293 /* list view */
294 else {
295 const int searchbox_width = int(float(UI_searchbox_size_x()) * 1.4f);
296 const int searchbox_height = UI_searchbox_size_y();
297
298 /* fake button, it holds space for search items */
299 uiDefBut(block,
301 0,
302 "",
303 10,
304 15,
305 searchbox_width,
306 searchbox_height,
307 nullptr,
308 0,
309 0,
310 nullptr);
311 but = uiDefSearchBut(block,
312 search,
313 0,
314 ICON_VIEWZOOM,
315 sizeof(search),
316 10,
317 0,
318 searchbox_width,
319 UI_UNIT_Y - 1,
320 "");
321 }
324 search_update_fn,
325 search_arg,
326 false,
327 nullptr,
328 search_exec_fn,
329 active_item);
330 UI_but_func_search_set_tooltip(but, item_tooltip_fn);
331
332 UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
334
335 /* give search-field focus */
337 /* this type of search menu requires undo */
338 but->flag |= UI_BUT_UNDO;
339
340 return block;
341}
342
344
345/* -------------------------------------------------------------------- */
348
360
361/* Search browse menu, assign. */
362static void template_ID_set_property_exec_fn(bContext *C, void *arg_template, void *item)
363{
364 TemplateID *template_ui = (TemplateID *)arg_template;
365
366 /* ID */
367 if (item) {
368 PointerRNA idptr = RNA_id_pointer_create(static_cast<ID *>(item));
369 RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, nullptr);
370 RNA_property_update(C, &template_ui->ptr, template_ui->prop);
371 }
372}
373
374static bool id_search_allows_id(TemplateID *template_ui, const int flag, ID *id, const char *query)
375{
376 ID *id_from = template_ui->ptr.owner_id;
377
378 /* Do self check. */
379 if ((flag & PROP_ID_SELF_CHECK) && id == id_from) {
380 return false;
381 }
382
383 /* Use filter. */
384 if (RNA_property_type(template_ui->prop) == PROP_POINTER) {
386 if (RNA_property_pointer_poll(&template_ui->ptr, template_ui->prop, &ptr) == 0) {
387 return false;
388 }
389 }
390
391 /* Hide dot prefixed data-blocks, but only if filter does not force them visible. */
392 if (U.uiflag & USER_HIDE_DOT) {
393 if ((id->name[2] == '.') && (query[0] != '.')) {
394 return false;
395 }
396 }
397
398 return true;
399}
400
401static bool id_search_add(const bContext *C, TemplateID *template_ui, uiSearchItems *items, ID *id)
402{
403 /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix
404 * followed by ID_NAME-2 characters from id->name
405 */
406 char name_ui[MAX_ID_FULL_NAME_UI];
407 int iconid = ui_id_icon_get(C, id, template_ui->preview);
408 const bool use_lib_prefix = template_ui->preview || iconid;
409 const bool has_sep_char = ID_IS_LINKED(id);
410
411 /* When using previews, the library hint (linked, overridden, missing) is added with a
412 * character prefix, otherwise we can use a icon. */
413 int name_prefix_offset;
414 BKE_id_full_name_ui_prefix_get(name_ui, id, use_lib_prefix, UI_SEP_CHAR, &name_prefix_offset);
415 if (!use_lib_prefix) {
416 iconid = UI_icon_from_library(id);
417 }
418
419 if (!UI_search_item_add(items,
420 name_ui,
421 id,
422 iconid,
423 has_sep_char ? int(UI_BUT_HAS_SEP_CHAR) : 0,
424 name_prefix_offset))
425 {
426 return false;
427 }
428
429 return true;
430}
431
432/* ID Search browse menu, do the search */
433static void id_search_cb(const bContext *C,
434 void *arg_template,
435 const char *str,
436 uiSearchItems *items,
437 const bool /*is_first*/)
438{
439 TemplateID *template_ui = (TemplateID *)arg_template;
440 ListBase *lb = template_ui->idlb;
441 const int flag = RNA_property_flag(template_ui->prop);
442
444
445 /* ID listbase */
446 LISTBASE_FOREACH (ID *, id, lb) {
447 if (id_search_allows_id(template_ui, flag, id, str)) {
448 search.add(id->name + 2, id);
449 }
450 }
451
452 const blender::Vector<ID *> filtered_ids = search.query(str);
453
454 for (ID *id : filtered_ids) {
455 if (!id_search_add(C, template_ui, items, id)) {
456 break;
457 }
458 }
459}
460
464static void id_search_cb_tagged(const bContext *C,
465 void *arg_template,
466 const char *str,
467 uiSearchItems *items)
468{
469 TemplateID *template_ui = (TemplateID *)arg_template;
470 ListBase *lb = template_ui->idlb;
471 const int flag = RNA_property_flag(template_ui->prop);
472
475
476 /* ID listbase */
477 LISTBASE_FOREACH (ID *, id, lb) {
478 if (id->tag & ID_TAG_DOIT) {
479 if (id_search_allows_id(template_ui, flag, id, str)) {
480 search.add(id->name + 2, id);
481 }
482 id->tag &= ~ID_TAG_DOIT;
483 }
484 }
485
486 blender::Vector<ID *> filtered_ids = search.query(str);
487
488 for (ID *id : filtered_ids) {
489 if (!id_search_add(C, template_ui, items, id)) {
490 break;
491 }
492 }
493}
494
499 void *arg_template,
500 const char *str,
501 uiSearchItems *items,
502 const bool /*is_first*/)
503{
504 TemplateID *template_ui = (TemplateID *)arg_template;
505 ListBase *lb = template_ui->idlb;
506 Scene *scene = nullptr;
507 ID *id_from = template_ui->ptr.owner_id;
508
509 if (id_from && GS(id_from->name) == ID_SCE) {
510 scene = (Scene *)id_from;
511 }
512 else {
513 scene = CTX_data_scene(C);
514 }
515
517
518 FOREACH_SCENE_OBJECT_BEGIN (scene, ob_iter) {
519 ob_iter->id.tag |= ID_TAG_DOIT;
520 }
522 id_search_cb_tagged(C, arg_template, str, items);
523}
524
526 bContext *C, ARegion *region, const rcti *item_rect, void * /*arg*/, void *active)
527{
528 ID *active_id = static_cast<ID *>(active);
529 return UI_tooltip_create_from_search_item_generic(C, region, item_rect, active_id);
530}
531
532/* ID Search browse menu, open */
533static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
534{
535 static TemplateID template_ui;
536 PointerRNA active_item_ptr;
537 void (*id_search_update_fn)(
538 const bContext *, void *, const char *, uiSearchItems *, const bool) = id_search_cb;
539
540 /* arg_litem is malloced, can be freed by parent button */
541 template_ui = *((TemplateID *)arg_litem);
542 active_item_ptr = RNA_property_pointer_get(&template_ui.ptr, template_ui.prop);
543
544 if (template_ui.filter) {
545 /* Currently only used for objects. */
546 if (template_ui.idcode == ID_OB) {
547 if (template_ui.filter == UI_TEMPLATE_ID_FILTER_AVAILABLE) {
548 id_search_update_fn = id_search_cb_objects_from_scene;
549 }
550 }
551 }
552
554 region,
555 id_search_update_fn,
556 &template_ui,
558 active_item_ptr.data,
560 template_ui.prv_rows,
561 template_ui.prv_cols,
562 template_ui.scale);
563}
564
566
567/* -------------------------------------------------------------------- */
570
571static void template_id_cb(bContext *C, void *arg_litem, void *arg_event);
572
574 PointerRNA *r_ptr,
575 PropertyRNA **r_prop)
576{
578
579 *r_ptr = {};
580 *r_prop = nullptr;
581
582 if (but && (but->funcN == template_id_cb) && but->func_argN) {
583 TemplateID *template_ui = static_cast<TemplateID *>(but->func_argN);
584 *r_ptr = template_ui->ptr;
585 *r_prop = template_ui->prop;
586 }
587}
588
590 Collection *collection,
591 const int parent_level,
592 Collection **r_collection_parent_best,
593 int *r_parent_level_best)
594{
595 if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY_REAL(collection)) {
596 return;
597 }
598 if (ID_IS_OVERRIDABLE_LIBRARY(collection) || ID_IS_OVERRIDE_LIBRARY_REAL(collection)) {
599 if (parent_level > *r_parent_level_best) {
600 *r_parent_level_best = parent_level;
601 *r_collection_parent_best = collection;
602 }
603 }
604 for (CollectionParent *iter = static_cast<CollectionParent *>(collection->runtime.parents.first);
605 iter != nullptr;
606 iter = iter->next)
607 {
608 if (iter->collection->id.lib != collection->id.lib && ID_IS_LINKED(iter->collection)) {
609 continue;
610 }
612 iter->collection, parent_level + 1, r_collection_parent_best, r_parent_level_best);
613 }
614}
615
617 Collection *root_collection, ID *target_id, const bool do_parents)
618{
619 root_collection->id.tag |= ID_TAG_DOIT;
620
621 /* Tag all local parents of the root collection, so that usages of the root collection and other
622 * linked ones can be replaced by the local overrides in those parents too. */
623 if (do_parents) {
624 for (CollectionParent *iter =
625 static_cast<CollectionParent *>(root_collection->runtime.parents.first);
626 iter != nullptr;
627 iter = iter->next)
628 {
629 if (ID_IS_LINKED(iter->collection)) {
630 continue;
631 }
632 iter->collection->id.tag |= ID_TAG_DOIT;
633 }
634 }
635
636 for (CollectionChild *iter = static_cast<CollectionChild *>(root_collection->children.first);
637 iter != nullptr;
638 iter = iter->next)
639 {
640 if (ID_IS_LINKED(iter->collection) && iter->collection->id.lib != target_id->lib) {
641 continue;
642 }
643 if (GS(target_id->name) == ID_OB &&
644 !BKE_collection_has_object_recursive(iter->collection, (Object *)target_id))
645 {
646 continue;
647 }
648 if (GS(target_id->name) == ID_GR &&
649 !BKE_collection_has_collection(iter->collection, (Collection *)target_id))
650 {
651 continue;
652 }
654 iter->collection, target_id, false);
655 }
656}
657
659 bContext *C, Main *bmain, ID *owner_id, ID *id, const char **r_undo_push_label)
660{
661 const char *undo_push_label;
662 if (r_undo_push_label == nullptr) {
663 r_undo_push_label = &undo_push_label;
664 }
665
666 /* If this is called on an already local override, 'toggle' between user-editable state, and
667 * system override with reset. */
668 if (!ID_IS_LINKED(id) && ID_IS_OVERRIDE_LIBRARY(id)) {
670 BKE_lib_override_library_get(bmain, id, nullptr, &id);
671 }
673 id->override_library->flag &= ~LIBOVERRIDE_FLAG_SYSTEM_DEFINED;
674 *r_undo_push_label = "Make Library Override Hierarchy Editable";
675 }
676 else {
677 BKE_lib_override_library_id_reset(bmain, id, true);
678 *r_undo_push_label = "Clear Library Override Hierarchy";
679 }
680
684 return id;
685 }
686
687 /* Attempt to perform a hierarchy override, based on contextual data available.
688 * NOTE: do not attempt to perform such hierarchy override at all cost, if there is not enough
689 * context, better to abort than create random overrides all over the place. */
691 WM_reportf(RPT_ERROR, "The data-block %s is not overridable", id->name);
692 return nullptr;
693 }
694
695 Object *object_active = CTX_data_active_object(C);
696 if (object_active == nullptr && GS(owner_id->name) == ID_OB) {
697 object_active = (Object *)owner_id;
698 }
699 if (object_active != nullptr) {
700 if (ID_IS_LINKED(object_active)) {
701 if (object_active->id.lib != id->lib || !ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(object_active))
702 {
703 /* The active object is from a different library than the overridden ID, or otherwise
704 * cannot be used in hierarchy. */
705 object_active = nullptr;
706 }
707 }
708 else if (!ID_IS_OVERRIDE_LIBRARY_REAL(object_active)) {
709 /* Fully local object cannot be used in override hierarchy either. */
710 object_active = nullptr;
711 }
712 }
713
714 Collection *collection_active_context = CTX_data_collection(C);
715 Collection *collection_active = collection_active_context;
716 if (collection_active == nullptr && GS(owner_id->name) == ID_GR) {
717 collection_active = (Collection *)owner_id;
718 }
719 if (collection_active != nullptr) {
720 if (ID_IS_LINKED(collection_active)) {
721 if (collection_active->id.lib != id->lib ||
722 !ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(collection_active))
723 {
724 /* The active collection is from a different library than the overridden ID, or otherwise
725 * cannot be used in hierarchy. */
726 collection_active = nullptr;
727 }
728 else {
729 int parent_level_best = -1;
730 Collection *collection_parent_best = nullptr;
732 collection_active, 0, &collection_parent_best, &parent_level_best);
733 collection_active = collection_parent_best;
734 }
735 }
736 else if (!ID_IS_OVERRIDE_LIBRARY_REAL(collection_active)) {
737 /* Fully local collection cannot be used in override hierarchy either. */
738 collection_active = nullptr;
739 }
740 }
741 if (collection_active == nullptr && object_active != nullptr &&
742 (ID_IS_LINKED(object_active) || ID_IS_OVERRIDE_LIBRARY_REAL(object_active)))
743 {
744 /* If we failed to find a valid 'active' collection so far for our override hierarchy, but do
745 * have a valid 'active' object, try to find a collection from that object. */
746 LISTBASE_FOREACH (Collection *, collection_iter, &bmain->collections) {
747 if (ID_IS_LINKED(collection_iter) && collection_iter->id.lib != id->lib) {
748 continue;
749 }
750 if (!ID_IS_OVERRIDE_LIBRARY_REAL(collection_iter)) {
751 continue;
752 }
753 if (!BKE_collection_has_object_recursive(collection_iter, object_active)) {
754 continue;
755 }
756 int parent_level_best = -1;
757 Collection *collection_parent_best = nullptr;
759 collection_iter, 0, &collection_parent_best, &parent_level_best);
760 collection_active = collection_parent_best;
761 break;
762 }
763 }
764
765 ID *id_override = nullptr;
766 Scene *scene = CTX_data_scene(C);
767 ViewLayer *view_layer = CTX_data_view_layer(C);
768 switch (GS(id->name)) {
769 case ID_GR:
770 if (collection_active != nullptr &&
771 BKE_collection_has_collection(collection_active, (Collection *)id))
772 {
774 if (object_active != nullptr) {
775 object_active->id.tag |= ID_TAG_DOIT;
776 }
778 scene,
779 view_layer,
780 nullptr,
781 id,
782 &collection_active->id,
783 nullptr,
784 &id_override,
785 false);
786 }
787 else if (object_active != nullptr && !ID_IS_LINKED(object_active) &&
788 &object_active->instance_collection->id == id)
789 {
790 object_active->id.tag |= ID_TAG_DOIT;
792 scene,
793 view_layer,
794 id->lib,
795 id,
796 &object_active->id,
797 &object_active->id,
798 &id_override,
799 false);
800 }
801 break;
802 case ID_OB:
803 if (collection_active != nullptr &&
804 BKE_collection_has_object_recursive(collection_active, (Object *)id))
805 {
807 if (object_active != nullptr) {
808 object_active->id.tag |= ID_TAG_DOIT;
809 }
811 scene,
812 view_layer,
813 nullptr,
814 id,
815 &collection_active->id,
816 nullptr,
817 &id_override,
818 false);
819 }
820 else {
821 if (object_active != nullptr) {
822 object_active->id.tag |= ID_TAG_DOIT;
823 }
825 bmain, scene, view_layer, nullptr, id, nullptr, nullptr, &id_override, false);
826 BKE_scene_collections_object_remove(bmain, scene, (Object *)id, true);
828 }
829 break;
830 case ID_ME:
831 case ID_CU_LEGACY:
832 case ID_MB:
833 case ID_LT:
834 case ID_LA:
835 case ID_CA:
836 case ID_SPK:
837 case ID_AR:
838 case ID_GD_LEGACY:
839 case ID_CV:
840 case ID_PT:
841 case ID_VO:
842 case ID_NT: /* Essentially geometry nodes from modifier currently. */
843 if (object_active != nullptr) {
844 if (collection_active != nullptr &&
845 BKE_collection_has_object_recursive(collection_active, object_active))
846 {
848 object_active->id.tag |= ID_TAG_DOIT;
850 scene,
851 view_layer,
852 nullptr,
853 id,
854 &collection_active->id,
855 nullptr,
856 &id_override,
857 false);
858 }
859 else {
860 object_active->id.tag |= ID_TAG_DOIT;
862 scene,
863 view_layer,
864 nullptr,
865 id,
866 &object_active->id,
867 nullptr,
868 &id_override,
869 false);
870 }
871 }
872 else {
874 bmain, scene, view_layer, nullptr, id, id, nullptr, &id_override, false);
875 }
876 break;
877 case ID_MA:
878 case ID_TE:
879 case ID_IM:
880 WM_reportf(RPT_WARNING, "The type of data-block %s is not yet implemented", id->name);
881 break;
882 case ID_WO:
883 WM_reportf(RPT_WARNING, "The type of data-block %s is not yet implemented", id->name);
884 break;
885 case ID_PA:
886 WM_reportf(RPT_WARNING, "The type of data-block %s is not yet implemented", id->name);
887 break;
888 default:
889 WM_reportf(RPT_WARNING, "The type of data-block %s is not yet implemented", id->name);
890 break;
891 }
892
893 if (id_override != nullptr) {
895
896 /* Ensure that the hierarchy root of the newly overridden data is instantiated in the scene, in
897 * case it's a collection or object. */
898 ID *hierarchy_root = id_override->override_library->hierarchy_root;
899 if (GS(hierarchy_root->name) == ID_OB) {
900 Object *object_hierarchy_root = reinterpret_cast<Object *>(hierarchy_root);
901 if (!BKE_scene_has_object(scene, object_hierarchy_root)) {
902 if (!ID_IS_LINKED(collection_active_context)) {
903 BKE_collection_object_add(bmain, collection_active_context, object_hierarchy_root);
904 }
905 else {
906 BKE_collection_object_add(bmain, scene->master_collection, object_hierarchy_root);
907 }
908 }
909 }
910 else if (GS(hierarchy_root->name) == ID_GR) {
911 Collection *collection_hierarchy_root = reinterpret_cast<Collection *>(hierarchy_root);
912 if (!BKE_collection_has_collection(scene->master_collection, collection_hierarchy_root)) {
913 if (!ID_IS_LINKED(collection_active_context)) {
914 BKE_collection_child_add(bmain, collection_active_context, collection_hierarchy_root);
915 }
916 else {
917 BKE_collection_child_add(bmain, scene->master_collection, collection_hierarchy_root);
918 }
919 }
920 }
921
922 *r_undo_push_label = "Make Library Override Hierarchy";
923
924 /* In theory we could rely on setting/updating the RNA ID pointer property (as done by calling
925 * code) to be enough.
926 *
927 * However, some rare ID pointers properties (like the 'active object in viewlayer' one used
928 * for the Object templateID in the Object properties) use notifiers that do not enforce a
929 * rebuild of outliner trees, leading to crashes.
930 *
931 * So for now, add some extra notifiers here. */
934 }
935 return id_override;
936}
937
939 Main *bmain,
940 TemplateID *template_ui,
941 PointerRNA *idptr,
942 const char **r_undo_push_label)
943{
944 ID *id = static_cast<ID *>(idptr->data);
945 ID *owner_id = template_ui->ptr.owner_id;
946
948 C, bmain, owner_id, id, r_undo_push_label);
949
950 if (id_override != nullptr) {
951 /* `idptr` is re-assigned to owner property to ensure proper updates etc. Here we also use it
952 * to ensure remapping of the owner property from the linked data to the newly created
953 * liboverride (note that in theory this remapping has already been done by code above), but
954 * only in case owner ID was already local ID (override or pure local data).
955 *
956 * Otherwise, owner ID will also have been overridden, and remapped already to use it's
957 * override of the data too. */
958 if (!ID_IS_LINKED(owner_id)) {
959 *idptr = RNA_id_pointer_create(id_override);
960 }
961 }
962 else {
963 WM_reportf(RPT_ERROR, "The data-block %s could not be overridden", id->name);
964 }
965}
966
967static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
968{
969 TemplateID *template_ui = (TemplateID *)arg_litem;
970 PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
971 ID *id = static_cast<ID *>(idptr.data);
972 const int event = POINTER_AS_INT(arg_event);
973 const char *undo_push_label = nullptr;
974
975 switch (event) {
976 case UI_ID_NOP:
977 /* Don't do anything, typically set for buttons that execute an operator instead. They may
978 * still assign the callback so the button can be identified as part of an ID-template. See
979 * #UI_context_active_but_prop_get_templateID(). */
980 break;
981 case UI_ID_RENAME:
982 /* Only for the undo push. */
983 undo_push_label = "Rename Data-Block";
984 break;
985 case UI_ID_BROWSE:
986 case UI_ID_PIN:
987 RNA_warning("warning, id event %d shouldn't come here", event);
988 break;
989 case UI_ID_OPEN:
990 case UI_ID_ADD_NEW:
991 /* these call UI_context_active_but_prop_get_templateID */
992 break;
993 case UI_ID_DELETE:
994 idptr = {};
995 RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, nullptr);
996 RNA_property_update(C, &template_ui->ptr, template_ui->prop);
997
998 if (id && CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
999 /* only way to force-remove data (on save) */
1000 id_us_clear_real(id);
1002 id->us = 0;
1003 undo_push_label = "Delete Data-Block";
1004 }
1005 else {
1006 undo_push_label = "Unlink Data-Block";
1007 }
1008
1009 break;
1010 case UI_ID_FAKE_USER:
1011 if (id) {
1012 if (id->flag & ID_FLAG_FAKEUSER) {
1013 id_us_plus(id);
1014 }
1015 else {
1016 id_us_min(id);
1017 }
1018 undo_push_label = "Fake User";
1019 }
1020 else {
1021 return;
1022 }
1023 break;
1024 case UI_ID_LOCAL:
1025 if (id) {
1026 Main *bmain = CTX_data_main(C);
1027 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
1028 template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label);
1029 }
1030 else {
1033
1034 /* Reassign to get proper updates/notifiers. */
1035 idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
1036 undo_push_label = "Make Local";
1037 }
1038 }
1039 if (undo_push_label != nullptr) {
1040 RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, nullptr);
1041 RNA_property_update(C, &template_ui->ptr, template_ui->prop);
1042 }
1043 }
1044 break;
1045 case UI_ID_OVERRIDE:
1046 if (id && ID_IS_OVERRIDE_LIBRARY(id)) {
1047 Main *bmain = CTX_data_main(C);
1048 if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
1049 template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label);
1050 }
1051 else {
1053 /* Reassign to get proper updates/notifiers. */
1054 idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
1055 RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, nullptr);
1056 RNA_property_update(C, &template_ui->ptr, template_ui->prop);
1057 undo_push_label = "Make Local";
1058 }
1059 }
1060 break;
1061 case UI_ID_ALONE:
1062 if (id) {
1063 const bool do_scene_obj = ((GS(id->name) == ID_OB) &&
1064 (template_ui->ptr.type == &RNA_LayerObjects));
1065
1066 /* make copy */
1067 if (do_scene_obj) {
1068 Main *bmain = CTX_data_main(C);
1069 Scene *scene = CTX_data_scene(C);
1073 }
1074 else {
1075 Main *bmain = CTX_data_main(C);
1076 id_single_user(C, id, &template_ui->ptr, template_ui->prop);
1079 }
1080 undo_push_label = "Make Single User";
1081 }
1082 break;
1083#if 0
1084 case UI_ID_AUTO_NAME:
1085 break;
1086#endif
1087 }
1088
1089 if (undo_push_label != nullptr) {
1090 ED_undo_push(C, undo_push_label);
1091 }
1092}
1093
1094static const char *template_id_browse_tip(const StructRNA *type)
1095{
1096 if (type) {
1097 switch ((ID_Type)RNA_type_to_ID_code(type)) {
1098 case ID_SCE:
1099 return N_("Browse Scene to be linked");
1100 case ID_OB:
1101 return N_("Browse Object to be linked");
1102 case ID_ME:
1103 return N_("Browse Mesh Data to be linked");
1104 case ID_CU_LEGACY:
1105 return N_("Browse Curve Data to be linked");
1106 case ID_MB:
1107 return N_("Browse Metaball Data to be linked");
1108 case ID_MA:
1109 return N_("Browse Material to be linked");
1110 case ID_TE:
1111 return N_("Browse Texture to be linked");
1112 case ID_IM:
1113 return N_("Browse Image to be linked");
1114 case ID_LS:
1115 return N_("Browse Line Style Data to be linked");
1116 case ID_LT:
1117 return N_("Browse Lattice Data to be linked");
1118 case ID_LA:
1119 return N_("Browse Light Data to be linked");
1120 case ID_CA:
1121 return N_("Browse Camera Data to be linked");
1122 case ID_WO:
1123 return N_("Browse World Settings to be linked");
1124 case ID_SCR:
1125 return N_("Choose Screen layout");
1126 case ID_TXT:
1127 return N_("Browse Text to be linked");
1128 case ID_SPK:
1129 return N_("Browse Speaker Data to be linked");
1130 case ID_SO:
1131 return N_("Browse Sound to be linked");
1132 case ID_AR:
1133 return N_("Browse Armature data to be linked");
1134 case ID_AC:
1135 return N_("Browse Action to be linked");
1136 case ID_NT:
1137 return N_("Browse Node Tree to be linked");
1138 case ID_BR:
1139 return N_("Browse Brush to be linked");
1140 case ID_PA:
1141 return N_("Browse Particle Settings to be linked");
1142 case ID_GD_LEGACY:
1143 return N_("Browse Grease Pencil Data to be linked");
1144 case ID_MC:
1145 return N_("Browse Movie Clip to be linked");
1146 case ID_MSK:
1147 return N_("Browse Mask to be linked");
1148 case ID_PAL:
1149 return N_("Browse Palette Data to be linked");
1150 case ID_PC:
1151 return N_("Browse Paint Curve Data to be linked");
1152 case ID_CF:
1153 return N_("Browse Cache Files to be linked");
1154 case ID_WS:
1155 return N_("Browse Workspace to be linked");
1156 case ID_LP:
1157 return N_("Browse LightProbe to be linked");
1158 case ID_CV:
1159 return N_("Browse Curves Data to be linked");
1160 case ID_PT:
1161 return N_("Browse Point Cloud Data to be linked");
1162 case ID_VO:
1163 return N_("Browse Volume Data to be linked");
1164 case ID_GP:
1165 return N_("Browse Grease Pencil v3 Data to be linked");
1166
1167 /* Use generic text. */
1168 case ID_LI:
1169 case ID_IP:
1170 case ID_KE:
1171 case ID_VF:
1172 case ID_GR:
1173 case ID_WM:
1174 break;
1175 }
1176 }
1177 return N_("Browse ID data to be linked");
1178}
1179
1185static void template_id_workspace_pin_extra_icon(const TemplateID &template_ui, uiBut *but)
1186{
1187 if ((template_ui.idcode != ID_SCE) || (template_ui.ptr.type != &RNA_Window)) {
1188 return;
1189 }
1190
1191 const wmWindow *win = static_cast<const wmWindow *>(template_ui.ptr.data);
1192 const WorkSpace *workspace = WM_window_get_active_workspace(win);
1194 "WORKSPACE_OT_scene_pin_toggle",
1196 (workspace->flags & WORKSPACE_USE_PIN_SCENE) ? ICON_PINNED :
1197 ICON_UNPINNED);
1198}
1199
1204#ifdef WITH_INTERNATIONAL
1205static const char *template_id_context(StructRNA *type)
1206{
1207 if (type) {
1209 }
1211}
1212#else
1213# define template_id_context(type) 0
1214#endif
1215
1217 const ID *id,
1218 const TemplateID &template_ui,
1219 StructRNA *type,
1220 const char *const newop,
1221 const bool editable,
1222 const bool id_open,
1223 const bool use_tab_but,
1224 int but_height)
1225{
1226 ID *idfrom = template_ui.ptr.owner_id;
1227 uiBut *but;
1228 const int but_type = use_tab_but ? UI_BTYPE_TAB : UI_BTYPE_BUT;
1229
1230 /* i18n markup, does nothing! */
1265 /* NOTE: BLT_I18N_MSGID_MULTI_CTXT takes a maximum number of parameters,
1266 * check the definition to see if a new call must be added when the limit
1267 * is exceeded. */
1268
1269 const char *button_text = (id) ? "" : CTX_IFACE_(template_id_context(type), "New");
1270 const int icon = (id && !use_tab_but) ? ICON_DUPLICATE : ICON_ADD;
1271 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
1272
1273 int w = id ? UI_UNIT_X : id_open ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
1274 if (!id) {
1275 w = std::max(UI_fontstyle_string_width(fstyle, button_text) + int(UI_UNIT_X * 1.5f), w);
1276 }
1277
1278 if (newop) {
1279 but = uiDefIconTextButO(block,
1280 but_type,
1281 newop,
1283 icon,
1284 button_text,
1285 0,
1286 0,
1287 w,
1288 but_height,
1289 nullptr);
1290 UI_but_funcN_set(but,
1292 MEM_new<TemplateID>(__func__, template_ui),
1296 }
1297 else {
1298 but = uiDefIconTextBut(
1299 block, but_type, 0, icon, button_text, 0, 0, w, but_height, nullptr, 0, 0, nullptr);
1300 UI_but_funcN_set(but,
1302 MEM_new<TemplateID>(__func__, template_ui),
1306 }
1307
1308 if ((idfrom && !ID_IS_EDITABLE(idfrom)) || !editable) {
1310 }
1311
1312#ifndef WITH_INTERNATIONAL
1313 UNUSED_VARS(type);
1314#endif
1315
1316 return but;
1317}
1318
1319static void template_ID(const bContext *C,
1320 uiLayout *layout,
1321 TemplateID &template_ui,
1322 StructRNA *type,
1323 int flag,
1324 const char *newop,
1325 const char *openop,
1326 const char *unlinkop,
1327 const char *text,
1328 const bool live_icon,
1329 const bool hide_buttons)
1330{
1331 uiBut *but;
1332 const bool editable = RNA_property_editable(&template_ui.ptr, template_ui.prop);
1333 const bool use_previews = template_ui.preview = (flag & UI_ID_PREVIEWS) != 0;
1334
1335 PointerRNA idptr = RNA_property_pointer_get(&template_ui.ptr, template_ui.prop);
1336 ID *id = static_cast<ID *>(idptr.data);
1337 ID *idfrom = template_ui.ptr.owner_id;
1338 // lb = template_ui->idlb;
1339
1340 /* Allow operators to take the ID from context. */
1341 uiLayoutSetContextPointer(layout, "id", &idptr);
1342
1343 uiBlock *block = uiLayoutGetBlock(layout);
1344 UI_block_align_begin(block);
1345
1346 if (idptr.type) {
1347 type = idptr.type;
1348 }
1349
1350 if (text && text[0]) {
1351 /* Add label respecting the separated layout property split state. */
1352 uiItemL_respect_property_split(layout, text, ICON_NONE);
1353 }
1354
1355 if (flag & UI_ID_BROWSE) {
1357 layout,
1358 block,
1359 &template_ui.ptr,
1360 template_ui.prop,
1362 MEM_new<TemplateID>(__func__, template_ui),
1364 use_previews,
1365 editable,
1366 live_icon,
1369 }
1370
1371 /* text button with name */
1372 if (id) {
1373 char name[UI_MAX_NAME_STR];
1374 const bool user_alert = (id->us <= 0);
1375
1376 int width = template_search_textbut_width(&idptr, RNA_struct_find_property(&idptr, "name"));
1377
1378 if ((template_ui.idcode == ID_SCE) && (template_ui.ptr.type == &RNA_Window)) {
1379 /* More room needed for "pin" icon. */
1380 width += UI_UNIT_X;
1381 }
1382
1383 const int height = template_search_textbut_height();
1384
1385 // text_idbutton(id, name);
1386 name[0] = '\0';
1387 but = uiDefButR(block,
1389 0,
1390 name,
1391 0,
1392 0,
1393 width,
1394 height,
1395 &idptr,
1396 "name",
1397 -1,
1398 0,
1399 0,
1401 /* Handle undo through the #template_id_cb set below. Default undo handling from the button
1402 * code (see #ui_apply_but_undo) would not work here, as the new name is not yet applied to the
1403 * ID. */
1405 Main *bmain = CTX_data_main(C);
1406 UI_but_func_rename_full_set(but, [bmain, id](std::string &new_name) {
1407 ED_id_rename(*bmain, *id, new_name);
1409 });
1410 UI_but_funcN_set(but,
1412 MEM_new<TemplateID>(__func__, template_ui),
1416 if (user_alert) {
1418 }
1419
1420 template_id_workspace_pin_extra_icon(template_ui, but);
1421
1422 if (!hide_buttons && !(idfrom && ID_IS_LINKED(idfrom))) {
1423 if (ID_IS_LINKED(id)) {
1424 const bool disabled = !BKE_idtype_idcode_is_localizable(GS(id->name));
1425 if (id->tag & ID_TAG_INDIRECT) {
1426 but = uiDefIconBut(block,
1428 0,
1429 ICON_LIBRARY_DATA_INDIRECT,
1430 0,
1431 0,
1432 UI_UNIT_X,
1433 UI_UNIT_Y,
1434 nullptr,
1435 0,
1436 0,
1437 TIP_("Indirect library data-block, cannot be made local, "
1438 "Shift + Click to create a library override hierarchy"));
1439 }
1440 else {
1441 but = uiDefIconBut(block,
1443 0,
1444 ICON_LIBRARY_DATA_DIRECT,
1445 0,
1446 0,
1447 UI_UNIT_X,
1448 UI_UNIT_Y,
1449 nullptr,
1450 0,
1451 0,
1452 TIP_("Direct linked library data-block, click to make local, "
1453 "Shift + Click to create a library override"));
1454 }
1455 if (disabled) {
1457 }
1458 else {
1459 UI_but_funcN_set(but,
1461 MEM_new<TemplateID>(__func__, template_ui),
1465 }
1466 }
1467 else if (ID_IS_OVERRIDE_LIBRARY(id)) {
1468 but = uiDefIconBut(
1469 block,
1471 0,
1472 ICON_LIBRARY_DATA_OVERRIDE,
1473 0,
1474 0,
1475 UI_UNIT_X,
1476 UI_UNIT_Y,
1477 nullptr,
1478 0,
1479 0,
1480 TIP_("Library override of linked data-block, click to make fully local, "
1481 "Shift + Click to clear the library override and toggle if it can be edited"));
1482 UI_but_funcN_set(but,
1484 MEM_new<TemplateID>(__func__, template_ui),
1488 }
1489 }
1490
1491 if ((ID_REAL_USERS(id) > 1) && (hide_buttons == false)) {
1492 char numstr[32];
1493 short numstr_len;
1494
1495 numstr_len = SNPRINTF_RLEN(numstr, "%d", ID_REAL_USERS(id));
1496
1497 but = uiDefBut(
1498 block,
1500 0,
1501 numstr,
1502 0,
1503 0,
1504 numstr_len * 0.2f * UI_UNIT_X + UI_UNIT_X,
1505 UI_UNIT_Y,
1506 nullptr,
1507 0,
1508 0,
1509 TIP_("Display number of users of this data (click to make a single-user copy)"));
1510 but->flag |= UI_BUT_UNDO;
1511
1512 UI_but_funcN_set(but,
1514 MEM_new<TemplateID>(__func__, template_ui),
1518 if (!BKE_id_copy_is_allowed(id) || (idfrom && !ID_IS_EDITABLE(idfrom)) || (!editable) ||
1519 /* object in editmode - don't change data */
1520 (idfrom && GS(idfrom->name) == ID_OB && (((Object *)idfrom)->mode & OB_MODE_EDIT)))
1521 {
1523 }
1524 }
1525
1526 if (user_alert) {
1528 }
1529
1530 if (!ID_IS_LINKED(id)) {
1531 if (ID_IS_ASSET(id)) {
1532 uiDefIconButO(block,
1533 /* Using `_N` version allows us to get the 'active' state by default. */
1535 "ASSET_OT_clear_single",
1537 /* 'active' state of a toggle button uses icon + 1, so to get proper asset
1538 * icon we need to pass its value - 1 here. */
1539 ICON_ASSET_MANAGER - 1,
1540 0,
1541 0,
1542 UI_UNIT_X,
1543 UI_UNIT_Y,
1544 nullptr);
1545 }
1546 else if (!ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_OB, ID_WS) && (hide_buttons == false))
1547 {
1548 uiDefIconButR(block,
1550 0,
1551 ICON_FAKE_USER_OFF,
1552 0,
1553 0,
1554 UI_UNIT_X,
1555 UI_UNIT_Y,
1556 &idptr,
1557 "use_fake_user",
1558 -1,
1559 0,
1560 0,
1561 nullptr);
1562 }
1563 }
1564 }
1565
1566 if ((flag & UI_ID_ADD_NEW) && (hide_buttons == false)) {
1568 block, id, template_ui, type, newop, editable, flag & UI_ID_OPEN, false, UI_UNIT_X);
1569 }
1570
1571 /* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack.
1572 * Only for images, sound and fonts */
1573 if (id && BKE_packedfile_id_check(id)) {
1574 but = uiDefIconButO(block,
1576 "FILE_OT_unpack_item",
1578 ICON_PACKAGE,
1579 0,
1580 0,
1581 UI_UNIT_X,
1582 UI_UNIT_Y,
1583 TIP_("Packed File, click to unpack"));
1585
1586 RNA_string_set(but->opptr, "id_name", id->name + 2);
1587 RNA_int_set(but->opptr, "id_type", GS(id->name));
1588
1589 if (!ID_IS_EDITABLE(id)) {
1591 }
1592 }
1593 else if (flag & UI_ID_OPEN) {
1594 const char *button_text = (id) ? "" : IFACE_("Open");
1595 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
1596
1597 int w = id ? UI_UNIT_X : (flag & UI_ID_ADD_NEW) ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
1598 if (!id) {
1599 w = std::max(UI_fontstyle_string_width(fstyle, button_text) + int(UI_UNIT_X * 1.5f), w);
1600 }
1601
1602 if (openop) {
1603 but = uiDefIconTextButO(block,
1605 openop,
1607 ICON_FILEBROWSER,
1608 (id) ? "" : IFACE_("Open"),
1609 0,
1610 0,
1611 w,
1612 UI_UNIT_Y,
1613 nullptr);
1614 UI_but_funcN_set(but,
1616 MEM_new<TemplateID>(__func__, template_ui),
1620 }
1621 else {
1622 but = uiDefIconTextBut(block,
1624 0,
1625 ICON_FILEBROWSER,
1626 (id) ? "" : IFACE_("Open"),
1627 0,
1628 0,
1629 w,
1630 UI_UNIT_Y,
1631 nullptr,
1632 0,
1633 0,
1634 nullptr);
1635 UI_but_funcN_set(but,
1637 MEM_new<TemplateID>(__func__, template_ui),
1641 }
1642
1643 if ((idfrom && !ID_IS_EDITABLE(idfrom)) || !editable) {
1645 }
1646 }
1647
1648 /* delete button */
1649 /* don't use RNA_property_is_unlink here */
1650 if (id && (flag & UI_ID_DELETE) && (hide_buttons == false)) {
1651 /* allow unlink if 'unlinkop' is passed, even when 'PROP_NEVER_UNLINK' is set */
1652 but = nullptr;
1653
1654 if (unlinkop) {
1655 but = uiDefIconButO(block,
1657 unlinkop,
1659 ICON_X,
1660 0,
1661 0,
1662 UI_UNIT_X,
1663 UI_UNIT_Y,
1664 nullptr);
1665 /* so we can access the template from operators, font unlinking needs this */
1666 UI_but_funcN_set(but,
1668 MEM_new<TemplateID>(__func__, template_ui),
1672 }
1673 else {
1674 if ((RNA_property_flag(template_ui.prop) & PROP_NEVER_UNLINK) == 0) {
1675 but = uiDefIconBut(
1676 block,
1678 0,
1679 ICON_X,
1680 0,
1681 0,
1682 UI_UNIT_X,
1683 UI_UNIT_Y,
1684 nullptr,
1685 0,
1686 0,
1687 TIP_("Unlink data-block "
1688 "(Shift + Click to set users to zero, data will then not be saved)"));
1689 UI_but_funcN_set(but,
1691 MEM_new<TemplateID>(__func__, template_ui),
1695
1696 if (RNA_property_flag(template_ui.prop) & PROP_NEVER_NULL) {
1698 }
1699 }
1700 }
1701
1702 if (but) {
1703 if ((idfrom && !ID_IS_EDITABLE(idfrom)) || !editable) {
1705 }
1706 }
1707 }
1708
1709 if (template_ui.idcode == ID_TE) {
1710 uiTemplateTextureShow(layout, C, &template_ui.ptr, template_ui.prop);
1711 }
1712 UI_block_align_end(block);
1713}
1714
1716{
1718
1719 if (but && but->type == UI_BTYPE_TAB) {
1720 return static_cast<ID *>(but->custom_data);
1721 }
1722 return nullptr;
1723}
1724
1725static void template_ID_tabs(const bContext *C,
1726 uiLayout *layout,
1727 TemplateID &template_id,
1728 StructRNA *type,
1729 int flag,
1730 const char *newop,
1731 const char *menu)
1732{
1733 const ARegion *region = CTX_wm_region(C);
1734 const PointerRNA active_ptr = RNA_property_pointer_get(&template_id.ptr, template_id.prop);
1735 MenuType *mt = menu ? WM_menutype_find(menu, false) : nullptr;
1736
1737 const int but_align = ui_but_align_opposite_to_area_align_get(region);
1738 const int but_height = UI_UNIT_Y * 1.1;
1739
1740 uiBlock *block = uiLayoutGetBlock(layout);
1741 const uiStyle *style = UI_style_get_dpi();
1742
1743 for (ID *id : BKE_id_ordered_list(template_id.idlb)) {
1744 const int name_width = UI_fontstyle_string_width(&style->widget, id->name + 2);
1745 const int but_width = name_width + UI_UNIT_X;
1746
1747 uiButTab *tab = (uiButTab *)uiDefButR_prop(block,
1749 0,
1750 id->name + 2,
1751 0,
1752 0,
1753 but_width,
1754 but_height,
1755 &template_id.ptr,
1756 template_id.prop,
1757 0,
1758 0.0f,
1759 sizeof(id->name) - 2,
1760 "");
1761 UI_but_funcN_set(tab,
1763 MEM_new<TemplateID>(__func__, template_id),
1764 id,
1767 UI_but_drag_set_id(tab, id);
1768 tab->custom_data = (void *)id;
1769 tab->menu = mt;
1770
1771 UI_but_drawflag_enable(tab, but_align);
1772 }
1773
1774 if (flag & UI_ID_ADD_NEW) {
1775 const bool editable = RNA_property_editable(&template_id.ptr, template_id.prop);
1776 uiBut *but;
1777
1778 if (active_ptr.type) {
1779 type = active_ptr.type;
1780 }
1781
1782 but = template_id_def_new_but(block,
1783 static_cast<const ID *>(active_ptr.data),
1784 template_id,
1785 type,
1786 newop,
1787 editable,
1788 flag & UI_ID_OPEN,
1789 true,
1790 but_height);
1791 UI_but_drawflag_enable(but, but_align);
1792 }
1793}
1794
1795static void ui_template_id(uiLayout *layout,
1796 const bContext *C,
1797 PointerRNA *ptr,
1798 const char *propname,
1799 const char *newop,
1800 const char *openop,
1801 const char *unlinkop,
1802 /* Only respected by tabs (use_tabs). */
1803 const char *menu,
1804 const char *text,
1805 int flag,
1806 int prv_rows,
1807 int prv_cols,
1808 int filter,
1809 bool use_tabs,
1810 float scale,
1811 const bool live_icon,
1812 const bool hide_buttons)
1813{
1814 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1815
1816 if (!prop || RNA_property_type(prop) != PROP_POINTER) {
1817 RNA_warning("pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1818 return;
1819 }
1820
1821 TemplateID template_ui;
1822 template_ui.ptr = *ptr;
1823 template_ui.prop = prop;
1824 template_ui.prv_rows = prv_rows;
1825 template_ui.prv_cols = prv_cols;
1826 template_ui.scale = scale;
1827
1828 if ((flag & UI_ID_PIN) == 0) {
1829 template_ui.filter = filter;
1830 }
1831 else {
1832 template_ui.filter = 0;
1833 }
1834
1835 if (newop) {
1837 }
1838 if (openop) {
1839 flag |= UI_ID_OPEN;
1840 }
1841
1843 short idcode = RNA_type_to_ID_code(type);
1844 template_ui.idcode = idcode;
1845 template_ui.idlb = which_libbase(CTX_data_main(C), idcode);
1846
1847 /* create UI elements for this template
1848 * - template_ID makes a copy of the template data and assigns it to the relevant buttons
1849 */
1850 if (template_ui.idlb) {
1851 if (use_tabs) {
1852 layout = uiLayoutRow(layout, true);
1853 template_ID_tabs(C, layout, template_ui, type, flag, newop, menu);
1854 }
1855 else {
1856 layout = uiLayoutRow(layout, true);
1857 template_ID(C,
1858 layout,
1859 template_ui,
1860 type,
1861 flag,
1862 newop,
1863 openop,
1864 unlinkop,
1865 text,
1866 live_icon,
1867 hide_buttons);
1868 }
1869 }
1870}
1871
1873 const bContext *C,
1874 PointerRNA *ptr,
1875 const char *propname,
1876 const char *newop,
1877 const char *openop,
1878 const char *unlinkop,
1879 int filter,
1880 const bool live_icon,
1881 const char *text)
1882{
1883 ui_template_id(layout,
1884 C,
1885 ptr,
1886 propname,
1887 newop,
1888 openop,
1889 unlinkop,
1890 nullptr,
1891 text,
1893 0,
1894 0,
1895 filter,
1896 false,
1897 1.0f,
1898 live_icon,
1899 false);
1900}
1901
1903 const bContext *C,
1904 ID *id,
1905 const char *newop,
1906 const char *unlinkop,
1907 const char *text)
1908{
1909 if (!id_can_have_animdata(id)) {
1910 RNA_warning("Cannot show Action selector for non-animatable ID: %s", id->name + 2);
1911 return;
1912 }
1913
1914 PropertyRNA *adt_action_prop = RNA_struct_type_find_property(&RNA_AnimData, "action");
1915 BLI_assert(adt_action_prop);
1916 BLI_assert(RNA_property_type(adt_action_prop) == PROP_POINTER);
1917
1918 /* Construct a pointer with the animated ID as owner, even when `adt` may be `nullptr`.
1919 * This way it is possible to use this RNA pointer to get/set `adt->action`, as that RNA property
1920 * has a `getter` & `setter` that only need the owner ID and are null-safe regarding the `adt`
1921 * itself. */
1922 AnimData *adt = BKE_animdata_from_id(id);
1923 PointerRNA adt_ptr = RNA_pointer_create(id, &RNA_AnimData, adt);
1924
1925 TemplateID template_ui;
1926 template_ui.ptr = adt_ptr;
1927 template_ui.prop = adt_action_prop;
1928 template_ui.prv_rows = 0;
1929 template_ui.prv_cols = 0;
1930 template_ui.scale = 1.0f;
1931 template_ui.filter = UI_TEMPLATE_ID_FILTER_ALL;
1932
1934 if (newop) {
1936 }
1937
1938 template_ui.idcode = ID_AC;
1939 template_ui.idlb = which_libbase(CTX_data_main(C), ID_AC);
1940 BLI_assert(template_ui.idlb);
1941
1942 uiLayout *row = uiLayoutRow(layout, true);
1944 C, row, template_ui, &RNA_Action, flag, newop, nullptr, unlinkop, text, false, false);
1945}
1946
1948 bContext *C,
1949 PointerRNA *ptr,
1950 const char *propname,
1951 const char *newop,
1952 const char *openop,
1953 const char *unlinkop,
1954 int filter,
1955 const char *text)
1956{
1957 ui_template_id(layout,
1958 C,
1959 ptr,
1960 propname,
1961 newop,
1962 openop,
1963 unlinkop,
1964 nullptr,
1965 text,
1967 0,
1968 0,
1969 filter,
1970 false,
1971 1.0f,
1972 false,
1973 false);
1974}
1975
1977 bContext *C,
1978 PointerRNA *ptr,
1979 const char *propname,
1980 const char *newop,
1981 const char *openop,
1982 const char *unlinkop,
1983 int rows,
1984 int cols,
1985 int filter,
1986 const bool hide_buttons)
1987{
1988 ui_template_id(layout,
1989 C,
1990 ptr,
1991 propname,
1992 newop,
1993 openop,
1994 unlinkop,
1995 nullptr,
1996 nullptr,
1998 rows,
1999 cols,
2000 filter,
2001 false,
2002 1.0f,
2003 false,
2004 hide_buttons);
2005}
2006
2008 bContext *C,
2009 PointerRNA *ptr,
2010 const char *propname,
2011 int rows,
2012 int cols,
2013 float scale,
2014 int filter)
2015{
2016 ui_template_id(layout,
2017 C,
2018 ptr,
2019 propname,
2020 nullptr,
2021 nullptr,
2022 nullptr,
2023 nullptr,
2024 nullptr,
2026 rows,
2027 cols,
2028 filter,
2029 false,
2030 scale < 0.5f ? 0.5f : scale,
2031 false,
2032 false);
2033}
2034
2036 bContext *C,
2037 PointerRNA *ptr,
2038 const char *propname,
2039 const char *newop,
2040 const char *menu,
2041 int filter)
2042{
2043 ui_template_id(layout,
2044 C,
2045 ptr,
2046 propname,
2047 newop,
2048 nullptr,
2049 nullptr,
2050 menu,
2051 nullptr,
2053 0,
2054 0,
2055 filter,
2056 true,
2057 1.0f,
2058 false,
2059 false);
2060}
2061
2063
2064/* -------------------------------------------------------------------- */
2067
2069 PointerRNA *ptr,
2070 const char *propname,
2071 const char *proptypename,
2072 const char *text)
2073{
2074 /* get properties... */
2075 PropertyRNA *propID = RNA_struct_find_property(ptr, propname);
2076 PropertyRNA *propType = RNA_struct_find_property(ptr, proptypename);
2077
2078 if (!propID || RNA_property_type(propID) != PROP_POINTER) {
2079 RNA_warning("pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2080 return;
2081 }
2082 if (!propType || RNA_property_type(propType) != PROP_ENUM) {
2084 "pointer-type property not found: %s.%s", RNA_struct_identifier(ptr->type), proptypename);
2085 return;
2086 }
2087
2088 /* Start drawing UI Elements using standard defines */
2089
2090 /* NOTE: split amount here needs to be synced with normal labels */
2091 uiLayout *split = uiLayoutSplit(layout, 0.33f, false);
2092
2093 /* FIRST PART ................................................ */
2094 uiLayout *row = uiLayoutRow(split, false);
2095
2096 /* Label - either use the provided text, or will become "ID-Block:" */
2097 if (text) {
2098 if (text[0]) {
2099 uiItemL(row, text, ICON_NONE);
2100 }
2101 }
2102 else {
2103 uiItemL(row, IFACE_("ID-Block:"), ICON_NONE);
2104 }
2105
2106 /* SECOND PART ................................................ */
2107 row = uiLayoutRow(split, true);
2108
2109 /* ID-Type Selector - just have a menu of icons */
2110
2111 /* HACK: special group just for the enum,
2112 * otherwise we get ugly layout with text included too... */
2113 uiLayout *sub = uiLayoutRow(row, true);
2115
2116 uiItemFullR(sub, ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
2117
2118 /* ID-Block Selector - just use pointer widget... */
2119
2120 /* HACK: special group to counteract the effects of the previous enum,
2121 * which now pushes everything too far right. */
2122 sub = uiLayoutRow(row, true);
2124
2125 uiItemFullR(sub, ptr, propID, 0, 0, UI_ITEM_NONE, "", ICON_NONE);
2126}
2127
2129
2130/* -------------------------------------------------------------------- */
2133
2140
2141static void template_search_exec_fn(bContext *C, void *arg_template, void *item)
2142{
2143 TemplateSearch *template_search = static_cast<TemplateSearch *>(arg_template);
2144 uiRNACollectionSearch *coll_search = &template_search->search_data;
2145 StructRNA *type = RNA_property_pointer_type(&coll_search->target_ptr, coll_search->target_prop);
2146
2147 PointerRNA item_ptr = RNA_pointer_create(nullptr, type, item);
2148 RNA_property_pointer_set(&coll_search->target_ptr, coll_search->target_prop, item_ptr, nullptr);
2149 RNA_property_update(C, &coll_search->target_ptr, coll_search->target_prop);
2150}
2151
2152static uiBlock *template_search_menu(bContext *C, ARegion *region, void *arg_template)
2153{
2154 static TemplateSearch template_search;
2155
2156 /* arg_template is malloced, can be freed by parent button */
2157 template_search = *((TemplateSearch *)arg_template);
2158 PointerRNA active_ptr = RNA_property_pointer_get(&template_search.search_data.target_ptr,
2159 template_search.search_data.target_prop);
2160
2162 region,
2164 &template_search,
2166 active_ptr.data,
2167 nullptr,
2168 template_search.preview_rows,
2169 template_search.preview_cols,
2170 1.0f);
2171}
2172
2174 uiLayout *layout,
2175 uiBlock *block,
2176 TemplateSearch &template_search,
2177 const bool editable,
2178 const bool live_icon)
2179{
2180 const char *ui_description = RNA_property_ui_description(
2181 template_search.search_data.target_prop);
2182
2184 layout,
2185 block,
2186 &template_search.search_data.target_ptr,
2187 template_search.search_data.target_prop,
2189 MEM_new<TemplateSearch>(__func__, template_search),
2190 ui_description,
2191 template_search.use_previews,
2192 editable,
2193 live_icon,
2196}
2197
2199 PointerRNA *active_ptr,
2200 const StructRNA *type)
2201{
2202 /* Skip text button without an active item. */
2203 if (active_ptr->data == nullptr) {
2204 return;
2205 }
2206
2207 PropertyRNA *name_prop;
2208#ifdef WITH_ANIM_BAKLAVA
2209 if (type == &RNA_ActionSlot) {
2210 name_prop = RNA_struct_find_property(active_ptr, "name_display");
2211 }
2212 else {
2213#endif /* WITH_ANIM_BAKLAVA */
2214 name_prop = RNA_struct_name_property(type);
2215#ifdef WITH_ANIM_BAKLAVA
2216 }
2217#endif /* WITH_ANIM_BAKLAVA */
2218
2219 const int width = template_search_textbut_width(active_ptr, name_prop);
2220 const int height = template_search_textbut_height();
2221 uiDefAutoButR(block, active_ptr, name_prop, 0, "", ICON_NONE, 0, 0, width, height);
2222}
2223
2225 const char *const operator_name,
2226 const wmOperatorCallContext opcontext,
2227 const int icon,
2228 const bool editable)
2229{
2230 if (!operator_name) {
2231 return;
2232 }
2233
2234 uiBut *but = uiDefIconButO(
2235 block, UI_BTYPE_BUT, operator_name, opcontext, icon, 0, 0, UI_UNIT_X, UI_UNIT_Y, nullptr);
2236
2237 if (!editable) {
2239 }
2240}
2241
2243 uiLayout *layout,
2244 TemplateSearch &template_search,
2245 const char *newop,
2246 const char *unlinkop,
2247 const char *text)
2248{
2249 uiBlock *block = uiLayoutGetBlock(layout);
2250 uiRNACollectionSearch *search_data = &template_search.search_data;
2251 const StructRNA *type = RNA_property_pointer_type(&search_data->target_ptr,
2252 search_data->target_prop);
2253 const bool editable = RNA_property_editable(&search_data->target_ptr, search_data->target_prop);
2254 PointerRNA active_ptr = RNA_property_pointer_get(&search_data->target_ptr,
2255 search_data->target_prop);
2256
2257 if (active_ptr.type) {
2258 /* can only get correct type when there is an active item */
2259 type = active_ptr.type;
2260 }
2261
2262 uiLayout *row = uiLayoutRow(layout, true);
2263 UI_block_align_begin(block);
2264
2265 uiLayout *decorator_layout = nullptr;
2266 if (text && text[0]) {
2267 /* Add label respecting the separated layout property split state. */
2268 decorator_layout = uiItemL_respect_property_split(row, text, ICON_NONE);
2269 }
2270
2271 template_search_add_button_searchmenu(C, row, block, template_search, editable, false);
2272 template_search_add_button_name(block, &active_ptr, type);
2274 block, newop, WM_OP_INVOKE_DEFAULT, ICON_DUPLICATE, editable);
2275 template_search_add_button_operator(block, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, editable);
2276
2277 UI_block_align_end(block);
2278
2279 if (decorator_layout) {
2280 uiItemDecoratorR(decorator_layout, nullptr, nullptr, RNA_NO_INDEX);
2281 }
2282}
2283
2285 PropertyRNA *targetprop,
2286 PointerRNA *searchptr,
2287 const char *const searchpropname)
2288{
2289 PropertyRNA *searchprop;
2290
2291 if (searchptr && !searchptr->data) {
2292 searchptr = nullptr;
2293 }
2294
2295 if (!searchptr && !searchpropname) {
2296 /* both nullptr means we don't use a custom rna collection to search in */
2297 }
2298 else if (!searchptr && searchpropname) {
2299 RNA_warning("searchpropname defined (%s) but searchptr is missing", searchpropname);
2300 }
2301 else if (searchptr && !searchpropname) {
2302 RNA_warning("searchptr defined (%s) but searchpropname is missing",
2303 RNA_struct_identifier(searchptr->type));
2304 }
2305 else if (!(searchprop = RNA_struct_find_property(searchptr, searchpropname))) {
2306 RNA_warning("search collection property not found: %s.%s",
2307 RNA_struct_identifier(searchptr->type),
2308 searchpropname);
2309 }
2310 else if (RNA_property_type(searchprop) != PROP_COLLECTION) {
2311 RNA_warning("search collection property is not a collection type: %s.%s",
2312 RNA_struct_identifier(searchptr->type),
2313 searchpropname);
2314 }
2315 /* check if searchprop has same type as targetprop */
2316 else if (RNA_property_pointer_type(searchptr, searchprop) !=
2317 RNA_property_pointer_type(targetptr, targetprop))
2318 {
2319 RNA_warning("search collection items from %s.%s are not of type %s",
2320 RNA_struct_identifier(searchptr->type),
2321 searchpropname,
2322 RNA_struct_identifier(RNA_property_pointer_type(targetptr, targetprop)));
2323 }
2324 else {
2325 return searchprop;
2326 }
2327
2328 return nullptr;
2329}
2330
2331static bool template_search_setup(TemplateSearch &template_search,
2332 PointerRNA *ptr,
2333 const char *const propname,
2334 PointerRNA *searchptr,
2335 const char *const searchpropname)
2336{
2337 template_search = {};
2338 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
2339
2340 if (!prop || RNA_property_type(prop) != PROP_POINTER) {
2341 RNA_warning("pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2342 return false;
2343 }
2344 PropertyRNA *searchprop = template_search_get_searchprop(ptr, prop, searchptr, searchpropname);
2345
2346 template_search.search_data.target_ptr = *ptr;
2347 template_search.search_data.target_prop = prop;
2348 template_search.search_data.search_ptr = *searchptr;
2349 template_search.search_data.search_prop = searchprop;
2350
2351 return true;
2352}
2353
2355 const bContext *C,
2356 PointerRNA *ptr,
2357 const char *propname,
2358 PointerRNA *searchptr,
2359 const char *searchpropname,
2360 const char *newop,
2361 const char *unlinkop,
2362 const char *text)
2363{
2364 TemplateSearch template_search;
2365 if (template_search_setup(template_search, ptr, propname, searchptr, searchpropname)) {
2366 template_search_buttons(C, layout, template_search, newop, unlinkop, text);
2367 }
2368}
2369
2371 bContext *C,
2372 PointerRNA *ptr,
2373 const char *propname,
2374 PointerRNA *searchptr,
2375 const char *searchpropname,
2376 const char *newop,
2377 const char *unlinkop,
2378 const int rows,
2379 const int cols,
2380 const char *text)
2381{
2382 TemplateSearch template_search;
2383 if (template_search_setup(template_search, ptr, propname, searchptr, searchpropname)) {
2384 template_search.use_previews = true;
2385 template_search.preview_rows = rows;
2386 template_search.preview_cols = cols;
2387
2388 template_search_buttons(C, layout, template_search, newop, unlinkop, text);
2389 }
2390}
2391
2393
2394/* -------------------------------------------------------------------- */
2397
2398/* ---------- */
2399
2401 PointerRNA *ptr,
2402 const char *propname,
2403 PointerRNA * /*root_ptr*/,
2404 const char *text)
2405{
2406 /* check that properties are valid */
2407 PropertyRNA *propPath = RNA_struct_find_property(ptr, propname);
2408 if (!propPath || RNA_property_type(propPath) != PROP_STRING) {
2409 RNA_warning("path property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2410 return;
2411 }
2412
2413 /* Start drawing UI Elements using standard defines */
2414 uiLayout *row = uiLayoutRow(layout, true);
2415
2416 /* Path (existing string) Widget */
2417 uiItemR(row, ptr, propname, UI_ITEM_NONE, text, ICON_RNA);
2418
2419 /* TODO: attach something to this to make allow
2420 * searching of nested properties to 'build' the path */
2421}
2422
2424
2425/* -------------------------------------------------------------------- */
2430
2431static void modifier_panel_id(void *md_link, char *r_name)
2432{
2433 ModifierData *md = (ModifierData *)md_link;
2435}
2436
2438{
2439 ARegion *region = CTX_wm_region(C);
2440
2442 ListBase *modifiers = &ob->modifiers;
2443
2444 const bool panels_match = UI_panel_list_matches_data(region, modifiers, modifier_panel_id);
2445
2446 if (!panels_match) {
2447 UI_panels_free_instanced(C, region);
2448 LISTBASE_FOREACH (ModifierData *, md, modifiers) {
2449 const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
2450 if (mti->panel_register == nullptr) {
2451 continue;
2452 }
2453
2454 char panel_idname[MAX_NAME];
2455 modifier_panel_id(md, panel_idname);
2456
2457 /* Create custom data RNA pointer. */
2458 PointerRNA *md_ptr = MEM_new<PointerRNA>(__func__);
2459 *md_ptr = RNA_pointer_create(&ob->id, &RNA_Modifier, md);
2460
2461 UI_panel_add_instanced(C, region, &region->panels, panel_idname, md_ptr);
2462 }
2463 }
2464 else {
2465 /* Assuming there's only one group of instanced panels, update the custom data pointers. */
2466 Panel *panel = static_cast<Panel *>(region->panels.first);
2467 LISTBASE_FOREACH (ModifierData *, md, modifiers) {
2468 const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type));
2469 if (mti->panel_register == nullptr) {
2470 continue;
2471 }
2472
2473 /* Move to the next instanced panel corresponding to the next modifier. */
2474 while ((panel->type == nullptr) || !(panel->type->flag & PANEL_TYPE_INSTANCED)) {
2475 panel = panel->next;
2476 BLI_assert(panel !=
2477 nullptr); /* There shouldn't be fewer panels than modifiers with UIs. */
2478 }
2479
2480 PointerRNA *md_ptr = MEM_new<PointerRNA>(__func__);
2481 *md_ptr = RNA_pointer_create(&ob->id, &RNA_Modifier, md);
2482 UI_panel_custom_data_set(panel, md_ptr);
2483
2484 panel = panel->next;
2485 }
2486 }
2487}
2488
2490
2491/* -------------------------------------------------------------------- */
2496
2498#define CONSTRAINT_TYPE_PANEL_PREFIX "OBJECT_PT_"
2499#define CONSTRAINT_BONE_TYPE_PANEL_PREFIX "BONE_PT_"
2500
2505{
2506 return (panel->panelname[0] == 'B') && (panel->panelname[1] == 'O') &&
2507 (panel->panelname[2] == 'N') && (panel->panelname[3] == 'E');
2508}
2509
2513static void constraint_reorder(bContext *C, Panel *panel, int new_index)
2514{
2515 const bool constraint_from_bone = constraint_panel_is_bone(panel);
2516
2517 PointerRNA *con_ptr = UI_panel_custom_data_get(panel);
2518 bConstraint *con = (bConstraint *)con_ptr->data;
2519
2520 PointerRNA props_ptr;
2521 wmOperatorType *ot = WM_operatortype_find("CONSTRAINT_OT_move_to_index", false);
2523 RNA_string_set(&props_ptr, "constraint", con->name);
2524 RNA_int_set(&props_ptr, "index", new_index);
2525 /* Set owner to #EDIT_CONSTRAINT_OWNER_OBJECT or #EDIT_CONSTRAINT_OWNER_BONE. */
2526 RNA_enum_set(&props_ptr, "owner", constraint_from_bone ? 1 : 0);
2527 WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr);
2528 WM_operator_properties_free(&props_ptr);
2529}
2530
2534static short get_constraint_expand_flag(const bContext * /*C*/, Panel *panel)
2535{
2536 PointerRNA *con_ptr = UI_panel_custom_data_get(panel);
2537 bConstraint *con = (bConstraint *)con_ptr->data;
2538
2539 return con->ui_expand_flag;
2540}
2541
2545static void set_constraint_expand_flag(const bContext * /*C*/, Panel *panel, short expand_flag)
2546{
2547 PointerRNA *con_ptr = UI_panel_custom_data_get(panel);
2548 bConstraint *con = (bConstraint *)con_ptr->data;
2549 con->ui_expand_flag = expand_flag;
2550}
2551
2558static void object_constraint_panel_id(void *md_link, char *r_idname)
2559{
2560 bConstraint *con = (bConstraint *)md_link;
2562
2563 /* Cannot get TypeInfo for invalid/legacy constraints. */
2564 if (cti == nullptr) {
2565 return;
2566 }
2568}
2569
2570static void bone_constraint_panel_id(void *md_link, char *r_idname)
2571{
2572 bConstraint *con = (bConstraint *)md_link;
2574
2575 /* Cannot get TypeInfo for invalid/legacy constraints. */
2576 if (cti == nullptr) {
2577 return;
2578 }
2580}
2581
2582void uiTemplateConstraints(uiLayout * /*layout*/, bContext *C, bool use_bone_constraints)
2583{
2584 ARegion *region = CTX_wm_region(C);
2585
2587 ListBase *constraints = {nullptr};
2588 if (use_bone_constraints) {
2590 }
2591 else if (ob != nullptr) {
2592 constraints = &ob->constraints;
2593 }
2594
2595 /* Switch between the bone panel ID function and the object panel ID function. */
2596 uiListPanelIDFromDataFunc panel_id_func = use_bone_constraints ? bone_constraint_panel_id :
2598
2599 const bool panels_match = UI_panel_list_matches_data(region, constraints, panel_id_func);
2600
2601 if (!panels_match) {
2602 UI_panels_free_instanced(C, region);
2603 for (bConstraint *con =
2604 (constraints == nullptr) ? nullptr : static_cast<bConstraint *>(constraints->first);
2605 con;
2606 con = con->next)
2607 {
2608 /* Don't show invalid/legacy constraints. */
2609 if (con->type == CONSTRAINT_TYPE_NULL) {
2610 continue;
2611 }
2612 /* Don't show temporary constraints (AutoIK and target-less IK constraints). */
2613 if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
2614 bKinematicConstraint *data = static_cast<bKinematicConstraint *>(con->data);
2615 if (data->flag & CONSTRAINT_IK_TEMP) {
2616 continue;
2617 }
2618 }
2619
2620 char panel_idname[MAX_NAME];
2621 panel_id_func(con, panel_idname);
2622
2623 /* Create custom data RNA pointer. */
2624 PointerRNA *con_ptr = MEM_new<PointerRNA>(__func__);
2625 *con_ptr = RNA_pointer_create(&ob->id, &RNA_Constraint, con);
2626
2627 Panel *new_panel = UI_panel_add_instanced(C, region, &region->panels, panel_idname, con_ptr);
2628
2629 if (new_panel) {
2630 /* Set the list panel functionality function pointers since we don't do it with python. */
2633 new_panel->type->reorder = constraint_reorder;
2634 }
2635 }
2636 }
2637 else {
2638 /* Assuming there's only one group of instanced panels, update the custom data pointers. */
2639 Panel *panel = static_cast<Panel *>(region->panels.first);
2641 /* Don't show invalid/legacy constraints. */
2642 if (con->type == CONSTRAINT_TYPE_NULL) {
2643 continue;
2644 }
2645 /* Don't show temporary constraints (AutoIK and target-less IK constraints). */
2646 if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
2647 bKinematicConstraint *data = static_cast<bKinematicConstraint *>(con->data);
2648 if (data->flag & CONSTRAINT_IK_TEMP) {
2649 continue;
2650 }
2651 }
2652
2653 /* Move to the next instanced panel corresponding to the next constraint. */
2654 while ((panel->type == nullptr) || !(panel->type->flag & PANEL_TYPE_INSTANCED)) {
2655 panel = panel->next;
2656 BLI_assert(panel != nullptr); /* There shouldn't be fewer panels than constraint panels. */
2657 }
2658
2659 PointerRNA *con_ptr = MEM_new<PointerRNA>(__func__);
2660 *con_ptr = RNA_pointer_create(&ob->id, &RNA_Constraint, con);
2661 UI_panel_custom_data_set(panel, con_ptr);
2662
2663 panel = panel->next;
2664 }
2665 }
2666}
2667
2668#undef CONSTRAINT_TYPE_PANEL_PREFIX
2669#undef CONSTRAINT_BONE_TYPE_PANEL_PREFIX
2670
2672
2673#define ERROR_LIBDATA_MESSAGE N_("Can't edit external library data")
2674
2675/* -------------------------------------------------------------------- */
2681
2685static void shaderfx_panel_id(void *fx_v, char *r_idname)
2686{
2687 ShaderFxData *fx = (ShaderFxData *)fx_v;
2689}
2690
2692{
2693 ARegion *region = CTX_wm_region(C);
2695 ListBase *shaderfx = &ob->shader_fx;
2696
2697 const bool panels_match = UI_panel_list_matches_data(region, shaderfx, shaderfx_panel_id);
2698
2699 if (!panels_match) {
2700 UI_panels_free_instanced(C, region);
2701 LISTBASE_FOREACH (ShaderFxData *, fx, shaderfx) {
2702 char panel_idname[MAX_NAME];
2703 shaderfx_panel_id(fx, panel_idname);
2704
2705 /* Create custom data RNA pointer. */
2706 PointerRNA *fx_ptr = MEM_new<PointerRNA>(__func__);
2707 *fx_ptr = RNA_pointer_create(&ob->id, &RNA_ShaderFx, fx);
2708
2709 UI_panel_add_instanced(C, region, &region->panels, panel_idname, fx_ptr);
2710 }
2711 }
2712 else {
2713 /* Assuming there's only one group of instanced panels, update the custom data pointers. */
2714 Panel *panel = static_cast<Panel *>(region->panels.first);
2715 LISTBASE_FOREACH (ShaderFxData *, fx, shaderfx) {
2716 const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(ShaderFxType(fx->type));
2717 if (fxi->panel_register == nullptr) {
2718 continue;
2719 }
2720
2721 /* Move to the next instanced panel corresponding to the next modifier. */
2722 while ((panel->type == nullptr) || !(panel->type->flag & PANEL_TYPE_INSTANCED)) {
2723 panel = panel->next;
2724 BLI_assert(panel !=
2725 nullptr); /* There shouldn't be fewer panels than modifiers with UIs. */
2726 }
2727
2728 PointerRNA *fx_ptr = MEM_new<PointerRNA>(__func__);
2729 *fx_ptr = RNA_pointer_create(&ob->id, &RNA_ShaderFx, fx);
2730 UI_panel_custom_data_set(panel, fx_ptr);
2731
2732 panel = panel->next;
2733 }
2734 }
2735}
2736
2738
2739/* -------------------------------------------------------------------- */
2742
2748
2749#ifdef USE_OP_RESET_BUT
2750static void ui_layout_operator_buts__reset_cb(bContext * /*C*/, void *op_pt, void * /*arg_dummy2*/)
2751{
2753}
2754#endif
2755
2757 PropertyRNA *prop,
2758 void *user_data)
2759{
2761 user_data);
2762
2765 {
2766 return false;
2767 }
2768 return params->op->type->poll_property(params->C, params->op, prop);
2769}
2770
2772 const bContext *C,
2773 wmOperator *op,
2774 uiLayout *layout,
2775 const eButLabelAlign label_align,
2776 int layout_flags)
2777{
2778 uiBlock *block = uiLayoutGetBlock(layout);
2780
2781 if (!op->properties) {
2782 op->properties = blender::bke::idprop::create_group("wmOperatorProperties").release();
2783 }
2784
2785 /* poll() on this operator may still fail,
2786 * at the moment there is no nice feedback when this happens just fails silently. */
2787 if (!WM_operator_repeat_check(C, op)) {
2788 UI_block_lock_set(block, true, N_("Operator cannot redo"));
2789 return return_info;
2790 }
2791
2792 /* useful for macros where only one of the steps can't be re-done */
2793 UI_block_lock_clear(block);
2794
2795 if (layout_flags & UI_TEMPLATE_OP_PROPS_SHOW_TITLE) {
2796 uiItemL(layout, WM_operatortype_name(op->type, op->ptr).c_str(), ICON_NONE);
2797 }
2798
2799 /* menu */
2800 if ((op->type->flag & OPTYPE_PRESET) && !(layout_flags & UI_TEMPLATE_OP_PROPS_HIDE_PRESETS)) {
2801 /* XXX, no simple way to get WM_MT_operator_presets.bl_label
2802 * from python! Label remains the same always! */
2803 PointerRNA op_ptr;
2804 uiLayout *row;
2805
2806 UI_block_set_active_operator(block, op, false);
2807
2808 row = uiLayoutRow(layout, true);
2809 uiItemM(row, "WM_MT_operator_presets", nullptr, ICON_NONE);
2810
2811 wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false);
2812 uiItemFullO_ptr(row, ot, "", ICON_ADD, nullptr, WM_OP_INVOKE_DEFAULT, UI_ITEM_NONE, &op_ptr);
2813 RNA_string_set(&op_ptr, "operator", op->type->idname);
2814
2816 row, ot, "", ICON_REMOVE, nullptr, WM_OP_INVOKE_DEFAULT, UI_ITEM_NONE, &op_ptr);
2817 RNA_string_set(&op_ptr, "operator", op->type->idname);
2818 RNA_boolean_set(&op_ptr, "remove_active", true);
2819 }
2820
2821 if (op->type->ui) {
2822 op->layout = layout;
2823 op->type->ui((bContext *)C, op);
2824 op->layout = nullptr;
2825
2826 /* #UI_LAYOUT_OP_SHOW_EMPTY ignored. retun_info is ignored too.
2827 * We could allow #wmOperatorType.ui callback to return this, but not needed right now. */
2828 }
2829 else {
2832 user_data.C = C;
2833 user_data.op = op;
2834 user_data.flag = layout_flags;
2835 const bool use_prop_split = (layout_flags & UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT) == 0;
2836
2838
2839 uiLayoutSetPropSep(layout, use_prop_split);
2840 uiLayoutSetPropDecorate(layout, false);
2841
2842 /* main draw call */
2843 return_info = uiDefAutoButsRNA(
2844 layout,
2845 &ptr,
2847 op->type->poll_property ? &user_data : nullptr,
2848 op->type->prop,
2849 label_align,
2850 (layout_flags & UI_TEMPLATE_OP_PROPS_COMPACT));
2851
2852 if ((return_info & UI_PROP_BUTS_NONE_ADDED) &&
2853 (layout_flags & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY))
2854 {
2855 uiItemL(layout, IFACE_("No Properties"), ICON_NONE);
2856 }
2857 }
2858
2859#ifdef USE_OP_RESET_BUT
2860 /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled
2861 * but this is not so important if this button is drawn in those cases
2862 * (which isn't all that likely anyway) - campbell */
2863 if (op->properties->len) {
2864 uiBut *but;
2865 uiLayout *col; /* needed to avoid alignment errors with previous buttons */
2866
2867 col = uiLayoutColumn(layout, false);
2868 block = uiLayoutGetBlock(col);
2869 but = uiDefIconTextBut(block,
2871 0,
2872 ICON_FILE_REFRESH,
2873 IFACE_("Reset"),
2874 0,
2875 0,
2876 UI_UNIT_X,
2877 UI_UNIT_Y,
2878 nullptr,
2879 0.0,
2880 0.0,
2881 0.0,
2882 0.0,
2883 TIP_("Reset operator defaults"));
2884 UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, nullptr);
2885 }
2886#endif
2887
2888 /* set various special settings for buttons */
2889
2890 /* Only do this if we're not refreshing an existing UI. */
2891 if (block->oldblock == nullptr) {
2892 const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0;
2893
2894 LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
2895 /* no undo for buttons for operator redo panels */
2897
2898 /* only for popups, see #36109. */
2899
2900 /* if button is operator's default property, and a text-field, enable focus for it
2901 * - this is used for allowing operators with popups to rename stuff with fewer clicks
2902 */
2903 if (is_popup) {
2904 if ((but->rnaprop == op->type->prop) && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_NUM)) {
2906 }
2907 }
2908 }
2909 }
2910
2911 return return_info;
2912}
2913
2915 wmOperator *op,
2916 uiLayout *layout,
2917 const eButLabelAlign label_align,
2918 int layout_flags,
2919 bool *r_has_advanced)
2920{
2921 if (op->type->flag & OPTYPE_MACRO) {
2922 LISTBASE_FOREACH (wmOperator *, macro_op, &op->macro) {
2924 C, macro_op, layout, label_align, layout_flags, r_has_advanced);
2925 }
2926 }
2927 else {
2928 /* Might want to make label_align adjustable somehow. */
2930 C, op, layout, label_align, layout_flags);
2931 if (return_info & UI_PROP_BUTS_ANY_FAILED_CHECK) {
2932 if (r_has_advanced) {
2933 *r_has_advanced = true;
2934 }
2935 }
2936 }
2937}
2938
2940 wmWindowManager *wm,
2941 wmOperator *op,
2942 int layout_flags)
2943{
2944 if (op->type->flag & OPTYPE_MACRO) {
2945 LISTBASE_FOREACH (wmOperator *, macro_op, &op->macro) {
2946 if (!ui_layout_operator_properties_only_booleans(C, wm, macro_op, layout_flags)) {
2947 return false;
2948 }
2949 }
2950 }
2951 else {
2953 user_data.C = C;
2954 user_data.op = op;
2955 user_data.flag = layout_flags;
2956
2958
2959 bool all_booleans = true;
2960 RNA_STRUCT_BEGIN (&ptr, prop) {
2961 if (RNA_property_flag(prop) & PROP_HIDDEN) {
2962 continue;
2963 }
2964 if (op->type->poll_property &&
2965 !ui_layout_operator_buts_poll_property(&ptr, prop, &user_data))
2966 {
2967 continue;
2968 }
2969 if (RNA_property_type(prop) != PROP_BOOLEAN) {
2970 all_booleans = false;
2971 break;
2972 }
2973 }
2975 if (all_booleans == false) {
2976 return false;
2977 }
2978 }
2979
2980 return true;
2981}
2982
2984 const bContext *C, uiLayout *layout, wmOperator *op, eButLabelAlign label_align, short flag)
2985{
2987
2988 /* If there are only checkbox items, don't use split layout by default. It looks weird if the
2989 * check-boxes only use half the width. */
2992 }
2993
2994 template_operator_property_buts_draw_recursive(C, op, layout, label_align, flag, nullptr);
2995}
2996
2998{
3000 uiBlock *block = uiLayoutGetBlock(layout);
3001
3002 if (op == nullptr) {
3003 return;
3004 }
3005
3006 /* Disable for now, doesn't fit well in popover. */
3007#if 0
3008 /* Repeat button with operator name as text. */
3009 uiItemFullO(layout,
3010 "SCREEN_OT_repeat_last",
3011 WM_operatortype_name(op->type, op->ptr),
3012 ICON_NONE,
3013 nullptr,
3015 0,
3016 nullptr);
3017#endif
3018
3019 if (WM_operator_repeat_check(C, op)) {
3020 int layout_flags = 0;
3021 if (block->panel == nullptr) {
3022 layout_flags = UI_TEMPLATE_OP_PROPS_SHOW_TITLE;
3023 }
3024#if 0
3025 bool has_advanced = false;
3026#endif
3027
3030 C, op, layout, UI_BUT_LABEL_ALIGN_NONE, layout_flags, nullptr /* &has_advanced */);
3031 /* Warning! this leaves the handle function for any other users of this block. */
3032
3033#if 0
3034 if (has_advanced) {
3035 uiItemO(layout, IFACE_("More..."), ICON_NONE, "SCREEN_OT_redo_last");
3036 }
3037#endif
3038 }
3039}
3040
3042{
3043 /* Copied from #wm_operator_create.
3044 * Create a slimmed down operator suitable only for UI drawing. */
3045 wmOperator *op = MEM_cnew<wmOperator>(ot->rna_ext.srna ? __func__ : ot->idname);
3046 STRNCPY(op->idname, ot->idname);
3047 op->type = ot;
3048
3049 /* Initialize properties but do not assume ownership of them.
3050 * This "minimal" operator owns nothing. */
3051 op->ptr = MEM_new<PointerRNA>("wmOperatorPtrRNA");
3052 op->properties = static_cast<IDProperty *>(properties->data);
3053 *op->ptr = *properties;
3054
3055 return op;
3056}
3057
3059 bContext *C, uiLayout *layout, const std::string &label, int index, bool valid)
3060{
3061 uiItemL(layout, label.c_str(), ICON_NONE);
3062 if (valid) {
3063 uiLayout *row = uiLayoutRow(layout, false);
3065 uiItemPopoverPanel(row, C, "WM_PT_operator_presets", "", ICON_PRESET);
3066 uiItemIntO(row, "", ICON_EXPORT, "COLLECTION_OT_exporter_export", "index", index);
3067 }
3068}
3069
3071 uiLayout *layout,
3072 wmOperator *op,
3073 const std::string &filename)
3074{
3075 uiLayout *col = uiLayoutColumn(layout, false);
3076
3077 uiLayoutSetPropSep(col, true);
3079
3080 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
3081 std::string placeholder = "//" + filename;
3083 col, op->ptr, prop, RNA_NO_INDEX, 0, UI_ITEM_NONE, nullptr, ICON_NONE, placeholder.c_str());
3084
3087}
3088
3089static void draw_exporter_item(uiList * /*ui_list*/,
3090 const bContext * /*C*/,
3091 uiLayout *layout,
3092 PointerRNA * /*idataptr*/,
3093 PointerRNA *itemptr,
3094 int /*icon*/,
3095 PointerRNA * /*active_dataptr*/,
3096 const char * /*active_propname*/,
3097 int /*index*/,
3098 int /*flt_flag*/)
3099{
3100 uiLayout *row = uiLayoutRow(layout, false);
3102 uiItemR(row, itemptr, "name", UI_ITEM_NONE, "", ICON_NONE);
3103}
3104
3106{
3107 Collection *collection = CTX_data_collection(C);
3108 ListBase *exporters = &collection->exporters;
3109 const int index = collection->active_exporter_index;
3110
3111 /* Register the exporter list type on first use. */
3112 static const uiListType *exporter_item_list = []() {
3113 uiListType *lt = MEM_cnew<uiListType>(__func__);
3114 STRNCPY(lt->idname, "COLLECTION_UL_exporter_list");
3117 return lt;
3118 }();
3119
3120 /* Draw exporter list and controls. */
3121 PointerRNA collection_ptr = RNA_pointer_create(&collection->id, &RNA_Collection, collection);
3122 uiLayout *row = uiLayoutRow(layout, false);
3123 uiTemplateList(row,
3124 C,
3125 exporter_item_list->idname,
3126 "",
3127 &collection_ptr,
3128 "exporters",
3129 &collection_ptr,
3130 "active_exporter_index",
3131 nullptr,
3132 3,
3133 5,
3135 1,
3137
3138 uiLayout *col = uiLayoutColumn(row, true);
3139 uiItemM(col, "COLLECTION_MT_exporter_add", "", ICON_ADD);
3140 uiItemIntO(col, "", ICON_REMOVE, "COLLECTION_OT_exporter_remove", "index", index);
3141
3142 col = uiLayoutColumn(layout, true);
3143 uiItemO(col, nullptr, ICON_EXPORT, "COLLECTION_OT_export_all");
3145
3146 /* Draw the active exporter. */
3147 CollectionExport *data = (CollectionExport *)BLI_findlink(exporters, index);
3148 if (!data) {
3149 return;
3150 }
3151
3152 using namespace blender;
3153 PointerRNA exporter_ptr = RNA_pointer_create(&collection->id, &RNA_CollectionExport, data);
3154 PanelLayout panel = uiLayoutPanelProp(C, layout, &exporter_ptr, "is_open");
3155
3157 if (!fh) {
3158 std::string label = std::string(IFACE_("Undefined")) + " " + data->fh_idname;
3159 draw_export_controls(C, panel.header, label, index, false);
3160 return;
3161 }
3162
3164 if (!ot) {
3165 std::string label = std::string(IFACE_("Undefined")) + " " + fh->export_operator;
3166 draw_export_controls(C, panel.header, label, index, false);
3167 return;
3168 }
3169
3170 /* Assign temporary operator to uiBlock, which takes ownership. */
3171 PointerRNA properties = RNA_pointer_create(&collection->id, ot->srna, data->export_properties);
3172 wmOperator *op = minimal_operator_create(ot, &properties);
3174
3175 /* Draw panel header and contents. */
3176 std::string label(fh->label);
3177 draw_export_controls(C, panel.header, label, index, true);
3178 if (panel.body) {
3179 draw_export_properties(C, panel.body, op, fh->get_default_filename(collection->id.name + 2));
3180 }
3181}
3182
3184
3185/* -------------------------------------------------------------------- */
3188
3189#define ERROR_LIBDATA_MESSAGE N_("Can't edit external library data")
3190
3191static void constraint_active_func(bContext * /*C*/, void *ob_v, void *con_v)
3192{
3194 static_cast<bConstraint *>(con_v));
3195}
3196
3197static void constraint_ops_extra_draw(bContext *C, uiLayout *layout, void *con_v)
3198{
3199 PointerRNA op_ptr;
3200 uiLayout *row;
3201 bConstraint *con = (bConstraint *)con_v;
3202
3204
3205 PointerRNA ptr = RNA_pointer_create(&ob->id, &RNA_Constraint, con);
3206 uiLayoutSetContextPointer(layout, "constraint", &ptr);
3208
3209 uiLayoutSetUnitsX(layout, 4.0f);
3210
3211 /* Apply. */
3212 uiItemO(layout,
3214 ICON_CHECKMARK,
3215 "CONSTRAINT_OT_apply");
3216
3217 /* Duplicate. */
3218 uiItemO(layout,
3220 ICON_DUPLICATE,
3221 "CONSTRAINT_OT_copy");
3222
3223 uiItemO(layout,
3224 CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy to Selected"),
3225 0,
3226 "CONSTRAINT_OT_copy_to_selected");
3227
3228 uiItemS(layout);
3229
3230 /* Move to first. */
3231 row = uiLayoutColumn(layout, false);
3232 uiItemFullO(row,
3233 "CONSTRAINT_OT_move_to_index",
3234 IFACE_("Move to First"),
3235 ICON_TRIA_UP,
3236 nullptr,
3239 &op_ptr);
3240 RNA_int_set(&op_ptr, "index", 0);
3241 if (!con->prev) {
3242 uiLayoutSetEnabled(row, false);
3243 }
3244
3245 /* Move to last. */
3246 row = uiLayoutColumn(layout, false);
3247 uiItemFullO(row,
3248 "CONSTRAINT_OT_move_to_index",
3249 IFACE_("Move to Last"),
3250 ICON_TRIA_DOWN,
3251 nullptr,
3254 &op_ptr);
3256 ob, con, nullptr);
3257 RNA_int_set(&op_ptr, "index", BLI_listbase_count(constraint_list) - 1);
3258 if (!con->next) {
3259 uiLayoutSetEnabled(row, false);
3260 }
3261}
3262
3263static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con)
3264{
3265 /* unless button has its own callback, it adds this callback to button */
3266 uiBlock *block = uiLayoutGetBlock(layout);
3268
3269 PointerRNA ptr = RNA_pointer_create(&ob->id, &RNA_Constraint, con);
3270
3271 if (block->panel) {
3272 UI_panel_context_pointer_set(block->panel, "constraint", &ptr);
3273 }
3274 else {
3275 uiLayoutSetContextPointer(layout, "constraint", &ptr);
3276 }
3277
3278 /* Constraint type icon. */
3279 uiLayout *sub = uiLayoutRow(layout, false);
3282 uiItemL(sub, "", RNA_struct_ui_icon(ptr.type));
3283
3285
3286 uiLayout *row = uiLayoutRow(layout, true);
3287
3288 uiItemR(row, &ptr, "name", UI_ITEM_NONE, "", ICON_NONE);
3289
3290 /* Enabled eye icon. */
3291 uiItemR(row, &ptr, "enabled", UI_ITEM_NONE, "", ICON_NONE);
3292
3293 /* Extra operators menu. */
3294 uiItemMenuF(row, "", ICON_DOWNARROW_HLT, constraint_ops_extra_draw, con);
3295
3296 /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
3297 sub = uiLayoutRow(row, false);
3300 uiItemO(sub, "", ICON_X, "CONSTRAINT_OT_delete");
3301
3302 /* Some extra padding at the end, so the 'x' icon isn't too close to drag button. */
3303 uiItemS(layout);
3304
3305 /* clear any locks set up for proxies/lib-linking */
3306 UI_block_lock_clear(block);
3307}
3308
3310{
3311 /* verify we have valid data */
3312 if (!RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
3313 RNA_warning("Expected constraint on object");
3314 return;
3315 }
3316
3317 Object *ob = (Object *)ptr->owner_id;
3318 bConstraint *con = static_cast<bConstraint *>(ptr->data);
3319
3320 if (!ob || !(GS(ob->id.name) == ID_OB)) {
3321 RNA_warning("Expected constraint on object");
3322 return;
3323 }
3324
3326
3327 draw_constraint_header(layout, ob, con);
3328}
3329
3331
3332/* -------------------------------------------------------------------- */
3335
3336#include "DNA_light_types.h"
3337#include "DNA_material_types.h"
3338#include "DNA_world_types.h"
3339
3340#define B_MATPRV 1
3341
3342static void do_preview_buttons(bContext *C, void *arg, int event)
3343{
3344 switch (event) {
3345 case B_MATPRV:
3347 break;
3348 }
3349}
3350
3352 bContext *C,
3353 ID *id,
3354 bool show_buttons,
3355 ID *parent,
3356 MTex *slot,
3357 const char *preview_id)
3358{
3359 Material *ma = nullptr;
3360 Tex *tex = (Tex *)id;
3361 short *pr_texture = nullptr;
3362
3363 char _preview_id[sizeof(uiPreview::preview_id)];
3364
3365 if (id && !ELEM(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA, ID_LS)) {
3366 RNA_warning("Expected ID of type material, texture, light, world or line style");
3367 return;
3368 }
3369
3370 /* decide what to render */
3371 ID *pid = id;
3372 ID *pparent = nullptr;
3373
3374 if (id && (GS(id->name) == ID_TE)) {
3375 if (parent && (GS(parent->name) == ID_MA)) {
3376 pr_texture = &((Material *)parent)->pr_texture;
3377 }
3378 else if (parent && (GS(parent->name) == ID_WO)) {
3379 pr_texture = &((World *)parent)->pr_texture;
3380 }
3381 else if (parent && (GS(parent->name) == ID_LA)) {
3382 pr_texture = &((Light *)parent)->pr_texture;
3383 }
3384 else if (parent && (GS(parent->name) == ID_LS)) {
3385 pr_texture = &((FreestyleLineStyle *)parent)->pr_texture;
3386 }
3387
3388 if (pr_texture) {
3389 if (*pr_texture == TEX_PR_OTHER) {
3390 pid = parent;
3391 }
3392 else if (*pr_texture == TEX_PR_BOTH) {
3393 pparent = parent;
3394 }
3395 }
3396 }
3397
3398 if (!preview_id || (preview_id[0] == '\0')) {
3399 /* If no identifier given, generate one from ID type. */
3400 SNPRINTF(_preview_id, "uiPreview_%s", BKE_idtype_idcode_to_name(GS(id->name)));
3401 preview_id = _preview_id;
3402 }
3403
3404 /* Find or add the uiPreview to the current Region. */
3405 ARegion *region = CTX_wm_region(C);
3406 uiPreview *ui_preview = static_cast<uiPreview *>(
3407 BLI_findstring(&region->ui_previews, preview_id, offsetof(uiPreview, preview_id)));
3408
3409 if (!ui_preview) {
3410 ui_preview = MEM_cnew<uiPreview>(__func__);
3411 STRNCPY(ui_preview->preview_id, preview_id);
3412 ui_preview->height = short(UI_UNIT_Y * 7.6f);
3413 ui_preview->id_session_uid = pid->session_uid;
3414 ui_preview->tag = UI_PREVIEW_TAG_DIRTY;
3415 BLI_addtail(&region->ui_previews, ui_preview);
3416 }
3417 else if (ui_preview->id_session_uid != pid->session_uid) {
3418 ui_preview->id_session_uid = pid->session_uid;
3419 ui_preview->tag |= UI_PREVIEW_TAG_DIRTY;
3420 }
3421
3422 if (ui_preview->height < UI_UNIT_Y) {
3423 ui_preview->height = UI_UNIT_Y;
3424 }
3425 else if (ui_preview->height > UI_UNIT_Y * 50) { /* Rather high upper limit, yet not insane! */
3426 ui_preview->height = UI_UNIT_Y * 50;
3427 }
3428
3429 /* layout */
3430 uiBlock *block = uiLayoutGetBlock(layout);
3431 uiLayout *row = uiLayoutRow(layout, false);
3432 uiLayout *col = uiLayoutColumn(row, false);
3434
3435 /* add preview */
3436 uiDefBut(
3437 block, UI_BTYPE_EXTRA, 0, "", 0, 0, UI_UNIT_X * 10, ui_preview->height, pid, 0.0, 0.0, "");
3439 [pid, pparent, slot, ui_preview](const bContext *C, rcti *rect) {
3440 ED_preview_draw(C, pid, pparent, slot, ui_preview, rect);
3441 });
3443
3444 uiDefIconButS(block,
3446 0,
3447 ICON_GRIP,
3448 0,
3449 0,
3450 UI_UNIT_X * 10,
3451 short(UI_UNIT_Y * 0.3f),
3452 &ui_preview->height,
3453 UI_UNIT_Y,
3454 UI_UNIT_Y * 50.0f,
3455 "");
3456
3457 /* add buttons */
3458 if (pid && show_buttons) {
3459 if (GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) {
3460 if (GS(pid->name) == ID_MA) {
3461 ma = (Material *)pid;
3462 }
3463 else {
3464 ma = (Material *)pparent;
3465 }
3466
3467 /* Create RNA Pointer */
3468 PointerRNA material_ptr = RNA_pointer_create(&ma->id, &RNA_Material, ma);
3469
3470 col = uiLayoutColumn(row, true);
3471 uiLayoutSetScaleX(col, 1.5);
3472 uiItemR(col, &material_ptr, "preview_render_type", UI_ITEM_R_EXPAND, "", ICON_NONE);
3473
3474 /* EEVEE preview file has baked lighting so use_preview_world has no effect,
3475 * just hide the option until this feature is supported. */
3477 uiItemS(col);
3478 uiItemR(col, &material_ptr, "use_preview_world", UI_ITEM_NONE, "", ICON_WORLD);
3479 }
3480 }
3481
3482 if (pr_texture) {
3483 /* Create RNA Pointer */
3484 PointerRNA texture_ptr = RNA_pointer_create(id, &RNA_Texture, tex);
3485
3486 uiLayoutRow(layout, true);
3487 uiDefButS(block,
3489 B_MATPRV,
3490 IFACE_("Texture"),
3491 0,
3492 0,
3493 UI_UNIT_X * 10,
3494 UI_UNIT_Y,
3495 pr_texture,
3496 10,
3498 "");
3499 if (GS(parent->name) == ID_MA) {
3500 uiDefButS(block,
3502 B_MATPRV,
3503 IFACE_("Material"),
3504 0,
3505 0,
3506 UI_UNIT_X * 10,
3507 UI_UNIT_Y,
3508 pr_texture,
3509 10,
3511 "");
3512 }
3513 else if (GS(parent->name) == ID_LA) {
3514 uiDefButS(block,
3516 B_MATPRV,
3518 0,
3519 0,
3520 UI_UNIT_X * 10,
3521 UI_UNIT_Y,
3522 pr_texture,
3523 10,
3525 "");
3526 }
3527 else if (GS(parent->name) == ID_WO) {
3528 uiDefButS(block,
3530 B_MATPRV,
3532 0,
3533 0,
3534 UI_UNIT_X * 10,
3535 UI_UNIT_Y,
3536 pr_texture,
3537 10,
3539 "");
3540 }
3541 else if (GS(parent->name) == ID_LS) {
3542 uiDefButS(block,
3544 B_MATPRV,
3545 IFACE_("Line Style"),
3546 0,
3547 0,
3548 UI_UNIT_X * 10,
3549 UI_UNIT_Y,
3550 pr_texture,
3551 10,
3553 "");
3554 }
3555 uiDefButS(block,
3557 B_MATPRV,
3558 IFACE_("Both"),
3559 0,
3560 0,
3561 UI_UNIT_X * 10,
3562 UI_UNIT_Y,
3563 pr_texture,
3564 10,
3566 "");
3567
3568 /* Alpha button for texture preview */
3569 if (*pr_texture != TEX_PR_OTHER) {
3570 row = uiLayoutRow(layout, false);
3571 uiItemR(row, &texture_ptr, "use_preview_alpha", UI_ITEM_NONE, nullptr, ICON_NONE);
3572 }
3573 }
3574 }
3575}
3576
3578
3579/* -------------------------------------------------------------------- */
3582
3587
3588static void rna_update_cb(bContext &C, const RNAUpdateCb &cb)
3589{
3590 /* we call update here on the pointer property, this way the
3591 * owner of the curve mapping can still define its own update
3592 * and notifier, even if the CurveMapping struct is shared. */
3593 RNA_property_update(&C, &const_cast<PointerRNA &>(cb.ptr), cb.prop);
3594}
3595
3596static void rna_update_cb(bContext *C, void *arg_cb, void * /*arg*/)
3597{
3598 RNAUpdateCb *cb = (RNAUpdateCb *)arg_cb;
3599 rna_update_cb(*C, *cb);
3600}
3601
3603{
3604 CBData data_tmp[MAXCOLORBAND];
3605
3606 for (int a = 0; a < coba->tot; a++) {
3607 data_tmp[a] = coba->data[coba->tot - (a + 1)];
3608 }
3609 for (int a = 0; a < coba->tot; a++) {
3610 data_tmp[a].pos = 1.0f - data_tmp[a].pos;
3611 coba->data[a] = data_tmp[a];
3612 }
3613
3614 /* May as well flip the `cur`. */
3615 coba->cur = coba->tot - (coba->cur + 1);
3616
3617 ED_undo_push(C, "Flip Color Ramp");
3618}
3619
3620static void colorband_distribute(bContext *C, ColorBand *coba, bool evenly)
3621{
3622 if (coba->tot > 1) {
3623 const int tot = evenly ? coba->tot - 1 : coba->tot;
3624 const float gap = 1.0f / tot;
3625 float pos = 0.0f;
3626 for (int a = 0; a < coba->tot; a++) {
3627 coba->data[a].pos = pos;
3628 pos += gap;
3629 }
3630 ED_undo_push(C, evenly ? "Distribute Stops Evenly" : "Distribute Stops from Left");
3631 }
3632}
3633
3634static uiBlock *colorband_tools_fn(bContext *C, ARegion *region, void *cb_v)
3635{
3636 RNAUpdateCb &cb = *static_cast<RNAUpdateCb *>(cb_v);
3637 const uiStyle *style = UI_style_get_dpi();
3638 PointerRNA coba_ptr = RNA_property_pointer_get(&cb.ptr, cb.prop);
3639 ColorBand *coba = static_cast<ColorBand *>(coba_ptr.data);
3640 short yco = 0;
3641 const short menuwidth = 10 * UI_UNIT_X;
3642
3643 uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS_PULLDOWN);
3644
3645 uiLayout *layout = UI_block_layout(block,
3648 0,
3649 0,
3651 0,
3653 style);
3654 UI_block_layout_set_current(block, layout);
3655 {
3656 uiLayoutSetContextPointer(layout, "color_ramp", &coba_ptr);
3657 }
3658
3659 /* We could move these to operators,
3660 * although this isn't important unless we want to assign key shortcuts to them. */
3661 {
3662 uiBut *but = uiDefIconTextBut(block,
3664 1,
3665 ICON_ARROW_LEFTRIGHT,
3666 IFACE_("Flip Color Ramp"),
3667 0,
3668 yco -= UI_UNIT_Y,
3669 menuwidth,
3670 UI_UNIT_Y,
3671 nullptr,
3672 0.0,
3673 0.0,
3674 "");
3675 UI_but_func_set(but, [coba, cb](bContext &C) {
3676 colorband_flip(&C, coba);
3678 rna_update_cb(C, cb);
3679 });
3680 }
3681 {
3682 uiBut *but = uiDefIconTextBut(block,
3684 1,
3685 ICON_BLANK1,
3686 IFACE_("Distribute Stops from Left"),
3687 0,
3688 yco -= UI_UNIT_Y,
3689 menuwidth,
3690 UI_UNIT_Y,
3691 nullptr,
3692 0.0,
3693 0.0,
3694 "");
3695 UI_but_func_set(but, [coba, cb](bContext &C) {
3696 colorband_distribute(&C, coba, false);
3698 rna_update_cb(C, cb);
3699 });
3700 }
3701 {
3702 uiBut *but = uiDefIconTextBut(block,
3704 1,
3705 ICON_BLANK1,
3706 IFACE_("Distribute Stops Evenly"),
3707 0,
3708 yco -= UI_UNIT_Y,
3709 menuwidth,
3710 UI_UNIT_Y,
3711 nullptr,
3712 0.0,
3713 0.0,
3714 "");
3715 UI_but_func_set(but, [coba, cb](bContext &C) {
3716 colorband_distribute(&C, coba, true);
3718 rna_update_cb(C, cb);
3719 });
3720 }
3721
3722 uiItemS(layout);
3723
3724 uiItemO(layout, IFACE_("Eyedropper"), ICON_EYEDROPPER, "UI_OT_eyedropper_colorramp");
3725
3726 uiItemS(layout);
3727
3728 {
3729 uiBut *but = uiDefIconTextBut(block,
3731 1,
3732 ICON_LOOP_BACK,
3733 IFACE_("Reset Color Ramp"),
3734 0,
3735 yco -= UI_UNIT_Y,
3736 menuwidth,
3737 UI_UNIT_Y,
3738 nullptr,
3739 0.0,
3740 0.0,
3741 "");
3742 UI_but_func_set(but, [coba, cb](bContext &C) {
3743 BKE_colorband_init(coba, true);
3744 ED_undo_push(&C, "Reset Color Ramp");
3746 rna_update_cb(C, cb);
3747 });
3748 }
3749
3751 UI_block_bounds_set_text(block, 3.0f * UI_UNIT_X);
3752
3753 return block;
3754}
3755
3756static void colorband_add(bContext &C, const RNAUpdateCb &cb, ColorBand &coba)
3757{
3758 float pos = 0.5f;
3759
3760 if (coba.tot > 1) {
3761 if (coba.cur > 0) {
3762 pos = (coba.data[coba.cur - 1].pos + coba.data[coba.cur].pos) * 0.5f;
3763 }
3764 else {
3765 pos = (coba.data[coba.cur + 1].pos + coba.data[coba.cur].pos) * 0.5f;
3766 }
3767 }
3768
3769 if (BKE_colorband_element_add(&coba, pos)) {
3770 rna_update_cb(C, cb);
3771 ED_undo_push(&C, "Add Color Ramp Stop");
3772 }
3773}
3774
3775static void colorband_update_cb(bContext * /*C*/, void *bt_v, void *coba_v)
3776{
3777 uiBut *bt = static_cast<uiBut *>(bt_v);
3778 ColorBand *coba = static_cast<ColorBand *>(coba_v);
3779
3780 /* Sneaky update here, we need to sort the color-band points to be in order,
3781 * however the RNA pointer then is wrong, so we update it */
3783 bt->rnapoin.data = coba->data + coba->cur;
3784}
3785
3787 uiBlock *block,
3788 ColorBand *coba,
3789 const rctf *butr,
3790 const RNAUpdateCb &cb,
3791 int expand)
3792{
3793 uiBut *bt;
3794 const float unit = BLI_rctf_size_x(butr) / 14.0f;
3795 const float xs = butr->xmin;
3796 const float ys = butr->ymin;
3797
3798 PointerRNA ptr = RNA_pointer_create(cb.ptr.owner_id, &RNA_ColorRamp, coba);
3799
3800 uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
3801
3803 UI_block_align_begin(block);
3804 uiLayout *row = uiLayoutRow(split, false);
3805
3806 bt = uiDefIconTextBut(block,
3808 0,
3809 ICON_ADD,
3810 "",
3811 0,
3812 0,
3813 2.0f * unit,
3814 UI_UNIT_Y,
3815 nullptr,
3816 0,
3817 0,
3818 TIP_("Add a new color stop to the color ramp"));
3819 UI_but_func_set(bt, [coba, cb](bContext &C) { colorband_add(C, cb, *coba); });
3820
3821 bt = uiDefIconTextBut(block,
3823 0,
3824 ICON_REMOVE,
3825 "",
3826 xs + 2.0f * unit,
3827 ys + UI_UNIT_Y,
3828 2.0f * unit,
3829 UI_UNIT_Y,
3830 nullptr,
3831 0,
3832 0,
3833 TIP_("Delete the active position"));
3834 UI_but_func_set(bt, [coba, cb](bContext &C) {
3835 if (BKE_colorband_element_remove(coba, coba->cur)) {
3836 rna_update_cb(C, cb);
3837 ED_undo_push(&C, "Delete Color Ramp Stop");
3838 }
3839 });
3840
3841 RNAUpdateCb *tools_cb = MEM_new<RNAUpdateCb>(__func__, cb);
3842 bt = uiDefIconBlockBut(block,
3844 tools_cb,
3845 0,
3846 ICON_DOWNARROW_HLT,
3847 xs + 4.0f * unit,
3848 ys + UI_UNIT_Y,
3849 2.0f * unit,
3850 UI_UNIT_Y,
3851 TIP_("Tools"));
3852 /* Pass ownership of `tools_cb` to the button. */
3854 bt,
3855 [](bContext *, void *, void *) {},
3856 tools_cb,
3857 nullptr,
3860
3861 UI_block_align_end(block);
3863
3864 row = uiLayoutRow(split, false);
3865
3866 UI_block_align_begin(block);
3867 uiItemR(row, &ptr, "color_mode", UI_ITEM_NONE, "", ICON_NONE);
3869 uiItemR(row, &ptr, "hue_interpolation", UI_ITEM_NONE, "", ICON_NONE);
3870 }
3871 else { /* COLBAND_BLEND_RGB */
3872 uiItemR(row, &ptr, "interpolation", UI_ITEM_NONE, "", ICON_NONE);
3873 }
3874 UI_block_align_end(block);
3875
3876 row = uiLayoutRow(layout, false);
3877
3878 bt = uiDefBut(
3879 block, UI_BTYPE_COLORBAND, 0, "", xs, ys, BLI_rctf_size_x(butr), UI_UNIT_Y, coba, 0, 0, "");
3880 bt->rnapoin = cb.ptr;
3881 bt->rnaprop = cb.prop;
3882 UI_but_func_set(bt, [cb](bContext &C) { rna_update_cb(C, cb); });
3883
3884 row = uiLayoutRow(layout, false);
3885
3886 if (coba->tot) {
3887 CBData *cbd = coba->data + coba->cur;
3888
3889 ptr = RNA_pointer_create(cb.ptr.owner_id, &RNA_ColorRampElement, cbd);
3890
3891 if (!expand) {
3892 split = uiLayoutSplit(layout, 0.3f, false);
3893
3894 row = uiLayoutRow(split, false);
3895 bt = uiDefButS(block,
3897 0,
3898 "",
3899 0,
3900 0,
3901 5.0f * UI_UNIT_X,
3902 UI_UNIT_Y,
3903 &coba->cur,
3904 0.0,
3905 float(std::max(0, coba->tot - 1)),
3906 TIP_("Choose active color stop"));
3908
3909 row = uiLayoutRow(split, false);
3910 uiItemR(row, &ptr, "position", UI_ITEM_NONE, IFACE_("Pos"), ICON_NONE);
3911
3912 row = uiLayoutRow(layout, false);
3913 uiItemR(row, &ptr, "color", UI_ITEM_NONE, "", ICON_NONE);
3914 }
3915 else {
3916 split = uiLayoutSplit(layout, 0.5f, false);
3917 uiLayout *subsplit = uiLayoutSplit(split, 0.35f, false);
3918
3919 row = uiLayoutRow(subsplit, false);
3920 bt = uiDefButS(block,
3922 0,
3923 "",
3924 0,
3925 0,
3926 5.0f * UI_UNIT_X,
3927 UI_UNIT_Y,
3928 &coba->cur,
3929 0.0,
3930 float(std::max(0, coba->tot - 1)),
3931 TIP_("Choose active color stop"));
3933
3934 row = uiLayoutRow(subsplit, false);
3935 uiItemR(row, &ptr, "position", UI_ITEM_R_SLIDER, IFACE_("Pos"), ICON_NONE);
3936
3937 row = uiLayoutRow(split, false);
3938 uiItemR(row, &ptr, "color", UI_ITEM_NONE, "", ICON_NONE);
3939 }
3940
3941 /* Some special (rather awkward) treatment to update UI state on certain property changes. */
3942 LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
3943 if (but->rnapoin.data != ptr.data) {
3944 continue;
3945 }
3946 if (!but->rnaprop) {
3947 continue;
3948 }
3949
3950 const char *prop_identifier = RNA_property_identifier(but->rnaprop);
3951 if (STREQ(prop_identifier, "position")) {
3952 UI_but_func_set(but, colorband_update_cb, but, coba);
3953 }
3954
3955 if (STREQ(prop_identifier, "color")) {
3956 UI_but_func_set(bt, [cb](bContext &C) { rna_update_cb(C, cb); });
3957 }
3958 }
3959 }
3960}
3961
3962void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, bool expand)
3963{
3964 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
3965
3966 if (!prop || RNA_property_type(prop) != PROP_POINTER) {
3967 return;
3968 }
3969
3970 const PointerRNA cptr = RNA_property_pointer_get(ptr, prop);
3971 if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp)) {
3972 return;
3973 }
3974
3975 rctf rect;
3976 rect.xmin = 0;
3977 rect.xmax = 10.0f * UI_UNIT_X;
3978 rect.ymin = 0;
3979 rect.ymax = 19.5f * UI_UNIT_X;
3980
3981 uiBlock *block = uiLayoutAbsoluteBlock(layout);
3982
3983 ID *id = cptr.owner_id;
3985
3987 layout, block, static_cast<ColorBand *>(cptr.data), &rect, RNAUpdateCb{*ptr, prop}, expand);
3988
3989 UI_block_lock_clear(block);
3990}
3991
3993
3994/* -------------------------------------------------------------------- */
3997
3998void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale)
3999{
4000 uiBlock *block = uiLayoutAbsoluteBlock(layout);
4001 uiBut *but = uiDefIconBut(block,
4003 0,
4004 ICON_X,
4005 0,
4006 0,
4007 UI_UNIT_X * icon_scale,
4008 UI_UNIT_Y * icon_scale,
4009 nullptr,
4010 0.0,
4011 0.0,
4012 "");
4014}
4015
4017
4018/* -------------------------------------------------------------------- */
4021
4028
4029/* ID Search browse menu, open */
4030static uiBlock *ui_icon_view_menu_cb(bContext *C, ARegion *region, void *arg_litem)
4031{
4032 static IconViewMenuArgs args;
4033
4034 /* arg_litem is malloced, can be freed by parent button */
4035 args = *((IconViewMenuArgs *)arg_litem);
4036 const int w = UI_UNIT_X * (args.icon_scale);
4037 const int h = UI_UNIT_X * (args.icon_scale + args.show_labels);
4038
4039 uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS_PULLDOWN);
4042
4043 bool free;
4044 const EnumPropertyItem *item;
4045 RNA_property_enum_items(C, &args.ptr, args.prop, &item, nullptr, &free);
4046
4047 for (int a = 0; item[a].identifier; a++) {
4048 const int x = (a % 8) * w;
4049 const int y = -(a / 8) * h;
4050
4051 const int icon = item[a].icon;
4052 const int value = item[a].value;
4053 uiBut *but;
4054 if (args.show_labels) {
4055 but = uiDefIconTextButR_prop(block,
4057 0,
4058 icon,
4059 item[a].name,
4060 x,
4061 y,
4062 w,
4063 h,
4064 &args.ptr,
4065 args.prop,
4066 -1,
4067 0,
4068 value,
4069 nullptr);
4070 }
4071 else {
4072 but = uiDefIconButR_prop(
4073 block, UI_BTYPE_ROW, 0, icon, x, y, w, h, &args.ptr, args.prop, -1, 0, value, nullptr);
4074 }
4076 }
4077
4078 UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
4080
4081 if (free) {
4082 MEM_freeN((void *)item);
4083 }
4084
4085 return block;
4086}
4087
4089 PointerRNA *ptr,
4090 const char *propname,
4091 bool show_labels,
4092 float icon_scale,
4093 float icon_scale_popup)
4094{
4095 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
4096
4097 if (!prop || RNA_property_type(prop) != PROP_ENUM) {
4099 "property of type Enum not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
4100 return;
4101 }
4102
4103 uiBlock *block = uiLayoutAbsoluteBlock(layout);
4104
4105 int tot_items;
4106 bool free_items;
4107 const EnumPropertyItem *items;
4109 static_cast<bContext *>(block->evil_C), ptr, prop, &items, &tot_items, &free_items);
4110 const int value = RNA_property_enum_get(ptr, prop);
4111 int icon = ICON_NONE;
4112 RNA_enum_icon_from_value(items, value, &icon);
4113
4114 uiBut *but;
4115 if (RNA_property_editable(ptr, prop)) {
4116 IconViewMenuArgs *cb_args = MEM_new<IconViewMenuArgs>(__func__);
4117 cb_args->ptr = *ptr;
4118 cb_args->prop = prop;
4119 cb_args->show_labels = show_labels;
4120 cb_args->icon_scale = icon_scale_popup;
4121
4122 but = uiDefBlockButN(block,
4124 cb_args,
4125 "",
4126 0,
4127 0,
4128 UI_UNIT_X * icon_scale,
4129 UI_UNIT_Y * icon_scale,
4130 "",
4133 }
4134 else {
4135 but = uiDefIconBut(block,
4137 0,
4138 ICON_X,
4139 0,
4140 0,
4141 UI_UNIT_X * icon_scale,
4142 UI_UNIT_Y * icon_scale,
4143 nullptr,
4144 0.0,
4145 0.0,
4146 "");
4147 }
4148
4150
4151 if (free_items) {
4152 MEM_freeN((void *)items);
4153 }
4154}
4155
4157
4158/* -------------------------------------------------------------------- */
4161
4162void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
4163{
4164 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
4165
4166 if (!prop || RNA_property_type(prop) != PROP_POINTER) {
4167 return;
4168 }
4169
4170 const PointerRNA cptr = RNA_property_pointer_get(ptr, prop);
4171 if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Histogram)) {
4172 return;
4173 }
4174 Histogram *hist = (Histogram *)cptr.data;
4175
4176 if (hist->height < UI_UNIT_Y) {
4177 hist->height = UI_UNIT_Y;
4178 }
4179 else if (hist->height > UI_UNIT_Y * 20) {
4180 hist->height = UI_UNIT_Y * 20;
4181 }
4182
4183 uiLayout *col = uiLayoutColumn(layout, true);
4184 uiBlock *block = uiLayoutGetBlock(col);
4185
4186 uiDefBut(block, UI_BTYPE_HISTOGRAM, 0, "", 0, 0, UI_UNIT_X * 10, hist->height, hist, 0, 0, "");
4187
4188 /* Resize grip. */
4189 uiDefIconButI(block,
4191 0,
4192 ICON_GRIP,
4193 0,
4194 0,
4195 UI_UNIT_X * 10,
4196 short(UI_UNIT_Y * 0.3f),
4197 &hist->height,
4198 UI_UNIT_Y,
4199 UI_UNIT_Y * 20.0f,
4200 "");
4201}
4202
4204
4205/* -------------------------------------------------------------------- */
4208
4209void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
4210{
4211 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
4212
4213 if (!prop || RNA_property_type(prop) != PROP_POINTER) {
4214 return;
4215 }
4216
4217 const PointerRNA cptr = RNA_property_pointer_get(ptr, prop);
4218 if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes)) {
4219 return;
4220 }
4221 Scopes *scopes = (Scopes *)cptr.data;
4222
4223 uiLayout *col = uiLayoutColumn(layout, true);
4224 uiBlock *block = uiLayoutGetBlock(col);
4225
4226 if (scopes->wavefrm_height < UI_UNIT_Y) {
4227 scopes->wavefrm_height = UI_UNIT_Y;
4228 }
4229 else if (scopes->wavefrm_height > UI_UNIT_Y * 20) {
4230 scopes->wavefrm_height = UI_UNIT_Y * 20;
4231 }
4232
4233 uiDefBut(block,
4235 0,
4236 "",
4237 0,
4238 0,
4239 UI_UNIT_X * 10,
4240 scopes->wavefrm_height,
4241 scopes,
4242 0,
4243 0,
4244 "");
4245
4246 /* Resize grip. */
4247 uiDefIconButI(block,
4249 0,
4250 ICON_GRIP,
4251 0,
4252 0,
4253 UI_UNIT_X * 10,
4254 short(UI_UNIT_Y * 0.3f),
4255 &scopes->wavefrm_height,
4256 UI_UNIT_Y,
4257 UI_UNIT_Y * 20.0f,
4258 "");
4259}
4260
4262
4263/* -------------------------------------------------------------------- */
4266
4267void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
4268{
4269 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
4270
4271 if (!prop || RNA_property_type(prop) != PROP_POINTER) {
4272 return;
4273 }
4274
4275 const PointerRNA cptr = RNA_property_pointer_get(ptr, prop);
4276 if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes)) {
4277 return;
4278 }
4279 Scopes *scopes = (Scopes *)cptr.data;
4280
4281 if (scopes->vecscope_height < UI_UNIT_Y) {
4282 scopes->vecscope_height = UI_UNIT_Y;
4283 }
4284 else if (scopes->vecscope_height > UI_UNIT_Y * 20) {
4285 scopes->vecscope_height = UI_UNIT_Y * 20;
4286 }
4287
4288 uiLayout *col = uiLayoutColumn(layout, true);
4289 uiBlock *block = uiLayoutGetBlock(col);
4290
4291 uiDefBut(block,
4293 0,
4294 "",
4295 0,
4296 0,
4297 UI_UNIT_X * 10,
4298 scopes->vecscope_height,
4299 scopes,
4300 0,
4301 0,
4302 "");
4303
4304 /* Resize grip. */
4305 uiDefIconButI(block,
4307 0,
4308 ICON_GRIP,
4309 0,
4310 0,
4311 UI_UNIT_X * 10,
4312 short(UI_UNIT_Y * 0.3f),
4313 &scopes->vecscope_height,
4314 UI_UNIT_Y,
4315 UI_UNIT_Y * 20.0f,
4316 "");
4317}
4318
4320
4321/* -------------------------------------------------------------------- */
4324
4325#define CURVE_ZOOM_MAX (1.0f / 25.0f)
4326
4328{
4329 return BLI_rctf_size_x(&cumap->curr) < BLI_rctf_size_x(&cumap->clipr);
4330}
4331
4333{
4334 return BLI_rctf_size_x(&cumap->curr) > CURVE_ZOOM_MAX * BLI_rctf_size_x(&cumap->clipr);
4335}
4336
4338{
4339 if (curvemap_can_zoom_in(cumap)) {
4340 const float dx = 0.1154f * BLI_rctf_size_x(&cumap->curr);
4341 cumap->curr.xmin += dx;
4342 cumap->curr.xmax -= dx;
4343 const float dy = 0.1154f * BLI_rctf_size_y(&cumap->curr);
4344 cumap->curr.ymin += dy;
4345 cumap->curr.ymax -= dy;
4346 }
4347
4349}
4350
4352{
4353 float d, d1;
4354
4355 if (curvemap_can_zoom_out(cumap)) {
4356 d = d1 = 0.15f * BLI_rctf_size_x(&cumap->curr);
4357
4358 if (cumap->flag & CUMA_DO_CLIP) {
4359 if (cumap->curr.xmin - d < cumap->clipr.xmin) {
4360 d1 = cumap->curr.xmin - cumap->clipr.xmin;
4361 }
4362 }
4363 cumap->curr.xmin -= d1;
4364
4365 d1 = d;
4366 if (cumap->flag & CUMA_DO_CLIP) {
4367 if (cumap->curr.xmax + d > cumap->clipr.xmax) {
4368 d1 = -cumap->curr.xmax + cumap->clipr.xmax;
4369 }
4370 }
4371 cumap->curr.xmax += d1;
4372
4373 d = d1 = 0.15f * BLI_rctf_size_y(&cumap->curr);
4374
4375 if (cumap->flag & CUMA_DO_CLIP) {
4376 if (cumap->curr.ymin - d < cumap->clipr.ymin) {
4377 d1 = cumap->curr.ymin - cumap->clipr.ymin;
4378 }
4379 }
4380 cumap->curr.ymin -= d1;
4381
4382 d1 = d;
4383 if (cumap->flag & CUMA_DO_CLIP) {
4384 if (cumap->curr.ymax + d > cumap->clipr.ymax) {
4385 d1 = -cumap->curr.ymax + cumap->clipr.ymax;
4386 }
4387 }
4388 cumap->curr.ymax += d1;
4389 }
4390
4392}
4393
4394/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
4395static uiBlock *curvemap_clipping_func(bContext *C, ARegion *region, void *cumap_v)
4396{
4397 CurveMapping *cumap = static_cast<CurveMapping *>(cumap_v);
4398 uiBut *bt;
4399 const float width = 8 * UI_UNIT_X;
4400
4401 uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
4404
4405 bt = uiDefButBitI(block,
4408 1,
4409 IFACE_("Use Clipping"),
4410 0,
4411 5 * UI_UNIT_Y,
4412 width,
4413 UI_UNIT_Y,
4414 &cumap->flag,
4415 0.0,
4416 0.0,
4417 "");
4418 UI_but_func_set(bt, [cumap](bContext & /*C*/) { BKE_curvemapping_changed(cumap, false); });
4419
4420 UI_block_align_begin(block);
4421 bt = uiDefButF(block,
4423 0,
4424 IFACE_("Min X:"),
4425 0,
4426 4 * UI_UNIT_Y,
4427 width,
4428 UI_UNIT_Y,
4429 &cumap->clipr.xmin,
4430 -100.0,
4431 cumap->clipr.xmax,
4432 "");
4435 bt = uiDefButF(block,
4437 0,
4438 IFACE_("Min Y:"),
4439 0,
4440 3 * UI_UNIT_Y,
4441 width,
4442 UI_UNIT_Y,
4443 &cumap->clipr.ymin,
4444 -100.0,
4445 cumap->clipr.ymax,
4446 "");
4449 bt = uiDefButF(block,
4451 0,
4452 IFACE_("Max X:"),
4453 0,
4454 2 * UI_UNIT_Y,
4455 width,
4456 UI_UNIT_Y,
4457 &cumap->clipr.xmax,
4458 cumap->clipr.xmin,
4459 100.0,
4460 "");
4463 bt = uiDefButF(block,
4465 0,
4466 IFACE_("Max Y:"),
4467 0,
4468 UI_UNIT_Y,
4469 width,
4470 UI_UNIT_Y,
4471 &cumap->clipr.ymax,
4472 cumap->clipr.ymin,
4473 100.0,
4474 "");
4477
4478 UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
4480
4481 return block;
4482}
4483
4485 bContext *C, ARegion *region, RNAUpdateCb &cb, bool show_extend, int reset_mode)
4486{
4487 PointerRNA cumap_ptr = RNA_property_pointer_get(&cb.ptr, cb.prop);
4488 CurveMapping *cumap = static_cast<CurveMapping *>(cumap_ptr.data);
4489
4490 short yco = 0;
4491 const short menuwidth = 10 * UI_UNIT_X;
4492
4493 uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
4494
4495 {
4496 uiBut *but = uiDefIconTextBut(block,
4498 1,
4499 ICON_BLANK1,
4500 IFACE_("Reset View"),
4501 0,
4502 yco -= UI_UNIT_Y,
4503 menuwidth,
4504 UI_UNIT_Y,
4505 nullptr,
4506 0.0,
4507 0.0,
4508 "");
4509 UI_but_func_set(but, [cumap](bContext &C) {
4512 });
4513 }
4514
4515 if (show_extend && !(cumap->flag & CUMA_USE_WRAPPING)) {
4516 {
4517 uiBut *but = uiDefIconTextBut(block,
4519 1,
4520 ICON_BLANK1,
4521 IFACE_("Extend Horizontal"),
4522 0,
4523 yco -= UI_UNIT_Y,
4524 menuwidth,
4525 UI_UNIT_Y,
4526 nullptr,
4527 0.0,
4528 0.0,
4529 "");
4530 UI_but_func_set(but, [cumap, cb](bContext &C) {
4532 BKE_curvemapping_changed(cumap, false);
4533 rna_update_cb(C, cb);
4534 ED_undo_push(&C, "CurveMap tools");
4536 });
4537 }
4538 {
4539 uiBut *but = uiDefIconTextBut(block,
4541 1,
4542 ICON_BLANK1,
4543 IFACE_("Extend Extrapolated"),
4544 0,
4545 yco -= UI_UNIT_Y,
4546 menuwidth,
4547 UI_UNIT_Y,
4548 nullptr,
4549 0.0,
4550 0.0,
4551 "");
4552 UI_but_func_set(but, [cumap, cb](bContext &C) {
4553 cumap->flag |= CUMA_EXTEND_EXTRAPOLATE;
4554 BKE_curvemapping_changed(cumap, false);
4555 rna_update_cb(C, cb);
4556 ED_undo_push(&C, "CurveMap tools");
4558 });
4559 }
4560 }
4561
4562 {
4563 uiBut *but = uiDefIconTextBut(block,
4565 1,
4566 ICON_BLANK1,
4567 IFACE_("Reset Curve"),
4568 0,
4569 yco -= UI_UNIT_Y,
4570 menuwidth,
4571 UI_UNIT_Y,
4572 nullptr,
4573 0.0,
4574 0.0,
4575 "");
4576 UI_but_func_set(but, [cumap, cb, reset_mode](bContext &C) {
4577 CurveMap *cuma = cumap->cm + cumap->cur;
4578 BKE_curvemap_reset(cuma, &cumap->clipr, cumap->preset, reset_mode);
4579 BKE_curvemapping_changed(cumap, false);
4580 rna_update_cb(C, cb);
4581 ED_undo_push(&C, "CurveMap tools");
4583 });
4584 }
4585
4587 UI_block_bounds_set_text(block, 3.0f * UI_UNIT_X);
4588
4589 return block;
4590}
4591
4593{
4594 return curvemap_tools_func(
4595 C, region, *static_cast<RNAUpdateCb *>(cb_v), true, CURVEMAP_SLOPE_POSITIVE);
4596}
4597
4599{
4600 return curvemap_tools_func(
4601 C, region, *static_cast<RNAUpdateCb *>(cb_v), true, CURVEMAP_SLOPE_NEGATIVE);
4602}
4603
4605{
4606 return curvemap_tools_func(
4607 C, region, *static_cast<RNAUpdateCb *>(cb_v), false, CURVEMAP_SLOPE_POSITIVE);
4608}
4609
4611{
4612 return curvemap_tools_func(
4613 C, region, *static_cast<RNAUpdateCb *>(cb_v), false, CURVEMAP_SLOPE_POSITIVE);
4614}
4615
4620
4627 PointerRNA *ptr,
4628 char labeltype,
4629 bool levels,
4630 bool brush,
4631 bool neg_slope,
4632 bool tone,
4633 const RNAUpdateCb &cb)
4634{
4635 CurveMapping *cumap = static_cast<CurveMapping *>(ptr->data);
4636 CurveMap *cm = &cumap->cm[cumap->cur];
4637 uiBut *bt;
4638 const float dx = UI_UNIT_X;
4640
4641 uiBlock *block = uiLayoutGetBlock(layout);
4642
4644
4645 if (tone) {
4646 uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
4647 uiItemR(uiLayoutRow(split, false), ptr, "tone", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
4648 }
4649
4650 /* curve chooser */
4651 uiLayout *row = uiLayoutRow(layout, false);
4652
4653 if (labeltype == 'v') {
4654 /* vector */
4655 uiLayout *sub = uiLayoutRow(row, true);
4657
4658 if (cumap->cm[0].curve) {
4659 bt = uiDefButI(block, UI_BTYPE_ROW, 0, "X", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, "");
4661 }
4662 if (cumap->cm[1].curve) {
4663 bt = uiDefButI(block, UI_BTYPE_ROW, 0, "Y", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, "");
4665 }
4666 if (cumap->cm[2].curve) {
4667 bt = uiDefButI(block, UI_BTYPE_ROW, 0, "Z", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, "");
4669 }
4670 }
4671 else if (labeltype == 'c' && cumap->tone != CURVE_TONE_FILMLIKE) {
4672 /* color */
4673 uiLayout *sub = uiLayoutRow(row, true);
4675
4676 if (cumap->cm[3].curve) {
4677 bt = uiDefButI(block,
4679 0,
4681 0,
4682 0,
4683 dx,
4684 dx,
4685 &cumap->cur,
4686 0.0,
4687 3.0,
4688 TIP_("Combined channels"));
4690 }
4691 if (cumap->cm[0].curve) {
4692 bt = uiDefButI(block,
4694 0,
4696 0,
4697 0,
4698 dx,
4699 dx,
4700 &cumap->cur,
4701 0.0,
4702 0.0,
4703 TIP_("Red channel"));
4705 }
4706 if (cumap->cm[1].curve) {
4707 bt = uiDefButI(block,
4709 0,
4711 0,
4712 0,
4713 dx,
4714 dx,
4715 &cumap->cur,
4716 0.0,
4717 1.0,
4718 TIP_("Green channel"));
4720 }
4721 if (cumap->cm[2].curve) {
4722 bt = uiDefButI(block,
4724 0,
4726 0,
4727 0,
4728 dx,
4729 dx,
4730 &cumap->cur,
4731 0.0,
4732 2.0,
4733 TIP_("Blue channel"));
4735 }
4736 }
4737 else if (labeltype == 'h') {
4738 /* HSV */
4739 uiLayout *sub = uiLayoutRow(row, true);
4741
4742 if (cumap->cm[0].curve) {
4743 bt = uiDefButI(block,
4745 0,
4746 IFACE_("H"),
4747 0,
4748 0,
4749 dx,
4750 dx,
4751 &cumap->cur,
4752 0.0,
4753 0.0,
4754 TIP_("Hue level"));
4756 }
4757 if (cumap->cm[1].curve) {
4758 bt = uiDefButI(block,
4760 0,
4761 IFACE_("S"),
4762 0,
4763 0,
4764 dx,
4765 dx,
4766 &cumap->cur,
4767 0.0,
4768 1.0,
4769 TIP_("Saturation level"));
4771 }
4772 if (cumap->cm[2].curve) {
4773 bt = uiDefButI(block,
4775 0,
4776 IFACE_("V"),
4777 0,
4778 0,
4779 dx,
4780 dx,
4781 &cumap->cur,
4782 0.0,
4783 2.0,
4784 TIP_("Value level"));
4786 }
4787 }
4788 else {
4790 }
4791
4792 if (labeltype == 'h') {
4793 bg = UI_GRAD_H;
4794 }
4795
4796 /* operation buttons */
4797 /* (Right aligned) */
4798 uiLayout *sub = uiLayoutRow(row, true);
4800
4801 if (!(cumap->flag & CUMA_USE_WRAPPING)) {
4802 /* Zoom in */
4803 bt = uiDefIconBut(
4804 block, UI_BTYPE_BUT, 0, ICON_ZOOM_IN, 0, 0, dx, dx, nullptr, 0.0, 0.0, TIP_("Zoom in"));
4805 UI_but_func_set(bt, [cumap](bContext &C) { curvemap_buttons_zoom_in(&C, cumap); });
4806 if (!curvemap_can_zoom_in(cumap)) {
4807 UI_but_disable(bt, "");
4808 }
4809
4810 /* Zoom out */
4811 bt = uiDefIconBut(
4812 block, UI_BTYPE_BUT, 0, ICON_ZOOM_OUT, 0, 0, dx, dx, nullptr, 0.0, 0.0, TIP_("Zoom out"));
4813 UI_but_func_set(bt, [cumap](bContext &C) { curvemap_buttons_zoom_out(&C, cumap); });
4814 if (!curvemap_can_zoom_out(cumap)) {
4815 UI_but_disable(bt, "");
4816 }
4817
4818 /* Clipping button. */
4819 const int icon = (cumap->flag & CUMA_DO_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
4820 bt = uiDefIconBlockBut(
4821 block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
4823 UI_but_func_set(bt, [cb](bContext &C) { rna_update_cb(C, cb); });
4824 }
4825
4826 RNAUpdateCb *tools_cb = MEM_new<RNAUpdateCb>(__func__, cb);
4827 if (brush && neg_slope) {
4828 bt = uiDefIconBlockBut(block,
4830 tools_cb,
4831 0,
4832 ICON_NONE,
4833 0,
4834 0,
4835 dx,
4836 dx,
4837 TIP_("Tools"));
4838 }
4839 else if (brush) {
4840 bt = uiDefIconBlockBut(
4841 block, curvemap_brush_tools_func, tools_cb, 0, ICON_NONE, 0, 0, dx, dx, TIP_("Tools"));
4842 }
4843 else if (neg_slope) {
4844 bt = uiDefIconBlockBut(
4845 block, curvemap_tools_negslope_func, tools_cb, 0, ICON_NONE, 0, 0, dx, dx, TIP_("Tools"));
4846 }
4847 else {
4848 bt = uiDefIconBlockBut(
4849 block, curvemap_tools_posslope_func, tools_cb, 0, ICON_NONE, 0, 0, dx, dx, TIP_("Tools"));
4850 }
4851 /* Pass ownership of `tools_cb` to the button. */
4853 bt,
4854 [](bContext *, void *, void *) {},
4855 tools_cb,
4856 nullptr,
4859
4860 UI_block_funcN_set(block,
4862 MEM_new<RNAUpdateCb>(__func__, cb),
4863 nullptr,
4866
4867 /* Curve itself. */
4868 const int size = max_ii(uiLayoutGetWidth(layout), UI_UNIT_X);
4869 row = uiLayoutRow(layout, false);
4871 block, UI_BTYPE_CURVE, 0, "", 0, 0, size, 8.0f * UI_UNIT_X, cumap, 0.0f, 1.0f, "");
4872 curve_but->gradient_type = bg;
4873
4874 /* Sliders for selected curve point. */
4875 int i;
4876 CurveMapPoint *cmp = nullptr;
4877 bool point_last_or_first = false;
4878 for (i = 0; i < cm->totpoint; i++) {
4879 if (cm->curve[i].flag & CUMA_SELECT) {
4880 cmp = &cm->curve[i];
4881 break;
4882 }
4883 }
4884 if (ELEM(i, 0, cm->totpoint - 1)) {
4885 point_last_or_first = true;
4886 }
4887
4888 if (cmp) {
4889 rctf bounds;
4890 if (cumap->flag & CUMA_DO_CLIP) {
4891 bounds = cumap->clipr;
4892 }
4893 else {
4894 bounds.xmin = bounds.ymin = -1000.0;
4895 bounds.xmax = bounds.ymax = 1000.0;
4896 }
4897
4899
4900 uiLayoutRow(layout, true);
4901
4902 /* Curve handle buttons. */
4903 bt = uiDefIconBut(block,
4905 1,
4906 ICON_HANDLE_AUTO,
4907 0,
4908 UI_UNIT_Y,
4909 UI_UNIT_X,
4910 UI_UNIT_Y,
4911 nullptr,
4912 0.0,
4913 0.0,
4914 TIP_("Auto Handle"));
4915 UI_but_func_set(bt, [cumap, cb](bContext &C) {
4916 CurveMap *cuma = cumap->cm + cumap->cur;
4918 BKE_curvemapping_changed(cumap, false);
4919 rna_update_cb(C, cb);
4920 });
4921 if (((cmp->flag & CUMA_HANDLE_AUTO_ANIM) == false) &&
4922 ((cmp->flag & CUMA_HANDLE_VECTOR) == false))
4923 {
4924 bt->flag |= UI_SELECT_DRAW;
4925 }
4926
4927 bt = uiDefIconBut(block,
4929 1,
4930 ICON_HANDLE_VECTOR,
4931 0,
4932 UI_UNIT_Y,
4933 UI_UNIT_X,
4934 UI_UNIT_Y,
4935 nullptr,
4936 0.0,
4937 0.0,
4938 TIP_("Vector Handle"));
4939 UI_but_func_set(bt, [cumap, cb](bContext &C) {
4940 CurveMap *cuma = cumap->cm + cumap->cur;
4942 BKE_curvemapping_changed(cumap, false);
4943 rna_update_cb(C, cb);
4944 });
4945 if (cmp->flag & CUMA_HANDLE_VECTOR) {
4946 bt->flag |= UI_SELECT_DRAW;
4947 }
4948
4949 bt = uiDefIconBut(block,
4951 1,
4952 ICON_HANDLE_AUTOCLAMPED,
4953 0,
4954 UI_UNIT_Y,
4955 UI_UNIT_X,
4956 UI_UNIT_Y,
4957 nullptr,
4958 0.0,
4959 0.0,
4960 TIP_("Auto Clamped"));
4961 UI_but_func_set(bt, [cumap, cb](bContext &C) {
4962 CurveMap *cuma = cumap->cm + cumap->cur;
4964 BKE_curvemapping_changed(cumap, false);
4965 rna_update_cb(C, cb);
4966 });
4967 if (cmp->flag & CUMA_HANDLE_AUTO_ANIM) {
4968 bt->flag |= UI_SELECT_DRAW;
4969 }
4970
4971 /* Curve handle position */
4972 bt = uiDefButF(block,
4974 0,
4975 "X:",
4976 0,
4977 2 * UI_UNIT_Y,
4978 UI_UNIT_X * 10,
4979 UI_UNIT_Y,
4980 &cmp->x,
4981 bounds.xmin,
4982 bounds.xmax,
4983 "");
4986 UI_but_func_set(bt, [cumap, cb](bContext &C) {
4987 BKE_curvemapping_changed(cumap, true);
4988 rna_update_cb(C, cb);
4989 });
4990
4991 bt = uiDefButF(block,
4993 0,
4994 "Y:",
4995 0,
4996 1 * UI_UNIT_Y,
4997 UI_UNIT_X * 10,
4998 UI_UNIT_Y,
4999 &cmp->y,
5000 bounds.ymin,
5001 bounds.ymax,
5002 "");
5005 UI_but_func_set(bt, [cumap, cb](bContext &C) {
5006 BKE_curvemapping_changed(cumap, true);
5007 rna_update_cb(C, cb);
5008 });
5009
5010 /* Curve handle delete point */
5011 bt = uiDefIconBut(
5012 block, UI_BTYPE_BUT, 0, ICON_X, 0, 0, dx, dx, nullptr, 0.0, 0.0, TIP_("Delete points"));
5013 UI_but_func_set(bt, [cumap, cb](bContext &C) {
5014 BKE_curvemap_remove(cumap->cm + cumap->cur, SELECT);
5015 BKE_curvemapping_changed(cumap, false);
5016 rna_update_cb(C, cb);
5017 });
5018 if (point_last_or_first) {
5020 }
5021 }
5022
5023 /* black/white levels */
5024 if (levels) {
5025 uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
5026 uiItemR(
5027 uiLayoutColumn(split, false), ptr, "black_level", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
5028 uiItemR(
5029 uiLayoutColumn(split, false), ptr, "white_level", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
5030
5031 uiLayoutRow(layout, false);
5032 bt = uiDefBut(block,
5034 0,
5035 IFACE_("Reset"),
5036 0,
5037 0,
5038 UI_UNIT_X * 10,
5039 UI_UNIT_Y,
5040 nullptr,
5041 0.0f,
5042 0.0f,
5043 TIP_("Reset Black/White point and curves"));
5044 UI_but_func_set(bt, [cumap, cb](bContext &C) {
5045 cumap->preset = CURVE_PRESET_LINE;
5046 for (int a = 0; a < CM_TOT; a++) {
5047 BKE_curvemap_reset(cumap->cm + a, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
5048 }
5049
5050 cumap->black[0] = cumap->black[1] = cumap->black[2] = 0.0f;
5051 cumap->white[0] = cumap->white[1] = cumap->white[2] = 1.0f;
5052 BKE_curvemapping_set_black_white(cumap, nullptr, nullptr);
5053
5054 BKE_curvemapping_changed(cumap, false);
5055 rna_update_cb(C, cb);
5056 });
5057 }
5058
5059 UI_block_funcN_set(block, nullptr, nullptr, nullptr);
5060}
5061
5063 PointerRNA *ptr,
5064 const char *propname,
5065 int type,
5066 bool levels,
5067 bool brush,
5068 bool neg_slope,
5069 bool tone)
5070{
5071 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
5072 uiBlock *block = uiLayoutGetBlock(layout);
5073
5074 if (!prop) {
5075 RNA_warning("curve property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
5076 return;
5077 }
5078
5079 if (RNA_property_type(prop) != PROP_POINTER) {
5080 RNA_warning("curve is not a pointer: %s.%s", RNA_struct_identifier(ptr->type), propname);
5081 return;
5082 }
5083
5085 if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveMapping)) {
5086 return;
5087 }
5088
5089 ID *id = cptr.owner_id;
5091
5093 layout, &cptr, type, levels, brush, neg_slope, tone, RNAUpdateCb{*ptr, prop});
5094
5095 UI_block_lock_clear(block);
5096}
5097
5099
5100/* -------------------------------------------------------------------- */
5103
5104static uiBlock *curve_profile_presets_fn(bContext *C, ARegion *region, void *cb_v)
5105{
5106 RNAUpdateCb &cb = *static_cast<RNAUpdateCb *>(cb_v);
5107 PointerRNA profile_ptr = RNA_property_pointer_get(&cb.ptr, cb.prop);
5108 CurveProfile *profile = static_cast<CurveProfile *>(profile_ptr.data);
5109 short yco = 0;
5110
5111 uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
5112
5113 for (const auto &item :
5114 {std::pair<StringRef, eCurveProfilePresets>(IFACE_("Default"), PROF_PRESET_LINE),
5115 std::pair<StringRef, eCurveProfilePresets>(IFACE_("Support Loops"), PROF_PRESET_SUPPORTS),
5116 std::pair<StringRef, eCurveProfilePresets>(IFACE_("Cornice Molding"), PROF_PRESET_CORNICE),
5117 std::pair<StringRef, eCurveProfilePresets>(IFACE_("Crown Molding"), PROF_PRESET_CROWN),
5118 std::pair<StringRef, eCurveProfilePresets>(IFACE_("Steps"), PROF_PRESET_STEPS)})
5119 {
5120 uiBut *but = uiDefIconTextBut(block,
5122 1,
5123 ICON_BLANK1,
5124 item.first,
5125 0,
5126 yco -= UI_UNIT_Y,
5127 0,
5128 UI_UNIT_Y,
5129 nullptr,
5130 0.0,
5131 0.0,
5132 "");
5133 const eCurveProfilePresets preset = item.second;
5134 UI_but_func_set(but, [profile, cb, preset](bContext &C) {
5135 profile->preset = preset;
5136 BKE_curveprofile_reset(profile);
5138 ED_undo_push(&C, "Reset Curve Profile");
5140 rna_update_cb(C, cb);
5141 });
5142 }
5143
5145 UI_block_bounds_set_text(block, int(3.0f * UI_UNIT_X));
5146
5147 return block;
5148}
5149
5150static uiBlock *curve_profile_tools_fn(bContext *C, ARegion *region, void *cb_v)
5151{
5152 RNAUpdateCb &cb = *static_cast<RNAUpdateCb *>(cb_v);
5153 PointerRNA profile_ptr = RNA_property_pointer_get(&cb.ptr, cb.prop);
5154 CurveProfile *profile = static_cast<CurveProfile *>(profile_ptr.data);
5155 short yco = 0;
5156
5157 uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
5158
5159 {
5160 uiBut *but = uiDefIconTextBut(block,
5162 1,
5163 ICON_BLANK1,
5164 IFACE_("Reset View"),
5165 0,
5166 yco -= UI_UNIT_Y,
5167 0,
5168 UI_UNIT_Y,
5169 nullptr,
5170 0.0,
5171 0.0,
5172 "");
5173 UI_but_func_set(but, [profile](bContext &C) {
5176 });
5177 }
5178 {
5179 uiBut *but = uiDefIconTextBut(block,
5181 1,
5182 ICON_BLANK1,
5183 IFACE_("Reset Curve"),
5184 0,
5185 yco -= UI_UNIT_Y,
5186 0,
5187 UI_UNIT_Y,
5188 nullptr,
5189 0.0,
5190 0.0,
5191 "");
5192 UI_but_func_set(but, [profile, cb](bContext &C) {
5193 BKE_curveprofile_reset(profile);
5195 ED_undo_push(&C, "Reset Profile");
5197 rna_update_cb(C, cb);
5198 });
5199 }
5200
5202 UI_block_bounds_set_text(block, int(3.0f * UI_UNIT_X));
5203
5204 return block;
5205}
5206
5208{
5209 return BLI_rctf_size_x(&profile->view_rect) >
5211}
5212
5214{
5215 return BLI_rctf_size_x(&profile->view_rect) < BLI_rctf_size_x(&profile->clip_rect);
5216}
5217
5219{
5220 if (curve_profile_can_zoom_in(profile)) {
5221 const float dx = 0.1154f * BLI_rctf_size_x(&profile->view_rect);
5222 profile->view_rect.xmin += dx;
5223 profile->view_rect.xmax -= dx;
5224 const float dy = 0.1154f * BLI_rctf_size_y(&profile->view_rect);
5225 profile->view_rect.ymin += dy;
5226 profile->view_rect.ymax -= dy;
5227 }
5228
5230}
5231
5233{
5234 if (curve_profile_can_zoom_out(profile)) {
5235 float d = 0.15f * BLI_rctf_size_x(&profile->view_rect);
5236 float d1 = d;
5237
5238 if (profile->flag & PROF_USE_CLIP) {
5239 if (profile->view_rect.xmin - d < profile->clip_rect.xmin) {
5240 d1 = profile->view_rect.xmin - profile->clip_rect.xmin;
5241 }
5242 }
5243 profile->view_rect.xmin -= d1;
5244
5245 d1 = d;
5246 if (profile->flag & PROF_USE_CLIP) {
5247 if (profile->view_rect.xmax + d > profile->clip_rect.xmax) {
5248 d1 = -profile->view_rect.xmax + profile->clip_rect.xmax;
5249 }
5250 }
5251 profile->view_rect.xmax += d1;
5252
5253 d = d1 = 0.15f * BLI_rctf_size_y(&profile->view_rect);
5254
5255 if (profile->flag & PROF_USE_CLIP) {
5256 if (profile->view_rect.ymin - d < profile->clip_rect.ymin) {
5257 d1 = profile->view_rect.ymin - profile->clip_rect.ymin;
5258 }
5259 }
5260 profile->view_rect.ymin -= d1;
5261
5262 d1 = d;
5263 if (profile->flag & PROF_USE_CLIP) {
5264 if (profile->view_rect.ymax + d > profile->clip_rect.ymax) {
5265 d1 = -profile->view_rect.ymax + profile->clip_rect.ymax;
5266 }
5267 }
5268 profile->view_rect.ymax += d1;
5269 }
5270
5272}
5273
5275{
5276 CurveProfile *profile = static_cast<CurveProfile *>(ptr->data);
5277 uiBut *bt;
5278
5279 uiBlock *block = uiLayoutGetBlock(layout);
5280
5282
5283 uiLayoutSetPropSep(layout, false);
5284
5285 /* Preset selector */
5286 /* There is probably potential to use simpler "uiItemR" functions here, but automatic updating
5287 * after a preset is selected would be more complicated. */
5288 uiLayout *row = uiLayoutRow(layout, true);
5289 RNAUpdateCb *presets_cb = MEM_new<RNAUpdateCb>(__func__, cb);
5290 bt = uiDefBlockBut(block,
5292 presets_cb,
5293 IFACE_("Preset"),
5294 0,
5295 0,
5296 UI_UNIT_X,
5297 UI_UNIT_X,
5298 "");
5299 /* Pass ownership of `presets_cb` to the button. */
5301 bt,
5302 [](bContext *, void *, void *) {},
5303 presets_cb,
5304 nullptr,
5307
5308 /* Show a "re-apply" preset button when it has been changed from the preset. */
5309 if (profile->flag & PROF_DIRTY_PRESET) {
5310 /* Only for dynamic presets. */
5312 bt = uiDefIconTextBut(block,
5314 0,
5315 ICON_NONE,
5316 IFACE_("Apply Preset"),
5317 0,
5318 0,
5319 UI_UNIT_X,
5320 UI_UNIT_X,
5321 nullptr,
5322 0.0,
5323 0.0,
5324 TIP_("Reapply and update the preset, removing changes"));
5325 UI_but_func_set(bt, [profile, cb](bContext &C) {
5326 BKE_curveprofile_reset(profile);
5328 rna_update_cb(C, cb);
5329 });
5330 }
5331 }
5332
5333 row = uiLayoutRow(layout, false);
5334
5335 /* (Left aligned) */
5336 uiLayout *sub = uiLayoutRow(row, true);
5338
5339 /* Zoom in */
5340 bt = uiDefIconBut(block,
5342 0,
5343 ICON_ZOOM_IN,
5344 0,
5345 0,
5346 UI_UNIT_X,
5347 UI_UNIT_X,
5348 nullptr,
5349 0.0,
5350 0.0,
5351 TIP_("Zoom in"));
5352 UI_but_func_set(bt, [profile](bContext &C) { curve_profile_zoom_in(&C, profile); });
5353 if (!curve_profile_can_zoom_in(profile)) {
5354 UI_but_disable(bt, "");
5355 }
5356
5357 /* Zoom out */
5358 bt = uiDefIconBut(block,
5360 0,
5361 ICON_ZOOM_OUT,
5362 0,
5363 0,
5364 UI_UNIT_X,
5365 UI_UNIT_X,
5366 nullptr,
5367 0.0,
5368 0.0,
5369 TIP_("Zoom out"));
5370 UI_but_func_set(bt, [profile](bContext &C) { curve_profile_zoom_out(&C, profile); });
5371 if (!curve_profile_can_zoom_out(profile)) {
5372 UI_but_disable(bt, "");
5373 }
5374
5375 /* (Right aligned) */
5376 sub = uiLayoutRow(row, true);
5378
5379 /* Flip path */
5380 bt = uiDefIconBut(block,
5382 0,
5383 ICON_ARROW_LEFTRIGHT,
5384 0,
5385 0,
5386 UI_UNIT_X,
5387 UI_UNIT_X,
5388 nullptr,
5389 0.0,
5390 0.0,
5391 TIP_("Reverse Path"));
5392 UI_but_func_set(bt, [profile, cb](bContext &C) {
5393 BKE_curveprofile_reverse(profile);
5395 rna_update_cb(C, cb);
5396 });
5397
5398 /* Clipping toggle */
5399 const int icon = (profile->flag & PROF_USE_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
5400 bt = uiDefIconBut(block,
5402 0,
5403 icon,
5404 0,
5405 0,
5406 UI_UNIT_X,
5407 UI_UNIT_X,
5408 nullptr,
5409 0.0,
5410 0.0,
5411 TIP_("Toggle Profile Clipping"));
5412 UI_but_func_set(bt, [profile, cb](bContext &C) {
5413 profile->flag ^= PROF_USE_CLIP;
5415 rna_update_cb(C, cb);
5416 });
5417
5418 /* Reset view, reset curve */
5419 RNAUpdateCb *tools_cb = MEM_new<RNAUpdateCb>(__func__, cb);
5420 bt = uiDefIconBlockBut(block,
5422 tools_cb,
5423 0,
5424 ICON_NONE,
5425 0,
5426 0,
5427 UI_UNIT_X,
5428 UI_UNIT_X,
5429 TIP_("Tools"));
5430 /* Pass ownership of `presets_cb` to the button. */
5432 bt,
5433 [](bContext *, void *, void *) {},
5434 tools_cb,
5435 nullptr,
5438
5439 UI_block_funcN_set(block,
5441 MEM_new<RNAUpdateCb>(__func__, cb),
5442 nullptr,
5445
5446 /* The path itself */
5447 int path_width = max_ii(uiLayoutGetWidth(layout), UI_UNIT_X);
5448 path_width = min_ii(path_width, int(16.0f * UI_UNIT_X));
5449 const int path_height = path_width;
5450 uiLayoutRow(layout, false);
5451 uiDefBut(block,
5453 0,
5454 "",
5455 0,
5456 0,
5457 short(path_width),
5458 short(path_height),
5459 profile,
5460 0.0f,
5461 1.0f,
5462 "");
5463
5464 /* Position sliders for (first) selected point */
5465 int i;
5466 float *selection_x, *selection_y;
5467 bool point_last_or_first = false;
5468 CurveProfilePoint *point = nullptr;
5469 for (i = 0; i < profile->path_len; i++) {
5470 if (profile->path[i].flag & PROF_SELECT) {
5471 point = &profile->path[i];
5472 selection_x = &point->x;
5473 selection_y = &point->y;
5474 break;
5475 }
5476 if (profile->path[i].flag & PROF_H1_SELECT) {
5477 point = &profile->path[i];
5478 selection_x = &point->h1_loc[0];
5479 selection_y = &point->h1_loc[1];
5480 }
5481 else if (profile->path[i].flag & PROF_H2_SELECT) {
5482 point = &profile->path[i];
5483 selection_x = &point->h2_loc[0];
5484 selection_y = &point->h2_loc[1];
5485 }
5486 }
5487 if (ELEM(i, 0, profile->path_len - 1)) {
5488 point_last_or_first = true;
5489 }
5490
5491 /* Selected point data */
5492 rctf bounds;
5493 if (point) {
5494 if (profile->flag & PROF_USE_CLIP) {
5495 bounds = profile->clip_rect;
5496 }
5497 else {
5498 bounds.xmin = bounds.ymin = -1000.0;
5499 bounds.xmax = bounds.ymax = 1000.0;
5500 }
5501
5502 row = uiLayoutRow(layout, true);
5503
5504 PointerRNA point_ptr = RNA_pointer_create(ptr->owner_id, &RNA_CurveProfilePoint, point);
5505 PropertyRNA *prop_handle_type = RNA_struct_find_property(&point_ptr, "handle_type_1");
5506 uiItemFullR(row,
5507 &point_ptr,
5508 prop_handle_type,
5510 0,
5512 "",
5513 ICON_NONE);
5514
5515 /* Position */
5516 bt = uiDefButF(block,
5518 0,
5519 "X:",
5520 0,
5521 2 * UI_UNIT_Y,
5522 UI_UNIT_X * 10,
5523 UI_UNIT_Y,
5524 selection_x,
5525 bounds.xmin,
5526 bounds.xmax,
5527 "");
5530 UI_but_func_set(bt, [profile, cb](bContext &C) {
5532 rna_update_cb(C, cb);
5533 });
5534 if (point_last_or_first) {
5536 }
5537 bt = uiDefButF(block,
5539 0,
5540 "Y:",
5541 0,
5542 1 * UI_UNIT_Y,
5543 UI_UNIT_X * 10,
5544 UI_UNIT_Y,
5545 selection_y,
5546 bounds.ymin,
5547 bounds.ymax,
5548 "");
5551 UI_but_func_set(bt, [profile, cb](bContext &C) {
5553 rna_update_cb(C, cb);
5554 });
5555 if (point_last_or_first) {
5557 }
5558
5559 /* Delete points */
5560 bt = uiDefIconBut(block,
5562 0,
5563 ICON_X,
5564 0,
5565 0,
5566 UI_UNIT_X,
5567 UI_UNIT_X,
5568 nullptr,
5569 0.0,
5570 0.0,
5571 TIP_("Delete points"));
5572 UI_but_func_set(bt, [profile, cb](bContext &C) {
5575 rna_update_cb(C, cb);
5576 });
5577 if (point_last_or_first) {
5579 }
5580 }
5581
5582 uiItemR(layout, ptr, "use_sample_straight_edges", UI_ITEM_NONE, nullptr, ICON_NONE);
5583 uiItemR(layout, ptr, "use_sample_even_lengths", UI_ITEM_NONE, nullptr, ICON_NONE);
5584
5585 UI_block_funcN_set(block, nullptr, nullptr, nullptr);
5586}
5587
5588void uiTemplateCurveProfile(uiLayout *layout, PointerRNA *ptr, const char *propname)
5589{
5590 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
5591
5592 uiBlock *block = uiLayoutGetBlock(layout);
5593
5594 if (!prop) {
5596 "Curve Profile property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
5597 return;
5598 }
5599
5600 if (RNA_property_type(prop) != PROP_POINTER) {
5602 "Curve Profile is not a pointer: %s.%s", RNA_struct_identifier(ptr->type), propname);
5603 return;
5604 }
5605
5607 if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveProfile)) {
5608 return;
5609 }
5610
5611 ID *id = cptr.owner_id;
5613
5614 CurveProfile_buttons_layout(layout, &cptr, RNAUpdateCb{*ptr, prop});
5615
5616 UI_block_lock_clear(block);
5617}
5618
5620
5621/* -------------------------------------------------------------------- */
5624
5625#define WHEEL_SIZE (5 * U.widget_unit)
5626
5628 PointerRNA *ptr,
5629 const char *propname,
5630 bool value_slider,
5631 bool lock,
5632 bool lock_luminosity,
5633 bool cubic)
5634{
5635 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
5636 uiBlock *block = uiLayoutGetBlock(layout);
5637 ColorPicker *cpicker = ui_block_colorpicker_create(block);
5638
5639 if (!prop) {
5640 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
5641 return;
5642 }
5643
5644 float softmin, softmax, step, precision;
5645 RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
5646
5647 uiLayout *col = uiLayoutColumn(layout, true);
5648 uiLayout *row = uiLayoutRow(col, true);
5649
5650 uiBut *but = nullptr;
5651 uiButHSVCube *hsv_but;
5652 switch (U.color_picker_type) {
5653 case USER_CP_SQUARE_SV:
5654 case USER_CP_SQUARE_HS:
5655 case USER_CP_SQUARE_HV:
5656 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
5658 0,
5659 "",
5660 0,
5661 0,
5662 WHEEL_SIZE,
5663 WHEEL_SIZE,
5664 ptr,
5665 prop,
5666 -1,
5667 0.0,
5668 0.0,
5669 "");
5670 switch (U.color_picker_type) {
5671 case USER_CP_SQUARE_SV:
5672 hsv_but->gradient_type = UI_GRAD_SV;
5673 break;
5674 case USER_CP_SQUARE_HS:
5675 hsv_but->gradient_type = UI_GRAD_HS;
5676 break;
5677 case USER_CP_SQUARE_HV:
5678 hsv_but->gradient_type = UI_GRAD_HV;
5679 break;
5680 }
5681 but = hsv_but;
5682 break;
5683
5684 /* user default */
5685 case USER_CP_CIRCLE_HSV:
5686 case USER_CP_CIRCLE_HSL:
5687 default:
5688 but = uiDefButR_prop(block,
5690 0,
5691 "",
5692 0,
5693 0,
5694 WHEEL_SIZE,
5695 WHEEL_SIZE,
5696 ptr,
5697 prop,
5698 -1,
5699 0.0,
5700 0.0,
5701 "");
5702 break;
5703 }
5704
5705 but->custom_data = cpicker;
5706
5707 cpicker->use_color_lock = lock;
5708 cpicker->use_color_cubic = cubic;
5709 cpicker->use_luminosity_lock = lock_luminosity;
5710
5711 if (lock_luminosity) {
5712 float color[4]; /* in case of alpha */
5715 }
5716
5717 if (value_slider) {
5718 switch (U.color_picker_type) {
5719 case USER_CP_CIRCLE_HSL:
5720 uiItemS(row);
5721 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
5723 0,
5724 "",
5725 WHEEL_SIZE + 6,
5726 0,
5727 14 * UI_SCALE_FAC,
5728 WHEEL_SIZE,
5729 ptr,
5730 prop,
5731 -1,
5732 softmin,
5733 softmax,
5734 "");
5735 hsv_but->gradient_type = UI_GRAD_L_ALT;
5736 break;
5737 case USER_CP_SQUARE_SV:
5738 uiItemS(col);
5739 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
5741 0,
5742 "",
5743 0,
5744 4,
5745 WHEEL_SIZE,
5746 18 * UI_SCALE_FAC,
5747 ptr,
5748 prop,
5749 -1,
5750 softmin,
5751 softmax,
5752 "");
5754 break;
5755 case USER_CP_SQUARE_HS:
5756 uiItemS(col);
5757 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
5759 0,
5760 "",
5761 0,
5762 4,
5763 WHEEL_SIZE,
5764 18 * UI_SCALE_FAC,
5765 ptr,
5766 prop,
5767 -1,
5768 softmin,
5769 softmax,
5770 "");
5772 break;
5773 case USER_CP_SQUARE_HV:
5774 uiItemS(col);
5775 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
5777 0,
5778 "",
5779 0,
5780 4,
5781 WHEEL_SIZE,
5782 18 * UI_SCALE_FAC,
5783 ptr,
5784 prop,
5785 -1,
5786 softmin,
5787 softmax,
5788 "");
5790 break;
5791
5792 /* user default */
5793 case USER_CP_CIRCLE_HSV:
5794 default:
5795 uiItemS(row);
5796 hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
5798 0,
5799 "",
5800 WHEEL_SIZE + 6,
5801 0,
5802 14 * UI_SCALE_FAC,
5803 WHEEL_SIZE,
5804 ptr,
5805 prop,
5806 -1,
5807 softmin,
5808 softmax,
5809 "");
5810 hsv_but->gradient_type = UI_GRAD_V_ALT;
5811 break;
5812 }
5813
5814 hsv_but->custom_data = cpicker;
5815 }
5816}
5817
5818static void ui_template_palette_menu(bContext * /*C*/, uiLayout *layout, void * /*but_p*/)
5819{
5820 uiLayout *row;
5821
5822 uiItemL(layout, IFACE_("Sort By:"), ICON_NONE);
5823 row = uiLayoutRow(layout, false);
5824 uiItemEnumO_value(row, IFACE_("Hue"), ICON_NONE, "PALETTE_OT_sort", "type", 1);
5825 row = uiLayoutRow(layout, false);
5826 uiItemEnumO_value(row, IFACE_("Saturation"), ICON_NONE, "PALETTE_OT_sort", "type", 2);
5827 row = uiLayoutRow(layout, false);
5828 uiItemEnumO_value(row, IFACE_("Value"), ICON_NONE, "PALETTE_OT_sort", "type", 3);
5829 row = uiLayoutRow(layout, false);
5830 uiItemEnumO_value(row, IFACE_("Luminance"), ICON_NONE, "PALETTE_OT_sort", "type", 4);
5831}
5832
5833void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname, bool /*colors*/)
5834{
5835 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
5836 uiBut *but = nullptr;
5837
5838 const int cols_per_row = std::max(uiLayoutGetWidth(layout) / UI_UNIT_X, 1);
5839
5840 if (!prop) {
5841 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
5842 return;
5843 }
5844
5845 const PointerRNA cptr = RNA_property_pointer_get(ptr, prop);
5846 if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Palette)) {
5847 return;
5848 }
5849
5850 uiBlock *block = uiLayoutGetBlock(layout);
5851
5852 Palette *palette = static_cast<Palette *>(cptr.data);
5853
5854 uiLayout *col = uiLayoutColumn(layout, true);
5855 uiLayoutRow(col, true);
5856 uiDefIconButO(block,
5858 "PALETTE_OT_color_add",
5860 ICON_ADD,
5861 0,
5862 0,
5863 UI_UNIT_X,
5864 UI_UNIT_Y,
5865 nullptr);
5866 uiDefIconButO(block,
5868 "PALETTE_OT_color_delete",
5870 ICON_REMOVE,
5871 0,
5872 0,
5873 UI_UNIT_X,
5874 UI_UNIT_Y,
5875 nullptr);
5876 if (palette->colors.first != nullptr) {
5877 but = uiDefIconButO(block,
5879 "PALETTE_OT_color_move",
5881 ICON_TRIA_UP,
5882 0,
5883 0,
5884 UI_UNIT_X,
5885 UI_UNIT_Y,
5886 nullptr);
5888 RNA_enum_set(but->opptr, "type", -1);
5889
5890 but = uiDefIconButO(block,
5892 "PALETTE_OT_color_move",
5894 ICON_TRIA_DOWN,
5895 0,
5896 0,
5897 UI_UNIT_X,
5898 UI_UNIT_Y,
5899 nullptr);
5901 RNA_enum_set(but->opptr, "type", 1);
5902
5903 /* Menu. */
5905 block, ui_template_palette_menu, nullptr, ICON_SORTSIZE, 0, 0, UI_UNIT_X, UI_UNIT_Y, "");
5906 }
5907
5908 col = uiLayoutColumn(layout, true);
5909 uiLayoutRow(col, true);
5910
5911 int row_cols = 0, col_id = 0;
5912 LISTBASE_FOREACH (PaletteColor *, color, &palette->colors) {
5913 if (row_cols >= cols_per_row) {
5914 uiLayoutRow(col, true);
5915 row_cols = 0;
5916 }
5917
5918 PointerRNA color_ptr = RNA_pointer_create(&palette->id, &RNA_PaletteColor, color);
5919 uiButColor *color_but = (uiButColor *)uiDefButR(block,
5921 0,
5922 "",
5923 0,
5924 0,
5925 UI_UNIT_X,
5926 UI_UNIT_Y,
5927 &color_ptr,
5928 "color",
5929 -1,
5930 0.0,
5931 1.0,
5932 "");
5933 color_but->is_pallete_color = true;
5934 color_but->palette_color_index = col_id;
5935 row_cols++;
5936 col_id++;
5937 }
5938}
5939
5940void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propname, int icon)
5941{
5942 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
5943
5944 if (!prop) {
5945 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
5946 return;
5947 }
5948
5949 uiBlock *block = uiLayoutGetBlock(layout);
5950
5951 uiBut *but = uiDefIconButO(block,
5953 "UI_OT_eyedropper_color",
5955 icon,
5956 0,
5957 0,
5958 UI_UNIT_X,
5959 UI_UNIT_Y,
5961 but->rnapoin = *ptr;
5962 but->rnaprop = prop;
5963 but->rnaindex = -1;
5964}
5965
5967
5968/* -------------------------------------------------------------------- */
5971
5972static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
5973{
5974 uiBut *but = static_cast<uiBut *>(arg1);
5975 const int cur = POINTER_AS_INT(arg2);
5976 wmWindow *win = CTX_wm_window(C);
5977 const bool shift = win->eventstate->modifier & KM_SHIFT;
5978
5979 if (!shift) {
5980 const int tot = RNA_property_array_length(&but->rnapoin, but->rnaprop);
5981
5982 /* Normally clicking only selects one layer */
5983 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, true);
5984 for (int i = 0; i < tot; i++) {
5985 if (i != cur) {
5986 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, false);
5987 }
5988 }
5989 }
5990
5991 /* view3d layer change should update depsgraph (invisible object changed maybe) */
5992 /* see `view3d_header.cc` */
5993}
5994
5996 PointerRNA *ptr,
5997 const char *propname,
5998 PointerRNA *used_ptr,
5999 const char *used_propname,
6000 int active_layer)
6001{
6002 const int cols_per_group = 5;
6003
6004 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
6005 if (!prop) {
6006 RNA_warning("layers property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
6007 return;
6008 }
6009
6010 /* the number of layers determines the way we group them
6011 * - we want 2 rows only (for now)
6012 * - The number of columns (cols) is the total number of buttons per row the 'remainder'
6013 * is added to this, as it will be ok to have first row slightly wider if need be.
6014 * - For now, only split into groups if group will have at least 5 items.
6015 */
6016 const int layers = RNA_property_array_length(ptr, prop);
6017 const int cols = (layers / 2) + (layers % 2);
6018 const int groups = ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group);
6019
6020 PropertyRNA *used_prop = nullptr;
6021 if (used_ptr && used_propname) {
6022 used_prop = RNA_struct_find_property(used_ptr, used_propname);
6023 if (!used_prop) {
6024 RNA_warning("used layers property not found: %s.%s",
6026 used_propname);
6027 return;
6028 }
6029
6030 if (RNA_property_array_length(used_ptr, used_prop) < layers) {
6031 used_prop = nullptr;
6032 }
6033 }
6034
6035 /* layers are laid out going across rows, with the columns being divided into groups */
6036
6037 for (int group = 0; group < groups; group++) {
6038 uiLayout *uCol = uiLayoutColumn(layout, true);
6039
6040 for (int row = 0; row < 2; row++) {
6041 uiLayout *uRow = uiLayoutRow(uCol, true);
6042 uiBlock *block = uiLayoutGetBlock(uRow);
6043 int layer = groups * cols_per_group * row + cols_per_group * group;
6044
6045 /* add layers as toggle buts */
6046 for (int col = 0; (col < cols_per_group) && (layer < layers); col++, layer++) {
6047 int icon = 0;
6048 const int butlay = 1 << layer;
6049
6050 if (active_layer & butlay) {
6051 icon = ICON_LAYER_ACTIVE;
6052 }
6053 else if (used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, layer)) {
6054 icon = ICON_LAYER_USED;
6055 }
6056
6057 uiBut *but = uiDefAutoButR(
6058 block, ptr, prop, layer, "", icon, 0, 0, UI_UNIT_X / 2, UI_UNIT_Y / 2);
6060 but->type = UI_BTYPE_TOGGLE;
6061 }
6062 }
6063 }
6064}
6065
6067
6068/* -------------------------------------------------------------------- */
6071
6072#define B_STOPRENDER 1
6073#define B_STOPCAST 2
6074#define B_STOPANIM 3
6075#define B_STOPCOMPO 4
6076#define B_STOPSEQ 5
6077#define B_STOPCLIP 6
6078#define B_STOPFILE 7
6079#define B_STOPOTHER 8
6080
6081static void do_running_jobs(bContext *C, void * /*arg*/, int event)
6082{
6083 switch (event) {
6084 case B_STOPRENDER:
6085 G.is_break = true;
6086 break;
6087 case B_STOPCAST:
6089 break;
6090 case B_STOPANIM:
6091 WM_operator_name_call(C, "SCREEN_OT_animation_play", WM_OP_INVOKE_SCREEN, nullptr, nullptr);
6092 break;
6093 case B_STOPCOMPO:
6095 break;
6096 case B_STOPSEQ:
6098 break;
6099 case B_STOPCLIP:
6101 break;
6102 case B_STOPFILE:
6104 break;
6105 case B_STOPOTHER:
6106 G.is_break = true;
6107 break;
6108 }
6109}
6110
6115
6116static std::string progress_tooltip_func(bContext * /*C*/, void *argN, const char * /*tip*/)
6117{
6118 ProgressTooltip_Store *arg = static_cast<ProgressTooltip_Store *>(argN);
6119 wmWindowManager *wm = arg->wm;
6120 void *owner = arg->owner;
6121
6122 const float progress = WM_jobs_progress(wm, owner);
6123
6124 /* create tooltip text and associate it with the job */
6125 char elapsed_str[32];
6126 char remaining_str[32] = "Unknown";
6127 const double elapsed = BLI_time_now_seconds() - WM_jobs_starttime(wm, owner);
6128 BLI_timecode_string_from_time_simple(elapsed_str, sizeof(elapsed_str), elapsed);
6129
6130 if (progress) {
6131 const double remaining = (elapsed / double(progress)) - elapsed;
6132 BLI_timecode_string_from_time_simple(remaining_str, sizeof(remaining_str), remaining);
6133 }
6134
6135 return fmt::format(
6136 "Time Remaining: {}\n"
6137 "Time Elapsed: {}",
6138 remaining_str,
6139 elapsed_str);
6140}
6141
6143{
6144 Main *bmain = CTX_data_main(C);
6146 ScrArea *area = CTX_wm_area(C);
6147 void *owner = nullptr;
6148 int handle_event, icon = 0;
6149 const char *op_name = nullptr;
6150 const char *op_description = nullptr;
6151
6152 uiBlock *block = uiLayoutGetBlock(layout);
6153 UI_block_layout_set_current(block, layout);
6154
6156
6157 /* another scene can be rendering too, for example via compositor */
6158 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
6159 if (WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY)) {
6160 handle_event = B_STOPOTHER;
6161 icon = ICON_NONE;
6162 owner = scene;
6163 }
6164 else {
6165 continue;
6166 }
6167
6169 handle_event = B_STOPSEQ;
6170 icon = ICON_SEQUENCE;
6171 owner = scene;
6172 break;
6173 }
6175 handle_event = B_STOPSEQ;
6176 icon = ICON_SEQUENCE;
6177 break;
6178 }
6180 handle_event = B_STOPSEQ;
6181 icon = ICON_SEQUENCE;
6182 break;
6183 }
6185 handle_event = B_STOPCLIP;
6186 icon = ICON_TRACKER;
6187 break;
6188 }
6190 handle_event = B_STOPCLIP;
6191 icon = ICON_TRACKER;
6192 break;
6193 }
6195 handle_event = B_STOPCLIP;
6196 icon = ICON_TRACKER;
6197 break;
6198 }
6200 handle_event = B_STOPCLIP;
6201 icon = ICON_TRACKER;
6202 break;
6203 }
6206 {
6207 handle_event = B_STOPFILE;
6208 icon = ICON_FILEBROWSER;
6209 break;
6210 }
6211 if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) {
6212 handle_event = B_STOPRENDER;
6213 icon = ICON_SCENE;
6214 if (U.render_display_type != USER_RENDER_DISPLAY_NONE) {
6215 op_name = "RENDER_OT_view_show";
6216 op_description = "Show the render window";
6217 }
6218 break;
6219 }
6220 if (WM_jobs_test(wm, scene, WM_JOB_TYPE_COMPOSITE)) {
6221 handle_event = B_STOPCOMPO;
6222 icon = ICON_RENDERLAYERS;
6223 break;
6224 }
6227 {
6228 /* Skip bake jobs in compositor to avoid compo header displaying
6229 * progress bar which is not being updated (bake jobs only need
6230 * to update NC_IMAGE context.
6231 */
6232 if (area->spacetype != SPACE_NODE) {
6233 handle_event = B_STOPOTHER;
6234 icon = ICON_IMAGE;
6235 break;
6236 }
6237 continue;
6238 }
6240 handle_event = B_STOPOTHER;
6241 icon = ICON_MOD_DYNAMICPAINT;
6242 break;
6243 }
6244 if (WM_jobs_test(wm, scene, WM_JOB_TYPE_POINTCACHE)) {
6245 handle_event = B_STOPOTHER;
6246 icon = ICON_PHYSICS;
6247 break;
6248 }
6250 handle_event = B_STOPOTHER;
6251 icon = ICON_MOD_FLUIDSIM;
6252 break;
6253 }
6255 handle_event = B_STOPOTHER;
6256 icon = ICON_MOD_OCEAN;
6257 break;
6258 }
6259 }
6260
6261 if (owner) {
6262 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
6263 const bool active = !(G.is_break || WM_jobs_is_stopped(wm, owner));
6264
6265 uiLayout *row = uiLayoutRow(layout, false);
6266 block = uiLayoutGetBlock(row);
6267
6268 /* get percentage done and set it as the UI text */
6269 const float progress = WM_jobs_progress(wm, owner);
6270 char text[8];
6271 SNPRINTF(text, "%d%%", int(progress * 100));
6272
6273 const char *name = active ? WM_jobs_name(wm, owner) : "Canceling...";
6274
6275 /* job icon as a button */
6276 if (op_name) {
6277 uiDefIconButO(block,
6279 op_name,
6281 icon,
6282 0,
6283 0,
6284 UI_UNIT_X,
6285 UI_UNIT_Y,
6286 TIP_(op_description));
6287 }
6288
6289 /* job name and icon if not previously set */
6290 const int textwidth = UI_fontstyle_string_width(fstyle, name);
6291 uiDefIconTextBut(block,
6293 0,
6294 op_name ? 0 : icon,
6295 name,
6296 0,
6297 0,
6298 textwidth + UI_UNIT_X * 1.5f,
6299 UI_UNIT_Y,
6300 nullptr,
6301 0.0f,
6302 0.0f,
6303 "");
6304
6305 /* stick progress bar and cancel button together */
6306 row = uiLayoutRow(layout, true);
6307 uiLayoutSetActive(row, active);
6308 block = uiLayoutGetBlock(row);
6309
6310 {
6311 ProgressTooltip_Store *tip_arg = static_cast<ProgressTooltip_Store *>(
6312 MEM_mallocN(sizeof(*tip_arg), __func__));
6313 tip_arg->wm = wm;
6314 tip_arg->owner = owner;
6315 uiButProgress *but_progress = (uiButProgress *)uiDefIconTextBut(block,
6317 0,
6318 ICON_NONE,
6319 text,
6320 UI_UNIT_X,
6321 0,
6322 UI_UNIT_X * 6.0f,
6323 UI_UNIT_Y,
6324 nullptr,
6325 0.0f,
6326 0.0f,
6327 nullptr);
6328
6329 but_progress->progress_factor = progress;
6331 }
6332
6333 if (!wm->runtime->is_interface_locked) {
6334 uiDefIconTextBut(block,
6336 handle_event,
6337 ICON_PANEL_CLOSE,
6338 "",
6339 0,
6340 0,
6341 UI_UNIT_X,
6342 UI_UNIT_Y,
6343 nullptr,
6344 0.0f,
6345 0.0f,
6346 TIP_("Stop this job"));
6347 }
6348 }
6349
6351 uiDefIconTextBut(block,
6353 B_STOPANIM,
6354 ICON_CANCEL,
6355 IFACE_("Anim Player"),
6356 0,
6357 0,
6358 UI_UNIT_X * 5.0f,
6359 UI_UNIT_Y,
6360 nullptr,
6361 0.0f,
6362 0.0f,
6363 TIP_("Stop animation playback"));
6364 }
6365}
6366
6368
6369/* -------------------------------------------------------------------- */
6372
6374{
6375 ReportList *reports = CTX_wm_reports(C);
6376 Report *report = BKE_reports_last_displayable(reports);
6377 const uiStyle *style = UI_style_get();
6378
6379 uiBut *but;
6380
6381 /* if the report display has timed out, don't show */
6382 if (!reports->reporttimer) {
6383 return;
6384 }
6385
6387
6388 if (!rti || rti->widthfac == 0.0f || !report) {
6389 return;
6390 }
6391
6392 uiLayout *ui_abs = uiLayoutAbsolute(layout, false);
6393 uiBlock *block = uiLayoutGetBlock(ui_abs);
6394 eUIEmbossType previous_emboss = UI_block_emboss_get(block);
6395
6396 uchar report_icon_color[4];
6397 uchar report_text_color[4];
6398
6400 UI_icon_colorid_from_report_type(report->type), SPACE_INFO, report_icon_color);
6402 UI_text_colorid_from_report_type(report->type), SPACE_INFO, report_text_color);
6403 report_text_color[3] = 255; /* This theme color is RGB only, so have to set alpha here. */
6404
6405 if (rti->flash_progress <= 1.0) {
6406 /* Flash report briefly according to progress through fade-out duration. */
6407 const int brighten_amount = int(32 * (1.0f - rti->flash_progress));
6408 add_v3_uchar_clamped(report_icon_color, brighten_amount);
6409 }
6410
6411 UI_fontstyle_set(&style->widget);
6412 int width = BLF_width(style->widget.uifont_id, report->message, report->len);
6413 width = min_ii(int(rti->widthfac * width), width);
6414 width = max_ii(width, 10 * UI_SCALE_FAC);
6415
6416 UI_block_align_begin(block);
6417
6418 /* Background for icon. */
6419 but = uiDefBut(block,
6421 0,
6422 "",
6423 0,
6424 0,
6425 UI_UNIT_X + (6 * UI_SCALE_FAC),
6426 UI_UNIT_Y,
6427 nullptr,
6428 0.0f,
6429 0.0f,
6430 "");
6431 /* UI_BTYPE_ROUNDBOX's bg color is set in but->col. */
6432 copy_v4_v4_uchar(but->col, report_icon_color);
6433
6434 /* Background for the rest of the message. */
6435 but = uiDefBut(block,
6437 0,
6438 "",
6439 UI_UNIT_X + (6 * UI_SCALE_FAC),
6440 0,
6441 UI_UNIT_X + width,
6442 UI_UNIT_Y,
6443 nullptr,
6444 0.0f,
6445 0.0f,
6446 "");
6447 /* Use icon background at low opacity to highlight, but still contrasting with area TH_TEXT. */
6448 copy_v3_v3_uchar(but->col, report_icon_color);
6449 but->col[3] = 64;
6450
6451 UI_block_align_end(block);
6453
6454 /* The report icon itself. */
6455 but = uiDefIconButO(block,
6457 "SCREEN_OT_info_log_show",
6460 (3 * UI_SCALE_FAC),
6461 0,
6462 UI_UNIT_X,
6463 UI_UNIT_Y,
6464 TIP_("Click to open the info editor"));
6465 copy_v4_v4_uchar(but->col, report_text_color);
6466
6467 /* The report message. */
6468 but = uiDefButO(block,
6470 "SCREEN_OT_info_log_show",
6472 report->message,
6473 UI_UNIT_X,
6474 0,
6475 width + UI_UNIT_X,
6476 UI_UNIT_Y,
6477 TIP_("Show in Info Log"));
6478
6479 UI_block_emboss_set(block, previous_emboss);
6480}
6481
6482static bool uiTemplateInputStatusAzone(uiLayout *layout, const AZone *az, const ARegion *region)
6483{
6484 if (az->type == AZONE_AREA) {
6485 uiItemL(layout, nullptr, ICON_MOUSE_LMB_DRAG);
6486 uiItemL(layout, IFACE_("Split/Dock"), ICON_NONE);
6487 uiItemS_ex(layout, 0.7f);
6488 uiItemL(layout, "", ICON_EVENT_SHIFT);
6489 uiItemL(layout, nullptr, ICON_MOUSE_LMB_DRAG);
6490 uiItemL(layout, IFACE_("Duplicate into Window"), ICON_NONE);
6491 uiItemS_ex(layout, 0.7f);
6492 uiItemL(layout, "", ICON_EVENT_CTRL);
6493 uiItemS_ex(layout, 1.5f);
6494 uiItemL(layout, nullptr, ICON_MOUSE_LMB_DRAG);
6495 uiItemL(layout, IFACE_("Swap Areas"), ICON_NONE);
6496 return true;
6497 }
6498
6499 if (az->type == AZONE_REGION) {
6500 uiItemL(layout, nullptr, ICON_MOUSE_LMB_DRAG);
6501 uiItemL(layout,
6502 (region->visible) ? IFACE_("Resize Region") : IFACE_("Show Hidden Region"),
6503 ICON_NONE);
6504 return true;
6505 }
6506
6507 return false;
6508}
6509
6511{
6512 wmWindow *win = CTX_wm_window(C);
6513 WorkSpace *workspace = CTX_wm_workspace(C);
6514
6515 /* Workspace status text has priority. */
6516 if (!workspace->runtime->status.is_empty()) {
6517 uiLayout *row = uiLayoutRow(layout, true);
6518 for (const blender::bke::WorkSpaceStatusItem &item : workspace->runtime->status) {
6519 if (item.space_factor != 0.0f) {
6520 uiItemS_ex(row, item.space_factor);
6521 }
6522 else {
6523 uiBut *but = uiItemL_ex(row, item.text.c_str(), item.icon, false, false);
6524 if (item.inverted) {
6526 }
6527 const float offset = ui_event_icon_offset(item.icon);
6528 if (offset != 0.0f) {
6529 uiItemS_ex(row, offset);
6530 }
6531 }
6532 }
6533 return;
6534 }
6535
6536 if (WM_window_modal_keymap_status_draw(C, win, layout)) {
6537 return;
6538 }
6539
6540 bScreen *screen = CTX_wm_screen(C);
6541 ARegion *region = screen->active_region;
6542 uiLayout *row = uiLayoutRow(layout, true);
6543
6544 if (region == nullptr) {
6545 /* Check if over an action zone. */
6546 LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
6547 LISTBASE_FOREACH (AZone *, az, &area_iter->actionzones) {
6548 if (BLI_rcti_isect_pt_v(&az->rect, win->eventstate->xy)) {
6549 region = az->region;
6550 if (uiTemplateInputStatusAzone(row, az, region)) {
6551 return;
6552 }
6553 break;
6554 }
6555 }
6556 }
6557 }
6558
6559 if (!region) {
6560 /* On a gap between editors. */
6561 uiItemL(row, nullptr, ICON_MOUSE_LMB_DRAG);
6562 uiItemL(row, IFACE_("Resize"), ICON_NONE);
6563 uiItemS_ex(row, 0.7f);
6564 uiItemL(row, nullptr, ICON_MOUSE_RMB);
6565 uiItemS_ex(row, -0.5f);
6566 uiItemL(row, IFACE_("Options"), ICON_NONE);
6567 return;
6568 }
6569
6570 /* Otherwise should cursor keymap status. */
6571 for (int i = 0; i < 3; i++) {
6573
6576 const char *msg_drag = CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT,
6578
6579 if (msg) {
6580 uiItemL(row, "", (ICON_MOUSE_LMB + i));
6581 uiItemS_ex(row, -0.5f);
6582 uiItemL(row, msg, ICON_NONE);
6583 uiItemS_ex(row, 0.7f);
6584 }
6585
6586 if (msg_drag) {
6587 uiItemL(row, "", (ICON_MOUSE_LMB_DRAG + i));
6588 uiItemL(row, msg_drag, ICON_NONE);
6589 uiItemS_ex(row, 0.7f);
6590 }
6591 }
6592}
6593
6594static std::string ui_template_status_tooltip(bContext *C, void * /*argN*/, const char * /*tip*/)
6595{
6596 Main *bmain = CTX_data_main(C);
6597 std::string tooltip_message = "";
6598
6600 char writer_ver_str[12];
6602 writer_ver_str, sizeof(writer_ver_str), bmain->versionfile, -1);
6603 tooltip_message += fmt::format(RPT_("File saved by newer Blender\n({}), expect loss of data"),
6604 writer_ver_str);
6605 }
6606 if (bmain->is_asset_edit_file) {
6607 if (!tooltip_message.empty()) {
6608 tooltip_message += "\n\n";
6609 }
6610 tooltip_message += RPT_(
6611 "This file is managed by the Blender asset system and cannot be overridden");
6612 }
6613
6614 return tooltip_message;
6615}
6616
6618{
6619 Main *bmain = CTX_data_main(C);
6620 Scene *scene = CTX_data_scene(C);
6621 ViewLayer *view_layer = CTX_data_view_layer(C);
6622 uiLayout *row = uiLayoutRow(layout, true);
6623
6624 const char *status_info_txt = ED_info_statusbar_string_ex(
6625 bmain, scene, view_layer, (U.statusbar_flag & ~STATUSBAR_SHOW_VERSION));
6626 /* True when the status is populated (delimiters required for following items). */
6627 bool has_status_info = false;
6628
6629 if (status_info_txt[0]) {
6630 uiItemL(row, status_info_txt, ICON_NONE);
6631 has_status_info = true;
6632 }
6633
6634 if (U.statusbar_flag & STATUSBAR_SHOW_EXTENSIONS_UPDATES) {
6636
6637 /* Special case, always show an alert for any blocked extensions. */
6638 if (wm->extensions_blocked > 0) {
6639 if (has_status_info) {
6640 uiItemS_ex(row, -0.5f);
6641 uiItemL(row, "|", ICON_NONE);
6642 uiItemS_ex(row, -0.5f);
6643 }
6645 /* This operator also works fine for blocked extensions. */
6646 uiItemO(row, "", ICON_ERROR, "EXTENSIONS_OT_userpref_show_for_update");
6647 uiBut *but = static_cast<uiBut *>(uiLayoutGetBlock(layout)->buttons.last);
6648 uchar color[4];
6650 copy_v4_v4_uchar(but->col, color);
6651
6652 BLI_str_format_integer_unit(but->icon_overlay_text.text, wm->extensions_blocked);
6654
6655 uiItemS_ex(row, 1.0f);
6656 has_status_info = true;
6657 }
6658
6659 if ((G.f & G_FLAG_INTERNET_ALLOW) == 0) {
6660 if (has_status_info) {
6661 uiItemS_ex(row, -0.5f);
6662 uiItemL(row, "|", ICON_NONE);
6663 uiItemS_ex(row, -0.5f);
6664 }
6665
6667 uiItemL(row, "", ICON_INTERNET_OFFLINE);
6668 }
6669 else {
6671 uiItemO(row, "", ICON_INTERNET_OFFLINE, "EXTENSIONS_OT_userpref_show_online");
6672 uiBut *but = static_cast<uiBut *>(uiLayoutGetBlock(layout)->buttons.last);
6673 uchar color[4];
6675 copy_v4_v4_uchar(but->col, color);
6676 }
6677
6678 uiItemS_ex(row, 1.0f);
6679 has_status_info = true;
6680 }
6681 else if ((wm->extensions_updates > 0) ||
6682 (wm->extensions_updates == WM_EXTENSIONS_UPDATE_CHECKING))
6683 {
6684 int icon = ICON_INTERNET;
6685 if (wm->extensions_updates == WM_EXTENSIONS_UPDATE_CHECKING) {
6686 icon = ICON_UV_SYNC_SELECT;
6687 }
6688
6689 if (has_status_info) {
6690 uiItemS_ex(row, -0.5f);
6691 uiItemL(row, "|", ICON_NONE);
6692 uiItemS_ex(row, -0.5f);
6693 }
6695 uiItemO(row, "", icon, "EXTENSIONS_OT_userpref_show_for_update");
6696 uiBut *but = static_cast<uiBut *>(uiLayoutGetBlock(layout)->buttons.last);
6697 uchar color[4];
6699 copy_v4_v4_uchar(but->col, color);
6700
6701 if (wm->extensions_updates > 0) {
6702 BLI_str_format_integer_unit(but->icon_overlay_text.text, wm->extensions_updates);
6704 }
6705
6706 uiItemS_ex(row, 1.0f);
6707 has_status_info = true;
6708 }
6709 }
6710
6711 if (!BKE_main_has_issues(bmain)) {
6712 if (U.statusbar_flag & STATUSBAR_SHOW_VERSION) {
6713 if (has_status_info) {
6714 uiItemS_ex(row, -0.5f);
6715 uiItemL(row, "|", ICON_NONE);
6716 uiItemS_ex(row, -0.5f);
6717 }
6718 const char *status_info_d_txt = ED_info_statusbar_string_ex(
6719 bmain, scene, view_layer, STATUSBAR_SHOW_VERSION);
6720 uiItemL(row, status_info_d_txt, ICON_NONE);
6721 }
6722 return;
6723 }
6724
6726 bmain, scene, view_layer, STATUSBAR_SHOW_VERSION);
6727 blender::StringRefNull warning_message;
6728
6729 /* Blender version part is shown as warning area when there are forward compatibility issues with
6730 * currently loaded .blend file. */
6732 warning_message = version_string;
6733 }
6734 else {
6735 /* For other issues, still show the version if enabled. */
6736 if (U.statusbar_flag & STATUSBAR_SHOW_VERSION) {
6737 uiItemL(layout, version_string.c_str(), ICON_NONE);
6738 }
6739 }
6740
6741 const uiStyle *style = UI_style_get();
6742 uiLayout *ui_abs = uiLayoutAbsolute(layout, false);
6743 uiBlock *block = uiLayoutGetBlock(ui_abs);
6744 eUIEmbossType previous_emboss = UI_block_emboss_get(block);
6745
6746 UI_fontstyle_set(&style->widget);
6747 const int width = max_ii(
6748 int(BLF_width(style->widget.uifont_id, warning_message.c_str(), warning_message.size())),
6749 int(10 * UI_SCALE_FAC));
6750
6751 UI_block_align_begin(block);
6752
6753 /* Background for icon. */
6754 uiBut *but = uiDefBut(block,
6756 0,
6757 "",
6758 0,
6759 0,
6760 UI_UNIT_X + (6 * UI_SCALE_FAC),
6761 UI_UNIT_Y,
6762 nullptr,
6763 0.0f,
6764 0.0f,
6765 "");
6766 /* UI_BTYPE_ROUNDBOX's bg color is set in but->col. */
6768
6769 if (!warning_message.is_empty()) {
6770 /* Background for the rest of the message. */
6771 but = uiDefBut(block,
6773 0,
6774 "",
6775 UI_UNIT_X + (6 * UI_SCALE_FAC),
6776 0,
6777 UI_UNIT_X + width,
6778 UI_UNIT_Y,
6779 nullptr,
6780 0.0f,
6781 0.0f,
6782 "");
6783
6784 /* Use icon background at low opacity to highlight, but still contrasting with area TH_TEXT. */
6786 but->col[3] = 64;
6787 }
6788
6789 UI_block_align_end(block);
6791
6792 /* The warning icon itself. */
6793 but = uiDefIconBut(block,
6795 0,
6796 ICON_ERROR,
6797 int(3 * UI_SCALE_FAC),
6798 0,
6799 UI_UNIT_X,
6800 UI_UNIT_Y,
6801 nullptr,
6802 0.0f,
6803 0.0f,
6804 nullptr);
6807 but->col[3] = 255; /* This theme color is RBG only, so have to set alpha here. */
6808
6809 /* The warning message, if any. */
6810 if (!warning_message.is_empty()) {
6811 but = uiDefBut(block,
6813 0,
6814 warning_message.c_str(),
6815 UI_UNIT_X,
6816 0,
6817 short(width + UI_UNIT_X),
6818 UI_UNIT_Y,
6819 nullptr,
6820 0.0f,
6821 0.0f,
6822 nullptr);
6824 }
6825
6826 UI_block_emboss_set(block, previous_emboss);
6827}
6828
6830
6831/* -------------------------------------------------------------------- */
6834
6835static void keymap_item_modified(bContext * /*C*/, void *kmi_p, void * /*unused*/)
6836{
6837 wmKeyMapItem *kmi = (wmKeyMapItem *)kmi_p;
6838 WM_keyconfig_update_tag(nullptr, kmi);
6839 U.runtime.is_dirty = true;
6840}
6841
6842static void template_keymap_item_properties(uiLayout *layout, const char *title, PointerRNA *ptr)
6843{
6844 uiItemS(layout);
6845
6846 if (title) {
6847 uiItemL(layout, title, ICON_NONE);
6848 }
6849
6850 uiLayout *flow = uiLayoutColumnFlow(layout, 2, false);
6851
6853 const bool is_set = RNA_property_is_set(ptr, prop);
6854 uiBut *but;
6855
6856 /* recurse for nested properties */
6857 if (RNA_property_type(prop) == PROP_POINTER) {
6858 PointerRNA propptr = RNA_property_pointer_get(ptr, prop);
6859
6860 if (propptr.data && RNA_struct_is_a(propptr.type, &RNA_OperatorProperties)) {
6861 const char *name = RNA_property_ui_name(prop);
6862 template_keymap_item_properties(layout, name, &propptr);
6863 continue;
6864 }
6865 }
6866
6867 uiLayout *box = uiLayoutBox(flow);
6868 uiLayoutSetActive(box, is_set);
6869 uiLayout *row = uiLayoutRow(box, false);
6870
6871 /* property value */
6872 uiItemFullR(row, ptr, prop, -1, 0, UI_ITEM_NONE, nullptr, ICON_NONE);
6873
6874 if (is_set) {
6875 /* unset operator */
6876 uiBlock *block = uiLayoutGetBlock(row);
6878 but = uiDefIconButO(block,
6880 "UI_OT_unset_property_button",
6882 ICON_X,
6883 0,
6884 0,
6885 UI_UNIT_X,
6886 UI_UNIT_Y,
6887 nullptr);
6888 but->rnapoin = *ptr;
6889 but->rnaprop = prop;
6891 }
6892 }
6894}
6895
6897{
6898 PointerRNA propptr = RNA_pointer_get(ptr, "properties");
6899
6900 if (propptr.data) {
6901 uiBut *but = static_cast<uiBut *>(uiLayoutGetBlock(layout)->buttons.last);
6902
6903 WM_operator_properties_sanitize(&propptr, false);
6904 template_keymap_item_properties(layout, nullptr, &propptr);
6905
6906 /* attach callbacks to compensate for missing properties update,
6907 * we don't know which keymap (item) is being modified there */
6908 for (; but; but = but->next) {
6909 /* operator buttons may store props for use (file selector, #36492) */
6910 if (but->rnaprop) {
6911 UI_but_func_set(but, keymap_item_modified, ptr->data, nullptr);
6912
6913 /* Otherwise the keymap will be re-generated which we're trying to edit,
6914 * see: #47685 */
6916 }
6917 }
6918 }
6919}
6920
6922
6923/* -------------------------------------------------------------------- */
6926
6928 const EnumPropertyItem *item)
6929{
6930 if (item == nullptr) {
6931 return nullptr;
6932 }
6933
6934 for (wmKeyMapItem *kmi = static_cast<wmKeyMapItem *>(keymap->items.first); kmi; kmi = kmi->next)
6935 {
6936 if (kmi->propvalue == item->value) {
6937 return kmi;
6938 }
6939 }
6940
6941 return nullptr;
6942}
6943
6944static bool keymap_item_can_collapse(const wmKeyMapItem *kmi_a, const wmKeyMapItem *kmi_b)
6945{
6946 return (kmi_a->shift == kmi_b->shift && kmi_a->ctrl == kmi_b->ctrl && kmi_a->alt == kmi_b->alt &&
6947 kmi_a->oskey == kmi_b->oskey);
6948}
6949
6951 const wmKeyMap *keymap,
6952 const EnumPropertyItem *item)
6953{
6954 const wmKeyMapItem *kmi = keymap_item_from_enum_item(keymap, item);
6955 if (kmi == nullptr) {
6956 return 0;
6957 }
6958
6959 if (kmi->val == KM_RELEASE) {
6960 /* Assume release events just disable something which was toggled on. */
6961 return 1;
6962 }
6963
6964 /* Try to merge some known XYZ items to save horizontal space. */
6965 const EnumPropertyItem *item_y = (item[1].identifier) ? item + 1 : nullptr;
6966 const EnumPropertyItem *item_z = (item_y && item[2].identifier) ? item + 2 : nullptr;
6967 const wmKeyMapItem *kmi_y = keymap_item_from_enum_item(keymap, item_y);
6968 const wmKeyMapItem *kmi_z = keymap_item_from_enum_item(keymap, item_z);
6969
6970 if (kmi_y && kmi_z && keymap_item_can_collapse(kmi, kmi_y) &&
6971 keymap_item_can_collapse(kmi_y, kmi_z))
6972 {
6973 const char *xyz_label = nullptr;
6974
6975 if (STREQ(item->identifier, "AXIS_X") && STREQ(item_y->identifier, "AXIS_Y") &&
6976 STREQ(item_z->identifier, "AXIS_Z"))
6977 {
6978 xyz_label = IFACE_("Axis");
6979 }
6980 else if (STREQ(item->identifier, "PLANE_X") && STREQ(item_y->identifier, "PLANE_Y") &&
6981 STREQ(item_z->identifier, "PLANE_Z"))
6982 {
6983 xyz_label = IFACE_("Plane");
6984 }
6985
6986 if (xyz_label) {
6987 int icon_mod[4] = {0};
6988#ifdef WITH_HEADLESS
6989 int icon = 0;
6990#else
6991 int icon = UI_icon_from_keymap_item(kmi, icon_mod);
6992#endif
6993 for (int j = 0; j < ARRAY_SIZE(icon_mod) && icon_mod[j]; j++) {
6994 uiItemL(layout, "", icon_mod[j]);
6995 }
6996 uiItemL(layout, "", icon);
6997
6998#ifndef WITH_HEADLESS
6999 icon = UI_icon_from_keymap_item(kmi_y, icon_mod);
7000#endif
7001 uiItemL(layout, "", icon);
7002
7003#ifndef WITH_HEADLESS
7004 icon = UI_icon_from_keymap_item(kmi_z, icon_mod);
7005#endif
7006 uiItemL(layout, "", icon);
7007 uiItemL(layout, xyz_label, ICON_NONE);
7008 uiItemS_ex(layout, 0.7f);
7009 return 3;
7010 }
7011 }
7012
7013 /* Single item without merging. */
7014 return uiTemplateEventFromKeymapItem(layout, item->name, kmi, false) ? 1 : 0;
7015}
7016
7018 const char *text,
7019 const wmKeyMapItem *kmi,
7020 bool text_fallback)
7021{
7022 bool ok = false;
7023
7024 int icon_mod[4];
7025#ifdef WITH_HEADLESS
7026 int icon = 0;
7027#else
7028 const int icon = UI_icon_from_keymap_item(kmi, icon_mod);
7029#endif
7030 if (icon != 0) {
7031 for (int j = 0; j < ARRAY_SIZE(icon_mod) && icon_mod[j]; j++) {
7032 uiItemL(layout, "", icon_mod[j]);
7033 }
7034
7035 /* Icon and text separately is closer together with aligned layout. */
7036
7037 uiItemL(layout, "", icon);
7038 if (icon >= ICON_MOUSE_LMB && icon <= ICON_MOUSE_MMB_SCROLL) {
7039 /* Negative space after narrow mice icons. */
7040 uiItemS_ex(layout, -0.5f);
7041 }
7042
7043 const float offset = ui_event_icon_offset(icon);
7044 if (offset != 0.0f) {
7045 uiItemS_ex(layout, offset);
7046 }
7047
7048 uiItemL(layout, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, text), ICON_NONE);
7049 uiItemS_ex(layout, 0.7f);
7050 ok = true;
7051 }
7052 else if (text_fallback) {
7053 const char *event_text = WM_key_event_string(kmi->type, true);
7054 uiItemL(layout, event_text, ICON_NONE);
7055 uiItemL(layout, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, text), ICON_NONE);
7056 uiItemS_ex(layout, 0.5f);
7057 ok = true;
7058 }
7059 return ok;
7060}
7061
7063
7064/* -------------------------------------------------------------------- */
7067
7068void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char *propname)
7069{
7070 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
7071
7072 if (!prop) {
7073 printf(
7074 "%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname);
7075 return;
7076 }
7077
7078 PointerRNA colorspace_settings_ptr = RNA_property_pointer_get(ptr, prop);
7079
7080 uiItemR(
7081 layout, &colorspace_settings_ptr, "name", UI_ITEM_NONE, IFACE_("Color Space"), ICON_NONE);
7082}
7083
7085 bContext * /*C*/,
7086 PointerRNA *ptr,
7087 const char *propname)
7088{
7089 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
7090
7091 if (!prop) {
7092 printf(
7093 "%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname);
7094 return;
7095 }
7096
7097 PointerRNA view_transform_ptr = RNA_property_pointer_get(ptr, prop);
7098 ColorManagedViewSettings *view_settings = static_cast<ColorManagedViewSettings *>(
7099 view_transform_ptr.data);
7100
7101 uiLayout *col = uiLayoutColumn(layout, false);
7102 uiItemR(col, &view_transform_ptr, "view_transform", UI_ITEM_NONE, IFACE_("View"), ICON_NONE);
7103 uiItemR(col, &view_transform_ptr, "look", UI_ITEM_NONE, IFACE_("Look"), ICON_NONE);
7104
7105 col = uiLayoutColumn(layout, false);
7106 uiItemR(col, &view_transform_ptr, "exposure", UI_ITEM_NONE, nullptr, ICON_NONE);
7107 uiItemR(col, &view_transform_ptr, "gamma", UI_ITEM_NONE, nullptr, ICON_NONE);
7108
7109 col = uiLayoutColumn(layout, false);
7110 uiItemR(col, &view_transform_ptr, "use_curve_mapping", UI_ITEM_NONE, nullptr, ICON_NONE);
7111 if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) {
7113 col, &view_transform_ptr, "curve_mapping", 'c', true, false, false, false);
7114 }
7115
7116 col = uiLayoutColumn(layout, false);
7117 uiItemR(col, &view_transform_ptr, "use_white_balance", UI_ITEM_NONE, nullptr, ICON_NONE);
7118 if (view_settings->flag & COLORMANAGE_VIEW_USE_WHITE_BALANCE) {
7119 uiItemR(
7120 col, &view_transform_ptr, "white_balance_temperature", UI_ITEM_NONE, nullptr, ICON_NONE);
7121 uiItemR(col, &view_transform_ptr, "white_balance_tint", UI_ITEM_NONE, nullptr, ICON_NONE);
7122 }
7123}
7124
7126
7127/* -------------------------------------------------------------------- */
7130
7133 char propname[64]; /* XXX arbitrary */
7134};
7135/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
7136static uiBlock *component_menu(bContext *C, ARegion *region, void *args_v)
7137{
7138 ComponentMenuArgs *args = (ComponentMenuArgs *)args_v;
7139
7140 uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
7142
7143 uiLayout *layout = uiLayoutColumn(UI_block_layout(block,
7146 0,
7147 0,
7148 UI_UNIT_X * 6,
7149 UI_UNIT_Y,
7150 0,
7151 UI_style_get()),
7152 false);
7153
7154 uiItemR(layout, &args->ptr, args->propname, UI_ITEM_R_EXPAND, "", ICON_NONE);
7155
7156 UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
7158
7159 return block;
7160}
7162 PointerRNA *ptr,
7163 const char *propname,
7164 const char *name)
7165{
7166 ComponentMenuArgs *args = MEM_new<ComponentMenuArgs>(__func__);
7167
7168 args->ptr = *ptr;
7169 STRNCPY(args->propname, propname);
7170
7171 uiBlock *block = uiLayoutGetBlock(layout);
7172 UI_block_align_begin(block);
7173
7174 uiBut *but = uiDefBlockButN(block,
7176 args,
7177 name,
7178 0,
7179 0,
7180 UI_UNIT_X * 6,
7181 UI_UNIT_Y,
7182 "",
7185 /* set rna directly, uiDefBlockButN doesn't do this */
7186 but->rnapoin = *ptr;
7187 but->rnaprop = RNA_struct_find_property(ptr, propname);
7188 but->rnaindex = 0;
7189
7190 UI_block_align_end(block);
7191}
7192
7194
7195/* -------------------------------------------------------------------- */
7198
7199void uiTemplateNodeSocket(uiLayout *layout, bContext * /*C*/, const float color[4])
7200{
7201 uiBlock *block = uiLayoutGetBlock(layout);
7202 UI_block_align_begin(block);
7203
7204 /* XXX using explicit socket colors is not quite ideal.
7205 * Eventually it should be possible to use theme colors for this purpose,
7206 * but this requires a better design for extendable color palettes in user preferences. */
7207 uiBut *but = uiDefBut(
7208 block, UI_BTYPE_NODE_SOCKET, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, nullptr, 0, 0, "");
7210
7211 UI_block_align_end(block);
7212}
7213
7215
7216/* -------------------------------------------------------------------- */
7219
7221{
7222 if (RNA_pointer_is_null(fileptr)) {
7223 return;
7224 }
7225
7226 /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
7227 uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
7228
7229 uiItemR(layout, fileptr, "velocity_name", UI_ITEM_NONE, nullptr, ICON_NONE);
7230 uiItemR(layout, fileptr, "velocity_unit", UI_ITEM_NONE, nullptr, ICON_NONE);
7231}
7232
7234{
7235 if (RNA_pointer_is_null(fileptr)) {
7236 return;
7237 }
7238
7239 /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
7240 uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
7241
7242 uiLayout *row, *sub;
7243
7244 /* Only enable render procedural option if the active engine supports it. */
7245 const RenderEngineType *engine_type = CTX_data_engine_type(C);
7246
7247 Scene *scene = CTX_data_scene(C);
7248 const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type,
7249 scene);
7250 CacheFile *cache_file = static_cast<CacheFile *>(fileptr->data);
7251 CacheFile *cache_file_eval = reinterpret_cast<CacheFile *>(
7253 bool is_alembic = cache_file_eval->type == CACHEFILE_TYPE_ALEMBIC;
7254
7255 if (!is_alembic) {
7256 row = uiLayoutRow(layout, false);
7257 uiItemL(row, RPT_("Only Alembic Procedurals supported"), ICON_INFO);
7258 }
7259 else if (!engine_supports_procedural) {
7260 row = uiLayoutRow(layout, false);
7261 /* For Cycles, verify that experimental features are enabled. */
7263 uiItemL(
7264 row,
7265 RPT_(
7266 "The Cycles Alembic Procedural is only available with the experimental feature set"),
7267 ICON_INFO);
7268 }
7269 else {
7270 uiItemL(
7271 row, RPT_("The active render engine does not have an Alembic Procedural"), ICON_INFO);
7272 }
7273 }
7274
7275 row = uiLayoutRow(layout, false);
7276 uiLayoutSetActive(row, is_alembic && engine_supports_procedural);
7277 uiItemR(row, fileptr, "use_render_procedural", UI_ITEM_NONE, nullptr, ICON_NONE);
7278
7279 const bool use_render_procedural = RNA_boolean_get(fileptr, "use_render_procedural");
7280 const bool use_prefetch = RNA_boolean_get(fileptr, "use_prefetch");
7281
7282 row = uiLayoutRow(layout, false);
7283 uiLayoutSetEnabled(row, use_render_procedural);
7284 uiItemR(row, fileptr, "use_prefetch", UI_ITEM_NONE, nullptr, ICON_NONE);
7285
7286 sub = uiLayoutRow(layout, false);
7287 uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural);
7288 uiItemR(sub, fileptr, "prefetch_cache_size", UI_ITEM_NONE, nullptr, ICON_NONE);
7289}
7290
7292{
7293 if (RNA_pointer_is_null(fileptr)) {
7294 return;
7295 }
7296
7297 /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
7298 uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
7299
7300 uiLayout *row, *sub, *subsub;
7301
7302 row = uiLayoutRow(layout, false);
7303 uiItemR(row, fileptr, "is_sequence", UI_ITEM_NONE, nullptr, ICON_NONE);
7304
7305 row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame"));
7306 sub = uiLayoutRow(row, true);
7307 uiLayoutSetPropDecorate(sub, false);
7308 uiItemR(sub, fileptr, "override_frame", UI_ITEM_NONE, "", ICON_NONE);
7309 subsub = uiLayoutRow(sub, true);
7310 uiLayoutSetActive(subsub, RNA_boolean_get(fileptr, "override_frame"));
7311 uiItemR(subsub, fileptr, "frame", UI_ITEM_NONE, "", ICON_NONE);
7312 uiItemDecoratorR(row, fileptr, "frame", 0);
7313
7314 row = uiLayoutRow(layout, false);
7315 uiItemR(row, fileptr, "frame_offset", UI_ITEM_NONE, nullptr, ICON_NONE);
7316 uiLayoutSetActive(row, !RNA_boolean_get(fileptr, "is_sequence"));
7317}
7318
7319static void cache_file_layer_item(uiList * /*ui_list*/,
7320 const bContext * /*C*/,
7321 uiLayout *layout,
7322 PointerRNA * /*dataptr*/,
7323 PointerRNA *itemptr,
7324 int /*icon*/,
7325 PointerRNA * /*active_dataptr*/,
7326 const char * /*active_propname*/,
7327 int /*index*/,
7328 int /*flt_flag*/)
7329{
7330 uiLayout *row = uiLayoutRow(layout, true);
7331 uiItemR(row, itemptr, "hide_layer", UI_ITEM_R_NO_BG, "", ICON_NONE);
7332 uiItemR(row, itemptr, "filepath", UI_ITEM_R_NO_BG, "", ICON_NONE);
7333}
7334
7336{
7337 uiListType *list_type = (uiListType *)MEM_callocN(sizeof(*list_type), __func__);
7338
7339 STRNCPY(list_type->idname, "UI_UL_cache_file_layers");
7340 list_type->draw_item = cache_file_layer_item;
7341
7342 return list_type;
7343}
7344
7346{
7347 if (RNA_pointer_is_null(fileptr)) {
7348 return;
7349 }
7350
7351 /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
7352 uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
7353
7354 uiLayout *row = uiLayoutRow(layout, false);
7355 uiLayout *col = uiLayoutColumn(row, true);
7356
7358 (bContext *)C,
7359 "UI_UL_cache_file_layers",
7360 "cache_file_layers",
7361 fileptr,
7362 "layers",
7363 fileptr,
7364 "active_index",
7365 "",
7366 1,
7367 5,
7369 1,
7371
7372 col = uiLayoutColumn(row, true);
7373 uiItemO(col, "", ICON_ADD, "cachefile.layer_add");
7374 uiItemO(col, "", ICON_REMOVE, "cachefile.layer_remove");
7375
7376 CacheFile *file = static_cast<CacheFile *>(fileptr->data);
7377 if (BLI_listbase_count(&file->layers) > 1) {
7378 uiItemS_ex(col, 1.0f);
7379 uiItemO(col, "", ICON_TRIA_UP, "cachefile.layer_move");
7380 uiItemO(col, "", ICON_TRIA_DOWN, "cachefile.layer_move");
7381 }
7382}
7383
7384bool uiTemplateCacheFilePointer(PointerRNA *ptr, const char *propname, PointerRNA *r_file_ptr)
7385{
7386 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
7387
7388 if (!prop) {
7389 printf(
7390 "%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname);
7391 return false;
7392 }
7393
7394 if (RNA_property_type(prop) != PROP_POINTER) {
7395 printf("%s: expected pointer property for %s.%s\n",
7396 __func__,
7398 propname);
7399 return false;
7400 }
7401
7402 *r_file_ptr = RNA_property_pointer_get(ptr, prop);
7403 return true;
7404}
7405
7407 const bContext *C,
7408 PointerRNA *ptr,
7409 const char *propname)
7410{
7411 if (!ptr->data) {
7412 return;
7413 }
7414
7415 PointerRNA fileptr;
7416 if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
7417 return;
7418 }
7419
7420 CacheFile *file = static_cast<CacheFile *>(fileptr.data);
7421
7422 uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr);
7423
7424 uiTemplateID(layout, C, ptr, propname, nullptr, "CACHEFILE_OT_open", nullptr);
7425
7426 if (!file) {
7427 return;
7428 }
7429
7431
7432 uiLayout *row, *sub;
7433
7434 uiLayoutSetPropSep(layout, true);
7435
7436 row = uiLayoutRow(layout, true);
7437 uiItemR(row, &fileptr, "filepath", UI_ITEM_NONE, nullptr, ICON_NONE);
7438 sub = uiLayoutRow(row, true);
7439 uiItemO(sub, "", ICON_FILE_REFRESH, "cachefile.reload");
7440
7441 if (sbuts->mainb == BCONTEXT_CONSTRAINT) {
7442 row = uiLayoutRow(layout, false);
7443 uiItemR(row, &fileptr, "scale", UI_ITEM_NONE, IFACE_("Manual Scale"), ICON_NONE);
7444 }
7445
7446 /* TODO: unused for now, so no need to expose. */
7447#if 0
7448 row = uiLayoutRow(layout, false);
7449 uiItemR(row, &fileptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE);
7450
7451 row = uiLayoutRow(layout, false);
7452 uiItemR(row, &fileptr, "up_axis", UI_ITEM_NONE, IFACE_("Up Axis"), ICON_NONE);
7453#endif
7454}
7455
7457
7458/* -------------------------------------------------------------------- */
7461static void uiTemplateRecentFiles_tooltip_func(bContext & /*C*/, uiTooltipData &tip, void *argN)
7462{
7463 char *path = (char *)argN;
7464
7465 /* File name and path. */
7466 char dirname[FILE_MAX];
7467 char filename[FILE_MAX];
7468 BLI_path_split_dir_file(path, dirname, sizeof(dirname), filename, sizeof(filename));
7471
7473
7474 if (!BLI_exists(path)) {
7476 return;
7477 }
7478
7479 /* Blender version. */
7480 char version_str[128] = {0};
7481 /* Load the thumbnail from cache if existing, but don't create if not. */
7482 ImBuf *thumb = IMB_thumb_read(path, THB_LARGE);
7483 if (thumb) {
7484 /* Look for version in existing thumbnail if available. */
7486 thumb->metadata, "Thumb::Blender::Version", version_str, sizeof(version_str));
7487 }
7488
7489 eFileAttributes attributes = BLI_file_attributes(path);
7490 if (!version_str[0] && !(attributes & FILE_ATTR_OFFLINE)) {
7491 /* Load Blender version directly from the file. */
7492 short version = BLO_version_from_file(path);
7493 if (version != 0) {
7494 SNPRINTF(version_str, "%d.%01d", version / 100, version % 100);
7495 }
7496 }
7497
7498 if (version_str[0]) {
7500 tip, fmt::format("Blender {}", version_str), {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
7502 }
7503
7504 BLI_stat_t status;
7505 if (BLI_stat(path, &status) != -1) {
7507 bool is_today, is_yesterday;
7508 std::string day_string;
7510 nullptr, int64_t(status.st_mtime), false, time_st, date_str, &is_today, &is_yesterday);
7511 if (is_today || is_yesterday) {
7512 day_string = (is_today ? N_("Today") : N_("Yesterday")) + std::string(" ");
7513 }
7515 fmt::format("{}: {}{}{}",
7516 N_("Modified"),
7517 day_string,
7518 (is_today || is_yesterday) ? "" : date_str,
7519 (is_today || is_yesterday) ? time_st : ""),
7520 {},
7523
7524 if (status.st_size > 0) {
7525 char size[16];
7526 BLI_filelist_entry_size_to_string(nullptr, status.st_size, false, size);
7528 tip, fmt::format("{}: {}", N_("Size"), size), {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
7529 }
7530 }
7531
7532 if (!thumb) {
7533 /* try to load from the blend file itself. */
7535 thumb = BKE_main_thumbnail_to_imbuf(nullptr, data);
7536 if (data) {
7537 MEM_freeN(data);
7538 }
7539 }
7540
7541 if (thumb) {
7544
7545 uiTooltipImage image_data;
7546 float scale = (72.0f * UI_SCALE_FAC) / float(std::max(thumb->x, thumb->y));
7547 image_data.ibuf = thumb;
7548 image_data.width = short(float(thumb->x) * scale);
7549 image_data.height = short(float(thumb->y) * scale);
7550 image_data.border = true;
7551 image_data.background = uiTooltipImageBackground::Checkerboard_Themed;
7552 image_data.premultiplied = true;
7553 UI_tooltip_image_field_add(tip, image_data);
7554 IMB_freeImBuf(thumb);
7555 }
7556}
7557
7558int uiTemplateRecentFiles(uiLayout *layout, int rows)
7559{
7560 int i = 0;
7561 LISTBASE_FOREACH_INDEX (RecentFile *, recent, &G.recent_files, i) {
7562 if (i >= rows) {
7563 break;
7564 }
7565
7566 const char *filename = BLI_path_basename(recent->filepath);
7568 uiItemFullO(layout,
7569 "WM_OT_open_mainfile",
7570 filename,
7571 BKE_blendfile_extension_check(filename) ? ICON_FILE_BLEND : ICON_FILE_BACKUP,
7572 nullptr,
7575 &ptr);
7576 RNA_string_set(&ptr, "filepath", recent->filepath);
7577 RNA_boolean_set(&ptr, "display_file_selector", false);
7578
7579 uiBlock *block = uiLayoutGetBlock(layout);
7580 uiBut *but = ui_but_last(block);
7583 }
7584
7585 return i;
7586}
7587
7589
7590/* -------------------------------------------------------------------- */
7593
7595{
7596 bScreen *screen = CTX_wm_screen(C);
7597 SpaceFile *sfile = CTX_wm_space_file(C);
7598
7599 ED_file_path_button(screen, sfile, params, uiLayoutGetBlock(layout));
7600}
7601
bool id_can_have_animdata(const ID *id)
Definition anim_data.cc:79
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:89
void BKE_blender_version_blendfile_string_from_values(char *str_buff, const size_t str_buff_maxncpy, const short file_version, const short file_subversion)
Definition blender.cc:149
bool BKE_blendfile_extension_check(const char *str)
Definition blendfile.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)
#define MAXCOLORBAND
CBData * BKE_colorband_element_add(ColorBand *coba, float position)
Definition colorband.cc:606
void BKE_colorband_update_sort(ColorBand *coba)
Definition colorband.cc:584
bool BKE_colorband_element_remove(ColorBand *coba, int index)
Definition colorband.cc:632
void BKE_colorband_init(ColorBand *coba, bool rangetype)
Definition colorband.cc:22
void BKE_curvemapping_set_black_white(CurveMapping *cumap, const float black[3], const float white[3])
void BKE_curvemapping_reset_view(CurveMapping *cumap)
void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
void BKE_curvemapping_changed(CurveMapping *cumap, bool rem_doubles)
void BKE_curvemap_remove(CurveMap *cuma, short flag)
void BKE_curvemap_handle_set(CurveMap *cuma, int type)
@ CURVEMAP_SLOPE_NEGATIVE
@ CURVEMAP_SLOPE_POSITIVE
const bConstraintTypeInfo * BKE_constraint_typeinfo_from_type(int type)
WorkSpace * CTX_wm_workspace(const bContext *C)
ReportList * CTX_wm_reports(const bContext *C)
bScreen * CTX_wm_screen(const bContext *C)
SpaceFile * CTX_wm_space_file(const bContext *C)
SpaceProperties * CTX_wm_space_properties(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
RenderEngineType * CTX_data_engine_type(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)
wmWindowManager * CTX_wm_manager(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
void BKE_curveprofile_update(struct CurveProfile *profile, int update_flags)
void BKE_curveprofile_reset_view(struct CurveProfile *profile)
void BKE_curveprofile_remove_by_flag(struct CurveProfile *profile, short flag)
@ PROF_UPDATE_CLIP
@ PROF_UPDATE_REMOVE_DOUBLES
@ PROF_UPDATE_NONE
void BKE_curveprofile_reset(struct CurveProfile *profile)
void BKE_curveprofile_reverse(struct CurveProfile *profile)
@ G_FLAG_INTERNET_OVERRIDE_PREF_OFFLINE
@ G_FLAG_INTERNET_ALLOW
const char * BKE_idtype_idcode_to_translation_context(short idcode)
Definition idtype.cc:182
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:168
#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:405
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
Definition lib_id.cc:1034
void id_us_plus(ID *id)
Definition lib_id.cc:351
bool BKE_id_copy_is_allowed(const ID *id)
Definition lib_id.cc:647
#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:2382
blender::Vector< ID * > BKE_id_ordered_list(const ListBase *lb)
Definition lib_id.cc:2505
bool BKE_lib_id_make_local(Main *bmain, ID *id, int flags)
Definition lib_id.cc:584
void id_fake_user_clear(ID *id)
Definition lib_id.cc:397
void id_us_clear_real(ID *id)
Definition lib_id.cc:324
void id_us_min(ID *id)
Definition lib_id.cc:359
@ LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR
void BKE_main_id_flag_listbase(ListBase *lb, int flag, bool value)
Definition lib_id.cc:1209
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)
Blender kernel freestyle line style functionality.
ListBase * which_libbase(Main *bmain, short type)
Definition main.cc:842
bool BKE_main_has_issues(const Main *bmain)
Definition main.cc:469
ImBuf * BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
Definition main.cc:806
const ModifierTypeInfo * BKE_modifier_get_info(ModifierType type)
void BKE_modifier_type_panel_id(ModifierType type, char *r_idname)
bool BKE_packedfile_id_check(const ID *id)
Report * BKE_reports_last_displayable(ReportList *reports)
Definition report.cc:329
bool BKE_scene_uses_cycles(const Scene *scene)
Definition scene.cc:2782
bool BKE_scene_uses_cycles_experimental_features(Scene *scene)
Definition scene.cc:2798
bool BKE_scene_uses_blender_eevee(const Scene *scene)
Definition scene.cc:2771
@ PANEL_TYPE_INSTANCED
#define BKE_ST_MAXNAME
Definition BKE_screen.hh:66
void BKE_shaderfxType_panel_id(ShaderFxType type, char *r_idname)
Definition shader_fx.cc:147
const ShaderFxTypeInfo * BKE_shaderfx_get_info(ShaderFxType type)
Definition shader_fx.cc:131
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:791
#define BLI_assert(a)
Definition BLI_assert.h:50
File and directory operations.
eFileAttributes BLI_file_attributes(const char *path)
Definition storage.cc:226
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BLI_filelist_entry_size_to_string(const struct stat *st, uint64_t st_size_fallback, bool compact, char r_size[FILELIST_DIRENTRY_SIZE_LEN])
struct stat BLI_stat_t
void BLI_filelist_entry_datetime_to_string(const struct stat *st, int64_t ts, bool compact, char r_time[FILELIST_DIRENTRY_TIME_LEN], char r_date[FILELIST_DIRENTRY_DATE_LEN], bool *r_is_today, bool *r_is_yesterday)
eFileAttributes
@ FILE_ATTR_OFFLINE
#define FILELIST_DIRENTRY_DATE_LEN
#define FILELIST_DIRENTRY_TIME_LEN
void BLI_kdtree_nd_ free(KDTree *tree)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4])
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3])
MINLINE void add_v3_uchar_clamped(uchar r[3], int i)
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAX
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2])
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:201
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
void BLI_str_format_integer_unit(char dst[BLI_STR_FORMAT_INT32_INTEGER_UNIT_SIZE], int number_to_format) ATTR_NONNULL(1)
Definition string.c:1279
#define SNPRINTF_RLEN(dst, format,...)
Definition BLI_string.h:598
#define BLI_string_join(...)
unsigned char uchar
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
size_t BLI_timecode_string_from_time_simple(char *str, size_t maxncpy, double time_seconds) ATTR_NONNULL()
Definition timecode.c:171
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
#define ELEM(...)
#define STREQ(a, b)
const char * dirname(char *path)
external readfile function prototypes.
BlendThumbnail * BLO_thumbnail_from_file(const char *filepath)
Definition readfile.cc:1422
short BLO_version_from_file(const char *filepath)
Definition readfile.cc:1449
#define BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE
#define BLT_I18NCONTEXT_ID_WINDOWMANAGER
#define BLT_I18NCONTEXT_ID_WORLD
#define BLT_I18NCONTEXT_ID_ACTION
#define BLT_I18NCONTEXT_ID_TEXT
#define BLT_I18NCONTEXT_ID_VOLUME
#define RPT_(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
#define BLT_I18NCONTEXT_COLOR
typedef double(DMatrix)[4][4]
void DEG_relations_tag_update(Main *bmain)
ID * DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
@ LIBOVERRIDE_FLAG_SYSTEM_DEFINED
Definition DNA_ID.h:367
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:676
#define ID_IS_OVERRIDABLE_LIBRARY(_id)
Definition DNA_ID.h:669
#define ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(_id)
Definition DNA_ID.h:665
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
#define ID_IS_ASSET(_id)
Definition DNA_ID.h:690
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
@ ID_FLAG_FAKEUSER
Definition DNA_ID.h:720
#define ID_REAL_USERS(id)
Definition DNA_ID.h:637
@ ID_TAG_INDIRECT
Definition DNA_ID.h:794
@ ID_TAG_DOIT
Definition DNA_ID.h:1003
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
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
@ CACHEFILE_TYPE_ALEMBIC
Object groups, one object can be in many groups at once.
#define CM_TOT
@ CUMA_EXTEND_EXTRAPOLATE
@ CUMA_DO_CLIP
@ CUMA_USE_WRAPPING
@ CUMA_HANDLE_AUTO_ANIM
@ CUMA_SELECT
@ CUMA_HANDLE_VECTOR
@ COLORMANAGE_VIEW_USE_WHITE_BALANCE
@ COLORMANAGE_VIEW_USE_CURVES
@ CURVE_TONE_FILMLIKE
@ CURVE_PRESET_LINE
@ CONSTRAINT_DISABLE
@ CONSTRAINT_IK_TEMP
@ CONSTRAINT_TYPE_KINEMATIC
@ CONSTRAINT_TYPE_NULL
@ HD_AUTO_ANIM
@ HD_VECT
@ HD_AUTO
@ PROF_DIRTY_PRESET
@ PROF_PRESET_CROWN
@ PROF_PRESET_LINE
@ PROF_PRESET_CORNICE
@ PROF_PRESET_SUPPORTS
@ PROF_PRESET_STEPS
#define MAX_NAME
Definition DNA_defs.h:50
@ OB_MODE_EDIT
Object is a sort of wrapper for general info.
@ UILST_LAYOUT_DEFAULT
@ RGN_TYPE_TOOL_HEADER
@ UI_PREVIEW_TAG_DIRTY
@ SPACE_NODE
@ SPACE_INFO
@ BCONTEXT_CONSTRAINT
@ COLBAND_BLEND_HSL
@ COLBAND_BLEND_HSV
@ TEX_PR_OTHER
@ TEX_PR_BOTH
@ TEX_PR_TEXTURE
@ USER_HIDE_DOT
@ USER_CP_SQUARE_SV
@ USER_CP_CIRCLE_HSL
@ USER_CP_SQUARE_HS
@ USER_CP_SQUARE_HV
@ USER_CP_CIRCLE_HSV
@ STATUSBAR_SHOW_VERSION
@ STATUSBAR_SHOW_EXTENSIONS_UPDATES
@ USER_RENDER_DISPLAY_NONE
#define UI_SCALE_FAC
@ WM_EXTENSIONS_UPDATE_CHECKING
@ WORKSPACE_USE_PIN_SCENE
void(*)(void *data_link, char *r_idname) uiListPanelIDFromDataFunc
void ED_file_path_button(bScreen *screen, const SpaceFile *sfile, FileSelectParams *params, uiBlock *block)
Definition file_draw.cc:72
const char * ED_info_statusbar_string_ex(Main *bmain, Scene *scene, ViewLayer *view_layer, const char statusbar_flag)
void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, uiPreview *ui_preview, rcti *rect)
bScreen * ED_screen_animation_no_scrub(const wmWindowManager *wm)
int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
Definition area.cc:2770
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
@ AZONE_REGION
@ AZONE_AREA
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:104
void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int arg_unused)
Definition ed_undo.cc:728
static void split(const char *text, const char *seps, char ***str, int *count)
Contains defines and structs used throughout the imbuf module.
bool IMB_metadata_get_field(const IDProperty *metadata, const char *key, char *value, size_t value_maxncpy)
Definition metadata.cc:42
ImBuf * IMB_thumb_read(const char *file_or_lib_path, ThumbSize size)
Definition thumbs.cc:499
@ THB_LARGE
Definition IMB_thumbs.hh:21
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
#define RNA_STRUCT_BEGIN(sptr, prop)
#define RNA_STRUCT_END
short RNA_type_to_ID_code(const StructRNA *type)
#define RNA_STRUCT_BEGIN_SKIP_RNA_TYPE(sptr, prop)
#define RNA_warning(format,...)
@ PROP_BOOLEAN
Definition RNA_types.hh:65
@ PROP_ENUM
Definition RNA_types.hh:69
@ PROP_STRING
Definition RNA_types.hh:68
@ PROP_POINTER
Definition RNA_types.hh:70
@ PROP_COLLECTION
Definition RNA_types.hh:71
@ PROP_NEVER_UNLINK
Definition RNA_types.hh:273
@ PROP_NEVER_NULL
Definition RNA_types.hh:266
@ PROP_ID_SELF_CHECK
Definition RNA_types.hh:259
@ PROP_HIDDEN
Definition RNA_types.hh:239
#define C
Definition RandGen.cpp:29
void UI_but_func_set(uiBut *but, std::function< void(bContext &)> func)
void * but_func_argN_copy(const void *argN)
void but_func_argN_free(void *argN)
int UI_text_colorid_from_report_type(int type)
@ UI_BLOCK_THEME_STYLE_POPUP
void UI_but_flag_disable(uiBut *but, int flag)
void UI_but_disable(uiBut *but, const char *disabled_hint)
uiBut * uiDefButS(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, short *poin, float min, float max, const char *tip)
eAutoPropButsReturn
@ UI_PROP_BUTS_ANY_FAILED_CHECK
@ UI_PROP_BUTS_NONE_ADDED
uiLayout * uiLayoutColumnFlow(uiLayout *layout, int number, bool align)
#define UI_UNIT_Y
void uiLayoutSetActive(uiLayout *layout, bool active)
eUIEmbossType UI_block_emboss_get(uiBlock *block)
uiBut * uiDefIconButR(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, PointerRNA *ptr, const char *propname, int index, float min, float max, const char *tip)
uiLayout * uiLayoutBox(uiLayout *layout)
eUIEmbossType
@ UI_EMBOSS_NONE
@ UI_EMBOSS
@ UI_EMBOSS_PULLDOWN
void UI_block_theme_style_set(uiBlock *block, char theme_style)
void UI_but_focus_on_enter_event(wmWindow *win, uiBut *but)
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
void UI_but_func_drawextra_set(uiBlock *block, std::function< void(const bContext *C, rcti *rect)> func)
void UI_but_func_tooltip_custom_set(uiBut *but, uiButToolTipCustomFunc func, void *arg, uiFreeArgFunc free_arg)
uiBut * uiDefButI(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, int *poin, float min, float max, const char *tip)
uiBut * uiDefIconTextButO(uiBlock *block, int type, const char *opname, wmOperatorCallContext opcontext, int icon, blender::StringRef str, int x, int y, short width, short height, const char *tip)
int UI_icon_from_report_type(int type)
void UI_tooltip_image_field_add(uiTooltipData &data, const uiTooltipImage &image_data)
void UI_but_func_rename_full_set(uiBut *but, std::function< void(std::string &new_name)> rename_full_func)
#define UI_SEP_CHAR
void UI_block_lock_clear(uiBlock *block)
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *arg, uiFreeArgFunc free_arg)
uiBut * uiDefIconBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int retval, int icon, int x, int y, short width, short height, const char *tip)
void(*)(const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first) uiButSearchUpdateFn
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, const char *tip)
void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
void UI_block_bounds_set_normal(uiBlock *block, int addval)
Definition interface.cc:574
void uiLayoutSetRedAlert(uiLayout *layout, bool redalert)
void UI_but_func_search_set(uiBut *but, uiButSearchCreateFn search_create_fn, uiButSearchUpdateFn search_update_fn, void *arg, bool free_arg, uiFreeArgFunc search_arg_free_fn, uiButHandleFunc search_exec_fn, void *active)
@ UI_BUT_ICON_LEFT
@ UI_BUT_ICON_INVERT
uiBut * uiDefIconButR_prop(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, const char *tip)
bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid, int but_flag, uint8_t name_prefix_offset)
void UI_panels_free_instanced(const bContext *C, ARegion *region)
void UI_tooltip_text_field_add(uiTooltipData &data, std::string text, std::string suffix, const uiTooltipStyle style, const uiTooltipColorID color_id, const bool is_pad=false)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
uiLayout * UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, const uiStyle *style)
const uiStyle * UI_style_get_dpi()
void uiLayoutSetScaleX(uiLayout *layout, float scale)
@ UI_DIR_DOWN
void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, const char *name, int icon, const char *placeholder=nullptr)
int UI_icon_colorid_from_report_type(int type)
@ UI_LAYOUT_MENU
@ UI_LAYOUT_PANEL
void UI_but_drawflag_enable(uiBut *but, int flag)
uiBut * uiDefButO(uiBlock *block, int type, const char *opname, wmOperatorCallContext opcontext, const char *str, int x, int y, short width, short height, const char *tip)
uiBut * uiDefIconBut(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, const char *tip)
void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn)
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, eUIEmbossType emboss)
void UI_but_number_step_size_set(uiBut *but, float step_size)
void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg)
void uiItemS(uiLayout *layout)
uiLayout * uiLayoutAbsolute(uiLayout *layout, bool align)
eButLabelAlign
@ UI_BUT_LABEL_ALIGN_NONE
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, const char *tip)
uiBut * UI_context_active_but_get(const bContext *C)
uiBut * uiDefButBitI(uiBlock *block, int type, int bit, int retval, blender::StringRef str, int x, int y, short width, short height, int *poin, float min, float max, const char *tip)
eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr, bool(*check_prop)(PointerRNA *ptr, PropertyRNA *prop, void *user_data), void *user_data, PropertyRNA *prop_activate_init, eButLabelAlign label_align, bool compact)
void *(*)(const void *argN) uiButArgNCopy
void(*)(void *argN) uiButArgNFree
int UI_searchbox_size_x()
uiLayout * uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
void uiItemS_ex(uiLayout *layout, float factor, LayoutSeparatorType type=LayoutSeparatorType::Auto)
PointerRNA * UI_but_extra_operator_icon_add(uiBut *but, const char *opname, wmOperatorCallContext opcontext, int icon)
void uiItemFullO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
void uiTemplateList(uiLayout *layout, const bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, const char *active_propname, const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns, enum uiTemplateListFlags flags)
void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data)
#define UI_ITEM_NONE
void uiLayoutSetUnitsX(uiLayout *layout, float unit)
const uiStyle * UI_style_get()
@ 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_fontstyle_set(const uiFontStyle *fs)
uiBut * uiDefIconButO(uiBlock *block, int type, const char *opname, wmOperatorCallContext opcontext, int icon, int x, int y, short width, short height, const char *tip)
uiBut * uiDefButF(uiBlock *block, int type, int retval, blender::StringRef str, int x, int y, short width, short height, float *poin, float min, float max, const char *tip)
uiBut * uiDefBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, blender::StringRef str, int x, int y, short width, short height, const char *tip)
#define UI_MAX_DRAW_STR
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss)
@ UI_BUT_REDALERT
@ UI_BUT_UNDO
@ UI_BUT_DISABLED
@ UI_BUT_HAS_SEP_CHAR
@ UI_BUT_ICON_PREVIEW
@ UI_BUT_UPDATE_DELAY
void uiLayoutSetKeepAspect(uiLayout *layout, bool keepaspect)
PointerRNA * UI_but_operator_ptr_ensure(uiBut *but)
@ UI_TIP_STYLE_NORMAL
@ UI_TIP_STYLE_SPACER
@ UI_TIP_STYLE_HEADER
void UI_block_func_set(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2)
int UI_icon_from_keymap_item(const wmKeyMapItem *kmi, int r_icon_mod[4])
void UI_block_bounds_set_text(uiBlock *block, int addval)
Definition interface.cc:584
void UI_block_align_begin(uiBlock *block)
int UI_searchbox_size_y()
uiBut * uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxncpy, int x, int y, short width, short height, const char *tip)
void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index)
void uiLayoutSetEmboss(uiLayout *layout, eUIEmbossType emboss)
int uiLayoutGetWidth(uiLayout *layout)
ARegion *(*)(bContext *C, ARegion *region, const rcti *item_rect, void *arg, void *active) uiButSearchTooltipFn
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
void uiItemEnumO_value(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
PanelLayout uiLayoutPanelProp(const bContext *C, uiLayout *layout, PointerRNA *open_prop_owner, const char *open_prop_name)
@ UI_BLOCK_SEARCH_MENU
@ UI_BLOCK_LOOP
@ UI_BLOCK_MOVEMOUSE_QUIT
@ UI_BLOCK_KEEP_OPEN
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
uiBut * uiDefIconButI(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, int *poin, float min, float max, const char *tip)
eButGradientType
@ UI_GRAD_L_ALT
@ UI_GRAD_SV
@ UI_GRAD_V_ALT
@ UI_GRAD_HV
@ UI_GRAD_HS
@ UI_GRAD_H
@ UI_GRAD_NONE
uiLayout * uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon)
void UI_block_funcN_set(uiBlock *block, uiButHandleNFunc funcN, void *argN, void *arg2, uiButArgNFree func_argN_free_fn=MEM_freeN, uiButArgNCopy func_argN_copy_fn=MEM_dupallocN)
void UI_but_number_precision_set(uiBut *but, float precision)
uiBut * uiDefIconTextButR_prop(uiBlock *block, int type, int retval, int icon, const char *str, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, const char *tip)
void uiTemplateTextureShow(uiLayout *layout, const bContext *C, PointerRNA *ptr, PropertyRNA *prop)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
uiLayout * uiLayoutSplit(uiLayout *layout, float percentage, bool align)
uiBut * uiDefIconButS(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, short *poin, float min, float max, const char *tip)
uiBlock * uiLayoutAbsoluteBlock(uiLayout *layout)
void(*)(bContext *C, void *arg1, void *arg2) uiButHandleFunc
@ UI_TEMPLATE_ID_FILTER_AVAILABLE
@ UI_TEMPLATE_ID_FILTER_ALL
@ UI_TIP_LC_ALERT
@ UI_TIP_LC_NORMAL
bool UI_panel_list_matches_data(ARegion *region, ListBase *data, uiListPanelIDFromDataFunc panel_idname_func)
void UI_block_direction_set(uiBlock *block, char direction)
void UI_block_set_active_operator(uiBlock *block, wmOperator *op, const bool free)
void UI_but_icon_indicator_color_set(uiBut *but, const uchar color[4])
uiBut * uiDefButR_prop(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, const char *tip)
#define UI_FSTYLE_WIDGET
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout)
void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
uiBut * uiDefBlockButN(uiBlock *block, uiBlockCreateFunc func, void *argN, blender::StringRef str, int x, int y, short width, short height, const char *tip, uiButArgNFree func_argN_free_fn=MEM_freeN, uiButArgNCopy func_argN_copy_fn=MEM_dupallocN)
#define UI_UNIT_X
uiBlock *(*)(bContext *C, ARegion *region, void *arg1) uiBlockCreateFunc
void UI_block_flag_enable(uiBlock *block, int flag)
@ UI_BTYPE_BUT
@ UI_BTYPE_TOGGLE
@ UI_BTYPE_PROGRESS
@ UI_BTYPE_EXTRA
@ UI_BTYPE_TAB
@ UI_BTYPE_VECTORSCOPE
@ UI_BTYPE_NODE_SOCKET
@ UI_BTYPE_ROUNDBOX
@ UI_BTYPE_COLORBAND
@ UI_BTYPE_BUT_MENU
@ UI_BTYPE_HISTOGRAM
@ UI_BTYPE_WAVEFORM
@ UI_BTYPE_HSVCIRCLE
@ UI_BTYPE_TEXT
@ UI_BTYPE_HSVCUBE
@ UI_BTYPE_LABEL
@ UI_BTYPE_CURVE
@ UI_BTYPE_ICON_TOGGLE_N
@ UI_BTYPE_ROW
@ UI_BTYPE_NUM
@ UI_BTYPE_CURVEPROFILE
@ UI_BTYPE_COLOR
@ UI_BTYPE_CHECKBOX
@ UI_BTYPE_GRIP
@ UI_BTYPE_ICON_TOGGLE
#define UI_MAX_NAME_STR
void UI_but_drag_set_id(uiBut *but, ID *id)
PointerRNA * UI_panel_custom_data_get(const Panel *panel)
ARegion * UI_tooltip_create_from_search_item_generic(bContext *C, const ARegion *searchbox_region, const rcti *item_rect, ID *id)
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
uiBut * uiDefIconMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, int x, int y, short width, short height, const char *tip)
void UI_panel_context_pointer_set(Panel *panel, const char *name, PointerRNA *ptr)
uiBut * uiDefButR(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, PointerRNA *ptr, const char *propname, int index, float min, float max, const char *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)
Panel * UI_panel_add_instanced(const bContext *C, ARegion *region, ListBase *panels, const char *panel_idname, PointerRNA *custom_data)
void UI_but_search_preview_grid_size_set(uiBut *but, int rows, int cols)
@ UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED
@ UI_TEMPLATE_OP_PROPS_SHOW_EMPTY
@ UI_TEMPLATE_OP_PROPS_SHOW_TITLE
@ UI_TEMPLATE_OP_PROPS_HIDE_PRESETS
@ UI_TEMPLATE_OP_PROPS_COMPACT
@ UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT
void UI_block_lock_set(uiBlock *block, bool val, const char *lockstr)
uiBut * uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert)
@ UI_LAYOUT_VERTICAL
void uiItemPopoverPanel(uiLayout *layout, const bContext *C, const char *panel_type, const char *name, int icon)
void UI_but_flag_enable(uiBut *but, int flag)
@ UI_TEMPLATE_LIST_FLAG_NONE
uiBut * uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int index, const char *name, int icon, int x, int y, int width, int height)
void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_EXPAND
@ UI_ITEM_R_NO_BG
@ UI_ITEM_R_ICON_ONLY
@ UI_ITEM_R_SLIDER
@ UI_LAYOUT_ALIGN_LEFT
@ UI_LAYOUT_ALIGN_RIGHT
@ UI_LAYOUT_ALIGN_EXPAND
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
void UI_block_align_end(uiBlock *block)
int UI_icon_from_library(const ID *id)
@ TH_INFO_WARNING_TEXT
@ TH_INFO_WARNING
@ TH_TEXT
void UI_GetThemeColorType4ubv(int colorid, int spacetype, unsigned char col[4])
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
@ WM_JOB_TYPE_DPAINT_BAKE
Definition WM_api.hh:1595
@ WM_JOB_TYPE_SEQ_BUILD_PROXY
Definition WM_api.hh:1592
@ WM_JOB_TYPE_COMPOSITE
Definition WM_api.hh:1577
@ WM_JOB_TYPE_OBJECT_BAKE
Definition WM_api.hh:1585
@ WM_JOB_TYPE_POINTCACHE
Definition WM_api.hh:1594
@ WM_JOB_TYPE_SEQ_DRAW_THUMBNAIL
Definition WM_api.hh:1607
@ WM_JOB_TYPE_ASSET_LIBRARY_LOAD
Definition WM_api.hh:1587
@ WM_JOB_TYPE_CLIP_BUILD_PROXY
Definition WM_api.hh:1588
@ WM_JOB_TYPE_CLIP_PREFETCH
Definition WM_api.hh:1591
@ WM_JOB_TYPE_SEQ_BUILD_PREVIEW
Definition WM_api.hh:1593
@ WM_JOB_TYPE_RENDER
Definition WM_api.hh:1578
@ WM_JOB_TYPE_ANY
Definition WM_api.hh:1575
@ WM_JOB_TYPE_OBJECT_SIM_OCEAN
Definition WM_api.hh:1582
@ WM_JOB_TYPE_CLIP_SOLVE_CAMERA
Definition WM_api.hh:1590
@ WM_JOB_TYPE_FILESEL_READDIR
Definition WM_api.hh:1586
@ WM_JOB_TYPE_CLIP_TRACK_MARKERS
Definition WM_api.hh:1589
@ WM_JOB_TYPE_OBJECT_SIM_FLUID
Definition WM_api.hh:1583
@ WM_JOB_TYPE_OBJECT_BAKE_TEXTURE
Definition WM_api.hh:1584
#define NC_WINDOW
Definition WM_types.hh:342
#define NC_ID
Definition WM_types.hh:362
#define NC_WM
Definition WM_types.hh:341
@ OPTYPE_PRESET
Definition WM_types.hh:175
@ OPTYPE_MACRO
Definition WM_types.hh:165
#define ND_SHADING_PREVIEW
Definition WM_types.hh:447
#define ND_DATACHANGED
Definition WM_types.hh:381
#define ND_LIB_OVERRIDE_CHANGED
Definition WM_types.hh:386
#define NA_ADDED
Definition WM_types.hh:552
#define NC_MATERIAL
Definition WM_types.hh:347
#define OP_PROP_TAG_ADVANCED
Definition WM_types.hh:243
#define NA_REMOVED
Definition WM_types.hh:553
wmOperatorCallContext
Definition WM_types.hh:216
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:219
@ WM_OP_INVOKE_SCREEN
Definition WM_types.hh:223
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
#define NA_RENAME
Definition WM_types.hh:554
@ KM_RELEASE
Definition WM_types.hh:285
#define ND_SPACE_VIEW3D
Definition WM_types.hh:494
#define NC_SPACE
Definition WM_types.hh:359
@ KM_SHIFT
Definition WM_types.hh:255
#define ND_SPACE_OUTLINER
Definition WM_types.hh:493
volatile int lock
#define U
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
btSequentialImpulseConstraintSolverMt int btPersistentManifold int btTypedConstraint ** constraints
constexpr bool is_empty() const
constexpr int64_t size() const
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
#define printf
#define SELECT
#define offsetof(t, d)
bool ED_id_rename(Main &bmain, ID &id, blender::StringRefNull name)
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define str(s)
uint col
void IMB_freeImBuf(ImBuf *)
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
void ui_def_but_icon(uiBut *but, const int icon, const int flag)
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)
float ui_event_icon_offset(const int icon_id)
#define RNA_NO_INDEX
@ UI_SELECT_DRAW
@ UI_HAS_ICON
ColorPicker * ui_block_colorpicker_create(uiBlock *block)
ARegion * ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiButSearch *search_but)
#define UI_MENU_PADDING
uiBut * ui_but_last(uiBlock *block) ATTR_WARN_UNUSED_RESULT
void ui_rna_collection_search_update_fn(const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first)
#define UI_MENU_WIDTH_MIN
static void template_id_workspace_pin_extra_icon(const TemplateID &template_ui, uiBut *but)
void uiTemplateIconView(uiLayout *layout, PointerRNA *ptr, const char *propname, bool show_labels, float icon_scale, float icon_scale_popup)
static void do_running_jobs(bContext *C, void *, int event)
static void curvemap_buttons_redraw(bContext &C)
static uiBlock * curvemap_tools_negslope_func(bContext *C, ARegion *region, void *cb_v)
void uiTemplateInputStatus(uiLayout *layout, bContext *C)
void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char *propname)
ID * ui_template_id_liboverride_hierarchy_make(bContext *C, Main *bmain, ID *owner_id, ID *id, const char **r_undo_push_label)
void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname, bool)
static bool curvemap_can_zoom_in(CurveMapping *cumap)
void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
static void template_keymap_item_properties(uiLayout *layout, const char *title, PointerRNA *ptr)
static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con)
#define template_id_context(type)
#define B_STOPFILE
static std::string progress_tooltip_func(bContext *, void *argN, const char *)
static void cache_file_layer_item(uiList *, const bContext *, uiLayout *layout, PointerRNA *, PointerRNA *itemptr, int, PointerRNA *, const char *, int, int)
static bool ui_layout_operator_buts_poll_property(PointerRNA *, PropertyRNA *prop, void *user_data)
static bool id_search_add(const bContext *C, TemplateID *template_ui, uiSearchItems *items, ID *id)
static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, const RNAUpdateCb &cb)
#define WHEEL_SIZE
#define TEMPLATE_SEARCH_TEXTBUT_HEIGHT
void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale)
void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
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 char *text, const bool live_icon, const bool hide_buttons)
static bool curve_profile_can_zoom_out(CurveProfile *profile)
static uiBlock * curve_profile_presets_fn(bContext *C, ARegion *region, void *cb_v)
static void id_search_cb_tagged(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
static void constraint_active_func(bContext *, void *ob_v, void *con_v)
void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *used_ptr, const char *used_propname, int active_layer)
static uiBlock * curve_profile_tools_fn(bContext *C, ARegion *region, void *cb_v)
void uiTemplatePathBuilder(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *, const char *text)
void uiTemplateCacheFileProcedural(uiLayout *layout, const bContext *C, PointerRNA *fileptr)
static const char * template_id_browse_tip(const StructRNA *type)
void uiTemplateConstraintHeader(uiLayout *layout, PointerRNA *ptr)
void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, bool levels, bool brush, bool neg_slope, bool tone)
static void bone_constraint_panel_id(void *md_link, char *r_idname)
static 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)
#define CURVE_ZOOM_MAX
void uiTemplateCacheFileLayers(uiLayout *layout, const bContext *C, PointerRNA *fileptr)
static const wmKeyMapItem * keymap_item_from_enum_item(const wmKeyMap *keymap, const EnumPropertyItem *item)
static uiBlock * template_search_menu(bContext *C, ARegion *region, void *arg_template)
static int template_search_textbut_height()
static void template_search_exec_fn(bContext *C, void *arg_template, void *item)
static eAutoPropButsReturn template_operator_property_buts_draw_single(const bContext *C, wmOperator *op, uiLayout *layout, const eButLabelAlign label_align, int layout_flags)
void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int filter, const char *text)
bool uiTemplateCacheFilePointer(PointerRNA *ptr, const char *propname, PointerRNA *r_file_ptr)
void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
#define TEMPLATE_SEARCH_TEXTBUT_MIN_WIDTH
static void ui_template_id(uiLayout *layout, const bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, const char *menu, const char *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 void colorband_flip(bContext *C, ColorBand *coba)
static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, const rctf *butr, const RNAUpdateCb &cb, int expand)
void uiTemplateAction(uiLayout *layout, const bContext *C, ID *id, const char *newop, const char *unlinkop, const char *text)
void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
static bool constraint_panel_is_bone(Panel *panel)
void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename, const char *text)
#define B_STOPRENDER
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)
static bool template_search_setup(TemplateSearch &template_search, PointerRNA *ptr, const char *const propname, PointerRNA *searchptr, const char *const searchpropname)
static int template_search_textbut_width(PointerRNA *ptr, PropertyRNA *name_prop)
static void template_ID_tabs(const bContext *C, uiLayout *layout, TemplateID &template_id, StructRNA *type, int flag, const char *newop, const char *menu)
void uiTemplateNodeSocket(uiLayout *layout, bContext *, const float color[4])
static void draw_exporter_item(uiList *, const bContext *, uiLayout *layout, PointerRNA *, PointerRNA *itemptr, int, PointerRNA *, const char *, int, int)
static void id_search_cb_objects_from_scene(const bContext *C, void *arg_template, const char *str, uiSearchItems *items, const bool)
static uiBlock * ui_icon_view_menu_cb(bContext *C, ARegion *region, void *arg_litem)
ID * UI_context_active_but_get_tab_ID(bContext *C)
static void keymap_item_modified(bContext *, void *kmi_p, void *)
void uiTemplateFileSelectPath(uiLayout *layout, bContext *C, FileSelectParams *params)
void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, bool expand)
void uiTemplatePreview(uiLayout *layout, bContext *C, ID *id, bool show_buttons, ID *parent, MTex *slot, const char *preview_id)
static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, bool levels, bool brush, bool neg_slope, bool tone, const RNAUpdateCb &cb)
void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propname, int icon)
void uiTemplateShaderFx(uiLayout *, bContext *C)
void uiTemplateOperatorPropertyButs(const bContext *C, uiLayout *layout, wmOperator *op, eButLabelAlign label_align, short flag)
static uiBlock * curvemap_brush_tools_func(bContext *C, ARegion *region, void *cb_v)
static void template_id_liboverride_hierarchy_collections_tag_recursive(Collection *root_collection, ID *target_id, const bool do_parents)
void uiTemplateGpencilColorPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, int rows, int cols, float scale, int filter)
static void template_search_add_button_searchmenu(const bContext *C, uiLayout *layout, uiBlock *block, TemplateSearch &template_search, const bool editable, const bool live_icon)
static void rna_update_cb(bContext &C, const RNAUpdateCb &cb)
static void colorband_add(bContext &C, const RNAUpdateCb &cb, ColorBand &coba)
void uiTemplateConstraints(uiLayout *, bContext *C, bool use_bone_constraints)
static void object_constraint_panel_id(void *md_link, char *r_idname)
void uiTemplateCacheFileVelocity(uiLayout *layout, PointerRNA *fileptr)
static void template_ID_set_property_exec_fn(bContext *C, void *arg_template, void *item)
static bool curve_profile_can_zoom_in(CurveProfile *profile)
static bool keymap_item_can_collapse(const wmKeyMapItem *kmi_a, const wmKeyMapItem *kmi_b)
static uiBlock * curvemap_tools_func(bContext *C, ARegion *region, RNAUpdateCb &cb, bool show_extend, int reset_mode)
void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int rows, int cols, int filter, const bool hide_buttons)
static void template_operator_property_buts_draw_recursive(const bContext *C, wmOperator *op, uiLayout *layout, const eButLabelAlign label_align, int layout_flags, bool *r_has_advanced)
void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *, PointerRNA *ptr, const char *propname)
void uiTemplateSearch(uiLayout *layout, const bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *searchptr, const char *searchpropname, const char *newop, const char *unlinkop, const char *text)
static void curvemap_buttons_zoom_in(bContext *C, CurveMapping *cumap)
void uiTemplateIDTabs(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *menu, int filter)
static bool id_search_allows_id(TemplateID *template_ui, const int flag, ID *id, const char *query)
void uiTemplateCollectionExporters(uiLayout *layout, bContext *C)
static wmOperator * minimal_operator_create(wmOperatorType *ot, PointerRNA *properties)
static void draw_export_properties(bContext *C, uiLayout *layout, wmOperator *op, const std::string &filename)
#define B_STOPCOMPO
static void template_search_buttons(const bContext *C, uiLayout *layout, TemplateSearch &template_search, const char *newop, const char *unlinkop, const char *text)
void uiTemplateSearchPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *searchptr, const char *searchpropname, const char *newop, const char *unlinkop, const int rows, const int cols, const char *text)
static void colorband_update_cb(bContext *, void *bt_v, void *coba_v)
void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
static uiBlock * curvemap_tools_posslope_func(bContext *C, ARegion *region, void *cb_v)
bool uiTemplateEventFromKeymapItem(uiLayout *layout, const char *text, const wmKeyMapItem *kmi, bool text_fallback)
void UI_context_active_but_prop_get_templateID(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop)
int uiTemplateRecentFiles(uiLayout *layout, int rows)
static short get_constraint_expand_flag(const bContext *, Panel *panel)
static void template_search_add_button_name(uiBlock *block, PointerRNA *active_ptr, const StructRNA *type)
#define B_STOPSEQ
static PropertyRNA * template_search_get_searchprop(PointerRNA *targetptr, PropertyRNA *targetprop, PointerRNA *searchptr, const char *const searchpropname)
void uiTemplateCurveProfile(uiLayout *layout, PointerRNA *ptr, const char *propname)
static bool curvemap_can_zoom_out(CurveMapping *cumap)
void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propname, bool value_slider, bool lock, bool lock_luminosity, bool cubic)
static uiBlock * id_search_menu(bContext *C, ARegion *region, void *arg_litem)
void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
static void curve_profile_zoom_out(bContext *C, CurveProfile *profile)
static void colorband_distribute(bContext *C, ColorBand *coba, bool evenly)
static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
static bool uiTemplateInputStatusAzone(uiLayout *layout, const AZone *az, const ARegion *region)
static bool ui_layout_operator_properties_only_booleans(const bContext *C, wmWindowManager *wm, wmOperator *op, int layout_flags)
static void template_add_button_search_menu(const bContext *C, uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, uiBlockCreateFunc block_func, void *block_argN, const char *const tip, const bool use_previews, const bool editable, const bool live_icon, uiButArgNFree func_argN_free_fn=MEM_freeN, uiButArgNCopy func_argN_copy_fn=MEM_dupallocN)
#define CONSTRAINT_BONE_TYPE_PANEL_PREFIX
static uiBlock * colorband_tools_fn(bContext *C, ARegion *region, void *cb_v)
static void constraint_reorder(bContext *C, Panel *panel, int new_index)
void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
uiListType * UI_UL_cache_file_layers()
static void set_constraint_expand_flag(const bContext *, Panel *panel, short expand_flag)
#define CONSTRAINT_TYPE_PANEL_PREFIX
static std::string ui_template_status_tooltip(bContext *C, void *, const char *)
static void curvemap_buttons_zoom_out(bContext *C, CurveMapping *cumap)
#define B_STOPOTHER
static void shaderfx_panel_id(void *fx_v, char *r_idname)
int uiTemplateStatusBarModalItem(uiLayout *layout, const wmKeyMap *keymap, const EnumPropertyItem *item)
#define B_STOPCLIP
void uiTemplateCacheFile(uiLayout *layout, const bContext *C, PointerRNA *ptr, const char *propname)
static void modifier_panel_id(void *md_link, char *r_name)
static void ui_template_palette_menu(bContext *, uiLayout *layout, void *)
#define B_MATPRV
static void curve_profile_zoom_in(bContext *C, CurveProfile *profile)
static void uiTemplateRecentFiles_tooltip_func(bContext &, uiTooltipData &tip, void *argN)
void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr)
void uiTemplateID(uiLayout *layout, const bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int filter, const bool live_icon, const char *text)
static void do_preview_buttons(bContext *C, void *arg, int event)
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)
#define ERROR_LIBDATA_MESSAGE
static void constraint_ops_extra_draw(bContext *C, uiLayout *layout, void *con_v)
#define B_STOPANIM
static void template_search_add_button_operator(uiBlock *block, const char *const operator_name, const wmOperatorCallContext opcontext, const int icon, const bool editable)
static uiBlock * curvemap_brush_tools_negslope_func(bContext *C, ARegion *region, void *cb_v)
#define B_STOPCAST
static uiBlock * component_menu(bContext *C, ARegion *region, void *args_v)
void uiTemplateComponentMenu(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *name)
static void draw_export_controls(bContext *C, uiLayout *layout, const std::string &label, int index, bool valid)
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 uiTemplateModifiers(uiLayout *, bContext *C)
void uiTemplateHeader(uiLayout *layout, bContext *C)
static uiBlock * curvemap_clipping_func(bContext *C, ARegion *region, void *cumap_v)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
bool RE_engine_supports_alembic_procedural(const RenderEngineType *render_type, Scene *scene)
#define GS(x)
Definition iris.cc:202
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
#define G(x, y, z)
std::unique_ptr< IDProperty, IDPropertyDeleter > create_group(StringRefNull prop_name, eIDPropertyFlag flags={})
Allocate a new IDProperty of type IDP_GROUP.
FileHandlerType * file_handler_find(StringRef idname)
void constraint_active_set(Object *ob, bConstraint *con)
ListBase * pose_constraint_list(const bContext *C)
Object * context_active_object(const bContext *C)
void object_single_user_make(Main *bmain, Scene *scene, Object *ob)
ListBase * constraint_list_from_constraint(Object *ob, bConstraint *con, bPoseChannel **r_pchan)
void RNA_property_boolean_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, bool value)
PropertyRNA * RNA_struct_type_find_property(StructRNA *srna, const char *identifier)
const char * RNA_property_ui_description(const PropertyRNA *prop)
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
bool RNA_struct_is_ID(const StructRNA *type)
void RNA_property_float_ui_range(PointerRNA *ptr, PropertyRNA *prop, float *softmin, float *softmax, float *step, float *precision)
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)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_enum_icon_from_value(const EnumPropertyItem *item, int value, int *r_icon)
PropertyType RNA_property_type(PropertyRNA *prop)
char * RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len)
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)
int RNA_struct_ui_icon(const StructRNA *type)
const char * RNA_struct_ui_description(const StructRNA *type)
bool RNA_pointer_is_null(const PointerRNA *ptr)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_property_ui_name(const PropertyRNA *prop)
bool RNA_property_editable(const PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
PropertyRNA * RNA_struct_name_property(const StructRNA *type)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_property_enum_items(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
int RNA_property_tags(PropertyRNA *prop)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
const char * RNA_property_identifier(const PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
__int64 int64_t
Definition stdint.h:89
ListBase ui_previews
ListBase panels
struct CollectionChild * next
struct CollectionParent * next
Collection_Runtime runtime
CBData data[32]
float luminosity_lock_value
CurveMapPoint * curve
CurveMap cm[4]
CurveProfilePoint * path
const char * identifier
Definition RNA_types.hh:506
const char * name
Definition RNA_types.hh:510
unsigned int flag
Definition DNA_ID.h:352
struct ID * hierarchy_root
Definition DNA_ID.h:343
int len
Definition DNA_ID.h:174
Definition DNA_ID.h:413
int tag
Definition DNA_ID.h:434
struct Library * lib
Definition DNA_ID.h:419
IDOverrideLibrary * override_library
Definition DNA_ID.h:459
short flag
Definition DNA_ID.h:430
char name[66]
Definition DNA_ID.h:425
unsigned int session_uid
Definition DNA_ID.h:454
IDProperty * metadata
void * last
void * first
ListBase scenes
Definition BKE_main.hh:210
bool is_asset_edit_file
Definition BKE_main.hh:151
bool has_forward_compatibility_issues
Definition BKE_main.hh:144
short versionfile
Definition BKE_main.hh:137
ListBase collections
Definition BKE_main.hh:231
void(* panel_register)(ARegionType *region_type)
ustring name
Definition graph/node.h:177
ListBase constraints
struct Collection * instance_collection
ListBase modifiers
ListBase shader_fx
ListBase colors
uiLayout * header
uiLayout * body
void(* reorder)(bContext *C, Panel *pa, int new_index)
void(* set_list_data_expand_flag)(const bContext *C, Panel *pa, short expand_flag)
short(* get_list_data_expand_flag)(const bContext *C, Panel *pa)
struct PanelType * type
char panelname[64]
struct Panel * next
ID * owner_id
Definition RNA_types.hh:40
StructRNA * type
Definition RNA_types.hh:41
void * data
Definition RNA_types.hh:42
struct wmTimer * reporttimer
const char * message
struct Collection * master_collection
int wavefrm_height
int vecscope_height
void(* panel_register)(struct ARegionType *region_type)
PropertyRNA * prop
uiRNACollectionSearch search_data
WorkSpaceRuntimeHandle * runtime
struct bConstraint * prev
struct bConstraint * next
ListBase areabase
struct ARegion * active_region
char export_operator[OP_MAX_TYPENAME]
std::string get_default_filename(const StringRefNull name)
float xmax
float xmin
float ymax
float ymin
uiBlock * oldblock
ListBase buttons
eButGradientType gradient_type
eButGradientType gradient_type
MenuType * menu
void * custom_data
uiButHandleNFunc funcN
IconTextOverlay icon_overlay_text
PropertyRNA * rnaprop
eButType type
PointerRNA * opptr
uiBut * next
PointerRNA rnapoin
void * func_argN
uchar col[4]
char idname[BKE_ST_MAXNAME]
uiListDrawItemFunc draw_item
char preview_id[64]
unsigned int id_session_uid
uiFontStyle widget
int xy[2]
Definition WM_types.hh:726
uint8_t modifier
Definition WM_types.hh:739
struct wmKeyMapItem * next
bool(* poll_property)(const bContext *C, wmOperator *op, const PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1048
const char * idname
Definition WM_types.hh:992
void(* ui)(bContext *C, wmOperator *op)
Definition WM_types.hh:1053
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
IDProperty * properties
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
void * customdata
Definition WM_types.hh:922
struct wmEvent * eventstate
#define N_(msgid)
bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *layout)
bool WM_operator_repeat_check(const bContext *, wmOperator *op)
void WM_main_add_notifier(uint type, void *reference)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
const char * WM_window_cursor_keymap_status_get(const wmWindow *win, int button_index, int type_index)
void WM_reportf(eReportType type, const char *format,...)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_jobs_stop_all_from_owner(wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:637
const char * WM_jobs_name(const wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:295
bool WM_jobs_is_stopped(const wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:322
float WM_jobs_progress(const wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:243
double WM_jobs_starttime(const wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:284
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:223
const char * WM_key_event_string(const short type, const bool compact)
void WM_keyconfig_update_tag(wmKeyMap *keymap, wmKeyMapItem *kmi)
MenuType * WM_menutype_find(const char *idname, bool quiet)
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_reset(wmOperator *op)
wmOperator * WM_operator_last_redo(const bContext *C)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
bool WM_uilisttype_add(uiListType *ult)
WorkSpace * WM_window_get_active_workspace(const wmWindow *win)
uint8_t flag
Definition wm_window.cc:138