Blender  V3.3
interface_layout.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <limits.h>
8 #include <math.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "DNA_armature_types.h"
15 #include "DNA_screen_types.h"
16 #include "DNA_userdef_types.h"
17 
18 #include "BLI_alloca.h"
19 #include "BLI_dynstr.h"
20 #include "BLI_listbase.h"
21 #include "BLI_math.h"
22 #include "BLI_memory_utils.h"
23 #include "BLI_rect.h"
24 #include "BLI_string.h"
25 #include "BLI_utildefines.h"
26 
27 #include "BLT_translation.h"
28 
29 #include "BKE_anim_data.h"
30 #include "BKE_armature.h"
31 #include "BKE_context.h"
32 #include "BKE_global.h"
33 #include "BKE_idprop.h"
34 #include "BKE_screen.h"
35 
36 #include "RNA_access.h"
37 #include "RNA_prototypes.h"
38 
39 #include "UI_interface.h"
40 
41 #include "WM_api.h"
42 #include "WM_types.h"
43 
44 #include "interface_intern.h"
45 
46 /* Show an icon button after each RNA button to use to quickly set keyframes,
47  * this is a way to display animation/driven/override status, see T54951. */
48 #define UI_PROP_DECORATE
49 /* Alternate draw mode where some buttons can use single icon width,
50  * giving more room for the text at the expense of nicely aligned text. */
51 #define UI_PROP_SEP_ICON_WIDTH_EXCEPTION
52 
53 /* -------------------------------------------------------------------- */
57 #define UI_OPERATOR_ERROR_RET(_ot, _opname, return_statement) \
58  if (ot == NULL) { \
59  ui_item_disabled(layout, _opname); \
60  RNA_warning("'%s' unknown operator", _opname); \
61  return_statement; \
62  } \
63  (void)0
64 
65 #define UI_ITEM_PROP_SEP_DIVIDE 0.4f
66 
67 /* uiLayoutRoot */
68 
69 typedef struct uiLayoutRoot {
70  struct uiLayoutRoot *next, *prev;
71 
72  int type;
74 
75  int emw, emh;
76  int padding;
77 
79  void *argv;
80 
81  const uiStyle *style;
85 
86 /* Item */
87 
88 typedef enum uiItemType {
90 
101 
103 #if 0
104  TEMPLATE_COLUMN_FLOW,
105  TEMPLATE_SPLIT,
106  TEMPLATE_BOX,
107 
108  TEMPLATE_HEADER,
109  TEMPLATE_HEADER_ID,
110 #endif
112 
113 typedef struct uiItem {
114  void *next, *prev;
116  int flag;
118 
119 enum {
122 
123  UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */
126  /* Show an icon button next to each property (to set keyframes, show status).
127  * Enabled by default, depends on 'UI_ITEM_PROP_SEP'. */
130 };
131 
132 typedef struct uiButtonItem {
136 
137 struct uiLayout {
139 
144 
146 
149 
150  int x, y, w, h;
151  float scale[2];
152  short space;
153  bool align;
154  bool active;
157  bool enabled;
158  bool redalert;
162  char alignment;
165  float units[2];
166 };
167 
168 typedef struct uiLayoutItemFlow {
170  int number;
171  int totcol;
173 
174 typedef struct uiLayoutItemGridFlow {
176 
177  /* Extra parameters */
178  bool row_major; /* Fill first row first, instead of filling first column first. */
179  bool even_columns; /* Same width for all columns. */
180  bool even_rows; /* Same height for all rows. */
188 
189  /* Pure internal runtime storage. */
192 
193 typedef struct uiLayoutItemBx {
197 
198 typedef struct uiLayoutItemSplit {
200  float percentage;
202 
203 typedef struct uiLayoutItemRoot {
206 
209 /* -------------------------------------------------------------------- */
213 static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_NAME_STR])
214 {
215  const int len = strlen(name);
216 
217  if (len != 0 && len + 1 < UI_MAX_NAME_STR) {
218  memcpy(namestr, name, len);
219  namestr[len] = ':';
220  namestr[len + 1] = '\0';
221  return namestr;
222  }
223 
224  return name;
225 }
226 
227 static int ui_item_fit(
228  int item, int pos, int all, int available, bool is_last, int alignment, float *extra_pixel)
229 {
230  /* available == 0 is unlimited */
231  if (ELEM(0, available, all)) {
232  return item;
233  }
234 
235  if (all > available) {
236  /* contents is bigger than available space */
237  if (is_last) {
238  return available - pos;
239  }
240 
241  const float width = *extra_pixel + (item * available) / (float)all;
242  *extra_pixel = width - (int)width;
243  return (int)width;
244  }
245 
246  /* contents is smaller or equal to available space */
247  if (alignment == UI_LAYOUT_ALIGN_EXPAND) {
248  if (is_last) {
249  return available - pos;
250  }
251 
252  const float width = *extra_pixel + (item * available) / (float)all;
253  *extra_pixel = width - (int)width;
254  return (int)width;
255  }
256  return item;
257 }
258 
259 /* variable button size in which direction? */
260 #define UI_ITEM_VARY_X 1
261 #define UI_ITEM_VARY_Y 2
262 
264 {
265  return ((ELEM(layout->root->type, UI_LAYOUT_HEADER, UI_LAYOUT_PIEMENU) ||
266  (layout->alignment != UI_LAYOUT_ALIGN_EXPAND)) ?
269 }
270 
271 static bool ui_layout_variable_size(uiLayout *layout)
272 {
273  /* Note that this code is probably a bit flaky, we'd probably want to know whether it's
274  * variable in X and/or Y, etc. But for now it mimics previous one,
275  * with addition of variable flag set for children of grid-flow layouts. */
276  return ui_layout_vary_direction(layout) == UI_ITEM_VARY_X || layout->variable_size;
277 }
278 
284  float text;
285  float icon;
286  float icon_only;
287 };
288 
298 static const struct uiTextIconPadFactor ui_text_pad_default = {
299  .text = 1.50f,
300  .icon = 0.25f,
301  .icon_only = 0.0f,
302 };
303 
305 static const struct uiTextIconPadFactor ui_text_pad_compact = {
306  .text = 1.25f,
307  .icon = 0.35f,
308  .icon_only = 0.0f,
309 };
310 
312 static const struct uiTextIconPadFactor ui_text_pad_none = {
313  .text = 0.25f,
314  .icon = 1.50f,
315  .icon_only = 0.0f,
316 };
317 
321 static int ui_text_icon_width_ex(uiLayout *layout,
322  const char *name,
323  int icon,
324  const struct uiTextIconPadFactor *pad_factor)
325 {
326  const int unit_x = UI_UNIT_X * (layout->scale[0] ? layout->scale[0] : 1.0f);
327 
328  /* When there is no text, always behave as if this is an icon-only button
329  * since it's not useful to return empty space. */
330  if (icon && !name[0]) {
331  return unit_x * (1.0f + pad_factor->icon_only);
332  }
333 
334  if (ui_layout_variable_size(layout)) {
335  if (!icon && !name[0]) {
336  return unit_x * (1.0f + pad_factor->icon_only);
337  }
338 
339  if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) {
340  layout->item.flag |= UI_ITEM_FIXED_SIZE;
341  }
342 
343  float margin = pad_factor->text;
344  if (icon) {
345  margin += pad_factor->icon;
346  }
347 
348  const float aspect = layout->root->block->aspect;
349  const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
350  return UI_fontstyle_string_width_with_block_aspect(fstyle, name, aspect) +
351  (int)ceilf(unit_x * margin);
352  }
353  return unit_x * 10;
354 }
355 
356 static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool compact)
357 {
358  return ui_text_icon_width_ex(
359  layout, name, icon, compact ? &ui_text_pad_compact : &ui_text_pad_default);
360 }
361 
362 static void ui_item_size(uiItem *item, int *r_w, int *r_h)
363 {
364  if (item->type == ITEM_BUTTON) {
365  uiButtonItem *bitem = (uiButtonItem *)item;
366 
367  if (r_w) {
368  *r_w = BLI_rctf_size_x(&bitem->but->rect);
369  }
370  if (r_h) {
371  *r_h = BLI_rctf_size_y(&bitem->but->rect);
372  }
373  }
374  else {
375  uiLayout *litem = (uiLayout *)item;
376 
377  if (r_w) {
378  *r_w = litem->w;
379  }
380  if (r_h) {
381  *r_h = litem->h;
382  }
383  }
384 }
385 
386 static void ui_item_offset(uiItem *item, int *r_x, int *r_y)
387 {
388  if (item->type == ITEM_BUTTON) {
389  uiButtonItem *bitem = (uiButtonItem *)item;
390 
391  if (r_x) {
392  *r_x = bitem->but->rect.xmin;
393  }
394  if (r_y) {
395  *r_y = bitem->but->rect.ymin;
396  }
397  }
398  else {
399  if (r_x) {
400  *r_x = 0;
401  }
402  if (r_y) {
403  *r_y = 0;
404  }
405  }
406 }
407 
408 static void ui_item_position(uiItem *item, int x, int y, int w, int h)
409 {
410  if (item->type == ITEM_BUTTON) {
411  uiButtonItem *bitem = (uiButtonItem *)item;
412 
413  bitem->but->rect.xmin = x;
414  bitem->but->rect.ymin = y;
415  bitem->but->rect.xmax = x + w;
416  bitem->but->rect.ymax = y + h;
417 
418  ui_but_update(bitem->but); /* for strlen */
419  }
420  else {
421  uiLayout *litem = (uiLayout *)item;
422 
423  litem->x = x;
424  litem->y = y + h;
425  litem->w = w;
426  litem->h = h;
427  }
428 }
429 
430 static void ui_item_move(uiItem *item, int delta_xmin, int delta_xmax)
431 {
432  if (item->type == ITEM_BUTTON) {
433  uiButtonItem *bitem = (uiButtonItem *)item;
434 
435  bitem->but->rect.xmin += delta_xmin;
436  bitem->but->rect.xmax += delta_xmax;
437 
438  ui_but_update(bitem->but); /* for strlen */
439  }
440  else {
441  uiLayout *litem = (uiLayout *)item;
442 
443  if (delta_xmin > 0) {
444  litem->x += delta_xmin;
445  }
446  else {
447  litem->w += delta_xmax;
448  }
449  }
450 }
451 
454 /* -------------------------------------------------------------------- */
458 int uiLayoutGetLocalDir(const uiLayout *layout)
459 {
460  switch (layout->item.type) {
461  case ITEM_LAYOUT_ROW:
462  case ITEM_LAYOUT_ROOT:
463  case ITEM_LAYOUT_OVERLAP:
464  return UI_LAYOUT_HORIZONTAL;
465  case ITEM_LAYOUT_COLUMN:
468  case ITEM_LAYOUT_SPLIT:
470  case ITEM_LAYOUT_BOX:
471  default:
472  return UI_LAYOUT_VERTICAL;
473  }
474 }
475 
476 static uiLayout *ui_item_local_sublayout(uiLayout *test, uiLayout *layout, bool align)
477 {
478  uiLayout *sub;
480  sub = uiLayoutRow(layout, align);
481  }
482  else {
483  sub = uiLayoutColumn(layout, align);
484  }
485 
486  sub->space = 0;
487  return sub;
488 }
489 
490 static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
491 {
492  wmWindow *win = CTX_wm_window(C);
493  uiBut *but = arg_but;
494  PointerRNA *ptr = &but->rnapoin;
495  PropertyRNA *prop = but->rnaprop;
496  const int index = POINTER_AS_INT(arg_index);
497  const bool shift = win->eventstate->modifier & KM_SHIFT;
498  const int len = RNA_property_array_length(ptr, prop);
499 
500  if (!shift) {
501  RNA_property_boolean_set_index(ptr, prop, index, true);
502 
503  for (int i = 0; i < len; i++) {
504  if (i != index) {
505  RNA_property_boolean_set_index(ptr, prop, i, 0);
506  }
507  }
508 
509  RNA_property_update(C, ptr, prop);
510 
511  LISTBASE_FOREACH (uiBut *, cbut, &but->block->buttons) {
512  ui_but_update(cbut);
513  }
514  }
515 }
516 
517 /* create buttons for an item with an RNA array */
518 static void ui_item_array(uiLayout *layout,
519  uiBlock *block,
520  const char *name,
521  int icon,
522  PointerRNA *ptr,
523  PropertyRNA *prop,
524  int len,
525  int x,
526  int y,
527  int w,
528  int UNUSED(h),
529  bool expand,
530  bool slider,
531  int toggle,
532  bool icon_only,
533  bool compact,
534  bool show_text)
535 {
536  const uiStyle *style = layout->root->style;
537 
538  /* retrieve type and subtype */
539  const PropertyType type = RNA_property_type(prop);
540  const PropertySubType subtype = RNA_property_subtype(prop);
541 
542  uiLayout *sub = ui_item_local_sublayout(layout, layout, 1);
543  UI_block_layout_set_current(block, sub);
544 
545  /* create label */
546  if (name[0] && show_text) {
547  uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
548  }
549 
550  /* create buttons */
551  if (type == PROP_BOOLEAN && ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
552  /* special check for layer layout */
553  const int cols = (len >= 20) ? 2 : 1;
554  const int colbuts = len / (2 * cols);
555  uint layer_used = 0;
556  uint layer_active = 0;
557 
558  UI_block_layout_set_current(block, uiLayoutAbsolute(layout, false));
559 
560  const int butw = UI_UNIT_X * 0.75;
561  const int buth = UI_UNIT_X * 0.75;
562 
563  if (ptr->type == &RNA_Armature) {
564  bArmature *arm = ptr->data;
565 
566  layer_used = arm->layer_used;
567 
568  if (arm->edbo) {
569  if (arm->act_edbone) {
570  layer_active |= arm->act_edbone->layer;
571  }
572  }
573  else {
574  if (arm->act_bone) {
575  layer_active |= arm->act_bone->layer;
576  }
577  }
578  }
579 
580  for (int b = 0; b < cols; b++) {
581  UI_block_align_begin(block);
582 
583  for (int a = 0; a < colbuts; a++) {
584  const int layer_num = a + b * colbuts;
585  const uint layer_flag = (1u << layer_num);
586 
587  if (layer_used & layer_flag) {
588  if (layer_active & layer_flag) {
589  icon = ICON_LAYER_ACTIVE;
590  }
591  else {
592  icon = ICON_LAYER_USED;
593  }
594  }
595  else {
596  icon = ICON_BLANK1;
597  }
598 
599  uiBut *but = uiDefAutoButR(
600  block, ptr, prop, layer_num, "", icon, x + butw * a, y + buth, butw, buth);
601  if (subtype == PROP_LAYER_MEMBER) {
602  UI_but_func_set(but, ui_layer_but_cb, but, POINTER_FROM_INT(layer_num));
603  }
604  }
605  for (int a = 0; a < colbuts; a++) {
606  const int layer_num = a + len / 2 + b * colbuts;
607  const uint layer_flag = (1u << layer_num);
608 
609  if (layer_used & layer_flag) {
610  if (layer_active & layer_flag) {
611  icon = ICON_LAYER_ACTIVE;
612  }
613  else {
614  icon = ICON_LAYER_USED;
615  }
616  }
617  else {
618  icon = ICON_BLANK1;
619  }
620 
621  uiBut *but = uiDefAutoButR(
622  block, ptr, prop, layer_num, "", icon, x + butw * a, y, butw, buth);
623  if (subtype == PROP_LAYER_MEMBER) {
624  UI_but_func_set(but, ui_layer_but_cb, but, POINTER_FROM_INT(layer_num));
625  }
626  }
627  UI_block_align_end(block);
628 
629  x += colbuts * butw + style->buttonspacex;
630  }
631  }
632  else if (subtype == PROP_MATRIX) {
633  int totdim, dim_size[3]; /* 3 == RNA_MAX_ARRAY_DIMENSION */
634  int row, col;
635 
636  UI_block_layout_set_current(block, uiLayoutAbsolute(layout, true));
637 
638  totdim = RNA_property_array_dimension(ptr, prop, dim_size);
639  if (totdim != 2) {
640  /* Only 2D matrices supported in UI so far. */
641  return;
642  }
643 
644  w /= dim_size[0];
645  /* h /= dim_size[1]; */ /* UNUSED */
646 
647  for (int a = 0; a < len; a++) {
648  col = a % dim_size[0];
649  row = a / dim_size[0];
650 
651  uiBut *but = uiDefAutoButR(block,
652  ptr,
653  prop,
654  a,
655  "",
656  ICON_NONE,
657  x + w * col,
658  y + (dim_size[1] * UI_UNIT_Y) - (row * UI_UNIT_Y),
659  w,
660  UI_UNIT_Y);
661  if (slider && but->type == UI_BTYPE_NUM) {
662  uiButNumber *number_but = (uiButNumber *)but;
663 
664  but->a1 = number_but->step_size;
666  }
667  }
668  }
669  else if (subtype == PROP_DIRECTION && !expand) {
670  uiDefButR_prop(block,
672  0,
673  name,
674  x,
675  y,
676  UI_UNIT_X * 3,
677  UI_UNIT_Y * 3,
678  ptr,
679  prop,
680  -1,
681  0,
682  0,
683  -1,
684  -1,
685  NULL);
686  }
687  else {
688  /* NOTE: this block of code is a bit arbitrary and has just been made
689  * to work with common cases, but may need to be re-worked */
690 
691  /* special case, boolean array in a menu, this could be used in a more generic way too */
692  if (ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) && !expand && ELEM(len, 3, 4)) {
693  uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, 0, 0, w, UI_UNIT_Y);
694  }
695  else {
696  /* Even if 'expand' is false, we expand anyway. */
697 
698  /* layout for known array subtypes */
699  char str[3] = {'\0'};
700 
701  if (!icon_only && show_text) {
702  if (type != PROP_BOOLEAN) {
703  str[1] = ':';
704  }
705  }
706 
707  /* Show check-boxes for rna on a non-emboss block (menu for eg). */
708  bool *boolarr = NULL;
709  if (type == PROP_BOOLEAN &&
711  boolarr = MEM_callocN(sizeof(bool) * len, __func__);
712  RNA_property_boolean_get_array(ptr, prop, boolarr);
713  }
714 
715  const char *str_buf = show_text ? str : "";
716  for (int a = 0; a < len; a++) {
717  if (!icon_only && show_text) {
718  str[0] = RNA_property_array_item_char(prop, a);
719  }
720  if (boolarr) {
721  icon = boolarr[a] ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
722  }
723 
724  const int width_item = ((compact && type == PROP_BOOLEAN) ?
725  min_ii(w, ui_text_icon_width(layout, str_buf, icon, false)) :
726  w);
727 
728  uiBut *but = uiDefAutoButR(
729  block, ptr, prop, a, str_buf, icon, 0, 0, width_item, UI_UNIT_Y);
730  if (slider && but->type == UI_BTYPE_NUM) {
731  uiButNumber *number_but = (uiButNumber *)but;
732 
733  but->a1 = number_but->step_size;
735  }
736  if ((toggle == 1) && but->type == UI_BTYPE_CHECKBOX) {
737  but->type = UI_BTYPE_TOGGLE;
738  }
739  if ((a == 0) && (subtype == PROP_AXISANGLE)) {
741  }
742  }
743 
744  if (boolarr) {
745  MEM_freeN(boolarr);
746  }
747  }
748  }
749 
750  UI_block_layout_set_current(block, layout);
751 }
752 
753 static void ui_item_enum_expand_handle(bContext *C, void *arg1, void *arg2)
754 {
755  wmWindow *win = CTX_wm_window(C);
756 
757  if ((win->eventstate->modifier & KM_SHIFT) == 0) {
758  uiBut *but = (uiBut *)arg1;
759  const int enum_value = POINTER_AS_INT(arg2);
760 
761  int current_value = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
762  if (!(current_value & enum_value)) {
763  current_value = enum_value;
764  }
765  else {
766  current_value &= enum_value;
767  }
768  RNA_property_enum_set(&but->rnapoin, but->rnaprop, current_value);
769  }
770 }
771 
776  uiBlock *block,
777  PointerRNA *ptr,
778  PropertyRNA *prop,
779  const char *uiname,
780  const int h,
781  const eButType but_type,
782  const bool icon_only,
783  const EnumPropertyItem *item,
784  const bool is_first)
785 {
786  const char *name = (!uiname || uiname[0]) ? item->name : "";
787  const int icon = item->icon;
788  const int value = item->value;
789  const int itemw = ui_text_icon_width(block->curlayout, icon_only ? "" : name, icon, 0);
790 
791  uiBut *but;
792  if (icon && name[0] && !icon_only) {
794  block, but_type, 0, icon, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
795  }
796  else if (icon) {
797  const int w = (is_first) ? itemw : ceilf(itemw - U.pixelsize);
798  but = uiDefIconButR_prop(
799  block, but_type, 0, icon, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
800  }
801  else {
802  but = uiDefButR_prop(
803  block, but_type, 0, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
804  }
805 
806  if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
807  /* If this is set, assert since we're clobbering someone elses callback. */
808  /* Buttons get their block's func by default, so we cannot assert in that case either. */
809  BLI_assert(ELEM(but->func, NULL, block->func));
811  }
812 
813  if (uiLayoutGetLocalDir(layout) != UI_LAYOUT_HORIZONTAL) {
814  but->drawflag |= UI_BUT_TEXT_LEFT;
815  }
816 
817  /* Allow quick, inaccurate swipe motions to switch tabs
818  * (no need to keep cursor over them). */
819  if (but_type == UI_BTYPE_TAB) {
820  but->flag |= UI_BUT_DRAG_LOCK;
821  }
822 }
823 
824 static void ui_item_enum_expand_exec(uiLayout *layout,
825  uiBlock *block,
826  PointerRNA *ptr,
827  PropertyRNA *prop,
828  const char *uiname,
829  const int h,
830  const eButType but_type,
831  const bool icon_only)
832 {
833  /* XXX: The way this function currently handles uiname parameter
834  * is insane and inconsistent with general UI API:
835  *
836  * - uiname is the *enum property* label.
837  * - when it is NULL or empty, we do not draw *enum items* labels,
838  * this doubles the icon_only parameter.
839  * - we *never* draw (i.e. really use) the enum label uiname, it is just used as a mere flag!
840  *
841  * Unfortunately, fixing this implies an API "soft break", so better to defer it for later... :/
842  * - mont29
843  */
844 
846 
847  const bool radial = (layout->root->type == UI_LAYOUT_PIEMENU);
848 
849  bool free;
850  const EnumPropertyItem *item_array;
851  if (radial) {
852  RNA_property_enum_items_gettexted_all(block->evil_C, ptr, prop, &item_array, NULL, &free);
853  }
854  else {
855  RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item_array, NULL, &free);
856  }
857 
858  /* We don't want nested rows, cols in menus. */
859  uiLayout *layout_radial = NULL;
860  if (radial) {
861  if (layout->root->layout == layout) {
862  layout_radial = uiLayoutRadial(layout);
863  UI_block_layout_set_current(block, layout_radial);
864  }
865  else {
866  if (layout->item.type == ITEM_LAYOUT_RADIAL) {
867  layout_radial = layout;
868  }
869  UI_block_layout_set_current(block, layout);
870  }
871  }
873  layout->root->type == UI_LAYOUT_MENU) {
874  UI_block_layout_set_current(block, layout);
875  }
876  else {
877  UI_block_layout_set_current(block, ui_item_local_sublayout(layout, layout, 1));
878  }
879 
880  for (const EnumPropertyItem *item = item_array; item->identifier; item++) {
881  const bool is_first = item == item_array;
882 
883  if (!item->identifier[0]) {
884  const EnumPropertyItem *next_item = item + 1;
885 
886  /* Separate items, potentially with a label. */
887  if (next_item->identifier) {
888  /* Item without identifier but with name:
889  * Add group label for the following items. */
890  if (item->name) {
891  if (!is_first) {
892  uiItemS(block->curlayout);
893  }
894  uiItemL(block->curlayout, item->name, item->icon);
895  }
896  else if (radial && layout_radial) {
897  uiItemS(layout_radial);
898  }
899  else {
900  uiItemS(block->curlayout);
901  }
902  }
903  continue;
904  }
905 
907  layout, block, ptr, prop, uiname, h, but_type, icon_only, item, is_first);
908  }
909 
910  UI_block_layout_set_current(block, layout);
911 
912  if (free) {
913  MEM_freeN((void *)item_array);
914  }
915 }
916 static void ui_item_enum_expand(uiLayout *layout,
917  uiBlock *block,
918  PointerRNA *ptr,
919  PropertyRNA *prop,
920  const char *uiname,
921  const int h,
922  const bool icon_only)
923 {
924  ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_ROW, icon_only);
925 }
926 static void ui_item_enum_expand_tabs(uiLayout *layout,
927  bContext *C,
928  uiBlock *block,
929  PointerRNA *ptr,
930  PropertyRNA *prop,
931  PointerRNA *ptr_highlight,
932  PropertyRNA *prop_highlight,
933  const char *uiname,
934  const int h,
935  const bool icon_only)
936 {
937  uiBut *last = block->buttons.last;
938 
939  ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_TAB, icon_only);
940  BLI_assert(last != block->buttons.last);
941 
942  for (uiBut *tab = last ? last->next : block->buttons.first; tab; tab = tab->next) {
944  }
945 
946  const bool use_custom_highlight = (prop_highlight != NULL);
947 
948  if (use_custom_highlight) {
949  const int highlight_array_len = RNA_property_array_length(ptr_highlight, prop_highlight);
950  bool *highlight_array = alloca(sizeof(bool) * highlight_array_len);
951  RNA_property_boolean_get_array(ptr_highlight, prop_highlight, highlight_array);
952  int i = 0;
953  for (uiBut *tab_but = last ? last->next : block->buttons.first;
954  (tab_but != NULL) && (i < highlight_array_len);
955  tab_but = tab_but->next, i++) {
956  SET_FLAG_FROM_TEST(tab_but->flag, !highlight_array[i], UI_BUT_INACTIVE);
957  }
958  }
959 }
960 
961 /* callback for keymap item change button */
962 static void ui_keymap_but_cb(bContext *UNUSED(C), void *but_v, void *UNUSED(key_v))
963 {
964  uiBut *but = but_v;
966  const uiButHotkeyEvent *hotkey_but = (uiButHotkeyEvent *)but;
967 
968  RNA_int_set(
969  &but->rnapoin, "shift", (hotkey_but->modifier_key & KM_SHIFT) ? KM_MOD_HELD : KM_NOTHING);
970  RNA_int_set(
971  &but->rnapoin, "ctrl", (hotkey_but->modifier_key & KM_CTRL) ? KM_MOD_HELD : KM_NOTHING);
972  RNA_int_set(
973  &but->rnapoin, "alt", (hotkey_but->modifier_key & KM_ALT) ? KM_MOD_HELD : KM_NOTHING);
974  RNA_int_set(
975  &but->rnapoin, "oskey", (hotkey_but->modifier_key & KM_OSKEY) ? KM_MOD_HELD : KM_NOTHING);
976 }
977 
985  uiBlock *block,
986  const char *name,
987  int icon,
988  PointerRNA *ptr,
989  PropertyRNA *prop,
990  int index,
991  int x,
992  int y,
993  int w_hint,
994  int h,
995  int flag)
996 {
997  uiLayout *sub = layout;
998  int prop_but_width = w_hint;
999 #ifdef UI_PROP_DECORATE
1000  uiLayout *layout_prop_decorate = NULL;
1001  const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
1002  const bool use_prop_decorate = use_prop_sep && (layout->item.flag & UI_ITEM_PROP_DECORATE) &&
1003  (layout->item.flag & UI_ITEM_PROP_DECORATE_NO_PAD) == 0;
1004 #endif
1005 
1006  const bool is_keymapitem_ptr = RNA_struct_is_a(ptr->type, &RNA_KeyMapItem);
1007  if ((flag & UI_ITEM_R_FULL_EVENT) && !is_keymapitem_ptr) {
1008  RNA_warning("Data is not a keymap item struct: %s. Ignoring 'full_event' option.",
1010  }
1011 
1012  UI_block_layout_set_current(block, layout);
1013 
1014  /* Only add new row if more than 1 item will be added. */
1015  if (name[0]
1016 #ifdef UI_PROP_DECORATE
1017  || use_prop_decorate
1018 #endif
1019  ) {
1020  /* Also avoid setting 'align' if possible. Set the space to zero instead as aligning a large
1021  * number of labels can end up aligning thousands of buttons when displaying key-map search (a
1022  * heavy operation), see: T78636. */
1023  sub = uiLayoutRow(layout, layout->align);
1024  sub->space = 0;
1025  }
1026 
1027  if (name[0]) {
1028 #ifdef UI_PROP_DECORATE
1029  if (use_prop_sep) {
1030  layout_prop_decorate = uiItemL_respect_property_split(layout, name, 0);
1031  }
1032  else
1033 #endif
1034  {
1035  int w_label;
1036  if (ui_layout_variable_size(layout)) {
1037  /* In this case, a pure label without additional padding.
1038  * Use a default width for property button(s). */
1039  prop_but_width = UI_UNIT_X * 5;
1040  w_label = ui_text_icon_width_ex(layout, name, ICON_NONE, &ui_text_pad_none);
1041  }
1042  else {
1043  w_label = w_hint / 3;
1044  }
1045  uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, "");
1046  }
1047  }
1048 
1049  const PropertyType type = RNA_property_type(prop);
1050  const PropertySubType subtype = RNA_property_subtype(prop);
1051 
1052  uiBut *but;
1053  if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH)) {
1054  UI_block_layout_set_current(block, uiLayoutRow(sub, true));
1055  but = uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, prop_but_width - UI_UNIT_X, h);
1056 
1057  /* BUTTONS_OT_file_browse calls UI_context_active_but_prop_get_filebrowser */
1058  uiDefIconButO(block,
1059  UI_BTYPE_BUT,
1060  subtype == PROP_DIRPATH ? "BUTTONS_OT_directory_browse" :
1061  "BUTTONS_OT_file_browse",
1063  ICON_FILEBROWSER,
1064  x,
1065  y,
1066  UI_UNIT_X,
1067  h,
1068  NULL);
1069  }
1070  else if (flag & UI_ITEM_R_EVENT) {
1071  but = uiDefButR_prop(block,
1073  0,
1074  name,
1075  x,
1076  y,
1077  prop_but_width,
1078  h,
1079  ptr,
1080  prop,
1081  index,
1082  0,
1083  0,
1084  -1,
1085  -1,
1086  NULL);
1087  }
1088  else if ((flag & UI_ITEM_R_FULL_EVENT) && is_keymapitem_ptr) {
1089  char buf[128];
1090 
1091  WM_keymap_item_to_string(ptr->data, false, buf, sizeof(buf));
1092 
1093  but = uiDefButR_prop(block,
1095  0,
1096  buf,
1097  x,
1098  y,
1099  prop_but_width,
1100  h,
1101  ptr,
1102  prop,
1103  0,
1104  0,
1105  0,
1106  -1,
1107  -1,
1108  NULL);
1110  if (flag & UI_ITEM_R_IMMEDIATE) {
1112  }
1113  }
1114  else {
1115  const char *str = (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY)) ? NULL : "";
1116  but = uiDefAutoButR(block, ptr, prop, index, str, icon, x, y, prop_but_width, h);
1117  }
1118 
1119 #ifdef UI_PROP_DECORATE
1120  /* Only for alignment. */
1121  if (use_prop_decorate) { /* Note that sep flag may have been unset meanwhile. */
1122  uiItemL(layout_prop_decorate ? layout_prop_decorate : sub, NULL, ICON_BLANK1);
1123  }
1124 #endif /* UI_PROP_DECORATE */
1125 
1126  UI_block_layout_set_current(block, layout);
1127  return but;
1128 }
1129 
1131  PointerRNA *r_ptr,
1132  PropertyRNA **r_prop,
1133  bool *r_is_undo,
1134  bool *r_is_userdef)
1135 {
1136  ARegion *region = CTX_wm_menu(C) ? CTX_wm_menu(C) : CTX_wm_region(C);
1137  uiBut *prevbut = NULL;
1138 
1139  memset(r_ptr, 0, sizeof(*r_ptr));
1140  *r_prop = NULL;
1141  *r_is_undo = false;
1142  *r_is_userdef = false;
1143 
1144  if (!region) {
1145  return;
1146  }
1147 
1148  LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
1149  LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
1150  if (but && but->rnapoin.data) {
1151  if (RNA_property_type(but->rnaprop) == PROP_STRING) {
1152  prevbut = but;
1153  }
1154  }
1155 
1156  /* find the button before the active one */
1157  if ((but->flag & UI_BUT_LAST_ACTIVE) && prevbut) {
1158  *r_ptr = prevbut->rnapoin;
1159  *r_prop = prevbut->rnaprop;
1160  *r_is_undo = (prevbut->flag & UI_BUT_UNDO) != 0;
1161  *r_is_userdef = UI_but_is_userdef(prevbut);
1162  return;
1163  }
1164  }
1165  }
1166 }
1167 
1170 /* -------------------------------------------------------------------- */
1177 static void ui_but_tip_from_enum_item(uiBut *but, const EnumPropertyItem *item)
1178 {
1179  if (but->tip == NULL || but->tip[0] == '\0') {
1180  if (item->description && item->description[0] &&
1181  !(but->optype && but->optype->get_description)) {
1182  but->tip = item->description;
1183  }
1184  }
1185 }
1186 
1187 /* disabled item */
1188 static void ui_item_disabled(uiLayout *layout, const char *name)
1189 {
1190  uiBlock *block = layout->root->block;
1191 
1192  UI_block_layout_set_current(block, layout);
1193 
1194  if (!name) {
1195  name = "";
1196  }
1197 
1198  const int w = ui_text_icon_width(layout, name, 0, 0);
1199 
1200  uiBut *but = uiDefBut(
1201  block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1202  UI_but_disable(but, "");
1203 }
1204 
1211  wmOperatorType *ot,
1212  const char *name,
1213  int icon,
1214  IDProperty *properties,
1216  int flag,
1217  PointerRNA *r_opptr)
1218 {
1219  /* Take care to fill 'r_opptr' whatever happens. */
1220  uiBlock *block = layout->root->block;
1221 
1222  if (!name) {
1223  if (ot && ot->srna && (flag & UI_ITEM_R_ICON_ONLY) == 0) {
1224  name = WM_operatortype_name(ot, NULL);
1225  }
1226  else {
1227  name = "";
1228  }
1229  }
1230 
1231  if (layout->root->type == UI_LAYOUT_MENU && !icon) {
1232  icon = ICON_BLANK1;
1233  }
1234 
1235  UI_block_layout_set_current(block, layout);
1236  ui_block_new_button_group(block, 0);
1237 
1238  const int w = ui_text_icon_width(layout, name, icon, 0);
1239 
1240  const eUIEmbossType prev_emboss = layout->emboss;
1241  if (flag & UI_ITEM_R_NO_BG) {
1242  layout->emboss = UI_EMBOSS_NONE_OR_STATUS;
1243  }
1244 
1245  /* create the button */
1246  uiBut *but;
1247  if (icon) {
1248  if (name[0]) {
1249  but = uiDefIconTextButO_ptr(
1250  block, UI_BTYPE_BUT, ot, context, icon, name, 0, 0, w, UI_UNIT_Y, NULL);
1251  }
1252  else {
1253  but = uiDefIconButO_ptr(block, UI_BTYPE_BUT, ot, context, icon, 0, 0, w, UI_UNIT_Y, NULL);
1254  }
1255  }
1256  else {
1257  but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, context, name, 0, 0, w, UI_UNIT_Y, NULL);
1258  }
1259 
1260  BLI_assert(but->optype != NULL);
1261 
1262  if (flag & UI_ITEM_R_NO_BG) {
1263  layout->emboss = prev_emboss;
1264  }
1265 
1266  if (flag & UI_ITEM_O_DEPRESS) {
1267  but->flag |= UI_SELECT_DRAW;
1268  }
1269 
1270  if (flag & UI_ITEM_R_ICON_ONLY) {
1272  }
1273 
1274  if (layout->redalert) {
1276  }
1277 
1278  if (layout->active_default) {
1280  }
1281 
1282  /* assign properties */
1283  if (properties || r_opptr) {
1284  PointerRNA *opptr = UI_but_operator_ptr_get(but);
1285  if (properties) {
1286  opptr->data = properties;
1287  }
1288  else {
1289  const IDPropertyTemplate val = {0};
1290  opptr->data = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
1291  }
1292  if (r_opptr) {
1293  *r_opptr = *opptr;
1294  }
1295  }
1296 
1297  return but;
1298 }
1299 
1300 static void ui_item_menu_hold(struct bContext *C, ARegion *butregion, uiBut *but)
1301 {
1302  uiPopupMenu *pup = UI_popup_menu_begin(C, "", ICON_NONE);
1303  uiLayout *layout = UI_popup_menu_layout(pup);
1304  uiBlock *block = layout->root->block;
1305  UI_popup_menu_but_set(pup, butregion, but);
1306 
1307  block->flag |= UI_BLOCK_POPUP_HOLD;
1308  block->flag |= UI_BLOCK_IS_FLIP;
1309 
1310  char direction = UI_DIR_DOWN;
1311  if (!but->drawstr[0]) {
1312  switch (RGN_ALIGN_ENUM_FROM_MASK(butregion->alignment)) {
1313  case RGN_ALIGN_LEFT:
1314  direction = UI_DIR_RIGHT;
1315  break;
1316  case RGN_ALIGN_RIGHT:
1317  direction = UI_DIR_LEFT;
1318  break;
1319  case RGN_ALIGN_BOTTOM:
1320  direction = UI_DIR_UP;
1321  break;
1322  default:
1323  direction = UI_DIR_DOWN;
1324  break;
1325  }
1326  }
1327  UI_block_direction_set(block, direction);
1328 
1329  const char *menu_id = but->hold_argN;
1330  MenuType *mt = WM_menutype_find(menu_id, true);
1331  if (mt) {
1332  uiLayoutSetContextFromBut(layout, but);
1333  UI_menutype_draw(C, mt, layout);
1334  }
1335  else {
1336  uiItemL(layout, TIP_("Menu Missing:"), ICON_NONE);
1337  uiItemL(layout, menu_id, ICON_NONE);
1338  }
1339  UI_popup_menu_end(C, pup);
1340 }
1341 
1343  wmOperatorType *ot,
1344  const char *name,
1345  int icon,
1346  IDProperty *properties,
1348  int flag,
1349  PointerRNA *r_opptr)
1350 {
1351  uiItemFullO_ptr_ex(layout, ot, name, icon, properties, context, flag, r_opptr);
1352 }
1353 
1355  wmOperatorType *ot,
1356  const char *name,
1357  int icon,
1358  IDProperty *properties,
1360  int flag,
1361  const char *menu_id,
1362  PointerRNA *r_opptr)
1363 {
1364  uiBut *but = uiItemFullO_ptr_ex(layout, ot, name, icon, properties, context, flag, r_opptr);
1366 }
1367 
1368 void uiItemFullO(uiLayout *layout,
1369  const char *opname,
1370  const char *name,
1371  int icon,
1372  IDProperty *properties,
1374  int flag,
1375  PointerRNA *r_opptr)
1376 {
1377  wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1378 
1379  UI_OPERATOR_ERROR_RET(ot, opname, {
1380  if (r_opptr) {
1381  *r_opptr = PointerRNA_NULL;
1382  }
1383  return;
1384  });
1385 
1386  uiItemFullO_ptr(layout, ot, name, icon, properties, context, flag, r_opptr);
1387 }
1388 
1389 static const char *ui_menu_enumpropname(uiLayout *layout,
1390  PointerRNA *ptr,
1391  PropertyRNA *prop,
1392  int retval)
1393 {
1394  bool free;
1395  const EnumPropertyItem *item;
1396  RNA_property_enum_items(layout->root->block->evil_C, ptr, prop, &item, NULL, &free);
1397 
1398  const char *name;
1399  if (RNA_enum_name(item, retval, &name)) {
1400  name = CTX_IFACE_(RNA_property_translation_context(prop), name);
1401  }
1402  else {
1403  name = "";
1404  }
1405 
1406  if (free) {
1407  MEM_freeN((void *)item);
1408  }
1409 
1410  return name;
1411 }
1412 
1414  wmOperatorType *ot,
1415  const char *name,
1416  int icon,
1417  const char *propname,
1418  int value)
1419 {
1420  PointerRNA ptr;
1422 
1423  PropertyRNA *prop = RNA_struct_find_property(&ptr, propname);
1424  if (prop == NULL) {
1425  RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
1426  return;
1427  }
1428 
1429  RNA_property_enum_set(&ptr, prop, value);
1430 
1431  if (!name) {
1432  name = ui_menu_enumpropname(layout, &ptr, prop, value);
1433  }
1434 
1435  uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1436 }
1437 void uiItemEnumO(uiLayout *layout,
1438  const char *opname,
1439  const char *name,
1440  int icon,
1441  const char *propname,
1442  int value)
1443 {
1444  wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1445 
1446  if (ot) {
1447  uiItemEnumO_ptr(layout, ot, name, icon, propname, value);
1448  }
1449  else {
1450  ui_item_disabled(layout, opname);
1451  RNA_warning("unknown operator '%s'", opname);
1452  }
1453 }
1454 
1456 {
1457  return (layout->item.type == ITEM_LAYOUT_RADIAL) ||
1458  ((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU));
1459 }
1460 
1462  wmOperatorType *ot,
1463  PointerRNA ptr,
1464  PropertyRNA *prop,
1465  IDProperty *properties,
1467  int flag,
1468  const EnumPropertyItem *item_array,
1469  int totitem)
1470 {
1471  const char *propname = RNA_property_identifier(prop);
1472  if (RNA_property_type(prop) != PROP_ENUM) {
1473  RNA_warning("%s.%s, not an enum type", RNA_struct_identifier(ptr.type), propname);
1474  return;
1475  }
1476 
1477  uiLayout *target, *split = NULL;
1478  uiBlock *block = layout->root->block;
1479  const bool radial = ui_layout_is_radial(layout);
1480 
1481  if (radial) {
1482  target = uiLayoutRadial(layout);
1483  }
1484  else if ((uiLayoutGetLocalDir(layout) == UI_LAYOUT_HORIZONTAL) && (flag & UI_ITEM_R_ICON_ONLY)) {
1485  target = layout;
1486  UI_block_layout_set_current(block, target);
1487 
1488  /* Add a blank button to the beginning of the row. */
1489  uiDefIconBut(block,
1491  0,
1492  ICON_BLANK1,
1493  0,
1494  0,
1495  1.25f * UI_UNIT_X,
1496  UI_UNIT_Y,
1497  NULL,
1498  0,
1499  0,
1500  0,
1501  0,
1502  NULL);
1503  }
1504  else {
1505  split = uiLayoutSplit(layout, 0.0f, false);
1506  target = uiLayoutColumn(split, layout->align);
1507  }
1508 
1509  bool last_iter = false;
1510  const EnumPropertyItem *item = item_array;
1511  for (int i = 1; item->identifier && !last_iter; i++, item++) {
1512  /* handle oversized pies */
1513  if (radial && (totitem > PIE_MAX_ITEMS) && (i >= PIE_MAX_ITEMS)) {
1514  if (item->name) { /* only visible items */
1515  const EnumPropertyItem *tmp;
1516 
1517  /* Check if there are more visible items for the next level. If not, we don't
1518  * add a new level and add the remaining item instead of the 'more' button. */
1519  for (tmp = item + 1; tmp->identifier; tmp++) {
1520  if (tmp->name) {
1521  break;
1522  }
1523  }
1524 
1525  if (tmp->identifier) { /* only true if loop above found item and did early-exit */
1527  block, ot, propname, properties, item_array, totitem, context, flag);
1528  /* break since rest of items is handled in new pie level */
1529  break;
1530  }
1531  last_iter = true;
1532  }
1533  else {
1534  continue;
1535  }
1536  }
1537 
1538  if (item->identifier[0]) {
1539  PointerRNA tptr;
1541  if (properties) {
1542  if (tptr.data) {
1543  IDP_FreeProperty(tptr.data);
1544  }
1545  tptr.data = IDP_CopyProperty(properties);
1546  }
1547  RNA_property_enum_set(&tptr, prop, item->value);
1548 
1549  uiItemFullO_ptr(target,
1550  ot,
1551  (flag & UI_ITEM_R_ICON_ONLY) ? NULL : item->name,
1552  item->icon,
1553  tptr.data,
1554  context,
1555  flag,
1556  NULL);
1557 
1558  ui_but_tip_from_enum_item(block->buttons.last, item);
1559  }
1560  else {
1561  if (item->name) {
1562  if (item != item_array && !radial && split != NULL) {
1563  target = uiLayoutColumn(split, layout->align);
1564 
1565  /* inconsistent, but menus with labels do not look good flipped */
1566  block->flag |= UI_BLOCK_NO_FLIP;
1567  }
1568 
1569  uiBut *but;
1570  if (item->icon || radial) {
1571  uiItemL(target, item->name, item->icon);
1572 
1573  but = block->buttons.last;
1574  }
1575  else {
1576  /* Do not use uiItemL here, as our root layout is a menu one,
1577  * it will add a fake blank icon! */
1578  but = uiDefBut(block,
1580  0,
1581  item->name,
1582  0,
1583  0,
1584  UI_UNIT_X * 5,
1585  UI_UNIT_Y,
1586  NULL,
1587  0.0,
1588  0.0,
1589  0,
1590  0,
1591  "");
1592  uiItemS(target);
1593  }
1594  ui_but_tip_from_enum_item(but, item);
1595  }
1596  else {
1597  if (radial) {
1598  /* invisible dummy button to ensure all items are
1599  * always at the same position */
1600  uiItemS(target);
1601  }
1602  else {
1603  /* XXX bug here, columns draw bottom item badly */
1604  uiItemS(target);
1605  }
1606  }
1607  }
1608  }
1609 }
1610 
1612  const char *opname,
1613  const char *propname,
1614  IDProperty *properties,
1616  int flag)
1617 {
1618  wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1619 
1620  if (!ot || !ot->srna) {
1621  ui_item_disabled(layout, opname);
1622  RNA_warning("%s '%s'", ot ? "unknown operator" : "operator missing srna", opname);
1623  return;
1624  }
1625 
1626  PointerRNA ptr;
1628  /* so the context is passed to itemf functions (some need it) */
1630  PropertyRNA *prop = RNA_struct_find_property(&ptr, propname);
1631 
1632  /* don't let bad properties slip through */
1633  BLI_assert((prop == NULL) || (RNA_property_type(prop) == PROP_ENUM));
1634 
1635  uiBlock *block = layout->root->block;
1636  if (prop && RNA_property_type(prop) == PROP_ENUM) {
1637  const EnumPropertyItem *item_array = NULL;
1638  int totitem;
1639  bool free;
1640 
1641  if (ui_layout_is_radial(layout)) {
1642  /* XXX: While "_all()" guarantees spatial stability,
1643  * it's bad when an enum has > 8 items total,
1644  * but only a small subset will ever be shown at once
1645  * (e.g. Mode Switch menu, after the introduction of GP editing modes).
1646  */
1647 #if 0
1649  block->evil_C, &ptr, prop, &item_array, &totitem, &free);
1650 #else
1651  RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
1652 #endif
1653  }
1654  else {
1655  RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
1656  }
1657 
1658  /* add items */
1659  uiItemsFullEnumO_items(layout, ot, ptr, prop, properties, context, flag, item_array, totitem);
1660 
1661  if (free) {
1662  MEM_freeN((void *)item_array);
1663  }
1664 
1665  /* intentionally don't touch UI_BLOCK_IS_FLIP here,
1666  * we don't know the context this is called in */
1667  }
1668  else if (prop && RNA_property_type(prop) != PROP_ENUM) {
1669  RNA_warning("%s.%s, not an enum type", RNA_struct_identifier(ptr.type), propname);
1670  return;
1671  }
1672  else {
1673  RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
1674  return;
1675  }
1676 }
1677 
1678 void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
1679 {
1680  uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0);
1681 }
1682 
1684  const char *name,
1685  int icon,
1686  const char *opname,
1687  const char *propname,
1688  int value)
1689 {
1690  wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1691  UI_OPERATOR_ERROR_RET(ot, opname, return );
1692 
1693  PointerRNA ptr;
1695 
1696  /* enum lookup */
1697  PropertyRNA *prop = RNA_struct_find_property(&ptr, propname);
1698  if (prop == NULL) {
1699  RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
1700  return;
1701  }
1702 
1703  RNA_property_enum_set(&ptr, prop, value);
1704 
1705  /* same as uiItemEnumO */
1706  if (!name) {
1707  name = ui_menu_enumpropname(layout, &ptr, prop, value);
1708  }
1709 
1710  uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1711 }
1712 
1714  const char *name,
1715  int icon,
1716  const char *opname,
1717  const char *propname,
1718  const char *value_str)
1719 {
1720  wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1721  UI_OPERATOR_ERROR_RET(ot, opname, return );
1722 
1723  PointerRNA ptr;
1725 
1726  PropertyRNA *prop = RNA_struct_find_property(&ptr, propname);
1727  if (prop == NULL) {
1728  RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
1729  return;
1730  }
1731 
1732  /* enum lookup */
1733  /* no need for translations here */
1734  const EnumPropertyItem *item;
1735  bool free;
1736  RNA_property_enum_items(layout->root->block->evil_C, &ptr, prop, &item, NULL, &free);
1737 
1738  int value;
1739  if (item == NULL || RNA_enum_value_from_id(item, value_str, &value) == 0) {
1740  if (free) {
1741  MEM_freeN((void *)item);
1742  }
1743  RNA_warning("%s.%s, enum %s not found", RNA_struct_identifier(ptr.type), propname, value_str);
1744  return;
1745  }
1746 
1747  if (free) {
1748  MEM_freeN((void *)item);
1749  }
1750 
1751  RNA_property_enum_set(&ptr, prop, value);
1752 
1753  /* same as uiItemEnumO */
1754  if (!name) {
1755  name = ui_menu_enumpropname(layout, &ptr, prop, value);
1756  }
1757 
1758  uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1759 }
1760 
1762  const char *name,
1763  int icon,
1764  const char *opname,
1765  const char *propname,
1766  int value)
1767 {
1768  wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1769  UI_OPERATOR_ERROR_RET(ot, opname, return );
1770 
1771  PointerRNA ptr;
1773  RNA_boolean_set(&ptr, propname, value);
1774 
1775  uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1776 }
1777 
1778 void uiItemIntO(uiLayout *layout,
1779  const char *name,
1780  int icon,
1781  const char *opname,
1782  const char *propname,
1783  int value)
1784 {
1785  wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1786  UI_OPERATOR_ERROR_RET(ot, opname, return );
1787 
1788  PointerRNA ptr;
1790  RNA_int_set(&ptr, propname, value);
1791 
1792  uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1793 }
1794 
1795 void uiItemFloatO(uiLayout *layout,
1796  const char *name,
1797  int icon,
1798  const char *opname,
1799  const char *propname,
1800  float value)
1801 {
1802  wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1803 
1804  UI_OPERATOR_ERROR_RET(ot, opname, return );
1805 
1806  PointerRNA ptr;
1808  RNA_float_set(&ptr, propname, value);
1809 
1810  uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1811 }
1812 
1814  const char *name,
1815  int icon,
1816  const char *opname,
1817  const char *propname,
1818  const char *value)
1819 {
1820  wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1821 
1822  UI_OPERATOR_ERROR_RET(ot, opname, return );
1823 
1824  PointerRNA ptr;
1826  RNA_string_set(&ptr, propname, value);
1827 
1828  uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1829 }
1830 
1831 void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
1832 {
1833  uiItemFullO(layout, opname, name, icon, NULL, layout->root->opcontext, 0, NULL);
1834 }
1835 
1836 /* RNA property items */
1837 
1838 static void ui_item_rna_size(uiLayout *layout,
1839  const char *name,
1840  int icon,
1841  PointerRNA *ptr,
1842  PropertyRNA *prop,
1843  int index,
1844  bool icon_only,
1845  bool compact,
1846  int *r_w,
1847  int *r_h)
1848 {
1849  int w = 0, h;
1850 
1851  /* arbitrary extended width by type */
1852  const PropertyType type = RNA_property_type(prop);
1853  const PropertySubType subtype = RNA_property_subtype(prop);
1854  const int len = RNA_property_array_length(ptr, prop);
1855 
1856  bool is_checkbox_only = false;
1857  if (!name[0] && !icon_only) {
1858  if (ELEM(type, PROP_STRING, PROP_POINTER)) {
1859  name = "non-empty text";
1860  }
1861  else if (type == PROP_BOOLEAN) {
1862  if (icon == ICON_NONE) {
1863  /* Exception for check-boxes, they need a little less space to align nicely. */
1864  is_checkbox_only = true;
1865  }
1866  icon = ICON_DOT;
1867  }
1868  else if (type == PROP_ENUM) {
1869  /* Find the longest enum item name, instead of using a dummy text! */
1870  const EnumPropertyItem *item_array;
1871  bool free;
1873  layout->root->block->evil_C, ptr, prop, &item_array, NULL, &free);
1874 
1875  for (const EnumPropertyItem *item = item_array; item->identifier; item++) {
1876  if (item->identifier[0]) {
1877  w = max_ii(w, ui_text_icon_width(layout, item->name, item->icon, compact));
1878  }
1879  }
1880  if (free) {
1881  MEM_freeN((void *)item_array);
1882  }
1883  }
1884  }
1885 
1886  if (!w) {
1887  if (type == PROP_ENUM && icon_only) {
1888  w = ui_text_icon_width(layout, "", ICON_BLANK1, compact);
1889  if (index != RNA_ENUM_VALUE) {
1890  w += 0.6f * UI_UNIT_X;
1891  }
1892  }
1893  else {
1894  /* not compact for float/int buttons, looks too squashed */
1896  layout, name, icon, ELEM(type, PROP_FLOAT, PROP_INT) ? false : compact);
1897  }
1898  }
1899  h = UI_UNIT_Y;
1900 
1901  /* increase height for arrays */
1902  if (index == RNA_NO_INDEX && len > 0) {
1903  if (!name[0] && icon == ICON_NONE) {
1904  h = 0;
1905  }
1906  if (layout->item.flag & UI_ITEM_PROP_SEP) {
1907  h = 0;
1908  }
1909  if (ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
1910  h += 2 * UI_UNIT_Y;
1911  }
1912  else if (subtype == PROP_MATRIX) {
1913  h += ceilf(sqrtf(len)) * UI_UNIT_Y;
1914  }
1915  else {
1916  h += len * UI_UNIT_Y;
1917  }
1918  }
1919 
1920  /* Increase width requirement if in a variable size layout. */
1921  if (ui_layout_variable_size(layout)) {
1922  if (type == PROP_BOOLEAN && name[0]) {
1923  w += UI_UNIT_X / 5;
1924  }
1925  else if (is_checkbox_only) {
1926  w -= UI_UNIT_X / 4;
1927  }
1928  else if (type == PROP_ENUM && !icon_only) {
1929  w += UI_UNIT_X / 4;
1930  }
1931  else if (ELEM(type, PROP_FLOAT, PROP_INT)) {
1932  w += UI_UNIT_X * 3;
1933  }
1934  }
1935 
1936  *r_w = w;
1937  *r_h = h;
1938 }
1939 
1940 static bool ui_item_rna_is_expand(PropertyRNA *prop, int index, int item_flag)
1941 {
1942  const bool is_array = RNA_property_array_check(prop);
1943  const int subtype = RNA_property_subtype(prop);
1944  return is_array && (index == RNA_NO_INDEX) &&
1945  ((item_flag & UI_ITEM_R_EXPAND) ||
1947 }
1948 
1957 {
1958  for (uiLayout *parent = cur_layout; parent; parent = parent->parent) {
1959  if (parent->heading[0]) {
1960  return parent;
1961  }
1962  }
1963 
1964  return NULL;
1965 }
1966 
1968  uiLayout *heading_layout,
1969  bool right_align,
1970  bool respect_prop_split)
1971 {
1972  const int prev_alignment = layout->alignment;
1973 
1974  if (right_align) {
1976  }
1977 
1978  if (respect_prop_split) {
1979  uiItemL_respect_property_split(layout, heading_layout->heading, ICON_NONE);
1980  }
1981  else {
1982  uiItemL(layout, heading_layout->heading, ICON_NONE);
1983  }
1984  /* After adding the heading label, we have to mark it somehow as added, so it's not added again
1985  * for other items in this layout. For now just clear it. */
1986  heading_layout->heading[0] = '\0';
1987 
1988  layout->alignment = prev_alignment;
1989 }
1990 
1996 static uiLayout *ui_item_prop_split_layout_hack(uiLayout *layout_parent, uiLayout *layout_split)
1997 {
1998  /* Tag item as using property split layout, this is inherited to children so they can get special
1999  * treatment if needed. */
2000  layout_parent->item.flag |= UI_ITEM_INSIDE_PROP_SEP;
2001 
2002  if (layout_parent->item.type == ITEM_LAYOUT_ROW) {
2003  /* Prevent further splits within the row. */
2004  uiLayoutSetPropSep(layout_parent, false);
2005 
2006  layout_parent->child_items_layout = uiLayoutRow(layout_split, true);
2007  return layout_parent->child_items_layout;
2008  }
2009  return layout_split;
2010 }
2011 
2012 void uiItemFullR(uiLayout *layout,
2013  PointerRNA *ptr,
2014  PropertyRNA *prop,
2015  int index,
2016  int value,
2017  int flag,
2018  const char *name,
2019  int icon)
2020 {
2021  uiBlock *block = layout->root->block;
2022  char namestr[UI_MAX_NAME_STR];
2023  const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
2024  const bool inside_prop_sep = ((layout->item.flag & UI_ITEM_INSIDE_PROP_SEP) != 0);
2025  /* Columns can define a heading to insert. If the first item added to a split layout doesn't have
2026  * a label to display in the first column, the heading is inserted there. Otherwise it's inserted
2027  * as a new row before the first item. */
2028  uiLayout *heading_layout = ui_layout_heading_find(layout);
2029  /* Although check-boxes use the split layout, they are an exception and should only place their
2030  * label in the second column, to not make that almost empty.
2031  *
2032  * Keep using 'use_prop_sep' instead of disabling it entirely because
2033  * we need the ability to have decorators still. */
2034  bool use_prop_sep_split_label = use_prop_sep;
2035  bool use_split_empty_name = (flag & UI_ITEM_R_SPLIT_EMPTY_NAME);
2036 
2037 #ifdef UI_PROP_DECORATE
2038  struct {
2039  bool use_prop_decorate;
2040  int len;
2041  uiLayout *layout;
2042  uiBut *but;
2043  } ui_decorate = {
2044  .use_prop_decorate = (((layout->item.flag & UI_ITEM_PROP_DECORATE) != 0) && use_prop_sep),
2045  };
2046 #endif /* UI_PROP_DECORATE */
2047 
2048  UI_block_layout_set_current(block, layout);
2049  ui_block_new_button_group(block, 0);
2050 
2051  /* retrieve info */
2052  const PropertyType type = RNA_property_type(prop);
2053  const bool is_array = RNA_property_array_check(prop);
2054  const int len = (is_array) ? RNA_property_array_length(ptr, prop) : 0;
2055 
2056  const bool icon_only = (flag & UI_ITEM_R_ICON_ONLY) != 0;
2057 
2058  /* Boolean with -1 to signify that the value depends on the presence of an icon. */
2059  const int toggle = ((flag & UI_ITEM_R_TOGGLE) ? 1 : ((flag & UI_ITEM_R_ICON_NEVER) ? 0 : -1));
2060  const bool no_icon = (toggle == 0);
2061 
2062  /* set name and icon */
2063  if (!name) {
2064  if (!icon_only) {
2065  name = RNA_property_ui_name(prop);
2066  }
2067  else {
2068  name = "";
2069  }
2070  }
2071 
2072  if (type != PROP_BOOLEAN) {
2073  flag &= ~UI_ITEM_R_CHECKBOX_INVERT;
2074  }
2075 
2076  if (flag & UI_ITEM_R_ICON_ONLY) {
2077  /* pass */
2078  }
2080  if (use_prop_sep == false) {
2081  name = ui_item_name_add_colon(name, namestr);
2082  }
2083  }
2084  else if (type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX) {
2085  if (use_prop_sep == false) {
2086  name = ui_item_name_add_colon(name, namestr);
2087  }
2088  }
2089  else if (type == PROP_ENUM && index != RNA_ENUM_VALUE) {
2090  if (flag & UI_ITEM_R_COMPACT) {
2091  name = "";
2092  }
2093  else {
2094  if (use_prop_sep == false) {
2095  name = ui_item_name_add_colon(name, namestr);
2096  }
2097  }
2098  }
2099 
2100  if (no_icon == false) {
2101  if (icon == ICON_NONE) {
2102  icon = RNA_property_ui_icon(prop);
2103  }
2104 
2105  /* Menus and pie-menus don't show checkbox without this. */
2106  if ((layout->root->type == UI_LAYOUT_MENU) ||
2107  /* Use check-boxes only as a fallback in pie-menu's, when no icon is defined. */
2108  ((layout->root->type == UI_LAYOUT_PIEMENU) && (icon == ICON_NONE))) {
2109  const int prop_flag = RNA_property_flag(prop);
2110  if (type == PROP_BOOLEAN) {
2111  if ((is_array == false) || (index != RNA_NO_INDEX)) {
2112  if (prop_flag & PROP_ICONS_CONSECUTIVE) {
2113  icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */
2114  }
2115  else if (is_array) {
2116  icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT :
2117  ICON_CHECKBOX_DEHLT;
2118  }
2119  else {
2120  icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
2121  }
2122  }
2123  }
2124  else if (type == PROP_ENUM) {
2125  if (index == RNA_ENUM_VALUE) {
2126  const int enum_value = RNA_property_enum_get(ptr, prop);
2127  if (prop_flag & PROP_ICONS_CONSECUTIVE) {
2128  icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */
2129  }
2130  else if (prop_flag & PROP_ENUM_FLAG) {
2131  icon = (enum_value & value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
2132  }
2133  else {
2134  icon = (enum_value == value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
2135  }
2136  }
2137  }
2138  }
2139  }
2140 
2141 #ifdef UI_PROP_SEP_ICON_WIDTH_EXCEPTION
2142  if (use_prop_sep) {
2143  if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) {
2144  use_prop_sep_split_label = false;
2145  /* For check-boxes we make an exception: We allow showing them in a split row even without
2146  * label. It typically relates to its neighbor items, so no need for an extra label. */
2147  use_split_empty_name = true;
2148  }
2149  }
2150 #endif
2151 
2152  if ((type == PROP_ENUM) && (RNA_property_flag(prop) & PROP_ENUM_FLAG)) {
2153  flag |= UI_ITEM_R_EXPAND;
2154  }
2155 
2156  const bool slider = (flag & UI_ITEM_R_SLIDER) != 0;
2157  const bool expand = (flag & UI_ITEM_R_EXPAND) != 0;
2158  const bool no_bg = (flag & UI_ITEM_R_NO_BG) != 0;
2159  const bool compact = (flag & UI_ITEM_R_COMPACT) != 0;
2160 
2161  /* get size */
2162  int w, h;
2163  ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, compact, &w, &h);
2164 
2165  const eUIEmbossType prev_emboss = layout->emboss;
2166  if (no_bg) {
2167  layout->emboss = UI_EMBOSS_NONE_OR_STATUS;
2168  }
2169 
2170  uiBut *but = NULL;
2171 
2172  /* Split the label / property. */
2173  uiLayout *layout_parent = layout;
2174 
2175  if (use_prop_sep) {
2176  uiLayout *layout_row = NULL;
2177 #ifdef UI_PROP_DECORATE
2178  if (ui_decorate.use_prop_decorate) {
2179  layout_row = uiLayoutRow(layout, true);
2180  layout_row->space = 0;
2181  ui_decorate.len = max_ii(1, len);
2182  }
2183 #endif /* UI_PROP_DECORATE */
2184 
2185  if ((name[0] == '\0') && !use_split_empty_name) {
2186  /* Ensure we get a column when text is not set. */
2187  layout = uiLayoutColumn(layout_row ? layout_row : layout, true);
2188  layout->space = 0;
2189  if (heading_layout) {
2190  ui_layout_heading_label_add(layout, heading_layout, false, false);
2191  }
2192  }
2193  else {
2194  uiLayout *layout_split = uiLayoutSplit(
2195  layout_row ? layout_row : layout, UI_ITEM_PROP_SEP_DIVIDE, true);
2196  bool label_added = false;
2197  uiLayout *layout_sub = uiLayoutColumn(layout_split, true);
2198  layout_sub->space = 0;
2199 
2200  if (!use_prop_sep_split_label) {
2201  /* Pass */
2202  }
2203  else if (ui_item_rna_is_expand(prop, index, flag)) {
2204  char name_with_suffix[UI_MAX_DRAW_STR + 2];
2205  char str[2] = {'\0'};
2206  for (int a = 0; a < len; a++) {
2207  str[0] = RNA_property_array_item_char(prop, a);
2208  const bool use_prefix = (a == 0 && name && name[0]);
2209  if (use_prefix) {
2210  char *s = name_with_suffix;
2211  s += STRNCPY_RLEN(name_with_suffix, name);
2212  *s++ = ' ';
2213  *s++ = str[0];
2214  *s++ = '\0';
2215  }
2216  but = uiDefBut(block,
2218  0,
2219  use_prefix ? name_with_suffix : str,
2220  0,
2221  0,
2222  w,
2223  UI_UNIT_Y,
2224  NULL,
2225  0.0,
2226  0.0,
2227  0,
2228  0,
2229  "");
2230  but->drawflag |= UI_BUT_TEXT_RIGHT;
2231  but->drawflag &= ~UI_BUT_TEXT_LEFT;
2232 
2233  label_added = true;
2234  }
2235  }
2236  else {
2237  if (name) {
2238  but = uiDefBut(
2239  block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
2240  but->drawflag |= UI_BUT_TEXT_RIGHT;
2241  but->drawflag &= ~UI_BUT_TEXT_LEFT;
2242 
2243  label_added = true;
2244  }
2245  }
2246 
2247  if (!label_added && heading_layout) {
2248  ui_layout_heading_label_add(layout_sub, heading_layout, true, false);
2249  }
2250 
2251  layout_split = ui_item_prop_split_layout_hack(layout_parent, layout_split);
2252 
2253  /* Watch out! We can only write into the new layout now. */
2254  if ((type == PROP_ENUM) && (flag & UI_ITEM_R_EXPAND)) {
2255  /* Expanded enums each have their own name. */
2256 
2257  /* Often expanded enum's are better arranged into a row,
2258  * so check the existing layout. */
2259  if (uiLayoutGetLocalDir(layout) == UI_LAYOUT_HORIZONTAL) {
2260  layout = uiLayoutRow(layout_split, true);
2261  }
2262  else {
2263  layout = uiLayoutColumn(layout_split, true);
2264  }
2265  }
2266  else {
2267  if (use_prop_sep_split_label) {
2268  name = "";
2269  }
2270  layout = uiLayoutColumn(layout_split, true);
2271  }
2272  layout->space = 0;
2273  }
2274 
2275 #ifdef UI_PROP_DECORATE
2276  if (ui_decorate.use_prop_decorate) {
2277  ui_decorate.layout = uiLayoutColumn(layout_row, true);
2278  ui_decorate.layout->space = 0;
2279  UI_block_layout_set_current(block, layout);
2280  ui_decorate.but = block->buttons.last;
2281 
2282  /* Clear after. */
2284  }
2285 #endif /* UI_PROP_DECORATE */
2286  }
2287  /* End split. */
2288  else if (heading_layout) {
2289  /* Could not add heading to split layout, fallback to inserting it to the layout with the
2290  * heading itself. */
2291  ui_layout_heading_label_add(heading_layout, heading_layout, false, false);
2292  }
2293 
2294  /* array property */
2295  if (index == RNA_NO_INDEX && is_array) {
2296  if (inside_prop_sep) {
2297  /* Within a split row, add array items to a column so they match the column layout of
2298  * previous items (e.g. transform vector with lock icon for each item). */
2299  layout = uiLayoutColumn(layout, true);
2300  }
2301 
2302  ui_item_array(layout,
2303  block,
2304  name,
2305  icon,
2306  ptr,
2307  prop,
2308  len,
2309  0,
2310  0,
2311  w,
2312  h,
2313  expand,
2314  slider,
2315  toggle,
2316  icon_only,
2317  compact,
2318  !use_prop_sep_split_label);
2319  }
2320  /* enum item */
2321  else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
2322  if (icon && name[0] && !icon_only) {
2324  block, UI_BTYPE_ROW, 0, icon, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
2325  }
2326  else if (icon) {
2328  block, UI_BTYPE_ROW, 0, icon, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
2329  }
2330  else {
2332  block, UI_BTYPE_ROW, 0, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
2333  }
2334  }
2335  /* expanded enum */
2336  else if (type == PROP_ENUM && expand) {
2337  ui_item_enum_expand(layout, block, ptr, prop, name, h, icon_only);
2338  }
2339  /* property with separate label */
2340  else if (ELEM(type, PROP_ENUM, PROP_STRING, PROP_POINTER)) {
2341  but = ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag);
2342  bool results_are_suggestions = false;
2343  if (type == PROP_STRING) {
2345  if (search_flag & PROP_STRING_SEARCH_SUGGESTION) {
2346  results_are_suggestions = true;
2347  }
2348  }
2349  but = ui_but_add_search(but, ptr, prop, NULL, NULL, results_are_suggestions);
2350 
2351  if (layout->redalert) {
2353  }
2354 
2355  if (layout->activate_init) {
2357  }
2358  }
2359  /* single button */
2360  else {
2361  but = uiDefAutoButR(block, ptr, prop, index, name, icon, 0, 0, w, h);
2362 
2363  if (slider && but->type == UI_BTYPE_NUM) {
2364  uiButNumber *num_but = (uiButNumber *)but;
2365 
2366  but->a1 = num_but->step_size;
2368  }
2369 
2370  if (flag & UI_ITEM_R_CHECKBOX_INVERT) {
2371  if (ELEM(but->type,
2377  }
2378  }
2379 
2380  if ((toggle == 1) && but->type == UI_BTYPE_CHECKBOX) {
2381  but->type = UI_BTYPE_TOGGLE;
2382  }
2383 
2384  if (layout->redalert) {
2386  }
2387 
2388  if (layout->activate_init) {
2390  }
2391  }
2392 
2393  /* The resulting button may have the icon set since boolean button drawing
2394  * is being 'helpful' and adding an icon for us.
2395  * In this case we want the ability not to have an icon.
2396  *
2397  * We could pass an argument not to set the icon to begin with however this is the one case
2398  * the functionality is needed. */
2399  if (but && no_icon) {
2400  if ((icon == ICON_NONE) && (but->icon != ICON_NONE)) {
2401  ui_def_but_icon_clear(but);
2402  }
2403  }
2404 
2405  /* Mark non-embossed text-fields inside a list-box. */
2406  if (but && (block->flag & UI_BLOCK_LIST_ITEM) && (but->type == UI_BTYPE_TEXT) &&
2409  }
2410 
2411 #ifdef UI_PROP_DECORATE
2412  if (ui_decorate.use_prop_decorate) {
2413  uiBut *but_decorate = ui_decorate.but ? ui_decorate.but->next : block->buttons.first;
2414  const bool use_blank_decorator = (flag & UI_ITEM_R_FORCE_BLANK_DECORATE);
2415  uiLayout *layout_col = uiLayoutColumn(ui_decorate.layout, false);
2416  layout_col->space = 0;
2417  layout_col->emboss = UI_EMBOSS_NONE;
2418 
2419  int i;
2420  for (i = 0; i < ui_decorate.len && but_decorate; i++) {
2421  PointerRNA *ptr_dec = use_blank_decorator ? NULL : &but_decorate->rnapoin;
2422  PropertyRNA *prop_dec = use_blank_decorator ? NULL : but_decorate->rnaprop;
2423 
2424  /* The icons are set in 'ui_but_anim_flag' */
2425  uiItemDecoratorR_prop(layout_col, ptr_dec, prop_dec, but_decorate->rnaindex);
2426  but = block->buttons.last;
2427 
2428  /* Order the decorator after the button we decorate, this is used so we can always
2429  * do a quick lookup. */
2430  BLI_remlink(&block->buttons, but);
2431  BLI_insertlinkafter(&block->buttons, but_decorate, but);
2432  but_decorate = but->next;
2433  }
2434  BLI_assert(ELEM(i, 1, ui_decorate.len));
2435 
2437  }
2438 #endif /* UI_PROP_DECORATE */
2439 
2440  if (no_bg) {
2441  layout->emboss = prev_emboss;
2442  }
2443 
2444  /* ensure text isn't added to icon_only buttons */
2445  if (but && icon_only) {
2446  BLI_assert(but->str[0] == '\0');
2447  }
2448 }
2449 
2450 void uiItemR(
2451  uiLayout *layout, PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
2452 {
2453  PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
2454 
2455  if (!prop) {
2456  ui_item_disabled(layout, propname);
2457  RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2458  return;
2459  }
2460 
2461  uiItemFullR(layout, ptr, prop, RNA_NO_INDEX, 0, flag, name, icon);
2462 }
2463 
2465  PointerRNA *ptr,
2466  PropertyRNA *prop,
2467  int index,
2468  int value,
2469  int flag,
2470  const char *name,
2471  int icon,
2472  const char *panel_type)
2473 {
2474  uiBlock *block = layout->root->block;
2475  uiBut *but = block->buttons.last;
2476  uiItemFullR(layout, ptr, prop, index, value, flag, name, icon);
2477  but = but->next;
2478  while (but) {
2479  if (but->rnaprop == prop && ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_COLOR)) {
2480  ui_but_rna_menu_convert_to_panel_type(but, panel_type);
2481  break;
2482  }
2483  but = but->next;
2484  }
2485  if (but == NULL) {
2486  const char *propname = RNA_property_identifier(prop);
2487  ui_item_disabled(layout, panel_type);
2488  RNA_warning("property could not use a popover: %s.%s (%s)",
2490  propname,
2491  panel_type);
2492  }
2493 }
2494 
2496  PointerRNA *ptr,
2497  PropertyRNA *prop,
2498  int index,
2499  int value,
2500  int flag,
2501  const char *name,
2502  int icon,
2503  const char *menu_type)
2504 {
2505  uiBlock *block = layout->root->block;
2506  uiBut *but = block->buttons.last;
2507  uiItemFullR(layout, ptr, prop, index, value, flag, name, icon);
2508  but = but->next;
2509  while (but) {
2510  if (but->rnaprop == prop && but->type == UI_BTYPE_MENU) {
2511  ui_but_rna_menu_convert_to_menu_type(but, menu_type);
2512  break;
2513  }
2514  but = but->next;
2515  }
2516  if (but == NULL) {
2517  const char *propname = RNA_property_identifier(prop);
2518  ui_item_disabled(layout, menu_type);
2519  RNA_warning("property could not use a menu: %s.%s (%s)",
2521  propname,
2522  menu_type);
2523  }
2524 }
2525 
2527  const char *name,
2528  int icon,
2529  struct PointerRNA *ptr,
2530  PropertyRNA *prop,
2531  int value)
2532 {
2533  if (RNA_property_type(prop) != PROP_ENUM) {
2534  const char *propname = RNA_property_identifier(prop);
2535  ui_item_disabled(layout, propname);
2536  RNA_warning("property not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname);
2537  return;
2538  }
2539 
2540  uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, value, 0, name, icon);
2541 }
2542 
2543 void uiItemEnumR(uiLayout *layout,
2544  const char *name,
2545  int icon,
2546  struct PointerRNA *ptr,
2547  const char *propname,
2548  int value)
2549 {
2550  PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
2551 
2552  if (prop == NULL) {
2553  ui_item_disabled(layout, propname);
2554  RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2555  return;
2556  }
2557 
2558  uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, value, 0, name, icon);
2559 }
2560 
2562  struct PointerRNA *ptr,
2563  PropertyRNA *prop,
2564  const char *value,
2565  const char *name,
2566  int icon)
2567 {
2568  if (UNLIKELY(RNA_property_type(prop) != PROP_ENUM)) {
2569  const char *propname = RNA_property_identifier(prop);
2570  ui_item_disabled(layout, propname);
2571  RNA_warning("not an enum property: %s.%s", RNA_struct_identifier(ptr->type), propname);
2572  return;
2573  }
2574 
2575  const EnumPropertyItem *item;
2576  bool free;
2577  RNA_property_enum_items(layout->root->block->evil_C, ptr, prop, &item, NULL, &free);
2578 
2579  int ivalue;
2580  if (!RNA_enum_value_from_id(item, value, &ivalue)) {
2581  const char *propname = RNA_property_identifier(prop);
2582  if (free) {
2583  MEM_freeN((void *)item);
2584  }
2585  ui_item_disabled(layout, propname);
2586  RNA_warning("enum property value not found: %s", value);
2587  return;
2588  }
2589 
2590  for (int a = 0; item[a].identifier; a++) {
2591  if (item[a].identifier[0] == '\0') {
2592  /* Skip enum item separators. */
2593  continue;
2594  }
2595  if (item[a].value == ivalue) {
2596  const char *item_name = name ?
2597  name :
2598  CTX_IFACE_(RNA_property_translation_context(prop), item[a].name);
2599  const int flag = item_name[0] ? 0 : UI_ITEM_R_ICON_ONLY;
2600 
2601  uiItemFullR(
2602  layout, ptr, prop, RNA_ENUM_VALUE, ivalue, flag, item_name, icon ? icon : item[a].icon);
2603  break;
2604  }
2605  }
2606 
2607  if (free) {
2608  MEM_freeN((void *)item);
2609  }
2610 }
2611 
2613  struct PointerRNA *ptr,
2614  const char *propname,
2615  const char *value,
2616  const char *name,
2617  int icon)
2618 {
2619  PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
2620  if (UNLIKELY(prop == NULL)) {
2621  ui_item_disabled(layout, propname);
2622  RNA_warning("enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2623  return;
2624  }
2625  uiItemEnumR_string_prop(layout, ptr, prop, value, name, icon);
2626 }
2627 
2628 void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname)
2629 {
2630  uiBlock *block = layout->root->block;
2631 
2632  PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
2633 
2634  if (!prop) {
2635  ui_item_disabled(layout, propname);
2636  RNA_warning("enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2637  return;
2638  }
2639 
2640  if (RNA_property_type(prop) != PROP_ENUM) {
2641  RNA_warning("not an enum property: %s.%s", RNA_struct_identifier(ptr->type), propname);
2642  return;
2643  }
2644 
2645  uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
2646  uiLayout *column = uiLayoutColumn(split, false);
2647 
2648  int totitem;
2649  const EnumPropertyItem *item;
2650  bool free;
2651  RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item, &totitem, &free);
2652 
2653  for (int i = 0; i < totitem; i++) {
2654  if (item[i].identifier[0]) {
2655  uiItemEnumR_prop(column, item[i].name, item[i].icon, ptr, prop, item[i].value);
2656  ui_but_tip_from_enum_item(block->buttons.last, &item[i]);
2657  }
2658  else {
2659  if (item[i].name) {
2660  if (i != 0) {
2661  column = uiLayoutColumn(split, false);
2662  /* inconsistent, but menus with labels do not look good flipped */
2663  block->flag |= UI_BLOCK_NO_FLIP;
2664  }
2665 
2666  uiItemL(column, item[i].name, ICON_NONE);
2667  uiBut *bt = block->buttons.last;
2668  bt->drawflag = UI_BUT_TEXT_LEFT;
2669 
2670  ui_but_tip_from_enum_item(bt, &item[i]);
2671  }
2672  else {
2673  uiItemS(column);
2674  }
2675  }
2676  }
2677 
2678  if (free) {
2679  MEM_freeN((void *)item);
2680  }
2681 
2682  /* intentionally don't touch UI_BLOCK_IS_FLIP here,
2683  * we don't know the context this is called in */
2684 }
2685 
2686 /* Pointer RNA button with search */
2687 
2688 static void search_id_collection(StructRNA *ptype, PointerRNA *r_ptr, PropertyRNA **r_prop)
2689 {
2690  /* look for collection property in Main */
2691  /* NOTE: using global Main is OK-ish here, UI shall not access other Mains anyway. */
2693 
2694  *r_prop = NULL;
2695 
2696  RNA_STRUCT_BEGIN (r_ptr, iprop) {
2697  /* if it's a collection and has same pointer type, we've got it */
2698  if (RNA_property_type(iprop) == PROP_COLLECTION) {
2699  StructRNA *srna = RNA_property_pointer_type(r_ptr, iprop);
2700 
2701  if (ptype == srna) {
2702  *r_prop = iprop;
2703  break;
2704  }
2705  }
2706  }
2708 }
2709 
2711 {
2712  uiRNACollectionSearch *coll_search = ptr;
2713  UI_butstore_free(coll_search->butstore_block, coll_search->butstore);
2714  MEM_freeN(ptr);
2715 }
2716 
2718  PointerRNA *ptr,
2719  PropertyRNA *prop,
2720  PointerRNA *searchptr,
2721  PropertyRNA *searchprop,
2722  const bool results_are_suggestions)
2723 {
2724  /* for ID's we do automatic lookup */
2725  bool has_search_fn = false;
2726 
2727  PointerRNA sptr;
2728  if (!searchprop) {
2729  if (RNA_property_type(prop) == PROP_STRING) {
2730  has_search_fn = (RNA_property_string_search_flag(prop) != 0);
2731  }
2732  if (RNA_property_type(prop) == PROP_POINTER) {
2733  StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
2734  search_id_collection(ptype, &sptr, &searchprop);
2735  searchptr = &sptr;
2736  }
2737  }
2738 
2739  /* turn button into search button */
2740  if (has_search_fn || searchprop) {
2741  uiRNACollectionSearch *coll_search = MEM_mallocN(sizeof(*coll_search), __func__);
2742  uiButSearch *search_but;
2743 
2745  search_but = (uiButSearch *)but;
2746 
2747  if (searchptr) {
2748  search_but->rnasearchpoin = *searchptr;
2749  search_but->rnasearchprop = searchprop;
2750  }
2751 
2752  but->hardmax = MAX2(but->hardmax, 256.0f);
2754  if (RNA_property_is_unlink(prop)) {
2755  but->flag |= UI_BUT_VALUE_CLEAR;
2756  }
2757 
2758  coll_search->target_ptr = *ptr;
2759  coll_search->target_prop = prop;
2760 
2761  if (searchptr) {
2762  coll_search->search_ptr = *searchptr;
2763  coll_search->search_prop = searchprop;
2764  }
2765  else {
2766  /* Rely on `has_search_fn`. */
2767  coll_search->search_ptr = PointerRNA_NULL;
2768  coll_search->search_prop = NULL;
2769  }
2770 
2771  coll_search->search_but = but;
2772  coll_search->butstore_block = but->block;
2773  coll_search->butstore = UI_butstore_create(coll_search->butstore_block);
2774  UI_butstore_register(coll_search->butstore, &coll_search->search_but);
2775 
2776  if (RNA_property_type(prop) == PROP_ENUM) {
2777  /* XXX, this will have a menu string,
2778  * but in this case we just want the text */
2779  but->str[0] = 0;
2780  }
2781 
2782  UI_but_func_search_set_results_are_suggestions(but, results_are_suggestions);
2783 
2787  coll_search,
2788  false,
2790  NULL,
2791  NULL);
2792  /* If this is called multiple times for the same button, an earlier call may have taken the
2793  * else branch below so the button was disabled. Now we have a searchprop, so it can be enabled
2794  * again. */
2795  but->flag &= ~UI_BUT_DISABLED;
2796  }
2797  else if (but->type == UI_BTYPE_SEARCH_MENU) {
2798  /* In case we fail to find proper searchprop,
2799  * so other code might have already set but->type to search menu... */
2800  but->flag |= UI_BUT_DISABLED;
2801  }
2802 
2803  return but;
2804 }
2805 
2807  PointerRNA *ptr,
2808  PropertyRNA *prop,
2809  PointerRNA *searchptr,
2810  PropertyRNA *searchprop,
2811  const char *name,
2812  int icon,
2813  bool results_are_suggestions)
2814 {
2815  const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
2816 
2818 
2819  const PropertyType type = RNA_property_type(prop);
2821  RNA_warning("Property %s.%s must be a pointer, string or enum",
2823  RNA_property_identifier(prop));
2824  return;
2825  }
2826  if (RNA_property_type(searchprop) != PROP_COLLECTION) {
2827  RNA_warning("search collection property is not a collection type: %s.%s",
2828  RNA_struct_identifier(searchptr->type),
2829  RNA_property_identifier(searchprop));
2830  return;
2831  }
2832 
2833  /* get icon & name */
2834  if (icon == ICON_NONE) {
2835  StructRNA *icontype;
2836  if (type == PROP_POINTER) {
2837  icontype = RNA_property_pointer_type(ptr, prop);
2838  }
2839  else {
2840  icontype = RNA_property_pointer_type(searchptr, searchprop);
2841  }
2842 
2843  icon = RNA_struct_ui_icon(icontype);
2844  }
2845  if (!name) {
2846  name = RNA_property_ui_name(prop);
2847  }
2848 
2849  char namestr[UI_MAX_NAME_STR];
2850  if (use_prop_sep == false) {
2851  name = ui_item_name_add_colon(name, namestr);
2852  }
2853 
2854  /* create button */
2855  uiBlock *block = uiLayoutGetBlock(layout);
2856 
2857  int w, h;
2858  ui_item_rna_size(layout, name, icon, ptr, prop, 0, 0, false, &w, &h);
2859  w += UI_UNIT_X; /* X icon needs more space */
2860  uiBut *but = ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0);
2861 
2862  but = ui_but_add_search(but, ptr, prop, searchptr, searchprop, results_are_suggestions);
2863 }
2864 
2866  PointerRNA *ptr,
2867  const char *propname,
2868  PointerRNA *searchptr,
2869  const char *searchpropname,
2870  const char *name,
2871  int icon)
2872 {
2873  /* validate arguments */
2874  PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
2875  if (!prop) {
2876  RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2877  return;
2878  }
2879  PropertyRNA *searchprop = RNA_struct_find_property(searchptr, searchpropname);
2880  if (!searchprop) {
2881  RNA_warning("search collection property not found: %s.%s",
2882  RNA_struct_identifier(searchptr->type),
2883  searchpropname);
2884  return;
2885  }
2886 
2887  uiItemPointerR_prop(layout, ptr, prop, searchptr, searchprop, name, icon, false);
2888 }
2889 
2890 void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
2891 {
2892  MenuType *mt = (MenuType *)arg_mt;
2893 
2894  UI_menutype_draw(C, mt, layout);
2895 
2896  /* Menus are created flipped (from event handling point of view). */
2897  layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
2898 }
2899 
2900 void ui_item_paneltype_func(bContext *C, uiLayout *layout, void *arg_pt)
2901 {
2902  PanelType *pt = (PanelType *)arg_pt;
2903  UI_paneltype_draw(C, pt, layout);
2904 
2905  /* Panels are created flipped (from event handling POV). */
2906  layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
2907 }
2908 
2909 static uiBut *ui_item_menu(uiLayout *layout,
2910  const char *name,
2911  int icon,
2912  uiMenuCreateFunc func,
2913  void *arg,
2914  void *argN,
2915  const char *tip,
2916  bool force_menu)
2917 {
2918  uiBlock *block = layout->root->block;
2919  uiLayout *heading_layout = ui_layout_heading_find(layout);
2920 
2921  UI_block_layout_set_current(block, layout);
2922  ui_block_new_button_group(block, 0);
2923 
2924  if (!name) {
2925  name = "";
2926  }
2927  if (layout->root->type == UI_LAYOUT_MENU && !icon) {
2928  icon = ICON_BLANK1;
2929  }
2930 
2931  struct uiTextIconPadFactor pad_factor = ui_text_pad_compact;
2932  if (layout->root->type == UI_LAYOUT_HEADER) { /* Ugly! */
2933  if (icon == ICON_NONE && force_menu) {
2934  /* pass */
2935  }
2936  else if (force_menu) {
2937  pad_factor.text = 1.85;
2938  pad_factor.icon_only = 0.6f;
2939  }
2940  else {
2941  pad_factor.text = 0.75f;
2942  }
2943  }
2944 
2945  const int w = ui_text_icon_width_ex(layout, name, icon, &pad_factor);
2946  const int h = UI_UNIT_Y;
2947 
2948  if (heading_layout) {
2949  ui_layout_heading_label_add(layout, heading_layout, true, true);
2950  }
2951 
2952  uiBut *but;
2953  if (name[0] && icon) {
2954  but = uiDefIconTextMenuBut(block, func, arg, icon, name, 0, 0, w, h, tip);
2955  }
2956  else if (icon) {
2957  but = uiDefIconMenuBut(block, func, arg, icon, 0, 0, w, h, tip);
2958  if (force_menu && name[0]) {
2960  }
2961  }
2962  else {
2963  but = uiDefMenuBut(block, func, arg, name, 0, 0, w, h, tip);
2964  }
2965 
2966  if (argN) {
2967  /* ugly! */
2968  if (arg != argN) {
2969  but->poin = (char *)but;
2970  }
2971  but->func_argN = argN;
2972  }
2973 
2974  if (ELEM(layout->root->type, UI_LAYOUT_PANEL, UI_LAYOUT_TOOLBAR) ||
2975  /* We never want a drop-down in menu! */
2976  (force_menu && layout->root->type != UI_LAYOUT_MENU)) {
2978  }
2979 
2980  return but;
2981 }
2982 
2983 void uiItemM_ptr(uiLayout *layout, MenuType *mt, const char *name, int icon)
2984 {
2985  uiBlock *block = layout->root->block;
2986  bContext *C = block->evil_C;
2987  if (WM_menutype_poll(C, mt) == false) {
2988  return;
2989  }
2990 
2991  if (!name) {
2992  name = CTX_IFACE_(mt->translation_context, mt->label);
2993  }
2994 
2995  if (layout->root->type == UI_LAYOUT_MENU && !icon) {
2996  icon = ICON_BLANK1;
2997  }
2998 
2999  ui_item_menu(layout,
3000  name,
3001  icon,
3003  mt,
3004  NULL,
3005  mt->description ? TIP_(mt->description) : "",
3006  false);
3007 }
3008 
3009 void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon)
3010 {
3011  MenuType *mt = WM_menutype_find(menuname, false);
3012  if (mt == NULL) {
3013  RNA_warning("not found %s", menuname);
3014  return;
3015  }
3016  uiItemM_ptr(layout, mt, name, icon);
3017 }
3018 
3019 void uiItemMContents(uiLayout *layout, const char *menuname)
3020 {
3021  MenuType *mt = WM_menutype_find(menuname, false);
3022  if (mt == NULL) {
3023  RNA_warning("not found %s", menuname);
3024  return;
3025  }
3026 
3027  uiBlock *block = layout->root->block;
3028  bContext *C = block->evil_C;
3029  if (WM_menutype_poll(C, mt) == false) {
3030  return;
3031  }
3032 
3033  bContextStore *previous_ctx = CTX_store_get(C);
3034  UI_menutype_draw(C, mt, layout);
3035 
3036  /* Restore context that was cleared by `UI_menutype_draw`. */
3037  if (layout->context) {
3038  CTX_store_set(C, previous_ctx);
3039  }
3040 }
3041 
3042 void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index)
3043 {
3044  uiBlock *block = layout->root->block;
3045 
3046  UI_block_layout_set_current(block, layout);
3047  uiLayout *col = uiLayoutColumn(layout, false);
3048  col->space = 0;
3049  col->emboss = UI_EMBOSS_NONE;
3050 
3051  if (ELEM(NULL, ptr, prop) || !RNA_property_animateable(ptr, prop)) {
3052  uiBut *but = uiDefIconBut(block,
3054  0,
3055  ICON_BLANK1,
3056  0,
3057  0,
3058  UI_UNIT_X,
3059  UI_UNIT_Y,
3060  NULL,
3061  0.0,
3062  0.0,
3063  0.0,
3064  0.0,
3065  "");
3066  but->flag |= UI_BUT_DISABLED;
3067  return;
3068  }
3069 
3070  const bool is_expand = ui_item_rna_is_expand(prop, index, 0);
3071  const bool is_array = RNA_property_array_check(prop);
3072 
3073  /* Loop for the array-case, but only do in case of an expanded array. */
3074  for (int i = 0; i < (is_expand ? RNA_property_array_length(ptr, prop) : 1); i++) {
3075  uiButDecorator *decorator_but = (uiButDecorator *)uiDefIconBut(block,
3077  0,
3078  ICON_DOT,
3079  0,
3080  0,
3081  UI_UNIT_X,
3082  UI_UNIT_Y,
3083  NULL,
3084  0.0,
3085  0.0,
3086  0.0,
3087  0.0,
3088  TIP_("Animate property"));
3089 
3090  UI_but_func_set(&decorator_but->but, ui_but_anim_decorate_cb, decorator_but, NULL);
3091  decorator_but->but.flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK;
3092  /* Reusing RNA search members, setting actual RNA data has many side-effects. */
3093  decorator_but->rnapoin = *ptr;
3094  decorator_but->rnaprop = prop;
3095  /* ui_def_but_rna() sets non-array buttons to have a RNA index of 0. */
3096  decorator_but->rnaindex = (!is_array || is_expand) ? i : index;
3097  }
3098 }
3099 
3100 void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index)
3101 {
3102  PropertyRNA *prop = NULL;
3103 
3104  if (ptr && propname) {
3105  /* validate arguments */
3106  prop = RNA_struct_find_property(ptr, propname);
3107  if (!prop) {
3108  ui_item_disabled(layout, propname);
3109  RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
3110  return;
3111  }
3112  }
3113 
3114  /* ptr and prop are allowed to be NULL here. */
3115  uiItemDecoratorR_prop(layout, ptr, prop, index);
3116 }
3117 
3119  uiLayout *layout, const bContext *C, PanelType *pt, const char *name, int icon)
3120 {
3121  if (!name) {
3122  name = CTX_IFACE_(pt->translation_context, pt->label);
3123  }
3124 
3125  if (layout->root->type == UI_LAYOUT_MENU && !icon) {
3126  icon = ICON_BLANK1;
3127  }
3128 
3129  const bool ok = (pt->poll == NULL) || pt->poll(C, pt);
3130  if (ok && (pt->draw_header != NULL)) {
3131  layout = uiLayoutRow(layout, true);
3132  Panel panel = {
3133  .type = pt,
3134  .layout = layout,
3135  .flag = PNL_POPOVER,
3136  };
3137  pt->draw_header(C, &panel);
3138  }
3139  uiBut *but = ui_item_menu(
3140  layout, name, icon, ui_item_paneltype_func, pt, NULL, pt->description, true);
3141  but->type = UI_BTYPE_POPOVER;
3142  if (!ok) {
3143  but->flag |= UI_BUT_DISABLED;
3144  }
3145 }
3146 
3148  uiLayout *layout, const bContext *C, const char *panel_type, const char *name, int icon)
3149 {
3150  PanelType *pt = WM_paneltype_find(panel_type, true);
3151  if (pt == NULL) {
3152  RNA_warning("Panel type not found '%s'", panel_type);
3153  return;
3154  }
3155  uiItemPopoverPanel_ptr(layout, C, pt, name, icon);
3156 }
3157 
3159  bContext *C,
3160  int space_id,
3161  int region_id,
3162  const char *context,
3163  const char *category)
3164 {
3165  SpaceType *st = BKE_spacetype_from_id(space_id);
3166  if (st == NULL) {
3167  RNA_warning("space type not found %d", space_id);
3168  return;
3169  }
3170  ARegionType *art = BKE_regiontype_from_id(st, region_id);
3171  if (art == NULL) {
3172  RNA_warning("region type not found %d", region_id);
3173  return;
3174  }
3175 
3176  LISTBASE_FOREACH (PanelType *, pt, &art->paneltypes) {
3177  /* Causes too many panels, check context. */
3178  if (pt->parent_id[0] == '\0') {
3179  if (/* (*context == '\0') || */ STREQ(pt->context, context)) {
3180  if ((*category == '\0') || STREQ(pt->category, category)) {
3181  if (pt->poll == NULL || pt->poll(C, pt)) {
3182  uiItemPopoverPanel_ptr(layout, C, pt, NULL, ICON_NONE);
3183  }
3184  }
3185  }
3186  }
3187  }
3188 }
3189 
3190 /* label item */
3191 static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
3192 {
3193  uiBlock *block = layout->root->block;
3194 
3195  UI_block_layout_set_current(block, layout);
3196  ui_block_new_button_group(block, 0);
3197 
3198  if (!name) {
3199  name = "";
3200  }
3201  if (layout->root->type == UI_LAYOUT_MENU && !icon) {
3202  icon = ICON_BLANK1;
3203  }
3204 
3205  const int w = ui_text_icon_width_ex(layout, name, icon, &ui_text_pad_none);
3206  uiBut *but;
3207  if (icon && name[0]) {
3208  but = uiDefIconTextBut(
3209  block, UI_BTYPE_LABEL, 0, icon, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, NULL);
3210  }
3211  else if (icon) {
3212  but = uiDefIconBut(
3213  block, UI_BTYPE_LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, NULL);
3214  }
3215  else {
3216  but = uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, NULL);
3217  }
3218 
3219  /* to compensate for string size padding in ui_text_icon_width,
3220  * make text aligned right if the layout is aligned right.
3221  */
3223  but->drawflag &= ~UI_BUT_TEXT_LEFT; /* default, needs to be unset */
3224  but->drawflag |= UI_BUT_TEXT_RIGHT;
3225  }
3226 
3227  /* Mark as a label inside a list-box. */
3228  if (block->flag & UI_BLOCK_LIST_ITEM) {
3229  but->flag |= UI_BUT_LIST_ITEM;
3230  }
3231 
3232  if (layout->redalert) {
3234  }
3235 
3236  return but;
3237 }
3238 
3240  uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert)
3241 {
3242  uiBut *but = uiItemL_(layout, name, icon);
3243 
3244  if (highlight) {
3245  /* TODO: add another flag for this. */
3247  }
3248 
3249  if (redalert) {
3251  }
3252 }
3253 
3254 void uiItemL(uiLayout *layout, const char *name, int icon)
3255 {
3256  uiItemL_(layout, name, icon);
3257 }
3258 
3260 {
3261  uiPropertySplitWrapper split_wrapper = {NULL};
3262 
3263  uiLayout *layout_row = uiLayoutRow(parent_layout, true);
3264  uiLayout *layout_split = uiLayoutSplit(layout_row, UI_ITEM_PROP_SEP_DIVIDE, true);
3265 
3266  split_wrapper.label_column = uiLayoutColumn(layout_split, true);
3267  split_wrapper.label_column->alignment = UI_LAYOUT_ALIGN_RIGHT;
3268  split_wrapper.property_row = ui_item_prop_split_layout_hack(parent_layout, layout_split);
3269  split_wrapper.decorate_column = uiLayoutColumn(layout_row, true);
3270 
3271  return split_wrapper;
3272 }
3273 
3275 {
3276  if (layout->item.flag & UI_ITEM_PROP_SEP) {
3277  uiBlock *block = uiLayoutGetBlock(layout);
3278  const uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(layout);
3279  /* Further items added to 'layout' will automatically be added to split_wrapper.property_row */
3280 
3281  uiItemL_(split_wrapper.label_column, text, icon);
3282  UI_block_layout_set_current(block, split_wrapper.property_row);
3283 
3284  return split_wrapper.decorate_column;
3285  }
3286 
3287  char namestr[UI_MAX_NAME_STR];
3288  if (text) {
3289  text = ui_item_name_add_colon(text, namestr);
3290  }
3291  uiItemL_(layout, text, icon);
3292 
3293  return layout;
3294 }
3295 
3296 void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, const char *name, int icon)
3297 {
3298  uiBut *but = uiItemL_(layout, name, icon);
3299 
3300  if (ptr && ptr->type) {
3301  if (RNA_struct_is_ID(ptr->type)) {
3303  }
3304  }
3305 }
3306 
3307 void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
3308 {
3309  /* label */
3310  uiBlock *block = layout->root->block;
3311  int *retvalue = (block->handle) ? &block->handle->retvalue : NULL;
3312 
3313  UI_block_layout_set_current(block, layout);
3314 
3315  if (!name) {
3316  name = "";
3317  }
3318  if (layout->root->type == UI_LAYOUT_MENU && !icon) {
3319  icon = ICON_BLANK1;
3320  }
3321 
3322  const int w = ui_text_icon_width(layout, name, icon, 0);
3323 
3324  if (icon && name[0]) {
3325  uiDefIconTextButI(block,
3326  UI_BTYPE_BUT,
3327  argval,
3328  icon,
3329  name,
3330  0,
3331  0,
3332  w,
3333  UI_UNIT_Y,
3334  retvalue,
3335  0.0,
3336  0.0,
3337  0,
3338  -1,
3339  "");
3340  }
3341  else if (icon) {
3342  uiDefIconButI(
3343  block, UI_BTYPE_BUT, argval, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
3344  }
3345  else {
3346  uiDefButI(
3347  block, UI_BTYPE_BUT, argval, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
3348  }
3349 }
3350 
3351 void uiItemS_ex(uiLayout *layout, float factor)
3352 {
3353  uiBlock *block = layout->root->block;
3354  const bool is_menu = ui_block_is_menu(block);
3355  if (is_menu && !UI_block_can_add_separator(block)) {
3356  return;
3357  }
3358  int space = (is_menu) ? 0.45f * UI_UNIT_X : 0.3f * UI_UNIT_X;
3359  space *= factor;
3360 
3361  UI_block_layout_set_current(block, layout);
3362  uiDefBut(block,
3363  (is_menu) ? UI_BTYPE_SEPR_LINE : UI_BTYPE_SEPR,
3364  0,
3365  "",
3366  0,
3367  0,
3368  space,
3369  space,
3370  NULL,
3371  0.0,
3372  0.0,
3373  0,
3374  0,
3375  "");
3376 }
3377 
3378 void uiItemS(uiLayout *layout)
3379 {
3380  uiItemS_ex(layout, 1.0f);
3381 }
3382 
3383 void uiItemSpacer(uiLayout *layout)
3384 {
3385  uiBlock *block = layout->root->block;
3386  const bool is_popup = ui_block_is_popup_any(block);
3387 
3388  if (is_popup) {
3389  printf("Error: separator_spacer() not supported in popups.\n");
3390  return;
3391  }
3392 
3393  if (block->direction & UI_DIR_RIGHT) {
3394  printf("Error: separator_spacer() only supported in horizontal blocks.\n");
3395  return;
3396  }
3397 
3398  UI_block_layout_set_current(block, layout);
3399  uiDefBut(block,
3401  0,
3402  "",
3403  0,
3404  0,
3405  0.3f * UI_UNIT_X,
3406  UI_UNIT_Y,
3407  NULL,
3408  0.0,
3409  0.0,
3410  0,
3411  0,
3412  "");
3413 }
3414 
3415 void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
3416 {
3417  if (!func) {
3418  return;
3419  }
3420 
3421  ui_item_menu(layout, name, icon, func, arg, NULL, "", false);
3422 }
3423 
3424 void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *argN)
3425 {
3426  if (!func) {
3427  return;
3428  }
3429 
3430  /* Second 'argN' only ensures it gets freed. */
3431  ui_item_menu(layout, name, icon, func, argN, argN, "", false);
3432 }
3433 
3434 typedef struct MenuItemLevel {
3436  /* don't use pointers to the strings because python can dynamically
3437  * allocate strings and free before the menu draws, see T27304. */
3442 
3443 static void menu_item_enum_opname_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
3444 {
3445  uiBut *but = arg;
3446  MenuItemLevel *lvl = but->func_argN;
3447  /* Use the operator properties from the button owning the menu. */
3448  IDProperty *op_props = but->opptr ? but->opptr->data : NULL;
3449 
3450  uiLayoutSetOperatorContext(layout, lvl->opcontext);
3451  uiItemsFullEnumO(layout, lvl->opname, lvl->propname, op_props, lvl->opcontext, 0);
3452 
3453  layout->root->block->flag |= UI_BLOCK_IS_FLIP;
3454 
3455  /* override default, needed since this was assumed pre 2.70 */
3457 }
3458 
3460  bContext *C,
3461  wmOperatorType *ot,
3462  const char *propname,
3463  const char *name,
3464  int icon,
3465  PointerRNA *r_opptr)
3466 {
3467  /* Caller must check */
3468  BLI_assert(ot->srna != NULL);
3469 
3470  if (name == NULL) {
3471  name = WM_operatortype_name(ot, NULL);
3472  }
3473 
3474  if (layout->root->type == UI_LAYOUT_MENU && !icon) {
3475  icon = ICON_BLANK1;
3476  }
3477 
3478  MenuItemLevel *lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
3479  BLI_strncpy(lvl->opname, ot->idname, sizeof(lvl->opname));
3480  BLI_strncpy(lvl->propname, propname, sizeof(lvl->propname));
3481  lvl->opcontext = layout->root->opcontext;
3482 
3483  uiBut *but = ui_item_menu(layout, name, icon, menu_item_enum_opname_menu, NULL, lvl, NULL, true);
3484  /* Use the menu button as owner for the operator properties, which will then be passed to the
3485  * individual menu items. */
3486  if (r_opptr) {
3487  but->opptr = MEM_callocN(sizeof(PointerRNA), "uiButOpPtr");
3489  BLI_assert(but->opptr->data == NULL);
3491  *r_opptr = *but->opptr;
3492  }
3493 
3494  /* add hotkey here, lower UI code can't detect it */
3495  if ((layout->root->block->flag & UI_BLOCK_LOOP) && (ot->prop && ot->invoke)) {
3496  char keybuf[128];
3498  C, ot->idname, layout->root->opcontext, NULL, false, keybuf, sizeof(keybuf))) {
3499  ui_but_add_shortcut(but, keybuf, false);
3500  }
3501  }
3502 }
3503 
3505  bContext *C,
3506  const char *opname,
3507  const char *propname,
3508  const char *name,
3509  int icon,
3510  PointerRNA *r_opptr)
3511 {
3512  wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
3513 
3514  UI_OPERATOR_ERROR_RET(ot, opname, return );
3515 
3516  if (!ot->srna) {
3517  ui_item_disabled(layout, opname);
3518  RNA_warning("operator missing srna '%s'", opname);
3519  return;
3520  }
3521 
3522  uiItemMenuEnumFullO_ptr(layout, C, ot, propname, name, icon, r_opptr);
3523 }
3524 
3526  bContext *C,
3527  const char *opname,
3528  const char *propname,
3529  const char *name,
3530  int icon)
3531 {
3532  uiItemMenuEnumFullO(layout, C, opname, propname, name, icon, NULL);
3533 }
3534 
3535 static void menu_item_enum_rna_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
3536 {
3537  MenuItemLevel *lvl = (MenuItemLevel *)(((uiBut *)arg)->func_argN);
3538 
3539  uiLayoutSetOperatorContext(layout, lvl->opcontext);
3540  uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
3541  layout->root->block->flag |= UI_BLOCK_IS_FLIP;
3542 }
3543 
3545  uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *name, int icon)
3546 {
3547  if (!name) {
3548  name = RNA_property_ui_name(prop);
3549  }
3550  if (layout->root->type == UI_LAYOUT_MENU && !icon) {
3551  icon = ICON_BLANK1;
3552  }
3553 
3554  MenuItemLevel *lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
3555  lvl->rnapoin = *ptr;
3556  BLI_strncpy(lvl->propname, RNA_property_identifier(prop), sizeof(lvl->propname));
3557  lvl->opcontext = layout->root->opcontext;
3558 
3559  ui_item_menu(layout,
3560  name,
3561  icon,
3563  NULL,
3564  lvl,
3566  false);
3567 }
3568 
3570  uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon)
3571 {
3572  PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
3573  if (!prop) {
3574  ui_item_disabled(layout, propname);
3575  RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
3576  return;
3577  }
3578 
3579  uiItemMenuEnumR_prop(layout, ptr, prop, name, icon);
3580 }
3581 
3583  bContext *C,
3584  PointerRNA *ptr,
3585  PropertyRNA *prop,
3586  PointerRNA *ptr_highlight,
3587  PropertyRNA *prop_highlight,
3588  bool icon_only)
3589 {
3590  uiBlock *block = layout->root->block;
3591 
3592  UI_block_layout_set_current(block, layout);
3594  layout, C, block, ptr, prop, ptr_highlight, prop_highlight, NULL, UI_UNIT_Y, icon_only);
3595 }
3596 
3599 /* -------------------------------------------------------------------- */
3603 /* single-row layout */
3604 static void ui_litem_estimate_row(uiLayout *litem)
3605 {
3606  int itemw, itemh;
3607  bool min_size_flag = true;
3608 
3609  litem->w = 0;
3610  litem->h = 0;
3611 
3612  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
3613  ui_item_size(item, &itemw, &itemh);
3614 
3615  min_size_flag = min_size_flag && (item->flag & UI_ITEM_FIXED_SIZE);
3616 
3617  litem->w += itemw;
3618  litem->h = MAX2(itemh, litem->h);
3619 
3620  if (item->next) {
3621  litem->w += litem->space;
3622  }
3623  }
3624 
3625  if (min_size_flag) {
3626  litem->item.flag |= UI_ITEM_FIXED_SIZE;
3627  }
3628 }
3629 
3630 static int ui_litem_min_width(int itemw)
3631 {
3632  return MIN2(2 * UI_UNIT_X, itemw);
3633 }
3634 
3635 static void ui_litem_layout_row(uiLayout *litem)
3636 {
3637  uiItem *last_free_item = NULL;
3638  int x, neww, newtotw, itemw, minw, itemh, offset;
3639  int freew, fixedx, freex, flag = 0, lastw = 0;
3640  float extra_pixel;
3641 
3642  /* x = litem->x; */ /* UNUSED */
3643  const int y = litem->y;
3644  int w = litem->w;
3645  int totw = 0;
3646  int tot = 0;
3647 
3648  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
3649  ui_item_size(item, &itemw, &itemh);
3650  totw += itemw;
3651  tot++;
3652  }
3653 
3654  if (totw == 0) {
3655  return;
3656  }
3657 
3658  if (w != 0) {
3659  w -= (tot - 1) * litem->space;
3660  }
3661  int fixedw = 0;
3662 
3663  /* keep clamping items to fixed minimum size until all are done */
3664  do {
3665  freew = 0;
3666  x = 0;
3667  flag = 0;
3668  newtotw = totw;
3669  extra_pixel = 0.0f;
3670 
3671  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
3672  if (item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
3673  continue;
3674  }
3675 
3676  ui_item_size(item, &itemw, &itemh);
3677  minw = ui_litem_min_width(itemw);
3678 
3679  if (w - lastw > 0) {
3680  neww = ui_item_fit(itemw, x, totw, w - lastw, !item->next, litem->alignment, &extra_pixel);
3681  }
3682  else {
3683  neww = 0; /* no space left, all will need clamping to minimum size */
3684  }
3685 
3686  x += neww;
3687 
3688  bool min_flag = item->flag & UI_ITEM_FIXED_SIZE;
3689  /* ignore min flag for rows with right or center alignment */
3690  if (item->type != ITEM_BUTTON &&
3691  ELEM(((uiLayout *)item)->alignment, UI_LAYOUT_ALIGN_RIGHT, UI_LAYOUT_ALIGN_CENTER) &&
3692  litem->alignment == UI_LAYOUT_ALIGN_EXPAND &&
3693  ((uiItem *)litem)->flag & UI_ITEM_FIXED_SIZE) {
3694  min_flag = false;
3695  }
3696 
3697  if ((neww < minw || min_flag) && w != 0) {
3698  /* fixed size */
3699  item->flag |= UI_ITEM_AUTO_FIXED_SIZE;
3700  if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_FIXED_SIZE) {
3701  minw = itemw;
3702  }
3703  fixedw += minw;
3704  flag = 1;
3705  newtotw -= itemw;
3706  }
3707  else {
3708  /* keep free size */
3709  item->flag &= ~UI_ITEM_AUTO_FIXED_SIZE;
3710  freew += itemw;
3711  }
3712  }
3713 
3714  totw = newtotw;
3715  lastw = fixedw;
3716  } while (flag);
3717 
3718  freex = 0;
3719  fixedx = 0;
3720  extra_pixel = 0.0f;
3721  x = litem->x;
3722 
3723  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
3724  ui_item_size(item, &itemw, &itemh);
3725  minw = ui_litem_min_width(itemw);
3726 
3727  if (item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
3728  /* fixed minimum size items */
3729  if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_FIXED_SIZE) {
3730  minw = itemw;
3731  }
3732  itemw = ui_item_fit(
3733  minw, fixedx, fixedw, min_ii(w, fixedw), !item->next, litem->alignment, &extra_pixel);
3734  fixedx += itemw;
3735  }
3736  else {
3737  /* free size item */
3738  itemw = ui_item_fit(
3739  itemw, freex, freew, w - fixedw, !item->next, litem->alignment, &extra_pixel);
3740  freex += itemw;
3741  last_free_item = item;
3742  }
3743 
3744  /* align right/center */
3745  offset = 0;
3746  if (litem->alignment == UI_LAYOUT_ALIGN_RIGHT) {
3747  if (freew + fixedw > 0 && freew + fixedw < w) {
3748  offset = w - (fixedw + freew);
3749  }
3750  }
3751  else if (litem->alignment == UI_LAYOUT_ALIGN_CENTER) {
3752  if (freew + fixedw > 0 && freew + fixedw < w) {
3753  offset = (w - (fixedw + freew)) / 2;
3754  }
3755  }
3756 
3757  /* position item */
3758  ui_item_position(item, x + offset, y - itemh, itemw, itemh);
3759 
3760  x += itemw;
3761  if (item->next) {
3762  x += litem->space;
3763  }
3764  }
3765 
3766  /* add extra pixel */
3767  uiItem *last_item = litem->items.last;
3768  extra_pixel = litem->w - (x - litem->x);
3769  if (extra_pixel > 0 && litem->alignment == UI_LAYOUT_ALIGN_EXPAND && last_free_item &&
3770  last_item && last_item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
3771  ui_item_move(last_free_item, 0, extra_pixel);
3772  for (uiItem *item = last_free_item->next; item; item = item->next) {
3773  ui_item_move(item, extra_pixel, extra_pixel);
3774  }
3775  }
3776 
3777  litem->w = x - litem->x;
3778  litem->h = litem->y - y;
3779  litem->x = x;
3780  litem->y = y;
3781 }
3782 
3783 /* single-column layout */
3784 static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
3785 {
3786  int itemw, itemh;
3787  bool min_size_flag = true;
3788 
3789  litem->w = 0;
3790  litem->h = 0;
3791 
3792  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
3793  ui_item_size(item, &itemw, &itemh);
3794 
3795  min_size_flag = min_size_flag && (item->flag & UI_ITEM_FIXED_SIZE);
3796 
3797  litem->w = MAX2(litem->w, itemw);
3798  litem->h += itemh;
3799 
3800  if (item->next && (!is_box || item != litem->items.first)) {
3801  litem->h += litem->space;
3802  }
3803  }
3804 
3805  if (min_size_flag) {
3806  litem->item.flag |= UI_ITEM_FIXED_SIZE;
3807  }
3808 }
3809 
3810 static void ui_litem_layout_column(uiLayout *litem, bool is_box, bool is_menu)
3811 {
3812  const int x = litem->x;
3813  int y = litem->y;
3814 
3815  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
3816  int itemw, itemh;
3817  ui_item_size(item, &itemw, &itemh);
3818 
3819  y -= itemh;
3820  ui_item_position(item, x, y, is_menu ? itemw : litem->w, itemh);
3821 
3822  if (item->next && (!is_box || item != litem->items.first)) {
3823  y -= litem->space;
3824  }
3825 
3826  if (is_box) {
3827  item->flag |= UI_ITEM_BOX_ITEM;
3828  }
3829  }
3830 
3831  litem->h = litem->y - y;
3832  litem->x = x;
3833  litem->y = y;
3834 }
3835 
3836 /* calculates the angle of a specified button in a radial menu,
3837  * stores a float vector in unit circle */
3838 static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum)
3839 {
3840  if (itemnum >= PIE_MAX_ITEMS) {
3841  itemnum %= PIE_MAX_ITEMS;
3842  printf("Warning: Pie menus with more than %i items are currently unsupported\n",
3843  PIE_MAX_ITEMS);
3844  }
3845 
3846  const RadialDirection dir = ui_radial_dir_order[itemnum];
3847  ui_but_pie_dir(dir, vec);
3848 
3849  return dir;
3850 }
3851 
3853 {
3854 
3855  if ((item->type == ITEM_BUTTON) && (((uiButtonItem *)item)->but->type == UI_BTYPE_LABEL)) {
3856  return false;
3857  }
3858 
3859  return true;
3860 }
3861 
3863 {
3864 
3866  return false;
3867  }
3868 
3869  return true;
3870 }
3871 
3873 {
3874  int itemh, itemw;
3875  int itemnum = 0;
3876  int totitems = 0;
3877 
3878  /* For the radial layout we will use Matt Ebb's design
3879  * for radiation, see http://mattebb.com/weblog/radiation/
3880  * also the old code at http://developer.blender.org/T5103
3881  */
3882 
3883  const int pie_radius = U.pie_menu_radius * UI_DPI_FAC;
3884 
3885  const int x = litem->x;
3886  const int y = litem->y;
3887 
3888  int minx = x, miny = y, maxx = x, maxy = y;
3889 
3890  /* first count total items */
3891  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
3892  totitems++;
3893  }
3894 
3895  if (totitems < 5) {
3897  }
3898 
3899  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
3900  /* not all button types are drawn in a radial menu, do filtering here */
3901  if (ui_item_is_radial_displayable(item)) {
3902  RadialDirection dir;
3903  float vec[2];
3904  float factor[2];
3905 
3906  dir = ui_get_radialbut_vec(vec, itemnum);
3907  factor[0] = (vec[0] > 0.01f) ? 0.0f : ((vec[0] < -0.01f) ? -1.0f : -0.5f);
3908  factor[1] = (vec[1] > 0.99f) ? 0.0f : ((vec[1] < -0.99f) ? -1.0f : -0.5f);
3909 
3910  itemnum++;
3911 
3912  if (item->type == ITEM_BUTTON) {
3913  uiButtonItem *bitem = (uiButtonItem *)item;
3914 
3915  bitem->but->pie_dir = dir;
3916  /* scale the buttons */
3917  bitem->but->rect.ymax *= 1.5f;
3918  /* add a little bit more here to include number */
3919  bitem->but->rect.xmax += 1.5f * UI_UNIT_X;
3920  /* enable drawing as pie item if supported by widget */
3921  if (ui_item_is_radial_drawable(bitem)) {
3922  bitem->but->emboss = UI_EMBOSS_RADIAL;
3923  bitem->but->drawflag |= UI_BUT_ICON_LEFT;
3924  }
3925  }
3926 
3927  ui_item_size(item, &itemw, &itemh);
3928 
3929  ui_item_position(item,
3930  x + vec[0] * pie_radius + factor[0] * itemw,
3931  y + vec[1] * pie_radius + factor[1] * itemh,
3932  itemw,
3933  itemh);
3934 
3935  minx = min_ii(minx, x + vec[0] * pie_radius - itemw / 2);
3936  maxx = max_ii(maxx, x + vec[0] * pie_radius + itemw / 2);
3937  miny = min_ii(miny, y + vec[1] * pie_radius - itemh / 2);
3938  maxy = max_ii(maxy, y + vec[1] * pie_radius + itemh / 2);
3939  }
3940  }
3941 
3942  litem->x = minx;
3943  litem->y = miny;
3944  litem->w = maxx - minx;
3945  litem->h = maxy - miny;
3946 }
3947 
3948 /* root layout */
3950 {
3951  /* nothing to do */
3952 }
3953 
3955 {
3956  /* first item is pie menu title, align on center of menu */
3957  uiItem *item = litem->items.first;
3958 
3959  if (item->type == ITEM_BUTTON) {
3960  int itemh, itemw, x, y;
3961  x = litem->x;
3962  y = litem->y;
3963 
3964  ui_item_size(item, &itemw, &itemh);
3965 
3967  item, x - itemw / 2, y + U.dpi_fac * (U.pie_menu_threshold + 9.0f), itemw, itemh);
3968  }
3969 }
3970 
3971 static void ui_litem_layout_root(uiLayout *litem)
3972 {
3973  if (litem->root->type == UI_LAYOUT_HEADER) {
3974  ui_litem_layout_row(litem);
3975  }
3976  else if (litem->root->type == UI_LAYOUT_PIEMENU) {
3978  }
3979  else if (litem->root->type == UI_LAYOUT_MENU) {
3980  ui_litem_layout_column(litem, false, true);
3981  }
3982  else {
3983  ui_litem_layout_column(litem, false, false);
3984  }
3985 }
3986 
3987 /* box layout */
3988 static void ui_litem_estimate_box(uiLayout *litem)
3989 {
3990  const uiStyle *style = litem->root->style;
3991 
3992  ui_litem_estimate_column(litem, true);
3993 
3994  int boxspace = style->boxspace;
3995  if (litem->root->type == UI_LAYOUT_HEADER) {
3996  boxspace = 0;
3997  }
3998  litem->w += 2 * boxspace;
3999  litem->h += 2 * boxspace;
4000 }
4001 
4002 static void ui_litem_layout_box(uiLayout *litem)
4003 {
4004  uiLayoutItemBx *box = (uiLayoutItemBx *)litem;
4005  const uiStyle *style = litem->root->style;
4006 
4007  int boxspace = style->boxspace;
4008  if (litem->root->type == UI_LAYOUT_HEADER) {
4009  boxspace = 0;
4010  }
4011 
4012  const int w = litem->w;
4013  const int h = litem->h;
4014 
4015  litem->x += boxspace;
4016  litem->y -= boxspace;
4017 
4018  if (w != 0) {
4019  litem->w -= 2 * boxspace;
4020  }
4021  if (h != 0) {
4022  litem->h -= 2 * boxspace;
4023  }
4024 
4025  ui_litem_layout_column(litem, true, false);
4026 
4027  litem->x -= boxspace;
4028  litem->y -= boxspace;
4029 
4030  if (w != 0) {
4031  litem->w += 2 * boxspace;
4032  }
4033  if (h != 0) {
4034  litem->h += 2 * boxspace;
4035  }
4036 
4037  /* roundbox around the sublayout */
4038  uiBut *but = box->roundbox;
4039  but->rect.xmin = litem->x;
4040  but->rect.ymin = litem->y;
4041  but->rect.xmax = litem->x + litem->w;
4042  but->rect.ymax = litem->y + litem->h;
4043 }
4044 
4045 /* multi-column layout, automatically flowing to the next */
4047 {
4048  const uiStyle *style = litem->root->style;
4049  uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem;
4050  int itemw, itemh, maxw = 0;
4051 
4052  /* compute max needed width and total height */
4053  int toth = 0;
4054  int totitem = 0;
4055  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
4056  ui_item_size(item, &itemw, &itemh);
4057  maxw = MAX2(maxw, itemw);
4058  toth += itemh;
4059  totitem++;
4060  }
4061 
4062  if (flow->number <= 0) {
4063  /* auto compute number of columns, not very good */
4064  if (maxw == 0) {
4065  flow->totcol = 1;
4066  return;
4067  }
4068 
4069  flow->totcol = max_ii(litem->root->emw / maxw, 1);
4070  flow->totcol = min_ii(flow->totcol, totitem);
4071  }
4072  else {
4073  flow->totcol = flow->number;
4074  }
4075 
4076  /* compute sizes */
4077  int x = 0;
4078  int y = 0;
4079  int emy = 0;
4080  int miny = 0;
4081 
4082  maxw = 0;
4083  const int emh = toth / flow->totcol;
4084 
4085  /* create column per column */
4086  int col = 0;
4087  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
4088  ui_item_size(item, &itemw, &itemh);
4089 
4090  y -= itemh + style->buttonspacey;
4091  miny = min_ii(miny, y);
4092  emy -= itemh;
4093  maxw = max_ii(itemw, maxw);
4094 
4095  /* decide to go to next one */
4096  if (col < flow->totcol - 1 && emy <= -emh) {
4097  x += maxw + litem->space;
4098  maxw = 0;
4099  y = 0;
4100  emy = 0; /* need to reset height again for next column */
4101  col++;
4102  }
4103  }
4104 
4105  litem->w = x;
4106  litem->h = litem->y - miny;
4107 }
4108 
4110 {
4111  const uiStyle *style = litem->root->style;
4112  uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem;
4113  int col, emh, itemw, itemh;
4114 
4115  /* compute max needed width and total height */
4116  int toth = 0;
4117  int totitem = 0;
4118  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
4119  ui_item_size(item, &itemw, &itemh);
4120  toth += itemh;
4121  totitem++;
4122  }
4123 
4124  /* compute sizes */
4125  int x = litem->x;
4126  int y = litem->y;
4127  int emy = 0;
4128  int miny = 0;
4129 
4130  emh = toth / flow->totcol;
4131 
4132  /* create column per column */
4133  col = 0;
4134  int w = (litem->w - (flow->totcol - 1) * style->columnspace) / flow->totcol;
4135  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
4136  ui_item_size(item, &itemw, &itemh);
4137 
4138  itemw = (litem->alignment == UI_LAYOUT_ALIGN_EXPAND) ? w : min_ii(w, itemw);
4139 
4140  y -= itemh;
4141  emy -= itemh;
4142  ui_item_position(item, x, y, itemw, itemh);
4143  y -= style->buttonspacey;
4144  miny = min_ii(miny, y);
4145 
4146  /* decide to go to next one */
4147  if (col < flow->totcol - 1 && emy <= -emh) {
4148  x += w + style->columnspace;
4149  y = litem->y;
4150  emy = 0; /* need to reset height again for next column */
4151  col++;
4152 
4153  const int remaining_width = litem->w - (x - litem->x);
4154  const int remaining_width_between_columns = (flow->totcol - col - 1) * style->columnspace;
4155  const int remaining_columns = flow->totcol - col;
4156  w = (remaining_width - remaining_width_between_columns) / remaining_columns;
4157  }
4158  }
4159 
4160  litem->h = litem->y - miny;
4161  litem->x = x;
4162  litem->y = miny;
4163 }
4164 
4165 /* multi-column and multi-row layout. */
4166 typedef struct UILayoutGridFlowInput {
4167  /* General layout control settings. */
4168  const bool row_major : 1; /* Fill rows before columns */
4169  const bool even_columns : 1; /* All columns will have same width. */
4170  const bool even_rows : 1; /* All rows will have same height. */
4171  const int space_x; /* Space between columns. */
4172  const int space_y; /* Space between rows. */
4173  /* Real data about current position and size of this layout item
4174  * (either estimated, or final values). */
4175  const int litem_w; /* Layout item width. */
4176  const int litem_x; /* Layout item X position. */
4177  const int litem_y; /* Layout item Y position. */
4178  /* Actual number of columns and rows to generate (computed from first pass usually). */
4179  const int tot_columns; /* Number of columns. */
4180  const int tot_rows; /* Number of rows. */
4182 
4183 typedef struct UILayoutGridFlowOutput {
4184  int *tot_items; /* Total number of items in this grid layout. */
4185  /* Width / X pos data. */
4186  float *global_avg_w; /* Computed average width of the columns. */
4187  int *cos_x_array; /* Computed X coordinate of each column. */
4188  int *widths_array; /* Computed width of each column. */
4189  int *tot_w; /* Computed total width. */
4190  /* Height / Y pos data. */
4191  int *global_max_h; /* Computed height of the tallest item in the grid. */
4192  int *cos_y_array; /* Computed Y coordinate of each column. */
4193  int *heights_array; /* Computed height of each column. */
4194  int *tot_h; /* Computed total height. */
4196 
4199  UILayoutGridFlowOutput *results)
4200 {
4201  float tot_w = 0.0f, tot_h = 0.0f;
4202  float global_avg_w = 0.0f, global_totweight_w = 0.0f;
4203  int global_max_h = 0;
4204 
4205  float *avg_w = NULL, *totweight_w = NULL;
4206  int *max_h = NULL;
4207 
4208  BLI_assert(
4209  parameters->tot_columns != 0 ||
4210  (results->cos_x_array == NULL && results->widths_array == NULL && results->tot_w == NULL));
4211  BLI_assert(
4212  parameters->tot_rows != 0 ||
4213  (results->cos_y_array == NULL && results->heights_array == NULL && results->tot_h == NULL));
4214 
4215  if (results->tot_items) {
4216  *results->tot_items = 0;
4217  }
4218 
4219  if (items->first == NULL) {
4220  if (results->global_avg_w) {
4221  *results->global_avg_w = 0.0f;
4222  }
4223  if (results->global_max_h) {
4224  *results->global_max_h = 0;
4225  }
4226  return;
4227  }
4228 
4229  if (parameters->tot_columns != 0) {
4230  avg_w = BLI_array_alloca(avg_w, parameters->tot_columns);
4231  totweight_w = BLI_array_alloca(totweight_w, parameters->tot_columns);
4232  memset(avg_w, 0, sizeof(*avg_w) * parameters->tot_columns);
4233  memset(totweight_w, 0, sizeof(*totweight_w) * parameters->tot_columns);
4234  }
4235  if (parameters->tot_rows != 0) {
4236  max_h = BLI_array_alloca(max_h, parameters->tot_rows);
4237  memset(max_h, 0, sizeof(*max_h) * parameters->tot_rows);
4238  }
4239 
4240  int i = 0;
4241  LISTBASE_FOREACH (uiItem *, item, items) {
4242  int item_w, item_h;
4243  ui_item_size(item, &item_w, &item_h);
4244 
4245  global_avg_w += (float)(item_w * item_w);
4246  global_totweight_w += (float)item_w;
4247  global_max_h = max_ii(global_max_h, item_h);
4248 
4249  if (parameters->tot_rows != 0 && parameters->tot_columns != 0) {
4250  const int index_col = parameters->row_major ? i % parameters->tot_columns :
4251  i / parameters->tot_rows;
4252  const int index_row = parameters->row_major ? i / parameters->tot_columns :
4253  i % parameters->tot_rows;
4254 
4255  avg_w[index_col] += (float)(item_w * item_w);
4256  totweight_w[index_col] += (float)item_w;
4257 
4258  max_h[index_row] = max_ii(max_h[index_row], item_h);
4259  }
4260 
4261  if (results->tot_items) {
4262  (*results->tot_items)++;
4263  }
4264  i++;
4265  }
4266 
4267  /* Finalize computing of column average sizes */
4268  global_avg_w /= global_totweight_w;
4269  if (parameters->tot_columns != 0) {
4270  for (i = 0; i < parameters->tot_columns; i++) {
4271  avg_w[i] /= totweight_w[i];
4272  tot_w += avg_w[i];
4273  }
4274  if (parameters->even_columns) {
4275  tot_w = ceilf(global_avg_w) * parameters->tot_columns;
4276  }
4277  }
4278  /* Finalize computing of rows max sizes */
4279  if (parameters->tot_rows != 0) {
4280  for (i = 0; i < parameters->tot_rows; i++) {
4281  tot_h += max_h[i];
4282  }
4283  if (parameters->even_rows) {
4284  tot_h = global_max_h * parameters->tot_columns;
4285  }
4286  }
4287 
4288  /* Compute positions and sizes of all cells. */
4289  if (results->cos_x_array != NULL && results->widths_array != NULL) {
4290  /* We enlarge/narrow columns evenly to match available width. */
4291  const float wfac = (float)(parameters->litem_w -
4292  (parameters->tot_columns - 1) * parameters->space_x) /
4293  tot_w;
4294 
4295  for (int col = 0; col < parameters->tot_columns; col++) {
4296  results->cos_x_array[col] = (col ? results->cos_x_array[col - 1] +
4297  results->widths_array[col - 1] + parameters->space_x :
4298  parameters->litem_x);
4299  if (parameters->even_columns) {
4300  /* (< remaining width > - < space between remaining columns >) / < remaining columns > */
4301  results->widths_array[col] = (((parameters->litem_w -
4302  (results->cos_x_array[col] - parameters->litem_x)) -
4303  (parameters->tot_columns - col - 1) * parameters->space_x) /
4304  (parameters->tot_columns - col));
4305  }
4306  else if (col == parameters->tot_columns - 1) {
4307  /* Last column copes width rounding errors... */
4308  results->widths_array[col] = parameters->litem_w -
4309  (results->cos_x_array[col] - parameters->litem_x);
4310  }
4311  else {
4312  results->widths_array[col] = (int)(avg_w[col] * wfac);
4313  }
4314  }
4315  }
4316  if (results->cos_y_array != NULL && results->heights_array != NULL) {
4317  for (int row = 0; row < parameters->tot_rows; row++) {
4318  if (parameters->even_rows) {
4319  results->heights_array[row] = global_max_h;
4320  }
4321  else {
4322  results->heights_array[row] = max_h[row];
4323  }
4324  results->cos_y_array[row] = (row ? results->cos_y_array[row - 1] - parameters->space_y -
4325  results->heights_array[row] :
4326  parameters->litem_y - results->heights_array[row]);
4327  }
4328  }
4329 
4330  if (results->global_avg_w) {
4331  *results->global_avg_w = global_avg_w;
4332  }
4333  if (results->global_max_h) {
4334  *results->global_max_h = global_max_h;
4335  }
4336  if (results->tot_w) {
4337  *results->tot_w = (int)tot_w + parameters->space_x * (parameters->tot_columns - 1);
4338  }
4339  if (results->tot_h) {
4340  *results->tot_h = tot_h + parameters->space_y * (parameters->tot_rows - 1);
4341  }
4342 }
4343 
4345 {
4346  const uiStyle *style = litem->root->style;
4347  uiLayoutItemGridFlow *gflow = (uiLayoutItemGridFlow *)litem;
4348 
4349  const int space_x = style->columnspace;
4350  const int space_y = style->buttonspacey;
4351 
4352  /* Estimate average needed width and height per item. */
4353  {
4354  float avg_w;
4355  int max_h;
4356 
4359  .row_major = gflow->row_major,
4360  .even_columns = gflow->even_columns,
4361  .even_rows = gflow->even_rows,
4362  .litem_w = litem->w,
4363  .litem_x = litem->x,
4364  .litem_y = litem->y,
4365  .space_x = space_x,
4366  .space_y = space_y,
4367  }),
4369  .tot_items = &gflow->tot_items,
4370  .global_avg_w = &avg_w,
4371  .global_max_h = &max_h,
4372  }));
4373 
4374  if (gflow->tot_items == 0) {
4375  litem->w = litem->h = 0;
4376  gflow->tot_columns = gflow->tot_rows = 0;
4377  return;
4378  }
4379 
4380  /* Even in varying column width case,
4381  * we fix our columns number from weighted average width of items,
4382  * a proper solving of required width would be too costly,
4383  * and this should give reasonably good results in all reasonable cases. */
4384  if (gflow->columns_len > 0) {
4385  gflow->tot_columns = gflow->columns_len;
4386  }
4387  else {
4388  if (avg_w == 0.0f) {
4389  gflow->tot_columns = 1;
4390  }
4391  else {
4392  gflow->tot_columns = min_ii(max_ii((int)(litem->w / avg_w), 1), gflow->tot_items);
4393  }
4394  }
4395  gflow->tot_rows = (int)ceilf((float)gflow->tot_items / gflow->tot_columns);
4396 
4397  /* Try to tweak number of columns and rows to get better filling of last column or row,
4398  * and apply 'modulo' value to number of columns or rows.
4399  * Note that modulo does not prevent ending with fewer columns/rows than modulo, if mandatory
4400  * to avoid empty column/row. */
4401  {
4402  const int modulo = (gflow->columns_len < -1) ? -gflow->columns_len : 0;
4403  const int step = modulo ? modulo : 1;
4404 
4405  if (gflow->row_major) {
4406  /* Adjust number of columns to be multiple of given modulo. */
4407  if (modulo && gflow->tot_columns % modulo != 0 && gflow->tot_columns > modulo) {
4408  gflow->tot_columns = gflow->tot_columns - (gflow->tot_columns % modulo);
4409  }
4410  /* Find smallest number of columns conserving computed optimal number of rows. */
4411  for (gflow->tot_rows = (int)ceilf((float)gflow->tot_items / gflow->tot_columns);
4412  (gflow->tot_columns - step) > 0 &&
4413  (int)ceilf((float)gflow->tot_items / (gflow->tot_columns - step)) <= gflow->tot_rows;
4414  gflow->tot_columns -= step) {
4415  /* pass */
4416  }
4417  }
4418  else {
4419  /* Adjust number of rows to be multiple of given modulo. */
4420  if (modulo && gflow->tot_rows % modulo != 0) {
4421  gflow->tot_rows = min_ii(gflow->tot_rows + modulo - (gflow->tot_rows % modulo),
4422  gflow->tot_items);
4423  }
4424  /* Find smallest number of rows conserving computed optimal number of columns. */
4425  for (gflow->tot_columns = (int)ceilf((float)gflow->tot_items / gflow->tot_rows);
4426  (gflow->tot_rows - step) > 0 &&
4427  (int)ceilf((float)gflow->tot_items / (gflow->tot_rows - step)) <= gflow->tot_columns;
4428  gflow->tot_rows -= step) {
4429  /* pass */
4430  }
4431  }
4432  }
4433 
4434  /* Set evenly-spaced axes size
4435  * (quick optimization in case we have even columns and rows). */
4436  if (gflow->even_columns && gflow->even_rows) {
4437  litem->w = (int)(gflow->tot_columns * avg_w) + space_x * (gflow->tot_columns - 1);
4438  litem->h = (int)(gflow->tot_rows * max_h) + space_y * (gflow->tot_rows - 1);
4439  return;
4440  }
4441  }
4442 
4443  /* Now that we have our final number of columns and rows,
4444  * we can compute actual needed space for non-evenly sized axes. */
4445  {
4446  int tot_w, tot_h;
4447 
4450  .row_major = gflow->row_major,
4451  .even_columns = gflow->even_columns,
4452  .even_rows = gflow->even_rows,
4453  .litem_w = litem->w,
4454  .litem_x = litem->x,
4455  .litem_y = litem->y,
4456  .space_x = space_x,
4457  .space_y = space_y,
4458  .tot_columns = gflow->tot_columns,
4459  .tot_rows = gflow->tot_rows,
4460  }),
4462  .tot_w = &tot_w,
4463  .tot_h = &tot_h,
4464  }));
4465 
4466  litem->w = tot_w;
4467  litem->h = tot_h;
4468  }
4469 }
4470 
4472 {
4473  const uiStyle *style = litem->root->style;
4474  uiLayoutItemGridFlow *gflow = (uiLayoutItemGridFlow *)litem;
4475 
4476  if (gflow->tot_items == 0) {
4477  litem->w = litem->h = 0;
4478  return;
4479  }
4480 
4481  BLI_assert(gflow->tot_columns > 0);
4482  BLI_assert(gflow->tot_rows > 0);
4483 
4484  const int space_x = style->columnspace;
4485  const int space_y = style->buttonspacey;
4486 
4487  int *widths = BLI_array_alloca(widths, gflow->tot_columns);
4488  int *heights = BLI_array_alloca(heights, gflow->tot_rows);
4489  int *cos_x = BLI_array_alloca(cos_x, gflow->tot_columns);
4490  int *cos_y = BLI_array_alloca(cos_y, gflow->tot_rows);
4491 
4492  /* This time we directly compute coordinates and sizes of all cells. */
4495  .row_major = gflow->row_major,
4496  .even_columns = gflow->even_columns,
4497  .even_rows = gflow->even_rows,
4498  .litem_w = litem->w,
4499  .litem_x = litem->x,
4500  .litem_y = litem->y,
4501  .space_x = space_x,
4502  .space_y = space_y,
4503  .tot_columns = gflow->tot_columns,
4504  .tot_rows = gflow->tot_rows,
4505  }),
4507  .cos_x_array = cos_x,
4508  .cos_y_array = cos_y,
4509  .widths_array = widths,
4510  .heights_array = heights,
4511  }));
4512 
4513  int i;
4514  LISTBASE_FOREACH_INDEX (uiItem *, item, &litem->items, i) {
4515  const int col = gflow->row_major ? i % gflow->tot_columns : i / gflow->tot_rows;
4516  const int row = gflow->row_major ? i / gflow->tot_columns : i % gflow->tot_rows;
4517  int item_w, item_h;
4518  ui_item_size(item, &item_w, &item_h);
4519 
4520  const int w = widths[col];
4521  const int h = heights[row];
4522 
4523  item_w = (litem->alignment == UI_LAYOUT_ALIGN_EXPAND) ? w : min_ii(w, item_w);
4524  item_h = (litem->alignment == UI_LAYOUT_ALIGN_EXPAND) ? h : min_ii(h, item_h);
4525 
4526  ui_item_position(item, cos_x[col], cos_y[row], item_w, item_h);
4527  }
4528 
4529  litem->h = litem->y - cos_y[gflow->tot_rows - 1];
4530  litem->x = (cos_x[gflow->tot_columns - 1] - litem->x) + widths[gflow->tot_columns - 1];
4531  litem->y = litem->y - litem->h;
4532 }
4533 
4534 /* free layout */
4536 {
4537  int minx = 1e6;
4538  int miny = 1e6;
4539  litem->w = 0;
4540  litem->h = 0;
4541 
4542  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
4543  int itemx, itemy, itemw, itemh;
4544  ui_item_offset(item, &itemx, &itemy);
4545  ui_item_size(item, &itemw, &itemh);
4546 
4547  minx = min_ii(minx, itemx);
4548  miny = min_ii(miny, itemy);
4549 
4550  litem->w = MAX2(litem->w, itemx + itemw);
4551  litem->h = MAX2(litem->h, itemy + itemh);
4552  }
4553 
4554  litem->w -= minx;
4555  litem->h -= miny;
4556 }
4557 
4559 {
4560  float scalex = 1.0f, scaley = 1.0f;
4561  int x, y, newx, newy, itemx, itemy, itemh, itemw;
4562 
4563  int minx = 1e6;
4564  int miny = 1e6;
4565  int totw = 0;
4566  int toth = 0;
4567 
4568  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
4569  ui_item_offset(item, &itemx, &itemy);
4570  ui_item_size(item, &itemw, &itemh);
4571 
4572  minx = min_ii(minx, itemx);
4573  miny = min_ii(miny, itemy);
4574 
4575  totw = max_ii(totw, itemx + itemw);
4576  toth = max_ii(toth, itemy + itemh);
4577  }
4578 
4579  totw -= minx;
4580  toth -= miny;
4581 
4582  if (litem->w && totw > 0) {
4583  scalex = (float)litem->w / (float)totw;
4584  }
4585  if (litem->h && toth > 0) {
4586  scaley = (float)litem->h / (float)toth;
4587  }
4588 
4589  x = litem->x;
4590  y = litem->y - scaley * toth;
4591 
4592  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
4593  ui_item_offset(item, &itemx, &itemy);
4594  ui_item_size(item, &itemw, &itemh);
4595 
4596  if (scalex != 1.0f) {
4597  newx = (itemx - minx) * scalex;
4598  itemw = (itemx - minx + itemw) * scalex - newx;
4599  itemx = minx + newx;
4600  }
4601 
4602  if (scaley != 1.0f) {
4603  newy = (itemy - miny) * scaley;
4604  itemh = (itemy - miny + itemh) * scaley - newy;
4605  itemy = miny + newy;
4606  }
4607 
4608  ui_item_position(item, x + itemx - minx, y + itemy - miny, itemw, itemh);
4609  }
4610 
4611  litem->w = scalex * totw;
4612  litem->h = litem->y - y;
4613  litem->x = x + litem->w;
4614  litem->y = y;
4615 }
4616 
4617 /* split layout */
4619 {
4620  ui_litem_estimate_row(litem);
4621  litem->item.flag &= ~UI_ITEM_FIXED_SIZE;
4622 }
4623 
4624 static void ui_litem_layout_split(uiLayout *litem)
4625 {
4627  float extra_pixel = 0.0f;
4628  const int tot = BLI_listbase_count(&litem->items);
4629 
4630  if (tot == 0) {
4631  return;
4632  }
4633 
4634  int x = litem->x;
4635  const int y = litem->y;
4636 
4637  const float percentage = (split->percentage == 0.0f) ? 1.0f / (float)tot : split->percentage;
4638 
4639  const int w = (litem->w - (tot - 1) * litem->space);
4640  int colw = w * percentage;
4641  colw = MAX2(colw, 0);
4642 
4643  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
4644  int itemh;
4645  ui_item_size(item, NULL, &itemh);
4646 
4647  ui_item_position(item, x, y - itemh, colw, itemh);
4648  x += colw;
4649 
4650  if (item->next) {
4651  const float width = extra_pixel + (w - (int)(w * percentage)) / ((float)tot - 1);
4652  extra_pixel = width - (int)width;
4653  colw = (int)width;
4654  colw = MAX2(colw, 0);
4655 
4656  x += litem->space;
4657  }
4658  }
4659 
4660  litem->w = x - litem->x;
4661  litem->h = litem->y - y;
4662  litem->x = x;
4663  litem->y = y;
4664 }
4665 
4666 /* overlap layout */
4668 {
4669  litem->w = 0;
4670  litem->h = 0;
4671 
4672  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
4673  int itemw, itemh;
4674  ui_item_size(item, &itemw, &itemh);
4675 
4676  litem->w = MAX2(itemw, litem->w);
4677  litem->h = MAX2(itemh, litem->h);
4678  }
4679 }
4680 
4682 {
4683 
4684  const int x = litem->x;
4685  const int y = litem->y;
4686 
4687  LISTBASE_FOREACH (uiItem *, item, &litem->items) {
4688  int itemw, itemh;
4689  ui_item_size(item, &itemw, &itemh);
4690  ui_item_position(item, x, y - itemh, litem->w, itemh);
4691 
4692  litem->h = MAX2(litem->h, itemh);
4693  }
4694 
4695  litem->x = x;
4696  litem->y = y - litem->h;
4697 }
4698 
4699 static void ui_litem_init_from_parent(uiLayout *litem, uiLayout *layout, int align)
4700 {
4701  litem->root = layout->root;
4702  litem->align = align;
4703  /* Children of grid-flow layout shall never have "ideal big size" returned as estimated size. */
4704  litem->variable_size = layout->variable_size || layout->item.type == ITEM_LAYOUT_GRID_FLOW;
4705  litem->active = true;
4706  litem->enabled = true;
4707  litem->context = layout->context;
4708  litem->redalert = layout->redalert;
4709  litem->w = layout->w;
4710  litem->emboss = layout->emboss;
4711  litem->item.flag = (layout->item.flag &
4713 
4714  if (layout->child_items_layout) {
4715  BLI_addtail(&layout->child_items_layout->items, litem);
4716  litem->parent = layout->child_items_layout;
4717  }
4718  else {
4719  BLI_addtail(&layout->items, litem);
4720  litem->parent = layout;
4721  }
4722 }
4723 
4724 static void ui_layout_heading_set(uiLayout *layout, const char *heading)
4725 {
4726  BLI_assert(layout->heading[0] == '\0');
4727  if (heading) {
4728  STRNCPY(layout->heading, heading);
4729  }
4730 }
4731 
4732 uiLayout *uiLayoutRow(uiLayout *layout, bool align)
4733 {
4734  uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
4735  ui_litem_init_from_parent(litem, layout, align);
4736 
4737  litem->item.type = ITEM_LAYOUT_ROW;
4738  litem->space = (align) ? 0 : layout->root->style->buttonspacex;
4739 
4740  UI_block_layout_set_current(layout->root->block, litem);
4741 
4742  return litem;
4743 }
4744 
4745 uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
4746 {
4747  uiLayout *litem = uiLayoutRow(layout, align);
4748  ui_layout_heading_set(litem, heading);
4749  return litem;
4750 }
4751 
4752 uiLayout *uiLayoutColumn(uiLayout *layout, bool align)
4753 {
4754  uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutColumn");
4755  ui_litem_init_from_parent(litem, layout, align);
4756 
4757  litem->item.type = ITEM_LAYOUT_COLUMN;
4758  litem->space = (align) ? 0 : layout->root->style->buttonspacey;
4759 
4760  UI_block_layout_set_current(layout->root->block, litem);
4761 
4762  return litem;
4763 }
4764 
4765 uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading)
4766 {
4767  uiLayout *litem = uiLayoutColumn(layout, align);
4768  ui_layout_heading_set(litem, heading);
4769  return litem;
4770 }
4771 
4772 uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align)
4773 {
4774  uiLayoutItemFlow *flow = MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow");
4775  ui_litem_init_from_parent(&flow->litem, layout, align);
4776 
4778  flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
4779  flow->number = number;
4780 
4781  UI_block_layout_set_current(layout->root->block, &flow->litem);
4782 
4783  return &flow->litem;
4784 }
4785 
4787  bool row_major,
4788  int columns_len,
4789  bool even_columns,
4790  bool even_rows,
4791  bool align)
4792 {
4793  uiLayoutItemGridFlow *flow = MEM_callocN(sizeof(uiLayoutItemGridFlow), __func__);
4795  ui_litem_init_from_parent(&flow->litem, layout, align);
4796 
4797  flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
4798  flow->row_major = row_major;
4799  flow->columns_len = columns_len;
4800  flow->even_columns = even_columns;
4801  flow->even_rows = even_rows;
4802 
4803  UI_block_layout_set_current(layout->root->block, &flow->litem);
4804 
4805  return &flow->litem;
4806 }
4807 
4809 {
4810  uiLayoutItemBx *box = MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx");
4811  ui_litem_init_from_parent(&box->litem, layout, false);
4812 
4813  box->litem.item.type = ITEM_LAYOUT_BOX;
4814  box->litem.space = layout->root->style->columnspace;
4815 
4816  UI_block_layout_set_current(layout->root->block, &box->litem);
4817 
4818  box->roundbox = uiDefBut(layout->root->block, type, 0, "", 0, 0, 0, 0, NULL, 0.0, 0.0, 0, 0, "");
4819 
4820  return box;
4821 }
4822 
4824 {
4825  /* radial layouts are only valid for radial menus */
4826  if (layout->root->type != UI_LAYOUT_PIEMENU) {
4827  return ui_item_local_sublayout(layout, layout, 0);
4828  }
4829 
4830  /* only one radial wheel per root layout is allowed, so check and return that, if it exists */
4831  LISTBASE_FOREACH (uiItem *, item, &layout->root->layout->items) {
4832  uiLayout *litem = (uiLayout *)item;
4833  if (litem->item.type == ITEM_LAYOUT_RADIAL) {
4834  UI_block_layout_set_current(layout->root->block, litem);
4835  return litem;
4836  }
4837  }
4838 
4839  uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRadial");
4840  ui_litem_init_from_parent(litem, layout, false);
4841 
4842  litem->item.type = ITEM_LAYOUT_RADIAL;
4843 
4844  UI_block_layout_set_current(layout->root->block, litem);
4845 
4846  return litem;
4847 }
4848 
4850 {
4851  return (uiLayout *)ui_layout_box(layout, UI_BTYPE_ROUNDBOX);
4852 }
4853 
4855 {
4856  LISTBASE_FOREACH (uiButtonItem *, bitem, &layout->items) {
4857  if (bitem->item.type != ITEM_BUTTON) {
4858  ui_layout_list_set_labels_active((uiLayout *)(&bitem->item));
4859  }
4860  else if (bitem->but->flag & UI_BUT_LIST_ITEM) {
4861  UI_but_flag_enable(bitem->but, UI_SELECT);
4862  }
4863  }
4864 }
4865 
4867  uiList *ui_list,
4868  PointerRNA *actptr,
4869  PropertyRNA *actprop)
4870 {
4872  uiBut *but = box->roundbox;
4873 
4874  but->custom_data = ui_list;
4875 
4876  but->rnapoin = *actptr;
4877  but->rnaprop = actprop;
4878 
4879  /* only for the undo string */
4880  if (but->flag & UI_BUT_UNDO) {
4881  but->tip = RNA_property_description(actprop);
4882  }
4883 
4884  return (uiLayout *)box;
4885 }
4886 
4887 uiLayout *uiLayoutAbsolute(uiLayout *layout, bool align)
4888 {
4889  uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutAbsolute");
4890  ui_litem_init_from_parent(litem, layout, align);
4891 
4892  litem->item.type = ITEM_LAYOUT_ABSOLUTE;
4893 
4894  UI_block_layout_set_current(layout->root->block, litem);
4895 
4896  return litem;
4897 }
4898 
4900 {
4901  uiBlock *block = uiLayoutGetBlock(layout);
4902  uiLayoutAbsolute(layout, false);
4903 
4904  return block;
4905 }
4906 
4908 {
4909  uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutOverlap");
4910  ui_litem_init_from_parent(litem, layout, false);
4911 
4912  litem->item.type = ITEM_LAYOUT_OVERLAP;
4913 
4914  UI_block_layout_set_current(layout->root->block, litem);
4915 
4916  return litem;
4917 }
4918 
4919 uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, bool align)
4920 {
4921  uiLayoutItemSplit *split = MEM_callocN(sizeof(uiLayoutItemSplit), "uiLayoutItemSplit");
4922  ui_litem_init_from_parent(&split->litem, layout, align);
4923 
4924  split->litem.item.type = ITEM_LAYOUT_SPLIT;
4925  split->litem.space = layout->root->style->columnspace;
4926  split->percentage = percentage;
4927 
4928  UI_block_layout_set_current(layout->root->block, &split->litem);
4929 
4930  return &split->litem;
4931 }
4932 
4933 void uiLayoutSetActive(uiLayout *layout, bool active)
4934 {
4935  layout->active = active;
4936 }
4937 
4938 void uiLayoutSetActiveDefault(uiLayout *layout, bool active_default)
4939 {
4940  layout->active_default = active_default;
4941 }
4942 
4943 void uiLayoutSetActivateInit(uiLayout *layout, bool activate_init)
4944 {
4945  layout->activate_init = activate_init;
4946 }
4947 
4949 {
4950  layout->enabled = enabled;
4951 }
4952 
4953 void uiLayoutSetRedAlert(uiLayout *layout, bool redalert)
4954 {
4955  layout->redalert = redalert;
4956 }
4957 
4958 void uiLayoutSetKeepAspect(uiLayout *layout, bool keepaspect)
4959 {
4960  layout->keepaspect = keepaspect;
4961 }
4962 
4963 void uiLayoutSetAlignment(uiLayout *layout, char alignment)
4964 {
4965  layout->alignment = alignment;
4966 }
4967 
4968 void uiLayoutSetScaleX(uiLayout *layout, float scale)
4969 {
4970  layout->scale[0] = scale;
4971 }
4972 
4973 void uiLayoutSetScaleY(uiLayout *layout, float scale)
4974 {
4975  layout->scale[1] = scale;
4976 }
4977 
4978 void uiLayoutSetUnitsX(uiLayout *layout, float unit)
4979 {
4980  layout->units[0] = unit;
4981 }
4982 
4983 void uiLayoutSetUnitsY(uiLayout *layout, float unit)
4984 {
4985  layout->units[1] = unit;
4986 }
4987 
4989 {
4990  layout->emboss = emboss;
4991 }
4992 
4994 {
4995  return (layout->item.flag & UI_ITEM_PROP_SEP) != 0;
4996 }
4997 
4998 void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
4999 {
5000  SET_FLAG_FROM_TEST(layout->item.flag, is_sep, UI_ITEM_PROP_SEP);
5001 }
5002 
5004 {
5005  return (layout->item.flag & UI_ITEM_PROP_DECORATE) != 0;
5006 }
5007 
5008 void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
5009 {
5011 }
5012 
5014 {
5015  return layout->active;
5016 }
5017 
5019 {
5020  return layout->active_default;
5021 }
5022 
5024 {
5025  return layout->activate_init;
5026 }
5027 
5029 {
5030  return layout->enabled;
5031 }
5032 
5034 {
5035  return layout->redalert;
5036 }
5037 
5039 {
5040  return layout->keepaspect;
5041 }
5042 
5044 {
5045  return layout->alignment;
5046 }
5047 
5049 {
5050  return layout->w;
5051 }
5052 
5054 {
5055  return layout->scale[0];
5056 }
5057 
5059 {
5060  return layout->scale[1];
5061 }
5062 
5064 {
5065  return layout->units[0];
5066 }
5067 
5069 {
5070  return layout->units[1];
5071 }
5072 
5074 {
5075  if (layout->emboss == UI_EMBOSS_UNDEFINED) {
5076  return layout->root->block->emboss;
5077  }
5078  return layout->emboss;
5079 }
5080 
5083 /* -------------------------------------------------------------------- */
5087 /* Disabled for performance reasons, but this could be turned on in the future. */
5088 // #define PROPERTY_SEARCH_USE_TOOLTIPS
5089 
5090 static bool block_search_panel_label_matches(const uiBlock *block, const char *search_string)
5091 {
5092  if ((block->panel != NULL) && (block->panel->type != NULL)) {
5093  if (BLI_strcasestr(block->panel->type->label, search_string)) {
5094  return true;
5095  }
5096  }
5097  return false;
5098 }
5099 
5103 static bool button_matches_search_filter(uiBut *but, const char *search_filter)
5104 {
5105  /* Do the shorter checks first for better performance in case there is a match. */
5106  if (BLI_strcasestr(but->str, search_filter)) {
5107  return true;
5108  }
5109 
5110  if (but->optype != NULL) {
5111  if (BLI_strcasestr(but->optype->name, search_filter)) {
5112  return true;
5113  }
5114  }
5115 
5116  if (but->rnaprop != NULL) {
5117  if (BLI_strcasestr(RNA_property_ui_name(but->rnaprop), search_filter)) {
5118  return true;
5119  }
5120 #ifdef PROPERTY_SEARCH_USE_TOOLTIPS
5121  if (BLI_strcasestr(RNA_property_description(but->rnaprop), search_filter)) {
5122  return true;
5123  }
5124 #endif
5125 
5126  /* Search through labels of enum property items if they are in a drop-down menu.
5127  * Unfortunately we have no #bContext here so we cannot search through RNA enums
5128  * with dynamic entries (or "itemf" functions) which require context. */
5129  if (but->type == UI_BTYPE_MENU) {
5130  PointerRNA *ptr = &but->rnapoin;
5131  PropertyRNA *enum_prop = but->rnaprop;
5132  int items_len;
5133  const EnumPropertyItem *items_array = NULL;
5134  bool free;
5135  RNA_property_enum_items_gettexted(NULL, ptr, enum_prop, &items_array, &items_len, &free);
5136  if (items_array == NULL) {
5137  return false;
5138  }
5139 
5140  bool found = false;
5141  for (int i = 0; i < items_len; i++) {
5142  /* Check for NULL name field which enums use for separators. */
5143  if (items_array[i].name == NULL) {
5144  continue;
5145  }
5146  if (BLI_strcasestr(items_array[i].name, search_filter)) {
5147  found = true;
5148  break;
5149  }
5150  }
5151  if (free) {
5152  MEM_freeN((EnumPropertyItem *)items_array);
5153  }
5154  if (found) {
5155  return true;
5156  }
5157  }
5158  }
5159 
5160  return false;
5161 }
5162 
5166 static bool button_group_has_search_match(uiButtonGroup *button_group, const char *search_filter)
5167 {
5168  LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
5169  uiBut *but = link->data;
5170  if (button_matches_search_filter(but, search_filter)) {
5171  return true;
5172  }
5173  }
5174 
5175  return false;
5176 }
5177 
5187 static bool block_search_filter_tag_buttons(uiBlock *block, const char *search_filter)
5188 {
5189  bool has_result = false;
5190  LISTBASE_FOREACH (uiButtonGroup *, button_group, &block->button_groups) {
5191  if (button_group_has_search_match(button_group, search_filter)) {
5192  has_result = true;
5193  }
5194  else {
5195  LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
5196  uiBut *but = link->data;
5198  }
5199  }
5200  }
5201  return has_result;
5202 }
5203 
5204 bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter)
5205 {
5206  if (search_filter == NULL || search_filter[0] == '\0') {
5207  return false;
5208  }
5209 
5210  Panel *panel = block->panel;
5211 
5212  if (panel != NULL && panel->type->flag & PANEL_TYPE_NO_SEARCH) {
5213  /* Panels for active blocks should always have a type, otherwise they wouldn't be created. */
5214  BLI_assert(block->panel->type != NULL);
5215  if (panel->type->flag & PANEL_TYPE_NO_SEARCH) {
5216  return false;
5217  }
5218  }
5219 
5220  const bool panel_label_matches = block_search_panel_label_matches(block, search_filter);
5221 
5222  const bool has_result = (panel_label_matches) ?
5223  true :
5224  block_search_filter_tag_buttons(block, search_filter);
5225 
5226  if (panel != NULL) {
5227  if (has_result) {
5229  }
5230  }
5231 
5232  return has_result;
5233 }
5234 
5237 /* -------------------------------------------------------------------- */
5241 static void ui_item_scale(uiLayout *litem, const float scale[2])
5242 {
5243  int x, y, w, h;
5244 
5245  LISTBASE_FOREACH_BACKWARD (uiItem *, item, &litem->items) {
5246  if (item->type != ITEM_BUTTON) {
5247  uiLayout *subitem = (uiLayout *)item;
5248  ui_item_scale(subitem, scale);
5249  }
5250 
5251  ui_item_size(item, &w, &h);
5252  ui_item_offset(item, &x, &y);
5253 
5254  if (scale[0] != 0.0f) {
5255  x *= scale[0];
5256  w *= scale[0];
5257  }
5258 
5259  if (scale[1] != 0.0f) {
5260  y *= scale[1];
5261  h *= scale[1];
5262  }
5263 
5264  ui_item_position(item, x, y, w, h);
5265  }
5266 }
5267 
5268 static void ui_item_estimate(uiItem *item)
5269 {
5270  if (item->type != ITEM_BUTTON) {
5271  uiLayout *litem = (uiLayout *)item;
5272 
5273  LISTBASE_FOREACH (uiItem *, subitem, &litem->items) {
5274  ui_item_estimate(subitem);
5275  }
5276 
5277  if (BLI_listbase_is_empty(&litem->items)) {
5278  litem->w = 0;
5279  litem->h = 0;
5280  return;
5281  }
5282 
5283  if (litem->scale[0] != 0.0f || litem->scale[1] != 0.0f) {
5284  ui_item_scale(litem, litem->scale);
5285  }
5286 
5287  switch (litem->item.type) {
5288  case ITEM_LAYOUT_COLUMN:
5289  ui_litem_estimate_column(litem, false);
5290  break;
5293  break;
5294  case ITEM_LAYOUT_GRID_FLOW:
5296  break;
5297  case ITEM_LAYOUT_ROW:
5298  ui_litem_estimate_row(litem);
5299  break;
5300  case ITEM_LAYOUT_BOX:
5301  ui_litem_estimate_box(litem);
5302  break;
5303  case ITEM_LAYOUT_ROOT:
5304  ui_litem_estimate_root(litem);
5305  break;
5306  case ITEM_LAYOUT_ABSOLUTE:
5308  break;
5309  case ITEM_LAYOUT_SPLIT:
5310  ui_litem_estimate_split(litem);
5311  break;
5312  case ITEM_LAYOUT_OVERLAP:
5314  break;
5315  default:
5316  break;
5317  }
5318 
5319  /* Force fixed size. */
5320  if (litem->units[0] > 0) {
5321  litem->w = UI_UNIT_X * litem->units[0];
5322  }
5323  if (litem->units[1] > 0) {
5324  litem->h = UI_UNIT_Y * litem->units[1];
5325  }
5326  }
5327 }
5328 
5329 static void ui_item_align(uiLayout *litem, short nr)
5330 {
5331  LISTBASE_FOREACH_BACKWARD (uiItem *, item, &litem->items) {
5332  if (item->type == ITEM_BUTTON) {
5333  uiButtonItem *bitem = (uiButtonItem *)item;
5334 #ifndef USE_UIBUT_SPATIAL_ALIGN
5335  if (ui_but_can_align(bitem->but))
5336 #endif
5337  {
5338  if (!bitem->but->alignnr) {
5339  bitem->but->alignnr = nr;
5340  }
5341  }
5342  }
5343  else if (item->type == ITEM_LAYOUT_ABSOLUTE) {
5344  /* pass */
5345  }
5346  else if (item->type == ITEM_LAYOUT_OVERLAP) {
5347  /* pass */
5348  }
5349  else if (item->type == ITEM_LAYOUT_BOX) {
5350  uiLayoutItemBx *box = (uiLayoutItemBx *)item;
5351  if (!box->roundbox->alignnr) {
5352  box->roundbox->alignnr = nr;
5353  }
5354  }
5355  else if (((uiLayout *)item)->align) {
5356  ui_item_align((uiLayout *)item, nr);
5357  }
5358  }
5359 }
5360 
5361 static void ui_item_flag(uiLayout *litem, int flag)
5362 {
5363  LISTBASE_FOREACH_BACKWARD (uiItem *, item, &litem->items) {
5364  if (item->type == ITEM_BUTTON) {
5365  uiButtonItem *bitem = (uiButtonItem *)item;
5366  bitem->but->flag |= flag;
5367  }
5368  else {
5369  ui_item_flag((uiLayout *)item, flag);
5370  }
5371  }
5372 }
5373 
5374 static void ui_item_layout(uiItem *item)
5375 {
5376  if (item->type != ITEM_BUTTON) {
5377  uiLayout *litem = (uiLayout *)item;
5378 
5379  if (BLI_listbase_is_empty(&litem->items)) {
5380  return;
5381  }
5382 
5383  if (litem->align) {
5384  ui_item_align(litem, ++litem->root->block->alignnr);
5385  }
5386  if (!litem->active) {
5387  ui_item_flag(litem, UI_BUT_INACTIVE);
5388  }
5389  if (!litem->enabled) {
5390  ui_item_flag(litem, UI_BUT_DISABLED);
5391  }
5392 
5393  switch (litem->item.type) {
5394  case ITEM_LAYOUT_COLUMN:
5395  ui_litem_layout_column(litem, false, false);
5396  break;
5399  break;
5400  case ITEM_LAYOUT_GRID_FLOW:
5402  break;
5403  case ITEM_LAYOUT_ROW:
5404  ui_litem_layout_row(litem);
5405  break;
5406  case ITEM_LAYOUT_BOX:
5407  ui_litem_layout_box(litem);
5408  break;
5409  case ITEM_LAYOUT_ROOT:
5410  ui_litem_layout_root(litem);
5411  break;
5412  case ITEM_LAYOUT_ABSOLUTE:
5413  ui_litem_layout_absolute(litem);
5414  break;
5415  case ITEM_LAYOUT_SPLIT:
5416  ui_litem_layout_split(litem);
5417  break;
5418  case ITEM_LAYOUT_OVERLAP:
5419  ui_litem_layout_overlap(litem);
5420  break;
5421  case ITEM_LAYOUT_RADIAL:
5422  ui_litem_layout_radial(litem);
5423  break;
5424  default:
5425  break;
5426  }
5427 
5428  LISTBASE_FOREACH (uiItem *, subitem, &litem->items) {
5429  if (item->flag & UI_ITEM_BOX_ITEM) {
5430  subitem->flag |= UI_ITEM_BOX_ITEM;
5431  }
5432  ui_item_layout(subitem);
5433  }
5434  }
5435  else {
5436  if (item->flag & UI_ITEM_BOX_ITEM) {
5437  uiButtonItem *bitem = (uiButtonItem *)item;
5438  bitem->but->drawflag |= UI_BUT_BOX_ITEM;
5439  }
5440  }
5441 }
5442 
5443 static void ui_layout_end(uiBlock *block, uiLayout *layout, int *r_x, int *r_y)
5444 {
5445  if (layout->root->handlefunc) {
5446  UI_block_func_handle_set(block, layout->root->handlefunc, layout->root->argv);
5447  }
5448 
5449  ui_item_estimate(&layout->item);
5450  ui_item_layout(&layout->item);
5451 
5452  if (r_x) {
5453  *r_x = layout->x;
5454  }
5455  if (r_y) {
5456  *r_y = layout->y;
5457  }
5458 }
5459 
5460 static void ui_layout_free(uiLayout *layout)
5461 {
5462  LISTBASE_FOREACH_MUTABLE (uiItem *, item, &layout->items) {
5463  if (item->type == ITEM_BUTTON) {
5464  uiButtonItem *bitem = (uiButtonItem *)item;
5465 
5466  bitem->but->layout = NULL;
5467  MEM_freeN(item);
5468  }
5469  else {
5470  ui_layout_free((uiLayout *)item);
5471  }
5472  }
5473 
5474  MEM_freeN(layout);
5475 }
5476 
5478 {
5479  if (root->padding) {
5480  /* add an invisible button for padding */
5481  uiBlock *block = root->block;
5482  uiLayout *prev_layout = block->curlayout;
5483 
5484  block->curlayout = root->layout;
5485  uiDefBut(
5486  block, UI_BTYPE_SEPR, 0, "", 0, 0, root->padding, root->padding, NULL, 0.0, 0.0, 0, 0, "");
5487  block->curlayout = prev_layout;
5488  }
5489 }
5490 
5492  int dir,
5493  int type,
5494  int x,
5495  int y,
5496  int size,
5497  int em,
5498  int padding,
5499  const uiStyle *style)
5500 {
5501  uiLayoutRoot *root = MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot");
5502  root->type = type;
5503  root->style = style;
5504  root->block = block;
5505  root->padding = padding;
5507 
5508  uiLayout *layout = MEM_callocN(sizeof(uiLayout), "uiLayout");
5510 
5511  /* Only used when 'UI_ITEM_PROP_SEP' is set. */
5512  layout->item.flag = UI_ITEM_PROP_DECORATE;
5513 
5514  layout->x = x;
5515  layout->y = y;
5516  layout->root = root;
5517  layout->space = style->templatespace;
5518  layout->active = true;
5519  layout->enabled = true;
5520  layout->context = NULL;
5521  layout->emboss = UI_EMBOSS_UNDEFINED;
5522 
5524  layout->space = 0;
5525  }
5526 
5527  if (dir == UI_LAYOUT_HORIZONTAL) {
5528  layout->h = size;
5529  layout->root->emh = em * UI_UNIT_Y;
5530  }
5531  else {
5532  layout->w = size;
5533  layout->root->emw = em * UI_UNIT_X;
5534  }
5535 
5536  block->curlayout = layout;
5537  root->layout = layout;
5538  BLI_addtail(&block->layouts, root);
5539 
5541 
5542  return layout;
5543 }
5544 
5546 {
5547  return layout->root->block;
5548 }
5549 
5551 {
5552  return layout->root->opcontext;
5553 }
5554 
5556 {
5557  block->curlayout = layout;
5558 }
5559 
5560 void ui_layout_add_but(uiLayout *layout, uiBut *but)
5561 {
5562  uiButtonItem *bitem = MEM_callocN(sizeof(uiButtonItem), "uiButtonItem");
5563  bitem->item.type = ITEM_BUTTON;
5564  bitem->but = but;
5565 
5566  int w, h;
5567  ui_item_size((uiItem *)bitem, &w, &h);
5568  /* XXX uiBut hasn't scaled yet
5569  * we can flag the button as not expandable, depending on its size */
5570  if (w <= 2 * UI_UNIT_X && (!but->str || but->str[0] == '\0')) {
5571  bitem->item.flag |= UI_ITEM_FIXED_SIZE;
5572  }
5573 
5574  if (layout->child_items_layout) {
5575  BLI_addtail(&layout->child_items_layout->items, bitem);
5576  }
5577  else {
5578  BLI_addtail(&layout->items, bitem);
5579  }
5580  but->layout = layout;
5581 
5582  if (layout->context) {
5583  but->context = layout->context;
5584  but->context->used = true;
5585  }
5586 
5587  if (layout->emboss != UI_EMBOSS_UNDEFINED) {
5588  but->emboss = layout->emboss;
5589  }
5590 
5592 }
5593 
5594 static uiButtonItem *ui_layout_find_button_item(const uiLayout *layout, const uiBut *but)
5595 {
5596  const ListBase *child_list = layout->child_items_layout ? &layout->child_items_layout->items :
5597  &layout->items;
5598 
5599  LISTBASE_FOREACH (uiItem *, item, child_list) {
5600  if (item->type == ITEM_BUTTON) {
5601  uiButtonItem *bitem = (uiButtonItem *)item;
5602 
5603  if (bitem->but == but) {
5604  return bitem;
5605  }
5606  }
5607  else {
5608  uiButtonItem *nested_item = ui_layout_find_button_item((uiLayout *)item, but);
5609  if (nested_item) {
5610  return nested_item;
5611  }
5612  }
5613  }
5614 
5615  return NULL;
5616 }
5617 
5618 void ui_layout_remove_but(uiLayout *layout, const uiBut *but)
5619 {
5620  uiButtonItem *bitem = ui_layout_find_button_item(layout, but);
5621  if (!bitem) {
5622  return;
5623  }
5624 
5625  BLI_freelinkN(&layout->items, bitem);
5626 }
5627 
5628 bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
5629 {
5630  uiButtonItem *bitem = ui_layout_find_button_item(layout, old_but_ptr);
5631  if (!bitem) {
5632  return false;
5633  }
5634 
5635  bitem->but = new_but;
5636  return true;
5637 }
5638 
5639 void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size)
5640 {
5641  if (fixed_size) {
5642  layout->item.flag |= UI_ITEM_FIXED_SIZE;
5643  }
5644  else {
5645  layout->item.flag &= ~UI_ITEM_FIXED_SIZE;
5646  }
5647 }
5648 
5650 {
5651  return (layout->item.flag & UI_ITEM_FIXED_SIZE) != 0;
5652 }
5653 
5655 {
5656  layout->root->opcontext = opcontext;
5657 }
5658 
5659 void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
5660 {
5661  layout->root->handlefunc = handlefunc;
5662  layout->root->argv = argv;
5663 }
5664 
5666 {
5667  LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
5668  ui_layout_free(root->layout);
5669  MEM_freeN(root);
5670  }
5671 }
5672 
5673 void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
5674 {
5675  BLI_assert(block->active);
5676 
5677  if (r_x) {
5678  *r_x = 0;
5679  }
5680  if (r_y) {
5681  *r_y = 0;
5682  }
5683 
5684  block->curlayout = NULL;
5685 
5686  LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
5688 
5689  /* NULL in advance so we don't interfere when adding button */
5690  ui_layout_end(block, root->layout, r_x, r_y);
5691  ui_layout_free(root->layout);
5692  MEM_freeN(root);
5693  }
5694 
5695  BLI_listbase_clear(&block->layouts);
5696 
5697  /* XXX silly trick, interface_templates.c doesn't get linked
5698  * because it's not used by other files in this module? */
5699  {
5701  }
5702 }
5703 
5705 {
5706  return !BLI_listbase_is_empty(&block->layouts);
5707 }
5708 
5709 void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
5710 {
5711  uiBlock *block = layout->root->block;
5712  layout->context = CTX_store_add(&block->contexts, name, ptr);
5713 }
5714 
5716 {
5717  return layout->context;
5718 }
5719 
5721 {
5722  uiBlock *block = layout->root->block;
5723  layout->context = CTX_store_add_all(&block->contexts, context);
5724 }
5725 
5727  uiButToolTipFunc func,
5728  void *arg,
5729  uiCopyArgFunc copy_arg,
5730  uiFreeArgFunc free_arg)
5731 {
5732  bool arg_used = false;
5733 
5734  LISTBASE_FOREACH (uiItem *, item, &layout->items) {
5735  /* Each button will call free_arg for "its" argument, so we need to
5736  * duplicate the allocation for each button after the first. */
5737  if (copy_arg != NULL && arg_used) {
5738  arg = copy_arg(arg);
5739  }
5740  arg_used = true;
5741 
5742  if (item->type == ITEM_BUTTON) {
5743  uiButtonItem *bitem = (uiButtonItem *)item;
5744  if (bitem->but->type == UI_BTYPE_DECORATOR) {
5745  continue;
5746  }
5747  UI_but_func_tooltip_set(bitem->but, func, arg, free_arg);
5748  }
5749  else {
5750  uiLayoutSetTooltipFunc((uiLayout *)item, func, arg, copy_arg, free_arg);
5751  }
5752  }
5753 
5754  if (!arg_used) {
5755  /* Free the original copy of arg in case the layout is empty. */
5756  free_arg(arg);
5757  }
5758 }
5759 
5761 {
5762  if (but->opptr) {
5763  uiLayoutSetContextPointer(layout, "button_operator", but->opptr);
5764  }
5765 
5766  if (but->rnapoin.data && but->rnaprop) {
5767  /* TODO: index could be supported as well */
5768  PointerRNA ptr_prop;
5769  RNA_pointer_create(NULL, &RNA_Property, but->rnaprop, &ptr_prop);
5770  uiLayoutSetContextPointer(layout, "button_prop", &ptr_prop);
5771  uiLayoutSetContextPointer(layout, "button_pointer", &but->rnapoin);
5772  }
5773 }
5774 
5776 {
5777  if (r_prop != NULL) {
5778  *r_prop = NULL;
5779  }
5780 
5782  MenuItemLevel *lvl = but->func_argN;
5783  wmOperatorType *ot = WM_operatortype_find(lvl->opname, false);
5784  if ((ot != NULL) && (r_prop != NULL)) {
5785  *r_prop = RNA_struct_type_find_property(ot->srna, lvl->propname);
5786  }
5787  return ot;
5788  }
5789  return NULL;
5790 }
5791 
5793 {
5795  return (MenuType *)but->poin;
5796  }
5797  return NULL;
5798 }
5799 
5801 {
5803  return (PanelType *)but->poin;
5804  }
5805  return NULL;
5806 }
5807 
5808 void UI_menutype_draw(bContext *C, MenuType *mt, struct uiLayout *layout)
5809 {
5810  Menu menu = {
5811  .layout = layout,
5812  .type = mt,
5813  };
5814 
5815  if (G.debug & G_DEBUG_WM) {
5816  printf("%s: opening menu \"%s\"\n", __func__, mt->idname);
5817  }
5818 
5819  if (layout->context) {
5820  CTX_store_set(C, layout->context);
5821  }
5822 
5823  mt->draw(C, &menu);
5824 
5825  if (layout->context) {
5826  CTX_store_set(C, NULL);
5827  }
5828 }
5829 
5830 static bool ui_layout_has_panel_label(const uiLayout *layout, const PanelType *pt)
5831 {
5832  LISTBASE_FOREACH (uiItem *, subitem, &layout->items) {
5833  if (subitem->type == ITEM_BUTTON) {
5834  uiButtonItem *bitem = (uiButtonItem *)subitem;
5835  if (!(bitem->but->flag & UI_HIDDEN) && STREQ(bitem->but->str, pt->label)) {
5836  return true;
5837  }
5838  }
5839  else {
5840  uiLayout *litem = (uiLayout *)subitem;
5841  if (ui_layout_has_panel_label(litem, pt)) {
5842  return true;
5843  }
5844  }
5845  }
5846 
5847  return false;
5848 }
5849 
5850 static void ui_paneltype_draw_impl(bContext *C, PanelType *pt, uiLayout *layout, bool show_header)
5851 {
5852  Panel *panel = MEM_callocN(sizeof(Panel), "popover panel");
5853  panel->type = pt;
5854  panel->flag = PNL_POPOVER;
5855 
5856  uiLayout *last_item = layout->items.last;
5857 
5858  /* Draw main panel. */
5859  if (show_header) {
5860  uiLayout *row = uiLayoutRow(layout, false);
5861  if (pt->draw_header) {
5862  panel->layout = row;
5863  pt->draw_header(C, panel);
5864  panel->layout = NULL;
5865  }
5866 
5867  /* draw_header() is often used to add a checkbox to the header. If we add the label like below
5868  * the label is disconnected from the checkbox, adding a weird looking gap. As workaround, let
5869  * the checkbox add the label instead. */
5870  if (!ui_layout_has_panel_label(row, pt)) {
5871  uiItemL(row, CTX_IFACE_(pt->translation_context, pt->label), ICON_NONE);
5872  }
5873  }
5874 
5875  panel->layout = layout;
5876  pt->draw(C, panel);
5877  panel->layout = NULL;
5879 
5880  MEM_freeN(panel);
5881 
5882  /* Draw child panels. */
5883  LISTBASE_FOREACH (LinkData *, link, &pt->children) {
5884  PanelType *child_pt = link->data;
5885 
5886  if (child_pt->poll == NULL || child_pt->poll(C, child_pt)) {
5887  /* Add space if something was added to the layout. */
5888  if (last_item != layout->items.last) {
5889  uiItemS(layout);
5890  last_item = layout->items.last;
5891  }
5892 
5893  uiLayout *col = uiLayoutColumn(layout, false);
5894  ui_paneltype_draw_impl(C, child_pt, col, true);
5895  }
5896  }
5897 }
5898 
5900 {
5901  if (layout->context) {
5902  CTX_store_set(C, layout->context);
5903  }
5904 
5905  ui_paneltype_draw_impl(C, pt, layout, false);
5906 
5907  if (layout->context) {
5908  CTX_store_set(C, NULL);
5909  }
5910 }
5911 
5914 /* -------------------------------------------------------------------- */
5926 {
5927  uiBut *but = bitem->but;
5928  BLI_dynstr_appendf(ds, "'type':%d, ", (int)but->type);
5929  BLI_dynstr_appendf(ds, "'draw_string':'''%s''', ", but->drawstr);
5930  /* Not exactly needed, rna has this. */
5931  BLI_dynstr_appendf(ds, "'tip':'''%s''', ", but->tip ? but->tip : "");
5932 
5933  if (but->optype) {
5934  char *opstr = WM_operator_pystring_ex(
5935  but->block->evil_C, NULL, false, true, but->optype, but->opptr);
5936  BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr ? opstr : "");
5937  MEM_freeN(opstr);
5938  }
5939 
5940  {
5941  PropertyRNA *prop = NULL;
5943  if (ot) {
5944  char *opstr = WM_operator_pystring_ex(but->block->evil_C, NULL, false, true, ot, NULL);
5945  BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr ? opstr : "");
5946  BLI_dynstr_appendf(ds, "'property':'''%s''', ", prop ? RNA_property_identifier(prop) : "");
5947  MEM_freeN(opstr);
5948  }
5949  }
5950 
5951  if (but->rnaprop) {
5952  BLI_dynstr_appendf(ds,
5953  "'rna':'%s.%s[%d]', ",
5956  but->rnaindex);
5957  }
5958 }
5959 
5961 {
5962  uiItem *item;
5963 
5964  BLI_dynstr_append(ds, "[");
5965 
5966  for (item = lb->first; item; item = item->next) {
5967 
5968  BLI_dynstr_append(ds, "{");
5969 
5970 #define CASE_ITEM(id) \
5971  case id: { \
5972  const char *id_str = STRINGIFY(id); \
5973  BLI_dynstr_append(ds, "'type': '"); \
5974  /* Skip 'ITEM_'. */ \
5975  BLI_dynstr_append(ds, id_str + 5); \
5976  BLI_dynstr_append(ds, "', "); \
5977  break; \
5978  } \
5979  ((void)0)
5980 
5981  switch (item->type) {
5994  }
5995 
5996 #undef CASE_ITEM
5997 
5998  switch (item->type) {
5999  case ITEM_BUTTON:
6001  break;
6002  default:
6003  BLI_dynstr_append(ds, "'items':");
6004  ui_layout_introspect_items(ds, &((uiLayout *)item)->items);
6005  break;
6006  }
6007 
6008  BLI_dynstr_append(ds, "}");
6009 
6010  if (item != lb->last) {
6011  BLI_dynstr_append(ds, ", ");
6012  }
6013  }
6014  /* Don't use a comma here as it's not needed and
6015  * causes the result to evaluate to a tuple of 1. */
6016  BLI_dynstr_append(ds, "]");
6017 }
6018 
6019 const char *UI_layout_introspect(uiLayout *layout)
6020 {
6021  DynStr *ds = BLI_dynstr_new();
6022  uiLayout layout_copy = *layout;
6023  layout_copy.item.next = NULL;
6024  layout_copy.item.prev = NULL;
6025  ListBase layout_dummy_list = {&layout_copy, &layout_copy};
6026  ui_layout_introspect_items(ds, &layout_dummy_list);
6027  const char *result = BLI_dynstr_get_cstring(ds);
6028  BLI_dynstr_free(ds);
6029  return result;
6030 }
6031 
6034 /* -------------------------------------------------------------------- */
6038 uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
6039 {
6040  const uiStyle *style = UI_style_get_dpi();
6041  const short icon_size = 64 * U.dpi_fac;
6042  const int text_points_max = MAX2(style->widget.points, style->widgetlabel.points);
6043  const int dialog_width = icon_size + (text_points_max * size * U.dpi_fac);
6044  /* By default, the space between icon and text/buttons will be equal to the 'columnspace',
6045  * this extra padding will add some space by increasing the left column width,
6046  * making the icon placement more symmetrical, between the block edge and the text. */
6047  const float icon_padding = 5.0f * U.dpi_fac;
6048  /* Calculate the factor of the fixed icon column depending on the block width. */
6049  const float split_factor = ((float)icon_size + icon_padding) /
6050  (float)(dialog_width - style->columnspace);
6051 
6052  uiLayout *block_layout = UI_block_layout(
6053  block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style);
6054 
6055  /* Split layout to put alert icon on left side. */
6056  uiLayout *split_block = uiLayoutSplit(block_layout, split_factor, false);
6057 
6058  /* Alert icon on the left. */
6059  uiLayout *layout = uiLayoutRow(split_block, false);
6060  /* Using 'align_left' with 'row' avoids stretching the icon along the width of column. */
6062  uiDefButAlert(block, icon, 0, 0, icon_size, icon_size);
6063 
6064  /* The rest of the content on the right. */
6065  layout = uiLayoutColumn(split_block, false);
6066 
6067  return layout;
6068 }
6069 
typedef float(TangentPoint)[2]
void CTX_store_set(bContext *C, bContextStore *store)
Definition: context.c:188
struct ARegion * CTX_wm_menu(const bContext *C)
Definition: context.c:760
bContextStore * CTX_store_add(ListBase *contexts, const char *name, const PointerRNA *ptr)
Definition: context.c:128
bContextStore * CTX_store_add_all(ListBase *contexts, bContextStore *context)
Definition: context.c:156
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
bContextStore * CTX_store_get(bContext *C)
Definition: context.c:183
#define G_MAIN
Definition: BKE_global.h:267
@ G_DEBUG_WM
Definition: BKE_global.h:179
struct IDProperty * IDP_New(char type, const IDPropertyTemplate *val, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: idprop.c:887
void IDP_FreeProperty(struct IDProperty *prop)
Definition: idprop.c:1093
struct IDProperty * IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
@ PANEL_TYPE_NO_SEARCH
Definition: BKE_screen.h:287
struct SpaceType * BKE_spacetype_from_id(int spaceid)
Definition: screen.c:353
struct ARegionType * BKE_regiontype_from_id(const struct SpaceType *st, int regionid)
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:22
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_dynstr.c:50
char * BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_dynstr.c:256
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition: BLI_dynstr.c:281
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL()
Definition: BLI_dynstr.c:75
void BLI_kdtree_nd_() free(KDTree *tree)
Definition: kdtree_impl.h:102
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:239
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
Definition: BLI_listbase.h:348
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:301
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
Definition: BLI_listbase.h:344
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
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)
Generic memory manipulation API.
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:198
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
#define STRNCPY_RLEN(dst, src)
Definition: BLI_string.h:484
char * BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:538
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
unsigned int uint
Definition: BLI_sys_types.h:67
#define POINTER_FROM_INT(i)
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define POINTER_AS_INT(i)
#define MAX2(a, b)
#define UNLIKELY(x)
#define ELEM(...)
#define MIN2(a, b)
#define STREQ(a, b)
#define TIP_(msgid)
#define CTX_IFACE_(context, msgid)
@ IDP_GROUP
Definition: DNA_ID.h:141
#define MAX_IDPROP_NAME
Definition: DNA_ID.h:131
#define RGN_ALIGN_ENUM_FROM_MASK(align)
@ PNL_POPOVER
@ RGN_ALIGN_BOTTOM
@ RGN_ALIGN_LEFT
@ RGN_ALIGN_RIGHT
#define OP_MAX_TYPENAME
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
Read Guarded memory(de)allocation.
#define RNA_STRUCT_BEGIN(sptr, prop)
Definition: RNA_access.h:569
#define RNA_STRUCT_END
Definition: RNA_access.h:589
#define RNA_warning(format,...)
Definition: RNA_access.h:756
eStringPropertySearchFlag
Definition: RNA_types.h:547
@ PROP_STRING_SEARCH_SUGGESTION
Definition: RNA_types.h:561
PropertyType
Definition: RNA_types.h:58
@ PROP_FLOAT
Definition: RNA_types.h:61
@ PROP_BOOLEAN
Definition: RNA_types.h:59
@ PROP_ENUM
Definition: RNA_types.h:63
@ PROP_INT
Definition: RNA_types.h:60
@ PROP_STRING
Definition: RNA_types.h:62
@ PROP_POINTER
Definition: RNA_types.h:64
@ PROP_COLLECTION
Definition: RNA_types.h:65
@ PROP_UNIT_ROTATION
Definition: RNA_types.h:75
@ PROP_ENUM_FLAG
Definition: RNA_types.h:266
@ PROP_ICONS_CONSECUTIVE
Definition: RNA_types.h:212
PropertySubType
Definition: RNA_types.h:125
@ PROP_MATRIX
Definition: RNA_types.h:158
@ PROP_DIRECTION
Definition: RNA_types.h:155
@ PROP_LAYER_MEMBER
Definition: RNA_types.h:171
@ PROP_COLOR
Definition: RNA_types.h:153
@ PROP_AXISANGLE
Definition: RNA_types.h:161
@ PROP_DIRPATH
Definition: RNA_types.h:130
@ PROP_COLOR_GAMMA
Definition: RNA_types.h:165
@ PROP_LAYER
Definition: RNA_types.h:170
@ PROP_FILEPATH
Definition: RNA_types.h:129
#define C
Definition: RandGen.cpp:25
@ UI_LAYOUT_ALIGN_LEFT
@ UI_LAYOUT_ALIGN_CENTER
@ UI_LAYOUT_ALIGN_RIGHT
@ UI_LAYOUT_ALIGN_EXPAND
@ UI_BUT_TEXT_RIGHT
Definition: UI_interface.h:261
@ UI_BUT_ICON_LEFT
Definition: UI_interface.h:260
@ UI_BUT_CHECKBOX_INVERT
Definition: UI_interface.h:300
@ UI_BUT_TEXT_LEFT
Definition: UI_interface.h:259
@ UI_BUT_BOX_ITEM
Definition: UI_interface.h:286
void UI_but_disable(uiBut *but, const char *disabled_hint)
Definition: interface.cc:5883
@ UI_LAYOUT_VERTICAL
@ UI_LAYOUT_HORIZONTAL
uiBut * uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:5623
#define UI_UNIT_Y
uiBut * uiDefIconTextButR_prop(uiBlock *block, int type, int retval, int icon, const char *str, int x, int y, short width, short height, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:5733
@ UI_BUT_DRAG_LOCK
Definition: UI_interface.h:194
@ UI_BUT_LIST_ITEM
Definition: UI_interface.h:215
@ UI_BUT_REDALERT
Definition: UI_interface.h:201
@ UI_BUT_UNDO
Definition: UI_interface.h:205
@ UI_BUT_ACTIVE_DEFAULT
Definition: UI_interface.h:212
@ UI_BUT_ACTIVATE_ON_INIT
Definition: UI_interface.h:219
@ UI_BUT_DISABLED
Definition: UI_interface.h:196
@ UI_BUT_INACTIVE
Definition: UI_interface.h:203
@ UI_BUT_VALUE_CLEAR
Definition: UI_interface.h:228
@ UI_BUT_LAST_ACTIVE
Definition: UI_interface.h:204
uiBut * uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, const char *str, int x, int y, short width, short height, const char *tip)
Definition: interface.cc:6118
eUIEmbossType
Definition: UI_interface.h:107
@ UI_EMBOSS_UNDEFINED
Definition: UI_interface.h:118
@ UI_EMBOSS_NONE
Definition: UI_interface.h:109
@ UI_EMBOSS_RADIAL
Definition: UI_interface.h:111
@ UI_EMBOSS_PULLDOWN
Definition: UI_interface.h:110
@ UI_EMBOSS_NONE_OR_STATUS
Definition: UI_interface.h:116
void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *but)
const struct uiStyle * UI_style_get_dpi(void)
uiBut * uiDefIconBut(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:5336
bool UI_block_can_add_separator(const uiBlock *block)
uiBut * uiDefBut(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:4806
uiBut * uiDefIconButI(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, int *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:5392
void UI_but_func_search_set_results_are_suggestions(uiBut *but, bool value)
Definition: interface.cc:6324
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *arg, uiFreeArgFunc free_arg)
Definition: interface.cc:6029
struct PointerRNA * UI_but_operator_ptr_get(uiBut *but)
Definition: interface.cc:5908
uiBut * uiDefIconTextButI(uiBlock *block, int type, int retval, int icon, const char *str, int x, int y, short width, short height, int *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:5677
uiBut * uiDefAutoButR(uiBlock *block, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, const char *name, int icon, int x, int y, int width, int height)
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)
Definition: interface.cc:6242
uiBut * uiDefIconButR_prop(uiBlock *block, int type, int retval, int icon, int x, int y, short width, short height, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:5570
bool UI_but_is_userdef(const uiBut *but)
@ UI_LAYOUT_PIEMENU
@ UI_LAYOUT_MENU
@ UI_LAYOUT_PANEL
@ UI_LAYOUT_VERT_BAR
@ UI_LAYOUT_TOOLBAR
@ UI_LAYOUT_HEADER
char *(* uiButToolTipFunc)(struct bContext *C, void *argN, const char *tip)
Definition: UI_interface.h:537
void *(* uiCopyArgFunc)(const void *arg)
Definition: UI_interface.h:602
struct uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void UI_but_drawflag_enable(uiBut *but, int flag)
Definition: interface.cc:5873
@ UI_DIR_DOWN
Definition: UI_interface.h:124
@ UI_DIR_RIGHT
Definition: UI_interface.h:126
@ UI_DIR_LEFT
Definition: UI_interface.h:125
@ UI_DIR_UP
Definition: UI_interface.h:123
void UI_butstore_free(uiBlock *block, uiButStore *bs)
void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg)
Definition: interface.cc:5953
void(* uiFreeArgFunc)(void *arg)
Definition: UI_interface.h:603
void UI_but_drag_set_id(uiBut *but, struct ID *id)
@ UI_ITEM_R_EVENT
@ UI_ITEM_R_TOGGLE
@ UI_ITEM_O_DEPRESS
@ UI_ITEM_R_SPLIT_EMPTY_NAME
@ UI_ITEM_R_ICON_NEVER
@ UI_ITEM_R_IMMEDIATE
@ UI_ITEM_R_FORCE_BLANK_DECORATE
@ UI_ITEM_R_COMPACT
@ UI_ITEM_R_EXPAND
@ UI_ITEM_R_NO_BG
@ UI_ITEM_R_CHECKBOX_INVERT
@ UI_ITEM_R_ICON_ONLY
@ UI_ITEM_R_FULL_EVENT
@ UI_ITEM_R_SLIDER
int int UI_fontstyle_string_width_with_block_aspect(const struct uiFontStyle *fs, const char *str, float aspect) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
void UI_but_type_set_menu_from_pulldown(uiBut *but)
Definition: interface.cc:5895
#define UI_MAX_DRAW_STR
Definition: UI_interface.h:91
uiBut * uiDefIconTextButO_ptr(uiBlock *block, int type, struct wmOperatorType *ot, wmOperatorCallContext opcontext, int icon, const char *str, int x, int y, short width, short height, const char *tip)
Definition: interface.cc:5757
#define UI_DPI_FAC
Definition: UI_interface.h:305
void UI_but_drawflag_disable(uiBut *but, int flag)
Definition: interface.cc:5878
uiBut * uiDefIconButO_ptr(uiBlock *block, int type, struct wmOperatorType *ot, wmOperatorCallContext opcontext, int icon, int x, int y, short width, short height, const char *tip)
Definition: interface.cc:5593
void UI_but_func_set(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2)
Definition: interface.cc:6000
uiBut * uiDefButR_prop(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:5280
uiButStore * UI_butstore_create(uiBlock *block)
void UI_block_align_begin(uiBlock *block)
Definition: interface.cc:3910
uiBut * uiDefIconMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, int x, int y, short width, short height, const char *tip)
Definition: interface.cc:6143
void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p)
uiBut * uiDefButO_ptr(uiBlock *block, int type, struct wmOperatorType *ot, wmOperatorCallContext opcontext, const char *str, int x, int y, short width, short height, const char *tip)
Definition: interface.cc:5303
uiBut * uiDefMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip)
Definition: interface.cc:6101
uiBut * uiDefButI(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, int *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.cc:5072
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup)
void(* uiMenuCreateFunc)(struct bContext *C, struct uiLayout *layout, void *arg1)
Definition: UI_interface.h:592
void(* uiMenuHandleFunc)(struct bContext *C, void *arg, int event)
Definition: UI_interface.h:593
void UI_block_direction_set(uiBlock *block, char direction)
Definition: interface.cc:5810
void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN)
Definition: interface.cc:6488
#define UI_FSTYLE_WIDGET
#define UI_UNIT_X
eButType
Definition: UI_interface.h:329
@ UI_BTYPE_BUT
Definition: UI_interface.h:330
@ UI_BTYPE_TOGGLE
Definition: UI_interface.h:340
@ UI_BTYPE_TAB
Definition: UI_interface.h:350
@ UI_BTYPE_HOTKEY_EVENT
Definition: UI_interface.h:377
@ UI_BTYPE_LISTBOX
Definition: UI_interface.h:366
@ UI_BTYPE_SEPR_SPACER
Definition: UI_interface.h:388
@ UI_BTYPE_ROUNDBOX
Definition: UI_interface.h:359
@ UI_BTYPE_NUM_SLIDER
Definition: UI_interface.h:339
@ UI_BTYPE_TEXT
Definition: UI_interface.h:332
@ UI_BTYPE_LABEL
Definition: UI_interface.h:354
@ UI_BTYPE_ICON_TOGGLE_N
Definition: UI_interface.h:343
@ UI_BTYPE_DECORATOR
Definition: UI_interface.h:391
@ UI_BTYPE_ROW
Definition: UI_interface.h:331
@ UI_BTYPE_SEARCH_MENU
Definition: UI_interface.h:372
@ UI_BTYPE_UNITVEC
Definition: UI_interface.h:362
@ UI_BTYPE_SEPR_LINE
Definition: UI_interface.h:386
@ UI_BTYPE_KEY_EVENT
Definition: UI_interface.h:355
@ UI_BTYPE_POPOVER
Definition: UI_interface.h:351
@ UI_BTYPE_CHECKBOX_N
Definition: UI_interface.h:348
@ UI_BTYPE_SEPR
Definition: UI_interface.h:385
@ UI_BTYPE_NUM
Definition: UI_interface.h:337
@ UI_BTYPE_COLOR
Definition: UI_interface.h:349
@ UI_BTYPE_CHECKBOX
Definition: UI_interface.h:347
@ UI_BTYPE_MENU
Definition: UI_interface.h:334
@ UI_BTYPE_ICON_TOGGLE
Definition: UI_interface.h:342
#define UI_MAX_NAME_STR
Definition: UI_interface.h:92
void UI_template_fix_linking(void)
uiBut * uiDefButAlert(uiBlock *block, int icon, int x, int y, short width, short height)
Definition: interface.cc:4847
void UI_but_unit_type_set(uiBut *but, int unit_type)
Definition: interface.cc:5934
void UI_but_flag_enable(uiBut *but, int flag)
Definition: interface.cc:5858
uiPopupMenu * UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL()
uiBut * uiDefIconButO(uiBlock *block, int type, const char *opname, wmOperatorCallContext opcontext, int icon, int x, int y, short width, short height, const char *tip)
Definition: interface.cc:5608
@ UI_BLOCK_LOOP
Definition: UI_interface.h:135
@ UI_BLOCK_IS_FLIP
Definition: UI_interface.h:136
@ UI_BLOCK_LIST_ITEM
Definition: UI_interface.h:155
@ UI_BLOCK_NO_FLIP
Definition: UI_interface.h:137
@ UI_BLOCK_POPUP_HOLD
Definition: UI_interface.h:154
void UI_block_align_end(uiBlock *block)
Definition: interface.cc:3923
eAlertIcon
@ KM_NOTHING
Definition: WM_types.h:266
wmOperatorCallContext
Definition: WM_types.h:199
@ WM_OP_INVOKE_REGION_WIN
Definition: WM_types.h:202
@ WM_OP_INVOKE_DEFAULT
Definition: WM_types.h:201
@ KM_CTRL
Definition: WM_types.h:239
@ KM_ALT
Definition: WM_types.h:240
@ KM_OSKEY
Definition: WM_types.h:242
@ KM_SHIFT
Definition: WM_types.h:238
#define KM_MOD_HELD
Definition: WM_types.h:253
__forceinline bool all(const avxb &b)
Definition: avxb.h:201
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
unsigned int U
Definition: btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
int len
Definition: draw_manager.c:108
#define str(s)
uint pos
uint col
uint padding(uint offset, uint alignment)
void ui_but_update(uiBut *but)
Definition: interface.cc:3900
uiBut * ui_but_change_type(uiBut *but, eButType new_type)
Definition: interface.cc:4025
void ui_def_but_icon_clear(uiBut *but)
Definition: interface.cc:4259
void ui_but_rna_menu_convert_to_panel_type(uiBut *but, const char *panel_type)
Definition: interface.cc:4485
void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_strip)
Definition: interface.cc:1205
void ui_but_rna_menu_convert_to_menu_type(uiBut *but, const char *menu_type)
Definition: interface.cc:4514
const char ui_radial_dir_order[8]
Definition: interface.cc:1544
bool ui_but_can_align(const uiBut *but)
int ui_but_align_opposite_to_area_align_get(const ARegion *region)
void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy))
void ui_block_new_button_group(uiBlock *block, uiButtonGroupFlag flag)
void ui_button_group_add_but(uiBlock *block, uiBut *but)
bool enabled
void ui_rna_collection_search_update_fn(const struct bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first)
#define RNA_NO_INDEX
RadialDirection
bool ui_block_is_popup_any(const uiBlock *block) ATTR_WARN_UNUSED_RESULT
struct ARegion * ui_searchbox_create_generic(struct bContext *C, struct ARegion *butregion, uiButSearch *search_but)
#define PIE_MAX_ITEMS
bool ui_block_is_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT
void ui_panel_tag_search_filter_match(struct Panel *panel)
@ UI_PIE_DEGREES_RANGE_LARGE
#define RNA_ENUM_VALUE
void ui_pie_menu_level_create(uiBlock *block, struct wmOperatorType *ot, const char *propname, struct IDProperty *properties, const EnumPropertyItem *items, int totitem, wmOperatorCallContext context, wmOperatorCallContext flag)
void ui_but_pie_dir(RadialDirection dir, float vec[2])
@ UI_SELECT_DRAW
@ UI_HIDDEN
@ UI_SELECT
@ UI_SEARCH_FILTER_NO_MATCH
static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
void uiItemBooleanO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
static uiLayout * ui_item_local_sublayout(uiLayout *test, uiLayout *layout, bool align)
static int ui_litem_min_width(int itemw)
void uiItemS_ex(uiLayout *layout, float factor)
static void ui_litem_layout_column_flow(uiLayout *litem)
static const struct uiTextIconPadFactor ui_text_pad_default
bool uiLayoutGetActivateInit(uiLayout *layout)
uiLayout * uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
void uiItemL_ex(uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert)
static uiBut * uiItemL_(uiLayout *layout, const char *name, int icon)
void uiLayoutSetActive(uiLayout *layout, bool active)
static void ui_litem_init_from_parent(uiLayout *litem, uiLayout *layout, int align)
static void ui_item_flag(uiLayout *litem, int flag)
static void ui_item_move(uiItem *item, int delta_xmin, int delta_xmax)
static void ui_item_size(uiItem *item, int *r_w, int *r_h)
bool uiLayoutGetPropDecorate(uiLayout *layout)
int uiLayoutGetAlignment(uiLayout *layout)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
static int ui_text_icon_width_ex(uiLayout *layout, const char *name, int icon, const struct uiTextIconPadFactor *pad_factor)
void uiLayoutSetUnitsY(uiLayout *layout, float unit)
void uiItemMenuEnumR_prop(uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *name, int icon)
uiLayout * uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading)
void uiItemMenuEnumFullO_ptr(uiLayout *layout, bContext *C, wmOperatorType *ot, const char *propname, const char *name, int icon, PointerRNA *r_opptr)
static void ui_litem_layout_column(uiLayout *litem, bool is_box, bool is_menu)
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
static void ui_item_estimate(uiItem *item)
static void ui_litem_layout_overlap(uiLayout *litem)
static uiBut * uiItemFullO_ptr_ex(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, int flag, PointerRNA *r_opptr)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
static bool button_matches_search_filter(uiBut *but, const char *search_filter)
bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter)
uiLayout * uiLayoutGridFlow(uiLayout *layout, bool row_major, int columns_len, bool even_columns, bool even_rows, bool align)
uiLayout * uiLayoutOverlap(uiLayout *layout)
void uiItemFullOMenuHold_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, int flag, const char *menu_id, PointerRNA *r_opptr)
static void ui_item_rna_size(uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, bool icon_only, bool compact, int *r_w, int *r_h)
void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size)
static void ui_litem_estimate_column_flow(uiLayout *litem)
#define CASE_ITEM(id)
static uiBut * ui_item_menu(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN, const char *tip, bool force_menu)
float uiLayoutGetUnitsY(uiLayout *layout)
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
void uiLayoutSetScaleY(uiLayout *layout, float scale)
void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
static void ui_layout_heading_set(uiLayout *layout, const char *heading)
void uiItemEnumO_string(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, const char *value_str)
static void ui_litem_estimate_split(uiLayout *litem)
static void ui_litem_estimate_overlap(uiLayout *litem)
static void ui_item_disabled(uiLayout *layout, const char *name)
static const char * ui_item_name_add_colon(const char *name, char namestr[UI_MAX_NAME_STR])
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 uiLayoutSetActiveDefault(uiLayout *layout, bool active_default)
bContextStore * uiLayoutGetContextStore(uiLayout *layout)
void uiLayoutSetRedAlert(uiLayout *layout, bool redalert)
void uiItemFullR_with_menu(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index, int value, int flag, const char *name, int icon, const char *menu_type)
void uiItemsFullEnumO_items(uiLayout *layout, wmOperatorType *ot, PointerRNA ptr, PropertyRNA *prop, IDProperty *properties, wmOperatorCallContext context, int flag, const EnumPropertyItem *item_array, int totitem)
static uiLayout * ui_layout_heading_find(uiLayout *cur_layout)
static void ui_item_position(uiItem *item, int x, int y, int w, int h)
#define UI_ITEM_PROP_SEP_DIVIDE
uiLayout * uiLayoutAbsolute(uiLayout *layout, bool align)
void uiLayoutSetScaleX(uiLayout *layout, float scale)
static bool ui_item_rna_is_expand(PropertyRNA *prop, int index, int item_flag)
static void ui_item_layout(uiItem *item)
static void ui_litem_layout_absolute(uiLayout *litem)
static bool ui_item_is_radial_displayable(uiItem *item)
float uiLayoutGetUnitsX(uiLayout *layout)
bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, IDProperty *properties, wmOperatorCallContext context, int flag)
static void ui_litem_grid_flow_compute(ListBase *items, UILayoutGridFlowInput *parameters, UILayoutGridFlowOutput *results)
struct UILayoutGridFlowInput UILayoutGridFlowInput
void uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, int flag, PointerRNA *r_opptr)
void uiItemMenuEnumO(uiLayout *layout, bContext *C, const char *opname, const char *propname, const char *name, int icon)
struct uiItem uiItem
void uiItemMenuEnumFullO(uiLayout *layout, bContext *C, const char *opname, const char *propname, const char *name, int icon, PointerRNA *r_opptr)
uiLayout * uiLayoutBox(uiLayout *layout)
static uiLayoutItemBx * ui_layout_box(uiLayout *layout, int type)
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
bool uiLayoutGetEnabled(uiLayout *layout)
void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
uiBlock * uiLayoutAbsoluteBlock(uiLayout *layout)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
wmOperatorType * UI_but_operatortype_get_from_enum_menu(uiBut *but, PropertyRNA **r_prop)
static void ui_item_enum_expand_exec(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, const char *uiname, const int h, const eButType but_type, const bool icon_only)
void uiItemS(uiLayout *layout)
PanelType * UI_but_paneltype_get(uiBut *but)
void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon)
#define UI_ITEM_VARY_X
float uiLayoutGetScaleY(uiLayout *layout)
void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index)
static bool block_search_filter_tag_buttons(uiBlock *block, const char *search_filter)
void uiItemPopoverPanelFromGroup(uiLayout *layout, bContext *C, int space_id, int region_id, const char *context, const char *category)
static void ui_item_offset(uiItem *item, int *r_x, int *r_y)
void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int icon, const char *propname, int value)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
bool uiLayoutGetActive(uiLayout *layout)
static void ui_layout_heading_label_add(uiLayout *layout, uiLayout *heading_layout, bool right_align, bool respect_prop_split)
uiLayout * uiLayoutColumnFlow(uiLayout *layout, int number, bool align)
static void ui_litem_layout_row(uiLayout *litem)
struct MenuItemLevel MenuItemLevel
void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname)
static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum)
static void ui_item_enum_expand_tabs(uiLayout *layout, bContext *C, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *ptr_highlight, PropertyRNA *prop_highlight, const char *uiname, const int h, const bool icon_only)
BLI_INLINE bool ui_layout_is_radial(const uiLayout *layout)
bool uiLayoutGetKeepAspect(uiLayout *layout)
static void ui_layout_add_padding_button(uiLayoutRoot *root)
struct uiLayoutItemRoot uiLayoutItemRoot
bool uiLayoutGetPropSep(uiLayout *layout)
void ui_item_paneltype_func(bContext *C, uiLayout *layout, void *arg_pt)
static int ui_layout_vary_direction(uiLayout *layout)
void UI_paneltype_draw(bContext *C, PanelType *pt, uiLayout *layout)
void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, const char *name, int icon)
void uiLayoutSetUnitsX(uiLayout *layout, float unit)
void uiItemFloatO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, float value)
static void ui_litem_estimate_row(uiLayout *litem)
static const struct uiTextIconPadFactor ui_text_pad_none
void uiItemEnumR_string_prop(uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *value, const char *name, int icon)
static void ui_layout_end(uiBlock *block, uiLayout *layout, int *r_x, int *r_y)
eUIEmbossType uiLayoutGetEmboss(uiLayout *layout)
void uiItemPointerR(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
void uiLayoutSetTooltipFunc(uiLayout *layout, uiButToolTipFunc func, void *arg, uiCopyArgFunc copy_arg, uiFreeArgFunc free_arg)
static bool block_search_panel_label_matches(const uiBlock *block, const char *search_string)
int uiLayoutGetLocalDir(const uiLayout *layout)
void uiItemSpacer(uiLayout *layout)
void uiItemM_ptr(uiLayout *layout, MenuType *mt, const char *name, int icon)
static int ui_item_fit(int item, int pos, int all, int available, bool is_last, int alignment, float *extra_pixel)
void ui_layout_list_set_labels_active(uiLayout *layout)
struct uiLayoutItemSplit uiLayoutItemSplit
void uiLayoutSetKeepAspect(uiLayout *layout, bool keepaspect)
struct uiLayoutItemFlow uiLayoutItemFlow
void UI_menutype_draw(bContext *C, MenuType *mt, struct uiLayout *layout)
bool uiLayoutGetFixedSize(uiLayout *layout)
#define UI_ITEM_VARY_Y
static void ui_litem_estimate_box(uiLayout *litem)
static void ui_rna_collection_search_arg_free_fn(void *ptr)
void UI_context_active_but_prop_get_filebrowser(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop, bool *r_is_undo, bool *r_is_userdef)
static bool ui_layout_has_panel_label(const uiLayout *layout, const PanelType *pt)
#define UI_PROP_DECORATE
static const struct uiTextIconPadFactor ui_text_pad_compact
void uiItemMContents(uiLayout *layout, const char *menuname)
bool uiLayoutGetActiveDefault(uiLayout *layout)
int uiLayoutGetOperatorContext(uiLayout *layout)
static void ui_litem_estimate_grid_flow(uiLayout *litem)
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h), bool expand, bool slider, int toggle, bool icon_only, bool compact, bool show_text)
static void ui_keymap_but_cb(bContext *UNUSED(C), void *but_v, void *UNUSED(key_v))
uiLayout * uiLayoutRadial(uiLayout *layout)
void uiItemEnumR_prop(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, PropertyRNA *prop, int value)
static void menu_item_enum_opname_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index)
void uiLayoutSetEmboss(uiLayout *layout, eUIEmbossType emboss)
static uiButtonItem * ui_layout_find_button_item(const uiLayout *layout, const uiBut *but)
static void ui_layout_introspect_items(DynStr *ds, ListBase *lb)
static void ui_item_scale(uiLayout *litem, const float scale[2])
int uiLayoutGetWidth(uiLayout *layout)
static void ui_layout_introspect_button(DynStr *ds, uiButtonItem *bitem)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
static void search_id_collection(StructRNA *ptype, PointerRNA *r_ptr, PropertyRNA **r_prop)
static void ui_litem_estimate_root(uiLayout *UNUSED(litem))
static void ui_litem_layout_split(uiLayout *litem)
void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value, const char *name, int icon)
void uiItemEnumO_value(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
struct uiLayoutRoot uiLayoutRoot
float uiLayoutGetScaleX(uiLayout *layout)
bool UI_block_layout_needs_resolving(const uiBlock *block)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutSplit(uiLayout *layout, float percentage, bool align)
void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but)
static void ui_but_tip_from_enum_item(uiBut *but, const EnumPropertyItem *item)
void uiItemFullO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, int flag, PointerRNA *r_opptr)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void UI_block_layout_free(uiBlock *block)
static void ui_litem_layout_radial(uiLayout *litem)
#define UI_OPERATOR_ERROR_RET(_ot, _opname, return_statement)
static void ui_litem_estimate_absolute(uiLayout *litem)
static void ui_item_enum_expand_handle(bContext *C, void *arg1, void *arg2)
void uiItemPointerR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop, const char *name, int icon, bool results_are_suggestions)
static uiBut * ui_item_with_label(uiLayout *layout, uiBlock *block, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int x, int y, int w_hint, int h, int flag)
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
uiLayout * uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon)
void uiItemEnumO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, const char *propname, int value)
static bool button_group_has_search_match(uiButtonGroup *button_group, const char *search_filter)
static bool ui_layout_variable_size(uiLayout *layout)
uiLayout * uiLayoutListBox(uiLayout *layout, uiList *ui_list, PointerRNA *actptr, PropertyRNA *actprop)
static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool compact)
void uiLayoutSetActivateInit(uiLayout *layout, bool activate_init)
static void ui_layout_free(uiLayout *layout)
static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, const char *uiname, const int h, const bool icon_only)
void uiItemStringO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, const char *value)
void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index, int value, int flag, const char *name, int icon)
static void ui_item_menu_hold(struct bContext *C, ARegion *butregion, uiBut *but)
void uiItemEnumR(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, const char *propname, int value)
static void ui_litem_layout_box(uiLayout *litem)
static void ui_paneltype_draw_impl(bContext *C, PanelType *pt, uiLayout *layout, bool show_header)
uiItemType
@ ITEM_LAYOUT_COLUMN_FLOW
@ ITEM_LAYOUT_SPLIT
@ ITEM_LAYOUT_GRID_FLOW
@ ITEM_LAYOUT_ROOT
@ ITEM_LAYOUT_OVERLAP
@ ITEM_LAYOUT_RADIAL
@ ITEM_LAYOUT_ROW
@ ITEM_LAYOUT_ROW_FLOW
@ ITEM_LAYOUT_BOX
@ ITEM_BUTTON
@ ITEM_LAYOUT_COLUMN
@ ITEM_LAYOUT_ABSOLUTE
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout)
void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
static void ui_item_align(uiLayout *litem, short nr)
struct uiLayoutItemBx uiLayoutItemBx
static void ui_litem_layout_grid_flow(uiLayout *litem)
static void menu_item_enum_rna_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
MenuType * UI_but_menutype_get(uiBut *but)
void ui_layout_remove_but(uiLayout *layout, const uiBut *but)
struct uiLayoutItemGridFlow uiLayoutItemGridFlow
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
const char * UI_layout_introspect(uiLayout *layout)
void uiItemPopoverPanel_ptr(uiLayout *layout, const bContext *C, PanelType *pt, const char *name, int icon)
bool uiLayoutGetRedAlert(uiLayout *layout)
void ui_layout_add_but(uiLayout *layout, uiBut *but)
static void ui_litem_layout_root(uiLayout *litem)
struct UILayoutGridFlowOutput UILayoutGridFlowOutput
void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *argN)
static void ui_item_enum_expand_elem_exec(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, const char *uiname, const int h, const eButType but_type, const bool icon_only, const EnumPropertyItem *item, const bool is_first)
void uiItemTabsEnumR_prop(uiLayout *layout, bContext *C, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *ptr_highlight, PropertyRNA *prop_highlight, bool icon_only)
uiLayout * UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, const uiStyle *style)
void uiItemPopoverPanel(uiLayout *layout, const bContext *C, const char *panel_type, const char *name, int icon)
static void ui_litem_layout_root_radial(uiLayout *litem)
struct uiButtonItem uiButtonItem
static uiLayout * ui_item_prop_split_layout_hack(uiLayout *layout_parent, uiLayout *layout_split)
static bool ui_item_is_radial_drawable(uiButtonItem *bitem)
void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon)
static const char * ui_menu_enumpropname(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int retval)
void uiItemFullR_with_popover(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index, int value, int flag, const char *name, int icon, const char *panel_type)
void uiLayoutContextCopy(uiLayout *layout, bContextStore *context)
void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
@ UI_ITEM_INSIDE_PROP_SEP
@ UI_ITEM_PROP_DECORATE_NO_PAD
@ UI_ITEM_PROP_DECORATE
@ UI_ITEM_PROP_SEP
@ UI_ITEM_FIXED_SIZE
@ UI_ITEM_BOX_ITEM
@ UI_ITEM_AUTO_FIXED_SIZE
uiLayout * uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
uiBut * ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop, const bool results_are_suggestions)
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
double parameters[NUM_PARAMETERS]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define G(x, y, z)
#define ceilf(x)
Definition: metal/compat.h:225
#define sqrtf(x)
Definition: metal/compat.h:243
static unsigned a[3]
Definition: RandGen.cpp:78
bool active
all scheduled work for the GPU.
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:92
static const pxr::TfToken st("st", pxr::TfToken::Immortal)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
const char * RNA_struct_identifier(const StructRNA *type)
Definition: rna_access.c:586
void RNA_property_boolean_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, bool value)
Definition: rna_access.c:2352
const char * RNA_property_description(PropertyRNA *prop)
Definition: rna_access.c:1005
bool RNA_property_array_check(PropertyRNA *prop)
Definition: rna_access.c:1080
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
Definition: rna_access.c:695
bool RNA_property_is_unlink(PropertyRNA *prop)
Definition: rna_access.c:5327
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
Definition: rna_access.c:5155
bool RNA_struct_is_ID(const StructRNA *type)
Definition: rna_access.c:655
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1000
bool RNA_enum_value_from_id(const EnumPropertyItem *item, const char *identifier, int *r_value)
Definition: rna_access.c:5076
eStringPropertySearchFlag RNA_property_string_search_flag(PropertyRNA *prop)
Definition: rna_access.c:3374
bool RNA_property_animateable(const PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:1993
int RNA_property_ui_icon(const PropertyRNA *prop)
Definition: rna_access.c:1900
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:4874
void RNA_property_boolean_get_array(PointerRNA *ptr, PropertyRNA *prop, bool *values)
Definition: rna_access.c:2242
PropertyType RNA_property_type(PropertyRNA *prop)
Definition: rna_access.c:1010
const PointerRNA PointerRNA_NULL
Definition: rna_access.c:61
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:4921
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
Definition: rna_access.c:3421
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
char RNA_property_array_item_char(PropertyRNA *prop, int index)
Definition: rna_access.c:1105
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2138
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2153
void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
Definition: rna_access.c:1560
const char * RNA_property_translation_context(const PropertyRNA *prop)
Definition: rna_access.c:1895
int RNA_property_array_dimension(const PointerRNA *ptr, PropertyRNA *prop, int length[])
Definition: rna_access.c:1085
PropertyRNA * RNA_struct_type_find_property(StructRNA *srna, const char *identifier)
Definition: rna_access.c:806
StructRNA * RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:1405
int RNA_property_flag(PropertyRNA *prop)
Definition: rna_access.c:1055
int RNA_struct_ui_icon(const StructRNA *type)
Definition: rna_access.c:601
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:4968
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:1075
bool RNA_enum_name(const EnumPropertyItem *item, const int value, const char **r_name)
Definition: rna_access.c:1692
void RNA_property_enum_items_gettexted_all(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
Definition: rna_access.c:1576
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3402
PropertySubType RNA_property_subtype(PropertyRNA *prop)
Definition: rna_access.c:1015
void RNA_property_enum_items(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
Definition: rna_access.c:1495
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
Definition: rna_access.c:2275
void RNA_main_pointer_create(struct Main *main, PointerRNA *r_ptr)
Definition: rna_access.c:105
const char * RNA_property_ui_name(const PropertyRNA *prop)
Definition: rna_access.c:1875
ListBase paneltypes
Definition: BKE_screen.h:198
short alignment
ListBase uiblocks
const char * identifier
Definition: RNA_types.h:461
const char * name
Definition: RNA_types.h:465
const char * description
Definition: RNA_types.h:467
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
char opname[OP_MAX_TYPENAME]
PointerRNA rnapoin
char propname[MAX_IDPROP_NAME]
wmOperatorCallContext opcontext
const char * description
Definition: BKE_screen.h:365
char label[BKE_ST_MAXNAME]
Definition: BKE_screen.h:362
char idname[BKE_ST_MAXNAME]
Definition: BKE_screen.h:361
void(* draw)(const struct bContext *C, struct Menu *menu)
Definition: BKE_screen.h:370
char translation_context[BKE_ST_MAXNAME]
Definition: BKE_screen.h:363
struct uiLayout * layout
Definition: BKE_screen.h:378
void(* draw)(const struct bContext *C, struct Panel *panel)
Definition: BKE_screen.h:248
bool(* poll)(const struct bContext *C, struct PanelType *pt)
Definition: BKE_screen.h:242
void(* draw_header)(const struct bContext *C, struct Panel *panel)
Definition: BKE_screen.h:244
char translation_context[BKE_ST_MAXNAME]
Definition: BKE_screen.h:226
ListBase children
Definition: BKE_screen.h:271
char * description
Definition: BKE_screen.h:225
char label[BKE_ST_MAXNAME]
Definition: BKE_screen.h:224
struct PointerRNA * custom_data_ptr
struct PanelType * type
struct uiLayout * layout
Panel_Runtime runtime
short flag
struct StructRNA * type
Definition: RNA_types.h:37
void * data
Definition: RNA_types.h:38
struct ID * owner_id
Definition: RNA_types.h:36
unsigned int layer_used
struct EditBone * act_edbone
ListBase * edbo
float xmax
Definition: DNA_vec_types.h:69
float xmin
Definition: DNA_vec_types.h:69
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70
eUIEmbossType emboss
ListBase layouts
ListBase button_groups
struct Panel * panel
uiPopupBlockHandle * handle
struct PieMenuData pie_data
ListBase buttons
uiButHandleFunc func
struct uiLayout * curlayout
void * evil_C
ListBase contexts
struct PropertyRNA * rnaprop
struct PointerRNA rnapoin
struct PointerRNA rnasearchpoin
struct PropertyRNA * rnasearchprop
const char * tip
struct bContextStore * context
void * custom_data
struct uiBut * next
RadialDirection pie_dir
eButType type
float hardmax
uiButHandleFunc func
uiBlock * block
eUIEmbossType emboss
uiMenuCreateFunc menu_create_func
char * poin
short alignnr
void * hold_argN
BIFIconID icon
struct PointerRNA * opptr
struct wmOperatorType * optype
char drawstr[UI_MAX_DRAW_STR]
uiLayout * layout
struct PropertyRNA * rnaprop
void * func_argN
char * str
struct PointerRNA rnapoin
void * prev
void * next
uiItemType type
const uiStyle * style
struct uiLayoutRoot * prev
struct uiLayoutRoot * next
wmOperatorCallContext opcontext
uiMenuHandleFunc handlefunc
uiBlock * block
uiLayout * layout
float scale[2]
char heading[UI_MAX_NAME_STR]
ListBase items
uiLayoutRoot * root
bool active_default
float units[2]
bContextStore * context
eUIEmbossType emboss
uiLayout * child_items_layout
uiLayout * parent
bool activate_init
bool variable_size
short boxspace
short buttonspacey
short buttonspacex
short templatespace
uiFontStyle widget
short columnspace
uiFontStyle widgetlabel
uint8_t modifier
Definition: WM_types.h:693
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
char *(* get_description)(struct bContext *C, struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:966
struct StructRNA * srna
Definition: WM_types.h:969
PropertyRNA * prop
Definition: WM_types.h:981
struct wmEvent * eventstate
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
int WM_keymap_item_to_string(const wmKeyMapItem *kmi, const bool compact, char *result, const int result_len)
Definition: wm_keymap.c:1213
char * WM_key_event_operator_string(const bContext *C, const char *opname, wmOperatorCallContext opcontext, IDProperty *properties, const bool is_strict, char *result, const int result_len)
Definition: wm_keymap.c:1636
MenuType * WM_menutype_find(const char *idname, bool quiet)
Definition: wm_menu_type.c:30
bool WM_menutype_poll(bContext *C, MenuType *mt)
Definition: wm_menu_type.c:87
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
const char * WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *properties)
void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring)
Definition: wm_operators.c:680
char * WM_operator_pystring_ex(bContext *C, wmOperator *op, const bool all_args, const bool macro_args, wmOperatorType *ot, PointerRNA *opptr)
Definition: wm_operators.c:192
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
Definition: wm_operators.c:661
void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context)
Definition: wm_operators.c:701
PanelType * WM_paneltype_find(const char *idname, bool quiet)
Definition: wm_panel_type.c:28