4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * Contributor(s): Blender Foundation 2009.
22 * ***** END GPL LICENSE BLOCK *****
30 #include "MEM_guardedalloc.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_screen_types.h"
35 #include "DNA_userdef_types.h"
36 #include "DNA_windowmanager_types.h"
38 #include "BLI_listbase.h"
39 #include "BLI_string.h"
41 #include "BKE_context.h"
42 #include "BKE_global.h"
43 #include "BKE_idprop.h"
44 #include "BKE_library.h"
45 #include "BKE_screen.h"
46 #include "BKE_utildefines.h"
48 #include "RNA_access.h"
50 #include "UI_interface.h"
51 #include "UI_resources.h"
52 #include "UI_view2d.h"
56 #include "ED_screen.h"
61 #include "interface_intern.h"
63 /************************ Structs and Defines *************************/
65 #define RNA_NO_INDEX -1
66 #define RNA_ENUM_VALUE -2
73 typedef struct uiLayoutRoot {
74 struct uiLayoutRoot *next, *prev;
81 uiMenuHandleFunc handlefunc;
91 typedef enum uiItemType {
96 ITEM_LAYOUT_COLUMN_FLOW,
104 TEMPLATE_COLUMN_FLOW,
113 typedef struct uiItem {
119 typedef struct uiButtonItem {
128 bContextStore *context;
142 typedef struct uiLayoutItemFlow {
148 typedef struct uiLayoutItemBx {
154 typedef struct uiLayoutItemSplt {
159 typedef struct uiLayoutItemRoot {
163 /************************** Item ***************************/
165 static char *ui_item_name_add_colon(char *name, char namestr[UI_MAX_NAME_STR])
167 int len= strlen(name);
169 if(len != 0 && len+1 < UI_MAX_NAME_STR) {
170 BLI_strncpy(namestr, name, UI_MAX_NAME_STR);
172 namestr[len+1]= '\0';
179 static int ui_item_fit(int item, int pos, int all, int available, int last, int alignment, int *offset)
181 /* available == 0 is unlimited */
188 if(all > available) {
189 /* contents is bigger than available space */
191 return available-pos;
193 return (item*available)/all;
196 /* contents is smaller or equal to available space */
197 if(alignment == UI_LAYOUT_ALIGN_EXPAND) {
199 return available-pos;
201 return (item*available)/all;
208 /* variable button size in which direction? */
209 #define UI_ITEM_VARY_X 1
210 #define UI_ITEM_VARY_Y 2
212 static int ui_layout_vary_direction(uiLayout *layout)
214 return (layout->root->type == UI_LAYOUT_HEADER || layout->alignment != UI_LAYOUT_ALIGN_EXPAND)? UI_ITEM_VARY_X: UI_ITEM_VARY_Y;
217 /* estimated size of text + icon */
218 static int ui_text_icon_width(uiLayout *layout, char *name, int icon, int compact)
220 int variable = ui_layout_vary_direction(layout) == UI_ITEM_VARY_X;
223 return UI_UNIT_X; /* icon only */
225 return (variable)? UI_GetStringWidth(name) + (compact? 5: 10) + UI_UNIT_X: 10*UI_UNIT_X; /* icon + text */
227 return (variable)? UI_GetStringWidth(name) + (compact? 5: 10) + UI_UNIT_X: 10*UI_UNIT_X; /* text only */
230 static void ui_item_size(uiItem *item, int *r_w, int *r_h)
232 if(item->type == ITEM_BUTTON) {
233 uiButtonItem *bitem= (uiButtonItem*)item;
235 if(r_w) *r_w= bitem->but->x2 - bitem->but->x1;
236 if(r_h) *r_h= bitem->but->y2 - bitem->but->y1;
239 uiLayout *litem= (uiLayout*)item;
241 if(r_w) *r_w= litem->w;
242 if(r_h) *r_h= litem->h;
246 static void ui_item_offset(uiItem *item, int *r_x, int *r_y)
248 if(item->type == ITEM_BUTTON) {
249 uiButtonItem *bitem= (uiButtonItem*)item;
251 if(r_x) *r_x= bitem->but->x1;
252 if(r_y) *r_y= bitem->but->y1;
260 static void ui_item_position(uiItem *item, int x, int y, int w, int h)
262 if(item->type == ITEM_BUTTON) {
263 uiButtonItem *bitem= (uiButtonItem*)item;
270 ui_check_but(bitem->but); /* for strlen */
273 uiLayout *litem= (uiLayout*)item;
282 /******************** Special RNA Items *********************/
284 static int ui_layout_local_dir(uiLayout *layout)
286 switch(layout->item.type) {
287 case ITEM_LAYOUT_ROW:
288 case ITEM_LAYOUT_ROOT:
289 return UI_LAYOUT_HORIZONTAL;
290 case ITEM_LAYOUT_COLUMN:
291 case ITEM_LAYOUT_COLUMN_FLOW:
292 case ITEM_LAYOUT_SPLIT:
293 case ITEM_LAYOUT_FREE:
294 case ITEM_LAYOUT_BOX:
296 return UI_LAYOUT_VERTICAL;
300 static uiLayout *ui_item_local_sublayout(uiLayout *test, uiLayout *layout, int align)
304 if(ui_layout_local_dir(test) == UI_LAYOUT_HORIZONTAL)
305 sub= uiLayoutRow(layout, align);
307 sub= uiLayoutColumn(layout, align);
313 /* create buttons for an item with an RNA array */
314 static void ui_item_array(uiLayout *layout, uiBlock *block, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int h, int expand, int slider)
316 uiStyle *style= layout->root->style;
319 PropertySubType subtype;
323 /* retrieve type and subtype */
324 type= RNA_property_type(prop);
325 subtype= RNA_property_subtype(prop);
327 sub= ui_item_local_sublayout(layout, layout, 1);
328 uiBlockSetCurLayout(block, sub);
331 if(strcmp(name, "") != 0)
332 uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
335 if(type == PROP_BOOLEAN && len == 20) {
336 /* special check for layer layout */
337 int butw, buth, unit;
339 uiBlockSetCurLayout(block, uiLayoutFree(layout, 0));
341 unit= UI_UNIT_X*0.75;
345 uiBlockBeginAlign(block);
347 uiDefAutoButR(block, ptr, prop, a, "", ICON_BLANK1, x + butw*a, y+buth, butw, buth);
349 uiDefAutoButR(block, ptr, prop, a+10, "", ICON_BLANK1, x + butw*a, y, butw, buth);
350 uiBlockEndAlign(block);
352 x += 5*butw + style->buttonspacex;
354 uiBlockBeginAlign(block);
356 uiDefAutoButR(block, ptr, prop, a+5, "", ICON_BLANK1, x + butw*a, y+buth, butw, buth);
358 uiDefAutoButR(block, ptr, prop, a+15, "", ICON_BLANK1, x + butw*a, y, butw, buth);
359 uiBlockEndAlign(block);
361 else if(subtype == PROP_MATRIX) {
365 uiBlockSetCurLayout(block, uiLayoutFree(layout, 1));
367 len= ceil(sqrt(len));
373 for(a=0; a<len; a++) {
377 but= uiDefAutoButR(block, ptr, prop, a, "", 0, x + w*col, y+(row-a-1)*UI_UNIT_Y, w, UI_UNIT_Y);
378 if(slider && but->type==NUM)
383 if(ELEM(subtype, PROP_COLOR, PROP_RGB))
384 uiDefAutoButR(block, ptr, prop, -1, "", 0, 0, 0, w, UI_UNIT_Y);
386 if(!ELEM(subtype, PROP_COLOR, PROP_RGB) || expand) {
387 /* layout for known array subtypes */
390 for(a=0; a<len; a++) {
391 str[0]= RNA_property_array_item_char(prop, a);
394 if(type == PROP_BOOLEAN) {
403 but= uiDefAutoButR(block, ptr, prop, a, str, 0, 0, 0, w, UI_UNIT_Y);
404 if(slider && but->type==NUM)
408 else if(ELEM(subtype, PROP_COLOR, PROP_RGB) && len == 4) {
409 but= uiDefAutoButR(block, ptr, prop, 3, "A:", 0, 0, 0, w, UI_UNIT_Y);
410 if(slider && but->type==NUM)
415 uiBlockSetCurLayout(block, layout);
418 static void ui_item_enum_row(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, char *uiname, int x, int y, int w, int h)
420 EnumPropertyItem *item;
421 const char *identifier;
423 int a, totitem, itemw, icon, value, free;
425 identifier= RNA_property_identifier(prop);
426 RNA_property_enum_items(block->evil_C, ptr, prop, &item, &totitem, &free);
428 uiBlockSetCurLayout(block, ui_item_local_sublayout(layout, layout, 1));
429 for(a=0; a<totitem; a++) {
430 if(!item[a].identifier[0])
433 name= (!uiname || uiname[0])? (char*)item[a].name: "";
435 value= item[a].value;
436 itemw= ui_text_icon_width(block->curlayout, name, icon, 0);
438 if(icon && strcmp(name, "") != 0)
439 uiDefIconTextButR(block, ROW, 0, icon, name, 0, 0, itemw, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
441 uiDefIconButR(block, ROW, 0, icon, 0, 0, itemw, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
443 uiDefButR(block, ROW, 0, name, 0, 0, itemw, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
445 uiBlockSetCurLayout(block, layout);
451 /* create label + button for RNA property */
452 static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int x, int y, int w, int h)
456 PropertySubType subtype;
459 sub= uiLayoutRow(layout, 0);
460 uiBlockSetCurLayout(block, sub);
462 if(strcmp(name, "") != 0) {
463 /* XXX UI_GetStringWidth is not accurate
464 labelw= UI_GetStringWidth(name);
465 CLAMP(labelw, w/4, 3*w/4);*/
467 uiDefBut(block, LABEL, 0, name, x, y, labelw, h, NULL, 0.0, 0.0, 0, 0, "");
471 subtype= RNA_property_subtype(prop);
473 if(subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) {
474 uiBlockSetCurLayout(block, uiLayoutRow(sub, 1));
475 uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, w-UI_UNIT_X, h);
477 /* BUTTONS_OT_file_browse calls uiFileBrowseContextProperty */
478 but= uiDefIconButO(block, BUT, "BUTTONS_OT_file_browse", WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, "Browse for file or directory.");
481 but= uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, w, h);
483 uiBlockSetCurLayout(block, layout);
487 void uiFileBrowseContextProperty(const bContext *C, PointerRNA *ptr, PropertyRNA **prop)
489 ARegion *ar= CTX_wm_region(C);
491 uiBut *but, *prevbut;
493 memset(ptr, 0, sizeof(*ptr));
499 for(block=ar->uiblocks.first; block; block=block->next) {
500 for(but=block->buttons.first; but; but= but->next) {
503 /* find the button before the active one */
504 if((but->flag & UI_BUT_LAST_ACTIVE) && prevbut && prevbut->rnapoin.id.data) {
505 if(RNA_property_type(prevbut->rnaprop) == PROP_STRING) {
506 *ptr= prevbut->rnapoin;
507 *prop= prevbut->rnaprop;
515 /********************* Button Items *************************/
518 static void ui_item_disabled(uiLayout *layout, char *name)
520 uiBlock *block= layout->root->block;
524 uiBlockSetCurLayout(block, layout);
529 w= ui_text_icon_width(layout, name, 0, 0);
531 but= uiDefBut(block, LABEL, 0, (char*)name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
532 but->flag |= UI_BUT_DISABLED;
538 PointerRNA uiItemFullO(uiLayout *layout, char *name, int icon, char *idname, IDProperty *properties, int context, int flag)
540 uiBlock *block= layout->root->block;
541 wmOperatorType *ot= WM_operatortype_find(idname, 0);
546 ui_item_disabled(layout, idname);
547 return PointerRNA_NULL;
552 if(layout->root->type == UI_LAYOUT_MENU && !icon)
556 uiBlockSetCurLayout(block, layout);
558 w= ui_text_icon_width(layout, name, icon, 0);
560 if(icon && strcmp(name, "") != 0)
561 but= uiDefIconTextButO(block, BUT, ot->idname, context, icon, (char*)name, 0, 0, w, UI_UNIT_Y, NULL);
563 but= uiDefIconButO(block, BUT, ot->idname, context, icon, 0, 0, w, UI_UNIT_Y, NULL);
565 but= uiDefButO(block, BUT, ot->idname, context, (char*)name, 0, 0, w, UI_UNIT_Y, NULL);
567 /* assign properties */
568 if(properties || (flag & UI_ITEM_O_RETURN_PROPS)) {
569 PointerRNA *opptr= uiButGetOperatorPtrRNA(but);
572 opptr->data= properties;
575 IDPropertyTemplate val = {0};
576 opptr->data= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
582 return PointerRNA_NULL;
585 static char *ui_menu_enumpropname(uiLayout *layout, char *opname, char *propname, int retval)
587 wmOperatorType *ot= WM_operatortype_find(opname, 0);
594 RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
595 prop= RNA_struct_find_property(&ptr, propname);
598 EnumPropertyItem *item;
602 RNA_property_enum_items(layout->root->block->evil_C, &ptr, prop, &item, &totitem, &free);
603 if(RNA_enum_name(item, retval, &name)) {
604 if(free) MEM_freeN(item);
615 void uiItemEnumO(uiLayout *layout, char *name, int icon, char *opname, char *propname, int value)
619 WM_operator_properties_create(&ptr, opname);
620 RNA_enum_set(&ptr, propname, value);
623 name= ui_menu_enumpropname(layout, opname, propname, value);
625 uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext, 0);
628 void uiItemsEnumO(uiLayout *layout, char *opname, char *propname)
630 wmOperatorType *ot= WM_operatortype_find(opname, 0);
634 uiBlock *block= layout->root->block;
636 if(!ot || !ot->srna) {
637 ui_item_disabled(layout, opname);
641 RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
642 prop= RNA_struct_find_property(&ptr, propname);
644 if(prop && RNA_property_type(prop) == PROP_ENUM) {
645 EnumPropertyItem *item;
646 int totitem, i, free;
647 uiLayout *split= uiLayoutSplit(layout, 0);
648 uiLayout *column= uiLayoutColumn(split, 0);
650 RNA_property_enum_items(block->evil_C, &ptr, prop, &item, &totitem, &free);
652 for(i=0; i<totitem; i++) {
653 if(item[i].identifier[0]) {
654 uiItemEnumO(column, (char*)item[i].name, item[i].icon, opname, propname, item[i].value);
659 column= uiLayoutColumn(split, 0);
660 /* inconsistent, but menus with labels do not look good flipped */
661 block->flag |= UI_BLOCK_NO_FLIP;
664 uiItemL(column, (char*)item[i].name, 0);
665 bt= block->buttons.last;
666 bt->flag= UI_TEXT_LEFT;
678 /* for use in cases where we have */
679 void uiItemEnumO_string(uiLayout *layout, char *name, int icon, char *opname, char *propname, char *value_str)
683 /* for getting the enum */
685 EnumPropertyItem *item;
688 WM_operator_properties_create(&ptr, opname);
691 if((prop= RNA_struct_find_property(&ptr, propname))) {
692 RNA_property_enum_items(layout->root->block->evil_C, &ptr, prop, &item, NULL, &free);
693 if(RNA_enum_value_from_id(item, value_str, &value)==0) {
694 if(free) MEM_freeN(item);
695 printf("uiItemEnumO_string: %s.%s, enum %s not found.\n", RNA_struct_identifier(ptr.type), propname, value_str);
703 printf("uiItemEnumO_string: %s.%s not found.\n", RNA_struct_identifier(ptr.type), propname);
707 RNA_property_enum_set(&ptr, prop, value);
709 /* same as uiItemEnumO */
711 name= ui_menu_enumpropname(layout, opname, propname, value);
713 uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext, 0);
716 void uiItemBooleanO(uiLayout *layout, char *name, int icon, char *opname, char *propname, int value)
720 WM_operator_properties_create(&ptr, opname);
721 RNA_boolean_set(&ptr, propname, value);
723 uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext, 0);
726 void uiItemIntO(uiLayout *layout, char *name, int icon, char *opname, char *propname, int value)
730 WM_operator_properties_create(&ptr, opname);
731 RNA_int_set(&ptr, propname, value);
733 uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext, 0);
736 void uiItemFloatO(uiLayout *layout, char *name, int icon, char *opname, char *propname, float value)
740 WM_operator_properties_create(&ptr, opname);
741 RNA_float_set(&ptr, propname, value);
743 uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext, 0);
746 void uiItemStringO(uiLayout *layout, char *name, int icon, char *opname, char *propname, char *value)
750 WM_operator_properties_create(&ptr, opname);
751 RNA_string_set(&ptr, propname, value);
753 uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext, 0);
756 void uiItemO(uiLayout *layout, char *name, int icon, char *opname)
758 uiItemFullO(layout, name, icon, opname, NULL, layout->root->opcontext, 0);
761 /* RNA property items */
763 static void ui_item_rna_size(uiLayout *layout, char *name, int icon, PropertyRNA *prop, int index, int *r_w, int *r_h)
766 PropertySubType subtype;
769 /* arbitrary extended width by type */
770 type= RNA_property_type(prop);
771 subtype= RNA_property_subtype(prop);
772 len= RNA_property_array_length(prop);
774 if(ELEM3(type, PROP_STRING, PROP_POINTER, PROP_ENUM) && !name[0])
775 name= "non-empty text";
776 else if(type == PROP_BOOLEAN && !name[0])
779 w= ui_text_icon_width(layout, name, icon, 0);
782 /* increase height for arrays */
783 if(index == RNA_NO_INDEX && len > 0) {
784 if(!name[0] && icon == 0)
787 if(type == PROP_BOOLEAN && len == 20)
789 else if(subtype == PROP_MATRIX)
790 h += ceil(sqrt(len))*UI_UNIT_Y;
794 else if(ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) {
795 if(type == PROP_BOOLEAN && strcmp(name, "") != 0)
797 else if(type == PROP_ENUM)
799 else if(type == PROP_FLOAT || type == PROP_INT)
807 void uiItemFullR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int value, int flag)
809 uiBlock *block= layout->root->block;
812 char namestr[UI_MAX_NAME_STR];
813 int len, w, h, slider, toggle, expand;
815 if(!ptr->data || !prop)
818 uiBlockSetCurLayout(block, layout);
821 type= RNA_property_type(prop);
822 len= RNA_property_array_length(prop);
824 /* set name and icon */
826 name= (char*)RNA_property_ui_name(prop);
828 icon= RNA_property_ui_icon(prop);
830 if(ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER))
831 name= ui_item_name_add_colon(name, namestr);
832 else if(type == PROP_BOOLEAN && len)
833 name= ui_item_name_add_colon(name, namestr);
834 else if(type == PROP_ENUM && index != RNA_ENUM_VALUE)
835 name= ui_item_name_add_colon(name, namestr);
837 if(layout->root->type == UI_LAYOUT_MENU) {
838 if(type == PROP_BOOLEAN)
839 icon= (RNA_property_boolean_get(ptr, prop))? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT;
840 else if(type == PROP_ENUM && index == RNA_ENUM_VALUE)
841 icon= (RNA_property_enum_get(ptr, prop) == value)? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT;
844 slider= (flag & UI_ITEM_R_SLIDER);
845 toggle= (flag & UI_ITEM_R_TOGGLE);
846 expand= (flag & UI_ITEM_R_EXPAND);
849 ui_item_rna_size(layout, name, icon, prop, index, &w, &h);
852 if(index == RNA_NO_INDEX && len > 0)
853 ui_item_array(layout, block, name, icon, ptr, prop, len, 0, 0, w, h, expand, slider);
855 else if(type == PROP_ENUM && index == RNA_ENUM_VALUE) {
856 char *identifier= (char*)RNA_property_identifier(prop);
858 if(icon && strcmp(name, "") != 0)
859 uiDefIconTextButR(block, ROW, 0, icon, name, 0, 0, w, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
861 uiDefIconButR(block, ROW, 0, icon, 0, 0, w, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
863 uiDefButR(block, ROW, 0, name, 0, 0, w, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
866 else if(type == PROP_ENUM && expand)
867 ui_item_enum_row(layout, block, ptr, prop, name, 0, 0, w, h);
868 /* property with separate label */
869 else if(type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) {
870 but= ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h);
871 ui_but_add_search(but, ptr, prop, NULL, NULL);
875 but= uiDefAutoButR(block, ptr, prop, index, (char*)name, icon, 0, 0, w, h);
877 if(slider && but->type==NUM)
880 if(toggle && but->type==OPTION)
885 void uiItemR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, char *propname, int flag)
889 if(!ptr->data || !propname)
892 prop= RNA_struct_find_property(ptr, propname);
895 ui_item_disabled(layout, propname);
896 printf("uiItemR: property not found: %s\n", propname);
900 uiItemFullR(layout, name, icon, ptr, prop, RNA_NO_INDEX, 0, flag);
903 void uiItemEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, int value)
907 if(!ptr->data || !propname)
910 prop= RNA_struct_find_property(ptr, propname);
912 if(!prop || RNA_property_type(prop) != PROP_ENUM) {
913 ui_item_disabled(layout, propname);
914 printf("uiItemEnumR: enum property not found: %s\n", propname);
918 uiItemFullR(layout, name, icon, ptr, prop, RNA_ENUM_VALUE, value, 0);
921 void uiItemEnumR_string(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, char *value)
924 EnumPropertyItem *item;
927 if(!ptr->data || !propname)
930 prop= RNA_struct_find_property(ptr, propname);
932 if(!prop || RNA_property_type(prop) != PROP_ENUM) {
933 ui_item_disabled(layout, propname);
934 printf("uiItemEnumR: enum property not found: %s\n", propname);
938 RNA_property_enum_items(layout->root->block->evil_C, ptr, prop, &item, NULL, &free);
940 if(!RNA_enum_value_from_id(item, value, &ivalue)) {
941 if(free) MEM_freeN(item);
942 ui_item_disabled(layout, propname);
943 printf("uiItemEnumR: enum property value not found: %s\n", value);
947 for(a=0; item[a].identifier; a++) {
948 if(item[a].value == ivalue) {
949 uiItemFullR(layout, (char*)item[a].name, item[a].icon, ptr, prop, RNA_ENUM_VALUE, ivalue, 0);
958 void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, char *propname)
961 uiBlock *block= layout->root->block;
964 prop= RNA_struct_find_property(ptr, propname);
967 ui_item_disabled(layout, propname);
971 if(RNA_property_type(prop) == PROP_ENUM) {
972 EnumPropertyItem *item;
973 int totitem, i, free;
974 uiLayout *split= uiLayoutSplit(layout, 0);
975 uiLayout *column= uiLayoutColumn(split, 0);
977 RNA_property_enum_items(block->evil_C, ptr, prop, &item, &totitem, &free);
979 for(i=0; i<totitem; i++) {
980 if(item[i].identifier[0]) {
981 uiItemEnumR(column, (char*)item[i].name, 0, ptr, propname, item[i].value);
986 column= uiLayoutColumn(split, 0);
987 /* inconsistent, but menus with labels do not look good flipped */
988 block->flag |= UI_BLOCK_NO_FLIP;
991 uiItemL(column, (char*)item[i].name, 0);
992 bt= block->buttons.last;
993 bt->flag= UI_TEXT_LEFT;
1005 /* Pointer RNA button with search */
1007 static void rna_search_cb(const struct bContext *C, void *arg_but, char *str, uiSearchItems *items)
1009 Scene *scene= CTX_data_scene(C);
1010 uiBut *but= arg_but;
1015 RNA_PROP_BEGIN(&but->rnasearchpoin, itemptr, but->rnasearchprop) {
1017 if(RNA_struct_is_ID(itemptr.type))
1018 iconid= ui_id_icon_get(scene, itemptr.data);
1020 name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
1023 if(BLI_strcasestr(name, str)) {
1024 if(!uiSearchItemAdd(items, name, SET_INT_IN_POINTER(i), iconid)) {
1038 static void search_id_collection(StructRNA *ptype, PointerRNA *ptr, PropertyRNA **prop)
1042 /* look for collection property in Main */
1043 RNA_main_pointer_create(G.main, ptr);
1047 RNA_STRUCT_BEGIN(ptr, iprop) {
1048 /* if it's a collection and has same pointer type, we've got it */
1049 if(RNA_property_type(iprop) == PROP_COLLECTION) {
1050 srna= RNA_property_pointer_type(ptr, iprop);
1061 void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop)
1066 /* for ID's we do automatic lookup */
1068 if(RNA_property_type(prop) == PROP_POINTER) {
1069 ptype= RNA_property_pointer_type(ptr, prop);
1070 search_id_collection(ptype, &sptr, &searchprop);
1075 /* turn button into search button */
1077 but->type= SEARCH_MENU;
1078 but->hardmax= MAX2(but->hardmax, 256);
1079 but->rnasearchpoin= *searchptr;
1080 but->rnasearchprop= searchprop;
1081 but->flag |= UI_ICON_LEFT|UI_TEXT_LEFT;
1083 uiButSetSearchFunc(but, rna_search_cb, but, NULL, NULL);
1087 void uiItemPointerR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, struct PointerRNA *searchptr, char *searchpropname)
1089 PropertyRNA *prop, *searchprop;
1093 StructRNA *icontype;
1096 /* validate arguments */
1097 if(!ptr->data || !searchptr->data)
1100 prop= RNA_struct_find_property(ptr, propname);
1103 printf("uiItemPointerR: property not found: %s\n", propname);
1107 type= RNA_property_type(prop);
1108 if(!ELEM(type, PROP_POINTER, PROP_STRING)) {
1109 printf("uiItemPointerR: property %s must be a pointer or string.\n", propname);
1113 searchprop= RNA_struct_find_property(searchptr, searchpropname);
1115 if(!searchprop || RNA_property_type(searchprop) != PROP_COLLECTION) {
1116 printf("uiItemPointerR: search collection property not found: %s\n", searchpropname);
1120 /* get icon & name */
1122 if(type == PROP_POINTER)
1123 icontype= RNA_property_pointer_type(ptr, prop);
1125 icontype= RNA_property_pointer_type(searchptr, searchprop);
1127 icon= RNA_struct_ui_icon(icontype);
1130 name= (char*)RNA_property_ui_name(prop);
1133 block= uiLayoutGetBlock(layout);
1135 ui_item_rna_size(layout, name, icon, prop, 0, &w, &h);
1136 but= ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h);
1138 ui_but_add_search(but, ptr, prop, searchptr, searchprop);
1142 static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
1144 MenuType *mt= (MenuType*)arg_mt;
1148 menu.layout= layout;
1152 static void ui_item_menu(uiLayout *layout, char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN)
1154 uiBlock *block= layout->root->block;
1158 uiBlockSetCurLayout(block, layout);
1160 if(layout->root->type == UI_LAYOUT_HEADER)
1161 uiBlockSetEmboss(block, UI_EMBOSS);
1165 if(layout->root->type == UI_LAYOUT_MENU && !icon)
1168 w= ui_text_icon_width(layout, name, icon, 1);
1171 if(layout->root->type == UI_LAYOUT_HEADER) /* ugly .. */
1175 but= uiDefIconTextMenuBut(block, func, arg, icon, (char*)name, 0, 0, w, h, "");
1177 but= uiDefMenuBut(block, func, arg, (char*)name, 0, 0, w, h, "");
1179 if(argN) { /* ugly .. */
1180 but->poin= (char*)but;
1181 but->func_argN= argN;
1184 if(layout->root->type == UI_LAYOUT_HEADER)
1185 uiBlockSetEmboss(block, UI_EMBOSS);
1186 else if(layout->root->type == UI_LAYOUT_PANEL)
1190 void uiItemM(uiLayout *layout, bContext *C, char *name, int icon, char *menuname)
1192 ARegion *ar= CTX_wm_region(C);
1198 for(mt=ar->type->menutypes.first; mt; mt=mt->next) {
1199 if(strcmp(menuname, mt->idname) == 0) {
1202 if(layout->root->type == UI_LAYOUT_MENU && !icon)
1204 ui_item_menu(layout, name, icon, ui_item_menutype_func, mt, NULL);
1209 printf("uiItemM: not found %s\n", menuname);
1213 void uiItemL(uiLayout *layout, char *name, int icon)
1215 uiBlock *block= layout->root->block;
1219 uiBlockSetCurLayout(block, layout);
1223 if(layout->root->type == UI_LAYOUT_MENU && !icon)
1226 w= ui_text_icon_width(layout, name, icon, 0);
1228 if(icon && strcmp(name, "") != 0)
1229 but= uiDefIconTextBut(block, LABEL, 0, icon, (char*)name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1231 but= uiDefIconBut(block, LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1233 but= uiDefBut(block, LABEL, 0, (char*)name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1237 void uiItemV(uiLayout *layout, char *name, int icon, int argval)
1240 uiBlock *block= layout->root->block;
1241 float *retvalue= (block->handle)? &block->handle->retvalue: NULL;
1244 uiBlockSetCurLayout(block, layout);
1248 if(layout->root->type == UI_LAYOUT_MENU && !icon)
1251 w= ui_text_icon_width(layout, name, icon, 0);
1253 if(icon && strcmp(name, "") != 0)
1254 uiDefIconTextButF(block, BUTM, 0, icon, (char*)name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, "");
1256 uiDefIconButF(block, BUTM, 0, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, "");
1258 uiDefButF(block, BUTM, 0, (char*)name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, "");
1261 /* separator item */
1262 void uiItemS(uiLayout *layout)
1264 uiBlock *block= layout->root->block;
1266 uiBlockSetCurLayout(block, layout);
1267 uiDefBut(block, SEPR, 0, "", 0, 0, EM_SEPR_X, EM_SEPR_Y, NULL, 0.0, 0.0, 0, 0, "");
1271 void uiItemMenuF(uiLayout *layout, char *name, int icon, uiMenuCreateFunc func, void *arg)
1276 ui_item_menu(layout, name, icon, func, arg, NULL);
1279 typedef struct MenuItemLevel {
1286 static void menu_item_enum_opname_menu(bContext *C, uiLayout *layout, void *arg)
1288 MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
1290 uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
1291 uiItemsEnumO(layout, lvl->opname, lvl->propname);
1294 void uiItemMenuEnumO(uiLayout *layout, char *name, int icon, char *opname, char *propname)
1296 wmOperatorType *ot= WM_operatortype_find(opname, 0);
1299 if(!ot || !ot->srna) {
1300 ui_item_disabled(layout, opname);
1306 if(layout->root->type == UI_LAYOUT_MENU && !icon)
1309 lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
1310 lvl->opname= opname;
1311 lvl->propname= propname;
1312 lvl->opcontext= layout->root->opcontext;
1314 ui_item_menu(layout, name, icon, menu_item_enum_opname_menu, NULL, lvl);
1317 static void menu_item_enum_rna_menu(bContext *C, uiLayout *layout, void *arg)
1319 MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
1321 uiLayoutSetOperatorContext(layout, lvl->opcontext);
1322 uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
1325 void uiItemMenuEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname)
1330 prop= RNA_struct_find_property(ptr, propname);
1332 ui_item_disabled(layout, propname);
1337 name= (char*)RNA_property_ui_name(prop);
1338 if(layout->root->type == UI_LAYOUT_MENU && !icon)
1341 lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
1343 lvl->propname= propname;
1344 lvl->opcontext= layout->root->opcontext;
1346 ui_item_menu(layout, name, icon, menu_item_enum_rna_menu, NULL, lvl);
1349 /**************************** Layout Items ***************************/
1351 /* single-row layout */
1352 static void ui_litem_estimate_row(uiLayout *litem)
1360 for(item=litem->items.first; item; item=item->next) {
1361 ui_item_size(item, &itemw, &itemh);
1364 litem->h= MAX2(itemh, litem->h);
1367 litem->w += litem->space;
1371 static int ui_litem_min_width(int itemw)
1373 return MIN2(2*UI_UNIT_X, itemw);
1376 static void ui_litem_layout_row(uiLayout *litem)
1379 int x, y, w, tot, totw, neww, itemw, minw, itemh, offset;
1380 int fixedw, freew, fixedx, freex, flag= 0, lastw= 0;
1388 for(item=litem->items.first; item; item=item->next) {
1389 ui_item_size(item, &itemw, &itemh);
1398 w -= (tot-1)*litem->space;
1401 /* keep clamping items to fixed minimum size until all are done */
1407 for(item=litem->items.first; item; item=item->next) {
1411 ui_item_size(item, &itemw, &itemh);
1412 minw= ui_litem_min_width(itemw);
1415 neww= ui_item_fit(itemw, x, totw, w-lastw, !item->next, litem->alignment, NULL);
1417 neww= 0; /* no space left, all will need clamping to minimum size */
1421 if((neww < minw || itemw == minw) && w != 0) {
1429 /* keep free size */
1442 for(item=litem->items.first; item; item=item->next) {
1443 ui_item_size(item, &itemw, &itemh);
1444 minw= ui_litem_min_width(itemw);
1447 /* fixed minimum size items */
1448 itemw= ui_item_fit(minw, fixedx, fixedw, MIN2(w, fixedw), !item->next, litem->alignment, NULL);
1452 /* free size item */
1453 itemw= ui_item_fit(itemw, freex, freew, w-fixedw, !item->next, litem->alignment, NULL);
1457 /* align right/center */
1459 if(litem->alignment == UI_LAYOUT_ALIGN_RIGHT) {
1460 if(fixedw == 0 && freew < w-fixedw)
1461 offset= (w - fixedw) - freew;
1463 else if(litem->alignment == UI_LAYOUT_ALIGN_CENTER) {
1464 if(fixedw == 0 && freew < w-fixedw)
1465 offset= ((w - fixedw) - freew)/2;
1469 ui_item_position(item, x+offset, y-itemh, itemw, itemh);
1476 litem->w= x - litem->x;
1477 litem->h= litem->y - y;
1482 /* single-column layout */
1483 static void ui_litem_estimate_column(uiLayout *litem)
1491 for(item=litem->items.first; item; item=item->next) {
1492 ui_item_size(item, &itemw, &itemh);
1494 litem->w= MAX2(litem->w, itemw);
1498 litem->h += litem->space;
1502 static void ui_litem_layout_column(uiLayout *litem)
1510 for(item=litem->items.first; item; item=item->next) {
1511 ui_item_size(item, NULL, &itemh);
1514 ui_item_position(item, x, y, litem->w, itemh);
1520 litem->h= litem->y - y;
1526 static void ui_litem_estimate_root(uiLayout *litem)
1531 static void ui_litem_layout_root(uiLayout *litem)
1533 if(litem->root->type == UI_LAYOUT_HEADER)
1534 ui_litem_layout_row(litem);
1536 ui_litem_layout_column(litem);
1540 static void ui_litem_estimate_box(uiLayout *litem)
1542 uiStyle *style= litem->root->style;
1544 ui_litem_estimate_column(litem);
1545 litem->w += 2*style->boxspace;
1546 litem->h += style->boxspace;
1549 static void ui_litem_layout_box(uiLayout *litem)
1551 uiLayoutItemBx *box= (uiLayoutItemBx*)litem;
1552 uiStyle *style= litem->root->style;
1559 litem->x += style->boxspace;
1561 if(w != 0) litem->w -= 2*style->boxspace;
1562 if(h != 0) litem->h -= 2*style->boxspace;
1564 ui_litem_layout_column(litem);
1566 litem->x -= style->boxspace;
1567 litem->y -= style->boxspace;
1569 if(w != 0) litem->w += 2*style->boxspace;
1570 if(h != 0) litem->h += style->boxspace;
1572 /* roundbox around the sublayout */
1576 but->x2= litem->x+litem->w;
1577 but->y2= litem->y+litem->h;
1580 /* multi-column layout, automatically flowing to the next */
1581 static void ui_litem_estimate_column_flow(uiLayout *litem)
1583 uiStyle *style= litem->root->style;
1584 uiLayoutItemFlow *flow= (uiLayoutItemFlow*)litem;
1586 int col, x, y, emh, emy, miny, itemw, itemh, maxw=0;
1589 /* compute max needed width and total height */
1592 for(item=litem->items.first; item; item=item->next) {
1593 ui_item_size(item, &itemw, &itemh);
1594 maxw= MAX2(maxw, itemw);
1599 if(flow->number <= 0) {
1600 /* auto compute number of columns, not very good */
1606 flow->totcol= MAX2(litem->root->emw/maxw, 1);
1607 flow->totcol= MIN2(flow->totcol, totitem);
1610 flow->totcol= flow->number;
1619 emh= toth/flow->totcol;
1621 /* create column per column */
1623 for(item=litem->items.first; item; item=item->next) {
1624 ui_item_size(item, &itemw, &itemh);
1626 y -= itemh + style->buttonspacey;
1627 miny= MIN2(miny, y);
1629 maxw= MAX2(itemw, maxw);
1631 /* decide to go to next one */
1632 if(col < flow->totcol-1 && emy <= -emh) {
1633 x += maxw + litem->space;
1641 litem->h= litem->y - miny;
1644 static void ui_litem_layout_column_flow(uiLayout *litem)
1646 uiStyle *style= litem->root->style;
1647 uiLayoutItemFlow *flow= (uiLayoutItemFlow*)litem;
1649 int col, x, y, w, emh, emy, miny, itemw, itemh;
1650 int toth, totitem, offset;
1652 /* compute max needed width and total height */
1655 for(item=litem->items.first; item; item=item->next) {
1656 ui_item_size(item, &itemw, &itemh);
1667 w= litem->w - (flow->totcol-1)*style->columnspace;
1668 emh= toth/flow->totcol;
1670 /* create column per column */
1672 for(item=litem->items.first; item; item=item->next) {
1673 ui_item_size(item, NULL, &itemh);
1674 itemw= ui_item_fit(1, x-litem->x, flow->totcol, w, col == flow->totcol-1, litem->alignment, &offset);
1678 ui_item_position(item, x+offset, y, itemw, itemh);
1679 y -= style->buttonspacey;
1680 miny= MIN2(miny, y);
1682 /* decide to go to next one */
1683 if(col < flow->totcol-1 && emy <= -emh) {
1684 x += itemw + style->columnspace;
1690 litem->h= litem->y - miny;
1696 static void ui_litem_estimate_free(uiLayout *litem)
1699 int itemx, itemy, itemw, itemh, minx, miny;
1706 for(item=litem->items.first; item; item=item->next) {
1707 ui_item_offset(item, &itemx, &itemy);
1708 ui_item_size(item, &itemw, &itemh);
1710 minx= MIN2(minx, itemx);
1711 miny= MIN2(miny, itemy);
1713 litem->w= MAX2(litem->w, itemx+itemw);
1714 litem->h= MAX2(litem->h, itemy+itemh);
1721 static void ui_litem_layout_free(uiLayout *litem)
1724 float scalex=1.0f, scaley=1.0f;
1725 int x, y, newx, newy, itemx, itemy, itemh, itemw, minx, miny, totw, toth;
1732 for(item=litem->items.first; item; item=item->next) {
1733 ui_item_offset(item, &itemx, &itemy);
1734 ui_item_size(item, &itemw, &itemh);
1736 minx= MIN2(minx, itemx);
1737 miny= MIN2(miny, itemy);
1739 totw= MAX2(totw, itemx+itemw);
1740 toth= MAX2(toth, itemy+itemh);
1746 if(litem->w && totw > 0)
1747 scalex= (float)litem->w/(float)totw;
1748 if(litem->h && toth > 0)
1749 scaley= (float)litem->h/(float)toth;
1752 y= litem->y - scaley*toth;
1754 for(item=litem->items.first; item; item=item->next) {
1755 ui_item_offset(item, &itemx, &itemy);
1756 ui_item_size(item, &itemw, &itemh);
1758 if(scalex != 1.0f) {
1759 newx= (itemx - minx)*scalex;
1760 itemw= (itemx - minx + itemw)*scalex - newx;
1764 if(scaley != 1.0f) {
1765 newy= (itemy - miny)*scaley;
1766 itemh= (itemy - miny + itemh)*scaley - newy;
1770 ui_item_position(item, x+itemx-minx, y+itemy-miny, itemw, itemh);
1773 litem->w= scalex*totw;
1774 litem->h= litem->y - y;
1775 litem->x= x + litem->w;
1780 static void ui_litem_estimate_split(uiLayout *litem)
1782 ui_litem_estimate_row(litem);
1785 static void ui_litem_layout_split(uiLayout *litem)
1787 uiLayoutItemSplt *split= (uiLayoutItemSplt*)litem;
1790 int itemh, x, y, w, tot=0, colw=0;
1795 for(item=litem->items.first; item; item=item->next)
1801 percentage= (split->percentage == 0.0f)? 1.0f/(float)tot: split->percentage;
1803 w= (litem->w - (tot-1)*litem->space);
1805 colw= MAX2(colw, 0);
1807 for(item=litem->items.first; item; item=item->next) {
1808 ui_item_size(item, NULL, &itemh);
1810 ui_item_position(item, x, y-itemh, colw, itemh);
1814 colw= (w - (int)(w*percentage))/(tot-1);
1815 colw= MAX2(colw, 0);
1821 litem->w= x - litem->x;
1822 litem->h= litem->y - y;
1827 /* layout create functions */
1828 uiLayout *uiLayoutRow(uiLayout *layout, int align)
1832 litem= MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
1833 litem->item.type= ITEM_LAYOUT_ROW;
1834 litem->root= layout->root;
1835 litem->align= align;
1838 litem->context= layout->context;
1839 litem->space= (align)? 0: layout->root->style->buttonspacex;
1840 BLI_addtail(&layout->items, litem);
1842 uiBlockSetCurLayout(layout->root->block, litem);
1847 uiLayout *uiLayoutColumn(uiLayout *layout, int align)
1851 litem= MEM_callocN(sizeof(uiLayout), "uiLayoutColumn");
1852 litem->item.type= ITEM_LAYOUT_COLUMN;
1853 litem->root= layout->root;
1854 litem->align= align;
1857 litem->context= layout->context;
1858 litem->space= (litem->align)? 0: layout->root->style->buttonspacey;
1859 BLI_addtail(&layout->items, litem);
1861 uiBlockSetCurLayout(layout->root->block, litem);
1866 uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align)
1868 uiLayoutItemFlow *flow;
1870 flow= MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow");
1871 flow->litem.item.type= ITEM_LAYOUT_COLUMN_FLOW;
1872 flow->litem.root= layout->root;
1873 flow->litem.align= align;
1874 flow->litem.active= 1;
1875 flow->litem.enabled= 1;
1876 flow->litem.context= layout->context;
1877 flow->litem.space= (flow->litem.align)? 0: layout->root->style->columnspace;
1878 flow->number= number;
1879 BLI_addtail(&layout->items, flow);
1881 uiBlockSetCurLayout(layout->root->block, &flow->litem);
1883 return &flow->litem;
1886 static uiLayout *ui_layout_box(uiLayout *layout, int type)
1888 uiLayoutItemBx *box;
1890 box= MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx");
1891 box->litem.item.type= ITEM_LAYOUT_BOX;
1892 box->litem.root= layout->root;
1893 box->litem.active= 1;
1894 box->litem.enabled= 1;
1895 box->litem.context= layout->context;
1896 box->litem.space= layout->root->style->columnspace;
1897 BLI_addtail(&layout->items, box);
1899 uiBlockSetCurLayout(layout->root->block, &box->litem);
1901 box->roundbox= uiDefBut(layout->root->block, type, 0, "", 0, 0, 0, 0, NULL, 0.0, 0.0, 0, 0, "");
1906 uiLayout *uiLayoutBox(uiLayout *layout)
1908 return ui_layout_box(layout, ROUNDBOX);
1911 uiLayout *uiLayoutListBox(uiLayout *layout)
1913 return ui_layout_box(layout, LISTBOX);
1916 ListBase *uiLayoutBoxGetList(uiLayout *layout)
1918 uiLayoutItemBx *box= (uiLayoutItemBx*)layout;
1922 uiLayout *uiLayoutFree(uiLayout *layout, int align)
1926 litem= MEM_callocN(sizeof(uiLayout), "uiLayoutFree");
1927 litem->item.type= ITEM_LAYOUT_FREE;
1928 litem->root= layout->root;
1929 litem->align= align;
1932 litem->context= layout->context;
1933 BLI_addtail(&layout->items, litem);
1935 uiBlockSetCurLayout(layout->root->block, litem);
1940 uiBlock *uiLayoutFreeBlock(uiLayout *layout)
1944 block= uiLayoutGetBlock(layout);
1945 uiLayoutFree(layout, 0);
1950 uiLayout *uiLayoutSplit(uiLayout *layout, float percentage)
1952 uiLayoutItemSplt *split;
1954 split= MEM_callocN(sizeof(uiLayoutItemSplt), "uiLayoutItemSplt");
1955 split->litem.item.type= ITEM_LAYOUT_SPLIT;
1956 split->litem.root= layout->root;
1957 split->litem.active= 1;
1958 split->litem.enabled= 1;
1959 split->litem.context= layout->context;
1960 split->litem.space= layout->root->style->columnspace;
1961 split->percentage= percentage;
1962 BLI_addtail(&layout->items, split);
1964 uiBlockSetCurLayout(layout->root->block, &split->litem);
1966 return &split->litem;
1969 void uiLayoutSetActive(uiLayout *layout, int active)
1971 layout->active= active;
1974 void uiLayoutSetEnabled(uiLayout *layout, int enabled)
1976 layout->enabled= enabled;
1979 void uiLayoutSetRedAlert(uiLayout *layout, int redalert)
1981 layout->redalert= redalert;
1984 void uiLayoutSetKeepAspect(uiLayout *layout, int keepaspect)
1986 layout->keepaspect= keepaspect;
1989 void uiLayoutSetAlignment(uiLayout *layout, int alignment)
1991 layout->alignment= alignment;
1994 void uiLayoutSetScaleX(uiLayout *layout, float scale)
1996 layout->scale[0]= scale;
1999 void uiLayoutSetScaleY(uiLayout *layout, float scale)
2001 layout->scale[1]= scale;
2004 int uiLayoutGetActive(uiLayout *layout)
2006 return layout->active;
2009 int uiLayoutGetEnabled(uiLayout *layout)
2011 return layout->enabled;
2014 int uiLayoutGetRedAlert(uiLayout *layout)
2016 return layout->redalert;
2019 int uiLayoutGetKeepAspect(uiLayout *layout)
2021 return layout->keepaspect;
2024 int uiLayoutGetAlignment(uiLayout *layout)
2026 return layout->alignment;
2029 int uiLayoutGetWidth(uiLayout *layout)
2034 float uiLayoutGetScaleX(uiLayout *layout)
2036 return layout->scale[0];
2039 float uiLayoutGetScaleY(uiLayout *layout)
2041 return layout->scale[0];
2044 /********************** Layout *******************/
2046 static void ui_item_scale(uiLayout *litem, float scale[2])
2051 for(item=litem->items.last; item; item=item->prev) {
2052 ui_item_size(item, &w, &h);
2053 ui_item_offset(item, &x, &y);
2055 if(scale[0] != 0.0f) {
2060 if(scale[1] != 0.0f) {
2065 ui_item_position(item, x, y, w, h);
2069 static void ui_item_estimate(uiItem *item)
2073 if(item->type != ITEM_BUTTON) {
2074 uiLayout *litem= (uiLayout*)item;
2076 for(subitem=litem->items.first; subitem; subitem=subitem->next)
2077 ui_item_estimate(subitem);
2079 if(litem->items.first == NULL)
2082 if(litem->scale[0] != 0.0f || litem->scale[1] != 0.0f)
2083 ui_item_scale(litem, litem->scale);
2085 switch(litem->item.type) {
2086 case ITEM_LAYOUT_COLUMN:
2087 ui_litem_estimate_column(litem);
2089 case ITEM_LAYOUT_COLUMN_FLOW:
2090 ui_litem_estimate_column_flow(litem);
2092 case ITEM_LAYOUT_ROW:
2093 ui_litem_estimate_row(litem);
2095 case ITEM_LAYOUT_BOX:
2096 ui_litem_estimate_box(litem);
2098 case ITEM_LAYOUT_ROOT:
2099 ui_litem_estimate_root(litem);
2101 case ITEM_LAYOUT_FREE:
2102 ui_litem_estimate_free(litem);
2104 case ITEM_LAYOUT_SPLIT:
2105 ui_litem_estimate_split(litem);
2113 static void ui_item_align(uiLayout *litem, int nr)
2116 uiButtonItem *bitem;
2117 uiLayoutItemBx *box;
2119 for(item=litem->items.last; item; item=item->prev) {
2120 if(item->type == ITEM_BUTTON) {
2121 bitem= (uiButtonItem*)item;
2122 if(ui_but_can_align(bitem->but))
2123 if(!bitem->but->alignnr)
2124 bitem->but->alignnr= nr;
2126 else if(item->type == ITEM_LAYOUT_FREE);
2127 else if(item->type == ITEM_LAYOUT_BOX) {
2128 box= (uiLayoutItemBx*)item;
2129 box->roundbox->alignnr= nr;
2130 BLI_remlink(&litem->root->block->buttons, box->roundbox);
2131 BLI_addhead(&litem->root->block->buttons, box->roundbox);
2134 ui_item_align((uiLayout*)item, nr);
2138 static void ui_item_flag(uiLayout *litem, int flag)
2141 uiButtonItem *bitem;
2143 for(item=litem->items.last; item; item=item->prev) {
2144 if(item->type == ITEM_BUTTON) {
2145 bitem= (uiButtonItem*)item;
2146 bitem->but->flag |= flag;
2149 ui_item_flag((uiLayout*)item, flag);
2153 static void ui_item_layout(uiItem *item)
2157 if(item->type != ITEM_BUTTON) {
2158 uiLayout *litem= (uiLayout*)item;
2160 if(litem->items.first == NULL)
2164 ui_item_align(litem, ++litem->root->block->alignnr);
2166 ui_item_flag(litem, UI_BUT_INACTIVE);
2168 ui_item_flag(litem, UI_BUT_DISABLED);
2170 switch(litem->item.type) {
2171 case ITEM_LAYOUT_COLUMN:
2172 ui_litem_layout_column(litem);
2174 case ITEM_LAYOUT_COLUMN_FLOW:
2175 ui_litem_layout_column_flow(litem);
2177 case ITEM_LAYOUT_ROW:
2178 ui_litem_layout_row(litem);
2180 case ITEM_LAYOUT_BOX:
2181 ui_litem_layout_box(litem);
2183 case ITEM_LAYOUT_ROOT:
2184 ui_litem_layout_root(litem);
2186 case ITEM_LAYOUT_FREE:
2187 ui_litem_layout_free(litem);
2189 case ITEM_LAYOUT_SPLIT:
2190 ui_litem_layout_split(litem);
2196 for(subitem=litem->items.first; subitem; subitem=subitem->next)
2197 ui_item_layout(subitem);
2201 static void ui_layout_items(const bContext *C, uiBlock *block, uiLayout *layout)
2203 ui_item_estimate(&layout->item);
2204 ui_item_layout(&layout->item);
2207 static void ui_layout_end(const bContext *C, uiBlock *block, uiLayout *layout, int *x, int *y)
2209 if(layout->root->handlefunc)
2210 uiBlockSetButmFunc(block, layout->root->handlefunc, layout->root->argv);
2212 ui_layout_items(C, block, layout);
2214 if(x) *x= layout->x;
2215 if(y) *y= layout->y;
2218 static void ui_layout_free(uiLayout *layout)
2220 uiItem *item, *next;
2222 for(item=layout->items.first; item; item=next) {
2225 if(item->type == ITEM_BUTTON)
2228 ui_layout_free((uiLayout*)item);
2231 if(layout->item.type == ITEM_LAYOUT_BOX)
2232 BLI_freelistN(&((uiLayoutItemBx*)layout)->items);
2237 uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int size, int em, uiStyle *style)
2242 root= MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot");
2246 root->opcontext= WM_OP_INVOKE_REGION_WIN;
2248 layout= MEM_callocN(sizeof(uiLayout), "uiLayout");
2249 layout->item.type= ITEM_LAYOUT_ROOT;
2254 layout->space= style->templatespace;
2257 layout->context= NULL;
2259 if(type == UI_LAYOUT_MENU)
2262 if(dir == UI_LAYOUT_HORIZONTAL) {
2264 layout->root->emh= em*UI_UNIT_Y;
2268 layout->root->emw= em*UI_UNIT_X;
2271 block->curlayout= layout;
2272 root->layout= layout;
2273 BLI_addtail(&block->layouts, root);
2278 uiBlock *uiLayoutGetBlock(uiLayout *layout)
2280 return layout->root->block;
2283 int uiLayoutGetOperatorContext(uiLayout *layout)
2285 return layout->root->opcontext;
2289 void uiBlockSetCurLayout(uiBlock *block, uiLayout *layout)
2291 block->curlayout= layout;
2294 void ui_layout_add_but(uiLayout *layout, uiBut *but)
2296 uiButtonItem *bitem;
2298 bitem= MEM_callocN(sizeof(uiButtonItem), "uiButtonItem");
2299 bitem->item.type= ITEM_BUTTON;
2301 BLI_addtail(&layout->items, bitem);
2303 if(layout->context) {
2304 but->context= layout->context;
2305 but->context->used= 1;
2309 void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
2311 layout->root->opcontext= opcontext;
2314 void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
2316 layout->root->handlefunc= handlefunc;
2317 layout->root->argv= argv;
2320 void uiBlockLayoutResolve(const bContext *C, uiBlock *block, int *x, int *y)
2327 block->curlayout= NULL;
2329 for(root=block->layouts.first; root; root=root->next) {
2330 /* NULL in advance so we don't interfere when adding button */
2331 ui_layout_end(C, block, root->layout, x, y);
2332 ui_layout_free(root->layout);
2335 BLI_freelistN(&block->layouts);
2337 /* XXX silly trick, interface_templates.c doesn't get linked
2338 * because it's not used by other files in this module? */
2340 void ui_template_fix_linking();
2341 ui_template_fix_linking();
2345 void uiLayoutSetContextPointer(uiLayout *layout, char *name, PointerRNA *ptr)
2347 uiBlock *block= layout->root->block;
2348 layout->context= CTX_store_add(&block->contexts, name, ptr);