2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * Contributor(s): Blender Foundation 2009.
20 * ***** END GPL LICENSE BLOCK *****
23 /** \file blender/editors/interface/interface_layout.c
24 * \ingroup edinterface
34 #include "MEM_guardedalloc.h"
36 #include "DNA_screen_types.h"
37 #include "DNA_armature_types.h"
38 #include "DNA_userdef_types.h"
40 #include "BLI_listbase.h"
41 #include "BLI_string.h"
42 #include "BLI_utildefines.h"
44 #include "BLF_translation.h"
46 #include "BKE_context.h"
47 #include "BKE_global.h"
48 #include "BKE_idprop.h"
49 #include "BKE_screen.h"
51 #include "RNA_access.h"
53 #include "UI_interface.h"
59 #include "interface_intern.h"
61 /************************ Structs and Defines *************************/
63 #define RNA_NO_INDEX -1
64 #define RNA_ENUM_VALUE -2
69 #define UI_OPERATOR_ERROR_RET(_ot, _opname, return_statement) \
71 ui_item_disabled(layout, _opname); \
72 RNA_warning("'%s' unknown operator", _opname); \
79 typedef struct uiLayoutRoot {
80 struct uiLayoutRoot *next, *prev;
87 uiMenuHandleFunc handlefunc;
97 typedef enum uiItemType {
102 ITEM_LAYOUT_COLUMN_FLOW,
103 ITEM_LAYOUT_ROW_FLOW,
105 ITEM_LAYOUT_ABSOLUTE,
111 TEMPLATE_COLUMN_FLOW,
120 typedef struct uiItem {
126 typedef struct uiButtonItem {
135 bContextStore *context;
149 typedef struct uiLayoutItemFlow {
155 typedef struct uiLayoutItemBx {
160 typedef struct uiLayoutItemSplit {
165 typedef struct uiLayoutItemRoot {
169 /************************** Item ***************************/
171 static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_NAME_STR])
173 int len = strlen(name);
175 if (len != 0 && len + 1 < UI_MAX_NAME_STR) {
176 BLI_strncpy(namestr, name, UI_MAX_NAME_STR);
178 namestr[len + 1] = '\0';
185 static int ui_item_fit(int item, int pos, int all, int available, int last, int alignment, int *offset)
187 /* available == 0 is unlimited */
194 if (all > available) {
195 /* contents is bigger than available space */
197 return available - pos;
199 return (item * available) / all;
202 /* contents is smaller or equal to available space */
203 if (alignment == UI_LAYOUT_ALIGN_EXPAND) {
205 return available - pos;
207 return (item * available) / all;
214 /* variable button size in which direction? */
215 #define UI_ITEM_VARY_X 1
216 #define UI_ITEM_VARY_Y 2
218 static int ui_layout_vary_direction(uiLayout *layout)
220 return (layout->root->type == UI_LAYOUT_HEADER || layout->alignment != UI_LAYOUT_ALIGN_EXPAND) ? UI_ITEM_VARY_X : UI_ITEM_VARY_Y;
223 /* estimated size of text + icon */
224 static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, int compact)
226 int variable = ui_layout_vary_direction(layout) == UI_ITEM_VARY_X;
228 if (icon && !name[0])
229 return UI_UNIT_X; /* icon only */
231 return (variable) ? UI_GetStringWidth(name) + (compact ? 5 : 10) + UI_UNIT_X : 10 * UI_UNIT_X; /* icon + text */
233 return (variable) ? UI_GetStringWidth(name) + (compact ? 5 : 10) + UI_UNIT_X : 10 * UI_UNIT_X; /* text only */
236 static void ui_item_size(uiItem *item, int *r_w, int *r_h)
238 if (item->type == ITEM_BUTTON) {
239 uiButtonItem *bitem = (uiButtonItem *)item;
241 if (r_w) *r_w = bitem->but->x2 - bitem->but->x1;
242 if (r_h) *r_h = bitem->but->y2 - bitem->but->y1;
245 uiLayout *litem = (uiLayout *)item;
247 if (r_w) *r_w = litem->w;
248 if (r_h) *r_h = litem->h;
252 static void ui_item_offset(uiItem *item, int *r_x, int *r_y)
254 if (item->type == ITEM_BUTTON) {
255 uiButtonItem *bitem = (uiButtonItem *)item;
257 if (r_x) *r_x = bitem->but->x1;
258 if (r_y) *r_y = bitem->but->y1;
266 static void ui_item_position(uiItem *item, int x, int y, int w, int h)
268 if (item->type == ITEM_BUTTON) {
269 uiButtonItem *bitem = (uiButtonItem *)item;
273 bitem->but->x2 = x + w;
274 bitem->but->y2 = y + h;
276 ui_check_but(bitem->but); /* for strlen */
279 uiLayout *litem = (uiLayout *)item;
288 /******************** Special RNA Items *********************/
290 static int ui_layout_local_dir(uiLayout *layout)
292 switch (layout->item.type) {
293 case ITEM_LAYOUT_ROW:
294 case ITEM_LAYOUT_ROOT:
295 case ITEM_LAYOUT_OVERLAP:
296 return UI_LAYOUT_HORIZONTAL;
297 case ITEM_LAYOUT_COLUMN:
298 case ITEM_LAYOUT_COLUMN_FLOW:
299 case ITEM_LAYOUT_SPLIT:
300 case ITEM_LAYOUT_ABSOLUTE:
301 case ITEM_LAYOUT_BOX:
303 return UI_LAYOUT_VERTICAL;
307 static uiLayout *ui_item_local_sublayout(uiLayout *test, uiLayout *layout, int align)
311 if (ui_layout_local_dir(test) == UI_LAYOUT_HORIZONTAL)
312 sub = uiLayoutRow(layout, align);
314 sub = uiLayoutColumn(layout, align);
320 static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
322 wmWindow *win = CTX_wm_window(C);
323 uiBut *but = arg_but, *cbut;
324 PointerRNA *ptr = &but->rnapoin;
325 PropertyRNA *prop = but->rnaprop;
326 int i, index = GET_INT_FROM_POINTER(arg_index);
327 int shift = win->eventstate->shift;
328 int len = RNA_property_array_length(ptr, prop);
331 RNA_property_boolean_set_index(ptr, prop, index, TRUE);
333 for (i = 0; i < len; i++)
335 RNA_property_boolean_set_index(ptr, prop, i, 0);
337 RNA_property_update(C, ptr, prop);
339 for (cbut = but->block->buttons.first; cbut; cbut = cbut->next)
344 /* create buttons for an item with an RNA array */
345 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), int expand, int slider, int toggle, int icon_only)
347 uiStyle *style = layout->root->style;
350 PropertySubType subtype;
354 /* retrieve type and subtype */
355 type = RNA_property_type(prop);
356 subtype = RNA_property_subtype(prop);
358 sub = ui_item_local_sublayout(layout, layout, 1);
359 uiBlockSetCurLayout(block, sub);
363 uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
366 if (type == PROP_BOOLEAN && ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
367 /* special check for layer layout */
368 int butw, buth, unit;
369 int cols = (len >= 20) ? 2 : 1;
370 int colbuts = len / (2 * cols);
373 uiBlockSetCurLayout(block, uiLayoutAbsolute(layout, FALSE));
375 unit = UI_UNIT_X * 0.75;
379 if (ptr->type == &RNA_Armature) {
380 bArmature *arm = (bArmature *)ptr->data;
381 layer_used = arm->layer_used;
384 for (b = 0; b < cols; b++) {
385 uiBlockBeginAlign(block);
387 for (a = 0; a < colbuts; a++) {
388 if (layer_used & (1 << (a + b * colbuts))) icon = ICON_LAYER_USED;
389 else icon = ICON_BLANK1;
391 but = uiDefAutoButR(block, ptr, prop, a + b * colbuts, "", icon, x + butw * a, y + buth, butw, buth);
392 if (subtype == PROP_LAYER_MEMBER)
393 uiButSetFunc(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(a + b * colbuts));
395 for (a = 0; a < colbuts; a++) {
396 if (layer_used & (1 << (a + len / 2 + b * colbuts))) icon = ICON_LAYER_USED;
397 else icon = ICON_BLANK1;
399 but = uiDefAutoButR(block, ptr, prop, a + len / 2 + b * colbuts, "", icon, x + butw * a, y, butw, buth);
400 if (subtype == PROP_LAYER_MEMBER)
401 uiButSetFunc(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(a + len / 2 + b * colbuts));
403 uiBlockEndAlign(block);
405 x += colbuts * butw + style->buttonspacex;
408 else if (subtype == PROP_MATRIX) {
409 int totdim, dim_size[3]; /* 3 == RNA_MAX_ARRAY_DIMENSION */
412 uiBlockSetCurLayout(block, uiLayoutAbsolute(layout, TRUE));
414 totdim = RNA_property_array_dimension(ptr, prop, dim_size);
415 if (totdim != 2) return; /* only 2D matrices supported in UI so far */
418 /* h /= dim_size[1]; */ /* UNUSED */
420 for (a = 0; a < len; a++) {
421 col = a % dim_size[0];
422 row = a / dim_size[0];
424 but = uiDefAutoButR(block, ptr, prop, a, "", ICON_NONE, x + w * col, y + (dim_size[1] * UI_UNIT_Y) - (row * UI_UNIT_Y), w, UI_UNIT_Y);
425 if (slider && but->type == NUM)
429 else if (subtype == PROP_DIRECTION) {
430 uiDefButR_prop(block, BUT_NORMAL, 0, name, x, y, UI_UNIT_X * 3, UI_UNIT_Y * 3, ptr, prop, 0, 0, 0, -1, -1, NULL);
433 /* note, this block of code is a bit arbitrary and has just been made
434 * to work with common cases, but may need to be re-worked */
436 /* special case, boolean array in a menu, this could be used in a more generic way too */
437 if (ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) && !expand) {
438 uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, 0, 0, w, UI_UNIT_Y);
443 /* even if 'expand' is fale, expanding anyway */
445 /* layout for known array subtypes */
446 char str[3] = {'\0'};
449 if (type != PROP_BOOLEAN) {
454 /* show checkboxes for rna on a non-emboss block (menu for eg) */
455 if (type == PROP_BOOLEAN && ELEM(layout->root->block->dt, UI_EMBOSSN, UI_EMBOSSP)) {
456 boolarr = MEM_callocN(sizeof(int) * len, "ui_item_array");
457 RNA_property_boolean_get_array(ptr, prop, boolarr);
460 for (a = 0; a < len; a++) {
461 if (!icon_only) str[0] = RNA_property_array_item_char(prop, a);
462 if (boolarr) icon = boolarr[a] ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
463 but = uiDefAutoButR(block, ptr, prop, a, str, icon, 0, 0, w, UI_UNIT_Y);
464 if (slider && but->type == NUM)
466 if (toggle && but->type == OPTION)
476 uiBlockSetCurLayout(block, layout);
479 static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, const char *uiname, int h, int icon_only)
482 EnumPropertyItem *item;
484 int a, totitem, itemw, icon, value, free;
486 RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item, &totitem, &free);
488 uiBlockSetCurLayout(block, ui_item_local_sublayout(layout, layout, 1));
489 for (a = 0; a < totitem; a++) {
490 if (!item[a].identifier[0])
493 name = (!uiname || uiname[0]) ? item[a].name : "";
495 value = item[a].value;
496 itemw = ui_text_icon_width(block->curlayout, name, icon, 0);
498 if (icon && name[0] && !icon_only)
499 but = uiDefIconTextButR_prop(block, ROW, 0, icon, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
501 but = uiDefIconButR_prop(block, ROW, 0, icon, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
503 but = uiDefButR_prop(block, ROW, 0, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
505 if (ui_layout_local_dir(layout) != UI_LAYOUT_HORIZONTAL)
506 but->flag |= UI_TEXT_LEFT;
508 uiBlockSetCurLayout(block, layout);
515 /* callback for keymap item change button */
516 static void ui_keymap_but_cb(bContext *UNUSED(C), void *but_v, void *UNUSED(key_v))
520 RNA_boolean_set(&but->rnapoin, "shift", (but->modifier_key & KM_SHIFT) != 0);
521 RNA_boolean_set(&but->rnapoin, "ctrl", (but->modifier_key & KM_CTRL) != 0);
522 RNA_boolean_set(&but->rnapoin, "alt", (but->modifier_key & KM_ALT) != 0);
523 RNA_boolean_set(&but->rnapoin, "oskey", (but->modifier_key & KM_OSKEY) != 0);
526 /* create label + button for RNA property */
527 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, int h, int flag)
532 PropertySubType subtype;
535 sub = uiLayoutRow(layout, FALSE);
536 uiBlockSetCurLayout(block, sub);
539 /* XXX UI_GetStringWidth is not accurate */
541 labelw = UI_GetStringWidth(name);
542 CLAMP(labelw, w / 4, 3 * w / 4);
545 uiDefBut(block, LABEL, 0, name, x, y, labelw, h, NULL, 0.0, 0.0, 0, 0, "");
549 type = RNA_property_type(prop);
550 subtype = RNA_property_subtype(prop);
552 if (subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) {
553 uiBlockSetCurLayout(block, uiLayoutRow(sub, TRUE));
554 uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, w - UI_UNIT_X, h);
556 /* BUTTONS_OT_file_browse calls uiFileBrowseContextProperty */
557 but = uiDefIconButO(block, BUT, subtype == PROP_DIRPATH ?
558 "BUTTONS_OT_directory_browse" :
559 "BUTTONS_OT_file_browse",
560 WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, NULL);
562 else if (flag & UI_ITEM_R_EVENT) {
563 uiDefButR_prop(block, KEYEVT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL);
565 else if (flag & UI_ITEM_R_FULL_EVENT) {
566 if (RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) {
569 WM_keymap_item_to_string(ptr->data, buf, sizeof(buf));
571 but = uiDefButR_prop(block, HOTKEYEVT, 0, buf, x, y, w, h, ptr, prop, 0, 0, 0, -1, -1, NULL);
572 uiButSetFunc(but, ui_keymap_but_cb, but, NULL);
573 if (flag & UI_ITEM_R_IMMEDIATE)
574 uiButSetFlag(but, UI_BUT_IMMEDIATE);
578 but = uiDefAutoButR(block, ptr, prop, index, (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY)) ? NULL : "", icon, x, y, w, h);
580 uiBlockSetCurLayout(block, layout);
584 void uiFileBrowseContextProperty(const bContext *C, PointerRNA *ptr, PropertyRNA **prop)
586 ARegion *ar = CTX_wm_region(C);
588 uiBut *but, *prevbut;
590 memset(ptr, 0, sizeof(*ptr));
596 for (block = ar->uiblocks.first; block; block = block->next) {
597 for (but = block->buttons.first; but; but = but->next) {
600 /* find the button before the active one */
601 if ((but->flag & UI_BUT_LAST_ACTIVE) && prevbut && prevbut->rnapoin.data) {
602 if (RNA_property_type(prevbut->rnaprop) == PROP_STRING) {
603 *ptr = prevbut->rnapoin;
604 *prop = prevbut->rnaprop;
612 /********************* Button Items *************************/
615 static void ui_item_disabled(uiLayout *layout, const char *name)
617 uiBlock *block = layout->root->block;
621 uiBlockSetCurLayout(block, layout);
626 w = ui_text_icon_width(layout, name, 0, 0);
628 but = uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
629 but->flag |= UI_BUT_DISABLED;
635 PointerRNA uiItemFullO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, IDProperty *properties, int context, int flag)
637 uiBlock *block = layout->root->block;
643 name = RNA_struct_ui_name(ot->srna);
648 if (layout->root->type == UI_LAYOUT_MENU && !icon)
652 uiBlockSetCurLayout(block, layout);
654 w = ui_text_icon_width(layout, name, icon, 0);
656 if (flag & UI_ITEM_R_NO_BG)
657 uiBlockSetEmboss(block, UI_EMBOSSN);
659 /* create the button */
662 but = uiDefIconTextButO_ptr(block, BUT, ot, context, icon, name, 0, 0, w, UI_UNIT_Y, NULL);
665 but = uiDefIconButO_ptr(block, BUT, ot, context, icon, 0, 0, w, UI_UNIT_Y, NULL);
669 but = uiDefButO_ptr(block, BUT, ot, context, name, 0, 0, w, UI_UNIT_Y, NULL);
672 assert(but->optype != NULL);
674 /* text alignment for toolbar buttons */
675 if ((layout->root->type == UI_LAYOUT_TOOLBAR) && !icon)
676 but->flag |= UI_TEXT_LEFT;
678 if (flag & UI_ITEM_R_NO_BG)
679 uiBlockSetEmboss(block, UI_EMBOSS);
681 if (layout->redalert)
682 uiButSetFlag(but, UI_BUT_REDALERT);
684 /* assign properties */
685 if (properties || (flag & UI_ITEM_O_RETURN_PROPS)) {
686 PointerRNA *opptr = uiButGetOperatorPtrRNA(but);
689 opptr->data = properties;
692 IDPropertyTemplate val = {0};
693 opptr->data = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
699 return PointerRNA_NULL;
702 PointerRNA uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, IDProperty *properties, int context, int flag)
704 wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
706 UI_OPERATOR_ERROR_RET(ot, opname, return PointerRNA_NULL);
708 return uiItemFullO_ptr(layout, ot, name, icon, properties, context, flag);
711 static const char *ui_menu_enumpropname(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int retval)
713 EnumPropertyItem *item;
717 RNA_property_enum_items_gettexted(layout->root->block->evil_C, ptr, prop, &item, &totitem, &free);
718 if (RNA_enum_name(item, retval, &name) == 0) {
729 /* same as below but 'prop' is already known */
730 static void uiItemEnumO_ptr__internal(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, PropertyRNA *prop, int value)
733 WM_operator_properties_create_ptr(&ptr, ot);
734 RNA_property_enum_set(&ptr, prop, value);
737 name = ui_menu_enumpropname(layout, &ptr, prop, value);
739 uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
741 void uiItemEnumO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, const char *propname, int value)
746 WM_operator_properties_create_ptr(&ptr, ot);
748 if ((prop = RNA_struct_find_property(&ptr, propname))) {
752 RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
756 RNA_property_enum_set(&ptr, prop, value);
759 name = ui_menu_enumpropname(layout, &ptr, prop, value);
761 uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
763 void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int icon, const char *propname, int value)
765 wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
768 uiItemEnumO_ptr(layout, ot, name, icon, propname, value);
771 ui_item_disabled(layout, opname);
772 RNA_warning("unknown operator '%s'", opname);
777 void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, IDProperty *properties, int context, int flag)
779 wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
784 uiBlock *block = layout->root->block;
786 if (!ot || !ot->srna) {
787 ui_item_disabled(layout, opname);
788 RNA_warning("%s '%s'", ot ? "unknown operator" : "operator missing srna", opname);
792 RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
793 prop = RNA_struct_find_property(&ptr, propname);
795 /* don't let bad properties slip through */
796 BLI_assert((prop == NULL) || (RNA_property_type(prop) == PROP_ENUM));
798 if (prop && RNA_property_type(prop) == PROP_ENUM) {
799 EnumPropertyItem *item;
800 int totitem, i, free;
801 uiLayout *split = uiLayoutSplit(layout, 0.0f, FALSE);
802 uiLayout *column = uiLayoutColumn(split, FALSE);
804 RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item, &totitem, &free);
806 for (i = 0; i < totitem; i++) {
807 if (item[i].identifier[0]) {
811 WM_operator_properties_create_ptr(&tptr, ot);
813 IDP_FreeProperty(tptr.data);
814 MEM_freeN(tptr.data);
816 tptr.data = IDP_CopyProperty(properties);
817 RNA_property_enum_set(&tptr, prop, item[i].value);
819 uiItemFullO_ptr(column, ot, item[i].name, item[i].icon, tptr.data, context, flag);
822 uiItemEnumO_ptr__internal(column, ot, item[i].name, item[i].icon, prop, item[i].value);
828 column = uiLayoutColumn(split, FALSE);
829 /* inconsistent, but menus with labels do not look good flipped */
830 block->flag |= UI_BLOCK_NO_FLIP;
833 uiItemL(column, item[i].name, ICON_NONE);
834 bt = block->buttons.last;
835 bt->flag = UI_TEXT_LEFT;
837 else /* XXX bug here, collums draw bottom item badly */
846 else if (prop && RNA_property_type(prop) != PROP_ENUM) {
847 RNA_warning("%s.%s, not an enum type", RNA_struct_identifier(ptr.type), propname);
851 RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
856 void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
858 uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0);
861 /* for use in cases where we have */
862 void uiItemEnumO_value(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
864 wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
868 UI_OPERATOR_ERROR_RET(ot, opname, return );
870 WM_operator_properties_create_ptr(&ptr, ot);
873 if ((prop = RNA_struct_find_property(&ptr, propname))) {
877 RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
881 RNA_property_enum_set(&ptr, prop, value);
883 /* same as uiItemEnumO */
885 name = ui_menu_enumpropname(layout, &ptr, prop, value);
887 uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
890 void uiItemEnumO_string(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, const char *value_str)
892 wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
896 EnumPropertyItem *item;
899 UI_OPERATOR_ERROR_RET(ot, opname, return );
901 WM_operator_properties_create_ptr(&ptr, ot);
904 if ((prop = RNA_struct_find_property(&ptr, propname))) {
905 RNA_property_enum_items_gettexted(layout->root->block->evil_C, &ptr, prop, &item, NULL, &free);
906 if (item == NULL || RNA_enum_value_from_id(item, value_str, &value) == 0) {
910 RNA_warning("%s.%s, enum %s not found", RNA_struct_identifier(ptr.type), propname, value_str);
919 RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
923 RNA_property_enum_set(&ptr, prop, value);
925 /* same as uiItemEnumO */
927 name = ui_menu_enumpropname(layout, &ptr, prop, value);
929 uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
932 void uiItemBooleanO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
934 wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
937 UI_OPERATOR_ERROR_RET(ot, opname, return );
939 WM_operator_properties_create_ptr(&ptr, ot);
940 RNA_boolean_set(&ptr, propname, value);
942 uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
945 void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
947 wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
950 UI_OPERATOR_ERROR_RET(ot, opname, return );
952 WM_operator_properties_create_ptr(&ptr, ot);
953 RNA_int_set(&ptr, propname, value);
955 uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
958 void uiItemFloatO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, float value)
960 wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
963 UI_OPERATOR_ERROR_RET(ot, opname, return );
965 WM_operator_properties_create_ptr(&ptr, ot);
966 RNA_float_set(&ptr, propname, value);
968 uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
971 void uiItemStringO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, const char *value)
973 wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
976 UI_OPERATOR_ERROR_RET(ot, opname, return );
978 WM_operator_properties_create_ptr(&ptr, ot);
979 RNA_string_set(&ptr, propname, value);
981 uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
984 void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
986 uiItemFullO(layout, opname, name, icon, NULL, layout->root->opcontext, 0);
989 /* RNA property items */
991 static void ui_item_rna_size(uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int icon_only, int *r_w, int *r_h)
994 PropertySubType subtype;
997 /* arbitrary extended width by type */
998 type = RNA_property_type(prop);
999 subtype = RNA_property_subtype(prop);
1000 len = RNA_property_array_length(ptr, prop);
1002 if (ELEM3(type, PROP_STRING, PROP_POINTER, PROP_ENUM) && !name[0] && !icon_only)
1003 name = "non-empty text";
1004 else if (type == PROP_BOOLEAN && !name[0] && !icon_only)
1007 w = ui_text_icon_width(layout, name, icon, 0);
1010 /* increase height for arrays */
1011 if (index == RNA_NO_INDEX && len > 0) {
1012 if (!name[0] && icon == ICON_NONE)
1015 if (ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER))
1017 else if (subtype == PROP_MATRIX)
1018 h += ceil(sqrt(len)) * UI_UNIT_Y;
1020 h += len * UI_UNIT_Y;
1022 else if (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) {
1023 if (type == PROP_BOOLEAN && name[0])
1025 else if (type == PROP_ENUM)
1027 else if (type == PROP_FLOAT || type == PROP_INT)
1035 void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index, int value, int flag, const char *name, int icon)
1037 uiBlock *block = layout->root->block;
1040 char namestr[UI_MAX_NAME_STR];
1041 int len, is_array, w, h, slider, toggle, expand, icon_only, no_bg;
1043 uiBlockSetCurLayout(block, layout);
1046 type = RNA_property_type(prop);
1047 is_array = RNA_property_array_check(prop);
1048 len = (is_array) ? RNA_property_array_length(ptr, prop) : 0;
1050 /* set name and icon */
1052 name = RNA_property_ui_name(prop);
1053 if (icon == ICON_NONE)
1054 icon = RNA_property_ui_icon(prop);
1056 if (ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER))
1057 name = ui_item_name_add_colon(name, namestr);
1058 else if (type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX)
1059 name = ui_item_name_add_colon(name, namestr);
1060 else if (type == PROP_ENUM && index != RNA_ENUM_VALUE)
1061 name = ui_item_name_add_colon(name, namestr);
1063 if (layout->root->type == UI_LAYOUT_MENU) {
1064 if (type == PROP_BOOLEAN && ((is_array == FALSE) || (index != RNA_NO_INDEX))) {
1065 if (is_array) icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
1066 else icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
1068 else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
1069 int enum_value = RNA_property_enum_get(ptr, prop);
1070 if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
1071 icon = (enum_value & value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
1074 icon = (enum_value == value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
1079 slider = (flag & UI_ITEM_R_SLIDER);
1080 toggle = (flag & UI_ITEM_R_TOGGLE);
1081 expand = (flag & UI_ITEM_R_EXPAND);
1082 icon_only = (flag & UI_ITEM_R_ICON_ONLY);
1083 no_bg = (flag & UI_ITEM_R_NO_BG);
1086 ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, &w, &h);
1089 uiBlockSetEmboss(block, UI_EMBOSSN);
1091 /* array property */
1092 if (index == RNA_NO_INDEX && is_array)
1093 ui_item_array(layout, block, name, icon, ptr, prop, len, 0, 0, w, h, expand, slider, toggle, icon_only);
1095 else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
1096 if (icon && name[0] && !icon_only)
1097 uiDefIconTextButR_prop(block, ROW, 0, icon, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
1099 uiDefIconButR_prop(block, ROW, 0, icon, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
1101 uiDefButR_prop(block, ROW, 0, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
1104 else if (type == PROP_ENUM && (expand || RNA_property_flag(prop) & PROP_ENUM_FLAG))
1105 ui_item_enum_expand(layout, block, ptr, prop, name, h, icon_only);
1106 /* property with separate label */
1107 else if (type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) {
1108 but = ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag);
1109 ui_but_add_search(but, ptr, prop, NULL, NULL);
1111 if (layout->redalert)
1112 uiButSetFlag(but, UI_BUT_REDALERT);
1116 but = uiDefAutoButR(block, ptr, prop, index, name, icon, 0, 0, w, h);
1118 if (slider && but->type == NUM)
1121 if (toggle && but->type == OPTION)
1124 if (layout->redalert)
1125 uiButSetFlag(but, UI_BUT_REDALERT);
1129 uiBlockSetEmboss(block, UI_EMBOSS);
1132 void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
1134 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1137 ui_item_disabled(layout, propname);
1138 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1142 uiItemFullR(layout, ptr, prop, RNA_NO_INDEX, 0, flag, name, icon);
1145 void uiItemEnumR(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, const char *propname, int value)
1147 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1149 if (!prop || RNA_property_type(prop) != PROP_ENUM) {
1150 ui_item_disabled(layout, propname);
1151 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1155 uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, value, 0, name, icon);
1158 void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value, const char *name, int icon)
1160 PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1161 EnumPropertyItem *item;
1162 int ivalue, a, free;
1164 if (!prop || RNA_property_type(prop) != PROP_ENUM) {
1165 ui_item_disabled(layout, propname);
1166 RNA_warning("enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1170 RNA_property_enum_items_gettexted(layout->root->block->evil_C, ptr, prop, &item, NULL, &free);
1172 if (!RNA_enum_value_from_id(item, value, &ivalue)) {
1176 ui_item_disabled(layout, propname);
1177 RNA_warning("enum property value not found: %s", value);
1181 for (a = 0; item[a].identifier; a++) {
1182 if (item[a].value == ivalue) {
1183 uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, name ? name : item[a].name, icon ? icon : item[a].icon);
1193 void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname)
1196 uiBlock *block = layout->root->block;
1199 prop = RNA_struct_find_property(ptr, propname);
1202 ui_item_disabled(layout, propname);
1203 RNA_warning("enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1207 if (RNA_property_type(prop) != PROP_ENUM) {
1208 RNA_warning("not an enum property: %s.%s", RNA_struct_identifier(ptr->type), propname);
1212 EnumPropertyItem *item;
1213 int totitem, i, free;
1214 uiLayout *split = uiLayoutSplit(layout, 0.0f, FALSE);
1215 uiLayout *column = uiLayoutColumn(split, FALSE);
1217 RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item, &totitem, &free);
1219 for (i = 0; i < totitem; i++) {
1220 if (item[i].identifier[0]) {
1221 uiItemEnumR(column, item[i].name, ICON_NONE, ptr, propname, item[i].value);
1226 column = uiLayoutColumn(split, FALSE);
1227 /* inconsistent, but menus with labels do not look good flipped */
1228 block->flag |= UI_BLOCK_NO_FLIP;
1231 uiItemL(column, item[i].name, ICON_NONE);
1232 bt = block->buttons.last;
1233 bt->flag = UI_TEXT_LEFT;
1246 /* Pointer RNA button with search */
1248 typedef struct CollItemSearch {
1249 struct CollItemSearch *next, *prev;
1255 static int sort_search_items_list(void *a, void *b)
1257 CollItemSearch *cis1 = (CollItemSearch *)a;
1258 CollItemSearch *cis2 = (CollItemSearch *)b;
1260 if (BLI_strcasecmp(cis1->name, cis2->name) > 0)
1266 static void rna_search_cb(const struct bContext *C, void *arg_but, const char *str, uiSearchItems *items)
1268 uiBut *but = arg_but;
1270 int i = 0, iconid = 0, flag = RNA_property_flag(but->rnaprop);
1271 ListBase *items_list = MEM_callocN(sizeof(ListBase), "items_list");
1272 CollItemSearch *cis;
1273 const int skip_filter = !but->changed;
1275 /* build a temporary list of relevant items first */
1276 RNA_PROP_BEGIN (&but->rnasearchpoin, itemptr, but->rnasearchprop)
1278 if (flag & PROP_ID_SELF_CHECK)
1279 if (itemptr.data == but->rnapoin.id.data)
1283 if (RNA_property_type(but->rnaprop) == PROP_POINTER) {
1284 if (RNA_property_pointer_poll(&but->rnapoin, but->rnaprop, &itemptr) == 0)
1288 if (itemptr.type && RNA_struct_is_ID(itemptr.type)) {
1289 ID *id = itemptr.data;
1290 char name_ui[MAX_ID_NAME];
1292 #if 0 /* this name is used for a string comparison and can't be modified, TODO */
1293 name_uiprefix_id(name_ui, id);
1295 BLI_strncpy(name_ui, id->name + 2, sizeof(name_ui));
1297 name = BLI_strdup(name_ui);
1298 iconid = ui_id_icon_get((bContext *)C, id, 0);
1301 name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); /* could use the string length here */
1306 if (skip_filter || BLI_strcasestr(name, str)) {
1307 cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch");
1308 cis->name = MEM_dupallocN(name);
1310 cis->iconid = iconid;
1311 BLI_addtail(items_list, cis);
1320 BLI_sortlist(items_list, sort_search_items_list);
1322 /* add search items from temporary list */
1323 for (cis = items_list->first; cis; cis = cis->next) {
1324 if (!uiSearchItemAdd(items, cis->name, SET_INT_IN_POINTER(cis->index), cis->iconid)) {
1329 for (cis = items_list->first; cis; cis = cis->next) {
1330 MEM_freeN(cis->name);
1332 BLI_freelistN(items_list);
1333 MEM_freeN(items_list);
1336 static void search_id_collection(StructRNA *ptype, PointerRNA *ptr, PropertyRNA **prop)
1340 /* look for collection property in Main */
1341 RNA_main_pointer_create(G.main, ptr);
1345 RNA_STRUCT_BEGIN (ptr, iprop)
1347 /* if it's a collection and has same pointer type, we've got it */
1348 if (RNA_property_type(iprop) == PROP_COLLECTION) {
1349 srna = RNA_property_pointer_type(ptr, iprop);
1351 if (ptype == srna) {
1360 void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop)
1365 /* for ID's we do automatic lookup */
1367 if (RNA_property_type(prop) == PROP_POINTER) {
1368 ptype = RNA_property_pointer_type(ptr, prop);
1369 search_id_collection(ptype, &sptr, &searchprop);
1374 /* turn button into search button */
1376 but->type = SEARCH_MENU;
1377 but->hardmax = MAX2(but->hardmax, 256);
1378 but->rnasearchpoin = *searchptr;
1379 but->rnasearchprop = searchprop;
1380 but->flag |= UI_ICON_LEFT | UI_TEXT_LEFT;
1382 uiButSetSearchFunc(but, rna_search_cb, but, NULL, NULL);
1386 void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
1388 PropertyRNA *prop, *searchprop;
1392 StructRNA *icontype;
1395 /* validate arguments */
1396 prop = RNA_struct_find_property(ptr, propname);
1399 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1403 type = RNA_property_type(prop);
1404 if (!ELEM(type, PROP_POINTER, PROP_STRING)) {
1405 RNA_warning("Property %s must be a pointer or string", propname);
1409 searchprop = RNA_struct_find_property(searchptr, searchpropname);
1413 RNA_warning("search collection property not found: %s.%s", RNA_struct_identifier(ptr->type), searchpropname);
1416 else if (RNA_property_type(searchprop) != PROP_COLLECTION) {
1417 RNA_warning("search collection property is not a collection type: %s.%s", RNA_struct_identifier(ptr->type), searchpropname);
1421 /* get icon & name */
1422 if (icon == ICON_NONE) {
1423 if (type == PROP_POINTER)
1424 icontype = RNA_property_pointer_type(ptr, prop);
1426 icontype = RNA_property_pointer_type(searchptr, searchprop);
1428 icon = RNA_struct_ui_icon(icontype);
1431 name = RNA_property_ui_name(prop);
1434 block = uiLayoutGetBlock(layout);
1436 ui_item_rna_size(layout, name, icon, ptr, prop, 0, 0, &w, &h);
1437 but = ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0);
1439 ui_but_add_search(but, ptr, prop, searchptr, searchprop);
1443 static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
1445 MenuType *mt = (MenuType *)arg_mt;
1449 menu.layout = layout;
1453 static void ui_item_menu(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN, const char *tip)
1455 uiBlock *block = layout->root->block;
1459 uiBlockSetCurLayout(block, layout);
1461 if (layout->root->type == UI_LAYOUT_HEADER)
1462 uiBlockSetEmboss(block, UI_EMBOSS);
1466 if (layout->root->type == UI_LAYOUT_MENU && !icon)
1469 w = ui_text_icon_width(layout, name, icon, 1);
1472 if (layout->root->type == UI_LAYOUT_HEADER) /* ugly .. */
1475 if (name[0] && icon)
1476 but = uiDefIconTextMenuBut(block, func, arg, icon, name, 0, 0, w, h, tip);
1478 but = uiDefIconMenuBut(block, func, arg, icon, 0, 0, w, h, tip);
1480 but = uiDefMenuBut(block, func, arg, name, 0, 0, w, h, tip);
1482 if (argN) { /* ugly .. */
1483 but->poin = (char *)but;
1484 but->func_argN = argN;
1487 if (layout->root->type == UI_LAYOUT_HEADER)
1488 uiBlockSetEmboss(block, UI_EMBOSS);
1489 else if (ELEM(layout->root->type, UI_LAYOUT_PANEL, UI_LAYOUT_TOOLBAR)) {
1491 but->flag |= UI_TEXT_LEFT;
1495 void uiItemM(uiLayout *layout, bContext *UNUSED(C), const char *menuname, const char *name, int icon)
1499 mt = WM_menutype_find(menuname, FALSE);
1502 RNA_warning("not found %s", menuname);
1507 name = IFACE_(mt->label);
1510 if (layout->root->type == UI_LAYOUT_MENU && !icon)
1513 ui_item_menu(layout, name, icon, ui_item_menutype_func, mt, NULL, TIP_(mt->description));
1517 static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
1519 uiBlock *block = layout->root->block;
1523 uiBlockSetCurLayout(block, layout);
1527 if (layout->root->type == UI_LAYOUT_MENU && !icon)
1530 w = ui_text_icon_width(layout, name, icon, 0);
1532 if (icon && name[0])
1533 but = uiDefIconTextBut(block, LABEL, 0, icon, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1535 but = uiDefIconBut(block, LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1537 but = uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1542 void uiItemL(uiLayout *layout, const char *name, int icon)
1544 uiItemL_(layout, name, icon);
1547 void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, const char *name, int icon)
1549 uiBut *but = uiItemL_(layout, name, icon);
1551 if (ptr && ptr->type)
1552 if (RNA_struct_is_ID(ptr->type))
1553 uiButSetDragID(but, ptr->id.data);
1558 void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
1561 uiBlock *block = layout->root->block;
1562 float *retvalue = (block->handle) ? &block->handle->retvalue : NULL;
1565 uiBlockSetCurLayout(block, layout);
1569 if (layout->root->type == UI_LAYOUT_MENU && !icon)
1572 w = ui_text_icon_width(layout, name, icon, 0);
1574 if (icon && name[0])
1575 uiDefIconTextButF(block, BUT, argval, icon, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, 0, "");
1577 uiDefIconButF(block, BUT, argval, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, 0, "");
1579 uiDefButF(block, BUT, argval, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, 0, "");
1582 /* separator item */
1583 void uiItemS(uiLayout *layout)
1585 uiBlock *block = layout->root->block;
1587 uiBlockSetCurLayout(block, layout);
1588 uiDefBut(block, SEPR, 0, "", 0, 0, EM_SEPR_X, EM_SEPR_Y, NULL, 0.0, 0.0, 0, 0, "");
1592 void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
1597 ui_item_menu(layout, name, icon, func, arg, NULL, "");
1600 typedef struct MenuItemLevel {
1602 /* don't use pointers to the strings because python can dynamically
1603 * allocate strings and free before the menu draws, see [#27304] */
1604 char opname[OP_MAX_TYPENAME];
1605 char propname[MAX_IDPROP_NAME];
1609 static void menu_item_enum_opname_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
1611 MenuItemLevel *lvl = (MenuItemLevel *)(((uiBut *)arg)->func_argN);
1613 uiLayoutSetOperatorContext(layout, lvl->opcontext);
1614 uiItemsEnumO(layout, lvl->opname, lvl->propname);
1617 void uiItemMenuEnumO(uiLayout *layout, const char *opname, const char *propname, const char *name, int icon)
1619 wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1622 UI_OPERATOR_ERROR_RET(ot, opname, return );
1625 ui_item_disabled(layout, opname);
1626 RNA_warning("operator missing srna '%s'", opname);
1631 name = RNA_struct_ui_name(ot->srna);
1632 if (layout->root->type == UI_LAYOUT_MENU && !icon)
1635 lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
1636 BLI_strncpy(lvl->opname, opname, sizeof(lvl->opname));
1637 BLI_strncpy(lvl->propname, propname, sizeof(lvl->propname));
1638 lvl->opcontext = layout->root->opcontext;
1640 ui_item_menu(layout, name, icon, menu_item_enum_opname_menu, NULL, lvl, RNA_struct_ui_description(ot->srna));
1643 static void menu_item_enum_rna_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
1645 MenuItemLevel *lvl = (MenuItemLevel *)(((uiBut *)arg)->func_argN);
1647 uiLayoutSetOperatorContext(layout, lvl->opcontext);
1648 uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
1651 void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon)
1656 prop = RNA_struct_find_property(ptr, propname);
1658 ui_item_disabled(layout, propname);
1659 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1664 name = RNA_property_ui_name(prop);
1665 if (layout->root->type == UI_LAYOUT_MENU && !icon)
1668 lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
1669 lvl->rnapoin = *ptr;
1670 BLI_strncpy(lvl->propname, propname, sizeof(lvl->propname));
1671 lvl->opcontext = layout->root->opcontext;
1673 ui_item_menu(layout, name, icon, menu_item_enum_rna_menu, NULL, lvl, RNA_property_description(prop));
1676 /**************************** Layout Items ***************************/
1678 /* single-row layout */
1679 static void ui_litem_estimate_row(uiLayout *litem)
1687 for (item = litem->items.first; item; item = item->next) {
1688 ui_item_size(item, &itemw, &itemh);
1691 litem->h = MAX2(itemh, litem->h);
1694 litem->w += litem->space;
1698 static int ui_litem_min_width(int itemw)
1700 return MIN2(2 * UI_UNIT_X, itemw);
1703 static void ui_litem_layout_row(uiLayout *litem)
1706 int x, y, w, tot, totw, neww, itemw, minw, itemh, offset;
1707 int fixedw, freew, fixedx, freex, flag = 0, lastw = 0;
1709 /* x= litem->x; */ /* UNUSED */
1715 for (item = litem->items.first; item; item = item->next) {
1716 ui_item_size(item, &itemw, &itemh);
1725 w -= (tot - 1) * litem->space;
1728 /* keep clamping items to fixed minimum size until all are done */
1734 for (item = litem->items.first; item; item = item->next) {
1738 ui_item_size(item, &itemw, &itemh);
1739 minw = ui_litem_min_width(itemw);
1742 neww = ui_item_fit(itemw, x, totw, w - lastw, !item->next, litem->alignment, NULL);
1744 neww = 0; /* no space left, all will need clamping to minimum size */
1748 if ((neww < minw || itemw == minw) && w != 0) {
1756 /* keep free size */
1769 for (item = litem->items.first; item; item = item->next) {
1770 ui_item_size(item, &itemw, &itemh);
1771 minw = ui_litem_min_width(itemw);
1774 /* fixed minimum size items */
1775 itemw = ui_item_fit(minw, fixedx, fixedw, MIN2(w, fixedw), !item->next, litem->alignment, NULL);
1779 /* free size item */
1780 itemw = ui_item_fit(itemw, freex, freew, w - fixedw, !item->next, litem->alignment, NULL);
1784 /* align right/center */
1786 if (litem->alignment == UI_LAYOUT_ALIGN_RIGHT) {
1787 if (freew + fixedw > 0 && freew + fixedw < w)
1788 offset = w - (fixedw + freew);
1790 else if (litem->alignment == UI_LAYOUT_ALIGN_CENTER) {
1791 if (freew + fixedw > 0 && freew + fixedw < w)
1792 offset = (w - (fixedw + freew)) / 2;
1796 ui_item_position(item, x + offset, y - itemh, itemw, itemh);
1803 litem->w = x - litem->x;
1804 litem->h = litem->y - y;
1809 /* single-column layout */
1810 static void ui_litem_estimate_column(uiLayout *litem)
1818 for (item = litem->items.first; item; item = item->next) {
1819 ui_item_size(item, &itemw, &itemh);
1821 litem->w = MAX2(litem->w, itemw);
1825 litem->h += litem->space;
1829 static void ui_litem_layout_column(uiLayout *litem)
1837 for (item = litem->items.first; item; item = item->next) {
1838 ui_item_size(item, NULL, &itemh);
1841 ui_item_position(item, x, y, litem->w, itemh);
1847 litem->h = litem->y - y;
1853 static void ui_litem_estimate_root(uiLayout *UNUSED(litem))
1858 static void ui_litem_layout_root(uiLayout *litem)
1860 if (litem->root->type == UI_LAYOUT_HEADER)
1861 ui_litem_layout_row(litem);
1863 ui_litem_layout_column(litem);
1867 static void ui_litem_estimate_box(uiLayout *litem)
1869 uiStyle *style = litem->root->style;
1871 ui_litem_estimate_column(litem);
1872 litem->w += 2 * style->boxspace;
1873 litem->h += style->boxspace;
1876 static void ui_litem_layout_box(uiLayout *litem)
1878 uiLayoutItemBx *box = (uiLayoutItemBx *)litem;
1879 uiStyle *style = litem->root->style;
1886 litem->x += style->boxspace;
1888 if (w != 0) litem->w -= 2 * style->boxspace;
1889 if (h != 0) litem->h -= 2 * style->boxspace;
1891 ui_litem_layout_column(litem);
1893 litem->x -= style->boxspace;
1894 litem->y -= style->boxspace;
1896 if (w != 0) litem->w += 2 * style->boxspace;
1897 if (h != 0) litem->h += style->boxspace;
1899 /* roundbox around the sublayout */
1900 but = box->roundbox;
1903 but->x2 = litem->x + litem->w;
1904 but->y2 = litem->y + litem->h;
1907 /* multi-column layout, automatically flowing to the next */
1908 static void ui_litem_estimate_column_flow(uiLayout *litem)
1910 uiStyle *style = litem->root->style;
1911 uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem;
1913 int col, x, y, emh, emy, miny, itemw, itemh, maxw = 0;
1916 /* compute max needed width and total height */
1919 for (item = litem->items.first; item; item = item->next) {
1920 ui_item_size(item, &itemw, &itemh);
1921 maxw = MAX2(maxw, itemw);
1926 if (flow->number <= 0) {
1927 /* auto compute number of columns, not very good */
1933 flow->totcol = MAX2(litem->root->emw / maxw, 1);
1934 flow->totcol = MIN2(flow->totcol, totitem);
1937 flow->totcol = flow->number;
1946 emh = toth / flow->totcol;
1948 /* create column per column */
1950 for (item = litem->items.first; item; item = item->next) {
1951 ui_item_size(item, &itemw, &itemh);
1953 y -= itemh + style->buttonspacey;
1954 miny = MIN2(miny, y);
1956 maxw = MAX2(itemw, maxw);
1958 /* decide to go to next one */
1959 if (col < flow->totcol - 1 && emy <= -emh) {
1960 x += maxw + litem->space;
1968 litem->h = litem->y - miny;
1971 static void ui_litem_layout_column_flow(uiLayout *litem)
1973 uiStyle *style = litem->root->style;
1974 uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem;
1976 int col, x, y, w, emh, emy, miny, itemw, itemh;
1977 int toth, totitem, offset;
1979 /* compute max needed width and total height */
1982 for (item = litem->items.first; item; item = item->next) {
1983 ui_item_size(item, &itemw, &itemh);
1994 w = litem->w - (flow->totcol - 1) * style->columnspace;
1995 emh = toth / flow->totcol;
1997 /* create column per column */
1999 for (item = litem->items.first; item; item = item->next) {
2000 ui_item_size(item, NULL, &itemh);
2001 itemw = ui_item_fit(1, x - litem->x, flow->totcol, w, col == flow->totcol - 1, litem->alignment, &offset);
2005 ui_item_position(item, x + offset, y, itemw, itemh);
2006 y -= style->buttonspacey;
2007 miny = MIN2(miny, y);
2009 /* decide to go to next one */
2010 if (col < flow->totcol - 1 && emy <= -emh) {
2011 x += itemw + style->columnspace;
2017 litem->h = litem->y - miny;
2023 static void ui_litem_estimate_absolute(uiLayout *litem)
2026 int itemx, itemy, itemw, itemh, minx, miny;
2033 for (item = litem->items.first; item; item = item->next) {
2034 ui_item_offset(item, &itemx, &itemy);
2035 ui_item_size(item, &itemw, &itemh);
2037 minx = MIN2(minx, itemx);
2038 miny = MIN2(miny, itemy);
2040 litem->w = MAX2(litem->w, itemx + itemw);
2041 litem->h = MAX2(litem->h, itemy + itemh);
2048 static void ui_litem_layout_absolute(uiLayout *litem)
2051 float scalex = 1.0f, scaley = 1.0f;
2052 int x, y, newx, newy, itemx, itemy, itemh, itemw, minx, miny, totw, toth;
2059 for (item = litem->items.first; item; item = item->next) {
2060 ui_item_offset(item, &itemx, &itemy);
2061 ui_item_size(item, &itemw, &itemh);
2063 minx = MIN2(minx, itemx);
2064 miny = MIN2(miny, itemy);
2066 totw = MAX2(totw, itemx + itemw);
2067 toth = MAX2(toth, itemy + itemh);
2073 if (litem->w && totw > 0)
2074 scalex = (float)litem->w / (float)totw;
2075 if (litem->h && toth > 0)
2076 scaley = (float)litem->h / (float)toth;
2079 y = litem->y - scaley * toth;
2081 for (item = litem->items.first; item; item = item->next) {
2082 ui_item_offset(item, &itemx, &itemy);
2083 ui_item_size(item, &itemw, &itemh);
2085 if (scalex != 1.0f) {
2086 newx = (itemx - minx) * scalex;
2087 itemw = (itemx - minx + itemw) * scalex - newx;
2088 itemx = minx + newx;
2091 if (scaley != 1.0f) {
2092 newy = (itemy - miny) * scaley;
2093 itemh = (itemy - miny + itemh) * scaley - newy;
2094 itemy = miny + newy;
2097 ui_item_position(item, x + itemx - minx, y + itemy - miny, itemw, itemh);
2100 litem->w = scalex * totw;
2101 litem->h = litem->y - y;
2102 litem->x = x + litem->w;
2107 static void ui_litem_estimate_split(uiLayout *litem)
2109 ui_litem_estimate_row(litem);
2112 static void ui_litem_layout_split(uiLayout *litem)
2114 uiLayoutItemSplit *split = (uiLayoutItemSplit *)litem;
2117 const int tot = BLI_countlist(&litem->items);
2118 int itemh, x, y, w, colw = 0;
2126 percentage = (split->percentage == 0.0f) ? 1.0f / (float)tot : split->percentage;
2128 w = (litem->w - (tot - 1) * litem->space);
2129 colw = w * percentage;
2130 colw = MAX2(colw, 0);
2132 for (item = litem->items.first; item; item = item->next) {
2133 ui_item_size(item, NULL, &itemh);
2135 ui_item_position(item, x, y - itemh, colw, itemh);
2139 colw = (w - (int)(w * percentage)) / (tot - 1);
2140 colw = MAX2(colw, 0);
2146 litem->w = x - litem->x;
2147 litem->h = litem->y - y;
2152 /* overlap layout */
2153 static void ui_litem_estimate_overlap(uiLayout *litem)
2161 for (item = litem->items.first; item; item = item->next) {
2162 ui_item_size(item, &itemw, &itemh);
2164 litem->w = MAX2(itemw, litem->w);
2165 litem->h = MAX2(itemh, litem->h);
2169 static void ui_litem_layout_overlap(uiLayout *litem)
2172 int itemw, itemh, x, y;
2177 for (item = litem->items.first; item; item = item->next) {
2178 ui_item_size(item, &itemw, &itemh);
2179 ui_item_position(item, x, y - itemh, litem->w, itemh);
2181 litem->h = MAX2(litem->h, itemh);
2185 litem->y = y - litem->h;
2188 /* layout create functions */
2189 uiLayout *uiLayoutRow(uiLayout *layout, int align)
2193 litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
2194 litem->item.type = ITEM_LAYOUT_ROW;
2195 litem->root = layout->root;
2196 litem->align = align;
2199 litem->context = layout->context;
2200 litem->space = (align) ? 0 : layout->root->style->buttonspacex;
2201 litem->w = layout->w;
2202 BLI_addtail(&layout->items, litem);
2204 uiBlockSetCurLayout(layout->root->block, litem);
2209 uiLayout *uiLayoutColumn(uiLayout *layout, int align)
2213 litem = MEM_callocN(sizeof(uiLayout), "uiLayoutColumn");
2214 litem->item.type = ITEM_LAYOUT_COLUMN;
2215 litem->root = layout->root;
2216 litem->align = align;
2219 litem->context = layout->context;
2220 litem->space = (litem->align) ? 0 : layout->root->style->buttonspacey;
2221 litem->w = layout->w;
2222 BLI_addtail(&layout->items, litem);
2224 uiBlockSetCurLayout(layout->root->block, litem);
2229 uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align)
2231 uiLayoutItemFlow *flow;
2233 flow = MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow");
2234 flow->litem.item.type = ITEM_LAYOUT_COLUMN_FLOW;
2235 flow->litem.root = layout->root;
2236 flow->litem.align = align;
2237 flow->litem.active = 1;
2238 flow->litem.enabled = 1;
2239 flow->litem.context = layout->context;
2240 flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
2241 flow->litem.w = layout->w;
2242 flow->number = number;
2243 BLI_addtail(&layout->items, flow);
2245 uiBlockSetCurLayout(layout->root->block, &flow->litem);
2247 return &flow->litem;
2250 static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
2252 uiLayoutItemBx *box;
2254 box = MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx");
2255 box->litem.item.type = ITEM_LAYOUT_BOX;
2256 box->litem.root = layout->root;
2257 box->litem.active = 1;
2258 box->litem.enabled = 1;
2259 box->litem.context = layout->context;
2260 box->litem.space = layout->root->style->columnspace;
2261 box->litem.w = layout->w;
2262 BLI_addtail(&layout->items, box);
2264 uiBlockSetCurLayout(layout->root->block, &box->litem);
2266 box->roundbox = uiDefBut(layout->root->block, type, 0, "", 0, 0, 0, 0, NULL, 0.0, 0.0, 0, 0, "");
2271 uiLayout *uiLayoutBox(uiLayout *layout)
2273 return (uiLayout *)ui_layout_box(layout, ROUNDBOX);
2276 uiLayout *uiLayoutListBox(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr, PropertyRNA *actprop)
2278 uiLayoutItemBx *box = ui_layout_box(layout, LISTBOX);
2279 uiBut *but = box->roundbox;
2281 but->rnasearchpoin = *ptr;
2282 but->rnasearchprop = prop;
2283 but->rnapoin = *actptr;
2284 but->rnaprop = actprop;
2286 return (uiLayout *)box;
2289 uiLayout *uiLayoutAbsolute(uiLayout *layout, int align)
2293 litem = MEM_callocN(sizeof(uiLayout), "uiLayoutAbsolute");
2294 litem->item.type = ITEM_LAYOUT_ABSOLUTE;
2295 litem->root = layout->root;
2296 litem->align = align;
2299 litem->context = layout->context;
2300 BLI_addtail(&layout->items, litem);
2302 uiBlockSetCurLayout(layout->root->block, litem);
2307 uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout)
2311 block = uiLayoutGetBlock(layout);
2312 uiLayoutAbsolute(layout, FALSE);
2317 uiLayout *uiLayoutOverlap(uiLayout *layout)
2321 litem = MEM_callocN(sizeof(uiLayout), "uiLayoutOverlap");
2322 litem->item.type = ITEM_LAYOUT_OVERLAP;
2323 litem->root = layout->root;
2326 litem->context = layout->context;
2327 BLI_addtail(&layout->items, litem);
2329 uiBlockSetCurLayout(layout->root->block, litem);
2334 uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align)
2336 uiLayoutItemSplit *split;
2338 split = MEM_callocN(sizeof(uiLayoutItemSplit), "uiLayoutItemSplit");
2339 split->litem.item.type = ITEM_LAYOUT_SPLIT;
2340 split->litem.root = layout->root;
2341 split->litem.align = align;
2342 split->litem.active = 1;
2343 split->litem.enabled = 1;
2344 split->litem.context = layout->context;
2345 split->litem.space = layout->root->style->columnspace;
2346 split->litem.w = layout->w;
2347 split->percentage = percentage;
2348 BLI_addtail(&layout->items, split);
2350 uiBlockSetCurLayout(layout->root->block, &split->litem);
2352 return &split->litem;
2355 void uiLayoutSetActive(uiLayout *layout, int active)
2357 layout->active = active;
2360 void uiLayoutSetEnabled(uiLayout *layout, int enabled)
2362 layout->enabled = enabled;
2365 void uiLayoutSetRedAlert(uiLayout *layout, int redalert)
2367 layout->redalert = redalert;
2370 void uiLayoutSetKeepAspect(uiLayout *layout, int keepaspect)
2372 layout->keepaspect = keepaspect;
2375 void uiLayoutSetAlignment(uiLayout *layout, int alignment)
2377 layout->alignment = alignment;
2380 void uiLayoutSetScaleX(uiLayout *layout, float scale)
2382 layout->scale[0] = scale;
2385 void uiLayoutSetScaleY(uiLayout *layout, float scale)
2387 layout->scale[1] = scale;
2390 int uiLayoutGetActive(uiLayout *layout)
2392 return layout->active;
2395 int uiLayoutGetEnabled(uiLayout *layout)
2397 return layout->enabled;
2400 int uiLayoutGetRedAlert(uiLayout *layout)
2402 return layout->redalert;
2405 int uiLayoutGetKeepAspect(uiLayout *layout)
2407 return layout->keepaspect;
2410 int uiLayoutGetAlignment(uiLayout *layout)
2412 return layout->alignment;
2415 int uiLayoutGetWidth(uiLayout *layout)
2420 float uiLayoutGetScaleX(uiLayout *layout)
2422 return layout->scale[0];
2425 float uiLayoutGetScaleY(uiLayout *layout)
2427 return layout->scale[1];
2430 /********************** Layout *******************/
2432 static void ui_item_scale(uiLayout *litem, float scale[2])
2437 for (item = litem->items.last; item; item = item->prev) {
2438 ui_item_size(item, &w, &h);
2439 ui_item_offset(item, &x, &y);
2441 if (scale[0] != 0.0f) {
2446 if (scale[1] != 0.0f) {
2451 ui_item_position(item, x, y, w, h);
2455 static void ui_item_estimate(uiItem *item)
2459 if (item->type != ITEM_BUTTON) {
2460 uiLayout *litem = (uiLayout *)item;
2462 for (subitem = litem->items.first; subitem; subitem = subitem->next)
2463 ui_item_estimate(subitem);
2465 if (litem->items.first == NULL)
2468 if (litem->scale[0] != 0.0f || litem->scale[1] != 0.0f)
2469 ui_item_scale(litem, litem->scale);
2471 switch (litem->item.type) {
2472 case ITEM_LAYOUT_COLUMN:
2473 ui_litem_estimate_column(litem);
2475 case ITEM_LAYOUT_COLUMN_FLOW:
2476 ui_litem_estimate_column_flow(litem);
2478 case ITEM_LAYOUT_ROW:
2479 ui_litem_estimate_row(litem);
2481 case ITEM_LAYOUT_BOX:
2482 ui_litem_estimate_box(litem);
2484 case ITEM_LAYOUT_ROOT:
2485 ui_litem_estimate_root(litem);
2487 case ITEM_LAYOUT_ABSOLUTE:
2488 ui_litem_estimate_absolute(litem);
2490 case ITEM_LAYOUT_SPLIT:
2491 ui_litem_estimate_split(litem);
2493 case ITEM_LAYOUT_OVERLAP:
2494 ui_litem_estimate_overlap(litem);
2502 static void ui_item_align(uiLayout *litem, short nr)
2505 uiButtonItem *bitem;
2506 uiLayoutItemBx *box;
2508 for (item = litem->items.last; item; item = item->prev) {
2509 if (item->type == ITEM_BUTTON) {
2510 bitem = (uiButtonItem *)item;
2511 if (ui_but_can_align(bitem->but))
2512 if (!bitem->but->alignnr)
2513 bitem->but->alignnr = nr;
2515 else if (item->type == ITEM_LAYOUT_ABSOLUTE) ;
2516 else if (item->type == ITEM_LAYOUT_OVERLAP) ;
2517 else if (item->type == ITEM_LAYOUT_BOX) {
2518 box = (uiLayoutItemBx *)item;
2519 box->roundbox->alignnr = nr;
2520 BLI_remlink(&litem->root->block->buttons, box->roundbox);
2521 BLI_addhead(&litem->root->block->buttons, box->roundbox);
2524 ui_item_align((uiLayout *)item, nr);
2528 static void ui_item_flag(uiLayout *litem, int flag)
2531 uiButtonItem *bitem;
2533 for (item = litem->items.last; item; item = item->prev) {
2534 if (item->type == ITEM_BUTTON) {
2535 bitem = (uiButtonItem *)item;
2536 bitem->but->flag |= flag;
2539 ui_item_flag((uiLayout *)item, flag);
2543 static void ui_item_layout(uiItem *item)
2547 if (item->type != ITEM_BUTTON) {
2548 uiLayout *litem = (uiLayout *)item;
2550 if (litem->items.first == NULL)
2554 ui_item_align(litem, ++litem->root->block->alignnr);
2556 ui_item_flag(litem, UI_BUT_INACTIVE);
2557 if (!litem->enabled)
2558 ui_item_flag(litem, UI_BUT_DISABLED);
2560 switch (litem->item.type) {
2561 case ITEM_LAYOUT_COLUMN:
2562 ui_litem_layout_column(litem);
2564 case ITEM_LAYOUT_COLUMN_FLOW:
2565 ui_litem_layout_column_flow(litem);
2567 case ITEM_LAYOUT_ROW:
2568 ui_litem_layout_row(litem);
2570 case ITEM_LAYOUT_BOX:
2571 ui_litem_layout_box(litem);
2573 case ITEM_LAYOUT_ROOT:
2574 ui_litem_layout_root(litem);
2576 case ITEM_LAYOUT_ABSOLUTE:
2577 ui_litem_layout_absolute(litem);
2579 case ITEM_LAYOUT_SPLIT:
2580 ui_litem_layout_split(litem);
2582 case ITEM_LAYOUT_OVERLAP:
2583 ui_litem_layout_overlap(litem);
2589 for (subitem = litem->items.first; subitem; subitem = subitem->next)
2590 ui_item_layout(subitem);
2594 static void ui_layout_end(uiBlock *block, uiLayout *layout, int *x, int *y)
2596 if (layout->root->handlefunc)
2597 uiBlockSetHandleFunc(block, layout->root->handlefunc, layout->root->argv);
2599 ui_item_estimate(&layout->item);
2600 ui_item_layout(&layout->item);
2602 if (x) *x = layout->x;
2603 if (y) *y = layout->y;
2606 static void ui_layout_free(uiLayout *layout)
2608 uiItem *item, *next;
2610 for (item = layout->items.first; item; item = next) {
2613 if (item->type == ITEM_BUTTON)
2616 ui_layout_free((uiLayout *)item);
2622 uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int size, int em, uiStyle *style)
2627 root = MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot");
2629 root->style = style;
2630 root->block = block;
2631 root->opcontext = WM_OP_INVOKE_REGION_WIN;
2633 layout = MEM_callocN(sizeof(uiLayout), "uiLayout");
2634 layout->item.type = ITEM_LAYOUT_ROOT;
2638 layout->root = root;
2639 layout->space = style->templatespace;
2641 layout->enabled = 1;
2642 layout->context = NULL;
2644 if (type == UI_LAYOUT_MENU)
2647 if (dir == UI_LAYOUT_HORIZONTAL) {
2649 layout->root->emh = em * UI_UNIT_Y;
2653 layout->root->emw = em * UI_UNIT_X;
2656 block->curlayout = layout;
2657 root->layout = layout;
2658 BLI_addtail(&block->layouts, root);
2663 uiBlock *uiLayoutGetBlock(uiLayout *layout)
2665 return layout->root->block;
2668 int uiLayoutGetOperatorContext(uiLayout *layout)
2670 return layout->root->opcontext;
2674 void uiBlockSetCurLayout(uiBlock *block, uiLayout *layout)
2676 block->curlayout = layout;
2679 void ui_layout_add_but(uiLayout *layout, uiBut *but)
2681 uiButtonItem *bitem;
2683 bitem = MEM_callocN(sizeof(uiButtonItem), "uiButtonItem");
2684 bitem->item.type = ITEM_BUTTON;
2686 BLI_addtail(&layout->items, bitem);
2688 if (layout->context) {
2689 but->context = layout->context;
2690 but->context->used = TRUE;
2694 void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
2696 layout->root->opcontext = opcontext;
2699 void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
2701 layout->root->handlefunc = handlefunc;
2702 layout->root->argv = argv;
2705 void uiBlockLayoutResolve(uiBlock *block, int *x, int *y)
2712 block->curlayout = NULL;
2714 for (root = block->layouts.first; root; root = root->next) {
2715 /* NULL in advance so we don't interfere when adding button */
2716 ui_layout_end(block, root->layout, x, y);
2717 ui_layout_free(root->layout);
2720 BLI_freelistN(&block->layouts);
2722 /* XXX silly trick, interface_templates.c doesn't get linked
2723 * because it's not used by other files in this module? */
2725 UI_template_fix_linking();
2729 void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
2731 uiBlock *block = layout->root->block;
2732 layout->context = CTX_store_add(&block->contexts, name, ptr);
2735 void uiLayoutContextCopy(uiLayout *layout, bContextStore *context)
2737 uiBlock *block = layout->root->block;
2738 layout->context = CTX_store_add_all(&block->contexts, context);
2742 /* introspect funcs */
2743 #include "BLI_dynstr.h"
2745 static void ui_intro_button(DynStr *ds, uiButtonItem *bitem)
2747 uiBut *but = bitem->but;
2748 BLI_dynstr_appendf(ds, "'type':%d, ", but->type); /* see ~ UI_interface.h:200 */
2749 BLI_dynstr_appendf(ds, "'draw_string':'''%s''', ", but->drawstr);
2750 BLI_dynstr_appendf(ds, "'tip':'''%s''', ", but->tip ? but->tip : ""); // not exactly needed, rna has this
2753 char *opstr = WM_operator_pystring(but->block->evil_C, but->optype, but->opptr, 0);
2754 BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr ? opstr : "");
2759 BLI_dynstr_appendf(ds, "'rna':'%s.%s[%d]', ", RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop), but->rnaindex);
2764 static void ui_intro_items(DynStr *ds, ListBase *lb)
2768 BLI_dynstr_append(ds, "[");
2770 for (item = lb->first; item; item = item->next) {
2772 BLI_dynstr_append(ds, "{");
2774 /* could also use the INT but this is nicer*/
2775 switch (item->type) {
2776 case ITEM_BUTTON: BLI_dynstr_append(ds, "'type':'BUTTON', "); break;
2777 case ITEM_LAYOUT_ROW: BLI_dynstr_append(ds, "'type':'ROW', "); break;
2778 case ITEM_LAYOUT_COLUMN: BLI_dynstr_append(ds, "'type':'COLUMN', "); break;
2779 case ITEM_LAYOUT_COLUMN_FLOW: BLI_dynstr_append(ds, "'type':'COLUMN_FLOW', "); break;
2780 case ITEM_LAYOUT_ROW_FLOW: BLI_dynstr_append(ds, "'type':'ROW_FLOW', "); break;
2781 case ITEM_LAYOUT_BOX: BLI_dynstr_append(ds, "'type':'BOX', "); break;
2782 case ITEM_LAYOUT_ABSOLUTE: BLI_dynstr_append(ds, "'type':'ABSOLUTE', "); break;
2783 case ITEM_LAYOUT_SPLIT: BLI_dynstr_append(ds, "'type':'SPLIT', "); break;
2784 case ITEM_LAYOUT_OVERLAP: BLI_dynstr_append(ds, "'type':'OVERLAP', "); break;
2785 case ITEM_LAYOUT_ROOT: BLI_dynstr_append(ds, "'type':'ROOT', "); break;
2786 default: BLI_dynstr_append(ds, "'type':'UNKNOWN', "); break;
2789 switch (item->type) {
2791 ui_intro_button(ds, (uiButtonItem *)item);
2794 BLI_dynstr_append(ds, "'items':");
2795 ui_intro_items(ds, &((uiLayout *)item)->items);
2799 BLI_dynstr_append(ds, "}");
2801 if (item != lb->last)
2802 BLI_dynstr_append(ds, ", ");
2804 BLI_dynstr_append(ds, "], ");
2807 static void ui_intro_uiLayout(DynStr *ds, uiLayout *layout)
2809 ui_intro_items(ds, &layout->items);
2812 static char *str = NULL; // XXX, constant re-freeing, far from ideal.
2813 const char *uiLayoutIntrospect(uiLayout *layout)
2815 DynStr *ds = BLI_dynstr_new();
2821 ui_intro_uiLayout(ds, layout);
2823 str = BLI_dynstr_get_cstring(ds);
2824 BLI_dynstr_free(ds);
2829 static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C), void *op_pt, void *UNUSED(arg_dummy2))
2831 WM_operator_properties_reset((wmOperator *)op_pt);
2834 /* this function does not initialize the layout, functions can be called on the layout before and after */
2835 void uiLayoutOperatorButs(const bContext *C, uiLayout *layout, wmOperator *op, int (*check_prop)(struct PointerRNA *, struct PropertyRNA *), const char label_align, const short flag)
2837 if (!op->properties) {
2838 IDPropertyTemplate val = {0};
2839 op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
2842 if (flag & UI_LAYOUT_OP_SHOW_TITLE) {
2843 uiItemL(layout, RNA_struct_ui_name(op->type->srna), ICON_NONE);
2846 /* poll() on this operator may still fail, at the moment there is no nice feedback when this happens
2847 * just fails silently */
2848 if (!WM_operator_repeat_check(C, op)) {
2849 uiBlockSetButLock(uiLayoutGetBlock(layout), TRUE, "Operator cannot redo");
2850 uiItemL(layout, IFACE_("* Redo Unsupported *"), ICON_NONE); // XXX, could give some nicer feedback or not show redo panel at all?
2854 if (op->type->flag & OPTYPE_PRESET) {
2855 /* XXX, no simple way to get WM_MT_operator_presets.bl_label from python! Label remains the same always! */
2859 uiLayoutGetBlock(layout)->ui_operator = op;
2861 row = uiLayoutRow(layout, TRUE);
2862 uiItemM(row, (bContext *)C, "WM_MT_operator_presets", NULL, ICON_NONE);
2864 WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add");
2865 RNA_string_set(&op_ptr, "operator", op->type->idname);
2866 op_ptr = uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMIN, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
2868 WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add");
2869 RNA_string_set(&op_ptr, "operator", op->type->idname);
2870 RNA_boolean_set(&op_ptr, "remove_active", TRUE);
2871 op_ptr = uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMOUT, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
2875 op->layout = layout;
2876 op->type->ui((bContext *)C, op);
2879 /* UI_LAYOUT_OP_SHOW_EMPTY ignored */
2882 wmWindowManager *wm = CTX_wm_manager(C);
2886 RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
2888 /* main draw call */
2889 empty = uiDefAutoButsRNA(layout, &ptr, check_prop, label_align) == 0;
2891 if (empty && (flag & UI_LAYOUT_OP_SHOW_EMPTY)) {
2892 uiItemL(layout, IFACE_("No Properties"), ICON_NONE);
2896 /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled
2897 * but this is not so important if this button is drawn in those cases
2898 * (which isn't all that likely anyway) - campbell */
2899 if (op->properties->len) {
2902 uiLayout *col; /* needed to avoid alignment errors with previous buttons */
2904 col = uiLayoutColumn(layout, FALSE);
2905 block = uiLayoutGetBlock(col);
2906 but = uiDefIconTextBut(block, BUT, 0, ICON_FILE_REFRESH, IFACE_("Reset"), 0, 0, 18, 20,
2907 NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Reset operator defaults"));
2908 uiButSetFunc(but, ui_layout_operator_buts__reset_cb, op, NULL);
2911 /* set various special settings for buttons */
2915 for (but = uiLayoutGetBlock(layout)->buttons.first; but; but = but->next) {
2916 /* no undo for buttons for operator redo panels */
2917 uiButClearFlag(but, UI_BUT_UNDO);
2919 /* if button is operator's default property, and a text-field, enable focus for it
2920 * - this is used for allowing operators with popups to rename stuff with fewer clicks
2922 if ((but->rnaprop == op->type->prop) && (but->type == TEX)) {
2923 uiButSetFocusOnEnter(CTX_wm_window(C), but);
2929 /* this is a bit of a hack but best keep it in one place at least */
2930 MenuType *uiButGetMenuType(uiBut *but)
2932 if (but->menu_create_func == ui_item_menutype_func) {
2933 return (MenuType *)but->poin;