/** * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Contributor(s): Blender Foundation 2009. * * ***** END GPL LICENSE BLOCK ***** */ #include #include #include #include #include "MEM_guardedalloc.h" #include "DNA_ID.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" #include "BLI_listbase.h" #include "BLI_string.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_screen.h" #include "BKE_utildefines.h" #include "RNA_access.h" #include "UI_interface.h" #include "UI_resources.h" #include "UI_view2d.h" #include "ED_util.h" #include "ED_types.h" #include "ED_screen.h" #include "WM_api.h" #include "WM_types.h" #include "interface_intern.h" /************************ Structs and Defines *************************/ #define RNA_NO_INDEX -1 #define RNA_ENUM_VALUE -2 #define EM_SEPR_X 6 #define EM_SEPR_Y 6 /* uiLayoutRoot */ typedef struct uiLayoutRoot { struct uiLayoutRoot *next, *prev; int type; int opcontext; int emw, emh; uiMenuHandleFunc handlefunc; void *argv; uiStyle *style; uiBlock *block; uiLayout *layout; } uiLayoutRoot; /* Item */ typedef enum uiItemType { ITEM_BUTTON, ITEM_LAYOUT_ROW, ITEM_LAYOUT_COLUMN, ITEM_LAYOUT_COLUMN_FLOW, ITEM_LAYOUT_ROW_FLOW, ITEM_LAYOUT_BOX, ITEM_LAYOUT_FREE, ITEM_LAYOUT_SPLIT, ITEM_LAYOUT_ROOT #if 0 TEMPLATE_COLUMN_FLOW, TEMPLATE_SPLIT, TEMPLATE_BOX, TEMPLATE_HEADER, TEMPLATE_HEADER_ID #endif } uiItemType; typedef struct uiItem { void *next, *prev; uiItemType type; int flag; } uiItem; typedef struct uiButtonItem { uiItem item; uiBut *but; } uiButtonItem; struct uiLayout { uiItem item; uiLayoutRoot *root; bContextStore *context; ListBase items; int x, y, w, h; float scale[2]; short space; char align; char active; char enabled; char redalert; char keepaspect; char alignment; }; typedef struct uiLayoutItemFlow { uiLayout litem; int number; int totcol; } uiLayoutItemFlow; typedef struct uiLayoutItemBx { uiLayout litem; uiBut *roundbox; } uiLayoutItemBx; typedef struct uiLayoutItemSplt { uiLayout litem; float percentage; } uiLayoutItemSplt; typedef struct uiLayoutItemRoot { uiLayout litem; } uiLayoutItemRoot; /************************** Item ***************************/ static char *ui_item_name_add_colon(char *name, char namestr[UI_MAX_NAME_STR]) { int len= strlen(name); if(len != 0 && len+1 < UI_MAX_NAME_STR) { BLI_strncpy(namestr, name, UI_MAX_NAME_STR); namestr[len]= ':'; namestr[len+1]= '\0'; return namestr; } return name; } static int ui_item_fit(int item, int pos, int all, int available, int last, int alignment, int *offset) { /* available == 0 is unlimited */ if(available == 0) return item; if(offset) *offset= 0; if(all > available) { /* contents is bigger than available space */ if(last) return available-pos; else return (item*available)/all; } else { /* contents is smaller or equal to available space */ if(alignment == UI_LAYOUT_ALIGN_EXPAND) { if(last) return available-pos; else return (item*available)/all; } else return item; } } /* variable button size in which direction? */ #define UI_ITEM_VARY_X 1 #define UI_ITEM_VARY_Y 2 static int ui_layout_vary_direction(uiLayout *layout) { return (layout->root->type == UI_LAYOUT_HEADER || layout->alignment != UI_LAYOUT_ALIGN_EXPAND)? UI_ITEM_VARY_X: UI_ITEM_VARY_Y; } /* estimated size of text + icon */ static int ui_text_icon_width(uiLayout *layout, char *name, int icon) { int variable = ui_layout_vary_direction(layout) == UI_ITEM_VARY_X; if(icon && strcmp(name, "") == 0) return UI_UNIT_X; /* icon only */ else if(icon) return (variable)? UI_GetStringWidth(name) + 4 + UI_UNIT_X: 10*UI_UNIT_X; /* icon + text */ else return (variable)? UI_GetStringWidth(name) + 4 + UI_UNIT_X: 10*UI_UNIT_X; /* text only */ } static void ui_item_size(uiItem *item, int *r_w, int *r_h) { if(item->type == ITEM_BUTTON) { uiButtonItem *bitem= (uiButtonItem*)item; if(r_w) *r_w= bitem->but->x2 - bitem->but->x1; if(r_h) *r_h= bitem->but->y2 - bitem->but->y1; } else { uiLayout *litem= (uiLayout*)item; if(r_w) *r_w= litem->w; if(r_h) *r_h= litem->h; } } static void ui_item_offset(uiItem *item, int *r_x, int *r_y) { if(item->type == ITEM_BUTTON) { uiButtonItem *bitem= (uiButtonItem*)item; if(r_x) *r_x= bitem->but->x1; if(r_y) *r_y= bitem->but->y1; } else { if(r_x) *r_x= 0; if(r_y) *r_y= 0; } } static void ui_item_position(uiItem *item, int x, int y, int w, int h) { if(item->type == ITEM_BUTTON) { uiButtonItem *bitem= (uiButtonItem*)item; bitem->but->x1= x; bitem->but->y1= y; bitem->but->x2= x+w; bitem->but->y2= y+h; ui_check_but(bitem->but); /* for strlen */ } else { uiLayout *litem= (uiLayout*)item; litem->x= x; litem->y= y+h; litem->w= w; litem->h= h; } } /******************** Special RNA Items *********************/ static int ui_layout_local_dir(uiLayout *layout) { switch(layout->item.type) { case ITEM_LAYOUT_ROW: case ITEM_LAYOUT_ROOT: return UI_LAYOUT_HORIZONTAL; case ITEM_LAYOUT_COLUMN: case ITEM_LAYOUT_COLUMN_FLOW: case ITEM_LAYOUT_SPLIT: case ITEM_LAYOUT_FREE: case ITEM_LAYOUT_BOX: default: return UI_LAYOUT_VERTICAL; } } static uiLayout *ui_item_local_sublayout(uiLayout *test, uiLayout *layout, int align) { uiLayout *sub; if(ui_layout_local_dir(test) == UI_LAYOUT_HORIZONTAL) sub= uiLayoutRow(layout, align); else sub= uiLayoutColumn(layout, align); sub->space= 0; return sub; } /* create buttons for an item with an RNA array */ 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) { uiStyle *style= layout->root->style; uiBut *but; PropertyType type; PropertySubType subtype; uiLayout *sub; int a; /* retrieve type and subtype */ type= RNA_property_type(prop); subtype= RNA_property_subtype(prop); sub= ui_item_local_sublayout(layout, layout, 1); uiBlockSetCurLayout(block, sub); /* create label */ if(strcmp(name, "") != 0) uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); /* create buttons */ if(type == PROP_BOOLEAN && len == 20) { /* special check for layer layout */ int butw, buth, unit; uiBlockSetCurLayout(block, uiLayoutFree(layout, 0)); unit= UI_UNIT_X*0.75; butw= unit; buth= unit; uiBlockBeginAlign(block); for(a=0; a<5; a++) uiDefAutoButR(block, ptr, prop, a, "", ICON_BLANK1, x + butw*a, y+buth, butw, buth); for(a=0; a<5; a++) uiDefAutoButR(block, ptr, prop, a+10, "", ICON_BLANK1, x + butw*a, y, butw, buth); uiBlockEndAlign(block); x += 5*butw + style->buttonspacex; uiBlockBeginAlign(block); for(a=0; a<5; a++) uiDefAutoButR(block, ptr, prop, a+5, "", ICON_BLANK1, x + butw*a, y+buth, butw, buth); for(a=0; a<5; a++) uiDefAutoButR(block, ptr, prop, a+15, "", ICON_BLANK1, x + butw*a, y, butw, buth); uiBlockEndAlign(block); } else if(subtype == PROP_MATRIX) { /* matrix layout */ int row, col; uiBlockSetCurLayout(block, uiLayoutFree(layout, 1)); len= ceil(sqrt(len)); h /= len; w /= len; // XXX test for(a=0; atype==NUM) but->type= NUMSLI; } } else if(len <= 4 && ELEM3(subtype, PROP_ROTATION, PROP_VECTOR, PROP_COLOR)) { if(subtype == PROP_COLOR) uiDefAutoButR(block, ptr, prop, -1, "", 0, 0, 0, w, UI_UNIT_Y); if(subtype != PROP_COLOR || expand) { /* layout for known array subtypes */ static char vectoritem[4]= {'X', 'Y', 'Z', 'W'}; static char quatitem[4]= {'W', 'X', 'Y', 'Z'}; static char coloritem[4]= {'R', 'G', 'B', 'A'}; char str[3]; for(a=0; atype==NUM) but->type= NUMSLI; } } else if(subtype == PROP_COLOR && len == 4) { but= uiDefAutoButR(block, ptr, prop, 3, "A:", 0, 0, 0, w, UI_UNIT_Y); if(slider && but->type==NUM) but->type= NUMSLI; } } else { for(a=0; atype==NUM) but->type= NUMSLI; } } uiBlockSetCurLayout(block, layout); } static void ui_item_enum_row(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int x, int y, int w, int h) { const EnumPropertyItem *item; int a, totitem, itemw; const char *propname; propname= RNA_property_identifier(prop); RNA_property_enum_items(ptr, prop, &item, &totitem); uiBlockSetCurLayout(block, ui_item_local_sublayout(layout, layout, 1)); for(a=0; acurlayout, (char*)item[a].name, 0); uiDefButR(block, ROW, 0, NULL, 0, 0, itemw, h, ptr, propname, -1, 0, item[a].value, -1, -1, NULL); } uiBlockSetCurLayout(block, layout); } /* create label + button for RNA property */ static void 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) { uiLayout *sub; PropertySubType subtype; sub= uiLayoutRow(layout, 0); uiBlockSetCurLayout(block, sub); if(strcmp(name, "") != 0) { w= w/2; uiDefBut(block, LABEL, 0, name, x, y, w, h, NULL, 0.0, 0.0, 0, 0, ""); } subtype= RNA_property_subtype(prop); if(subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) { uiBlockSetCurLayout(block, uiLayoutRow(sub, 1)); uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, w-UI_UNIT_X, h); uiDefIconBut(block, BUT, 0, ICON_FILESEL, x, y, UI_UNIT_X, h, NULL, 0.0f, 0.0f, 0.0f, 0.0f, "DUMMY file select button"); /* XXX */ } else uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, w, h); uiBlockSetCurLayout(block, layout); } /********************* Button Items *************************/ /* disabled item */ static void ui_item_disabled(uiLayout *layout, char *name) { uiBlock *block= layout->root->block; uiBut *but; int w; uiBlockSetCurLayout(block, layout); if(!name) name= ""; w= ui_text_icon_width(layout, name, 0); but= uiDefBut(block, LABEL, 0, (char*)name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); but->flag |= UI_BUT_DISABLED; but->lock = 1; but->lockstr = ""; } /* operator items */ void uiItemFullO(uiLayout *layout, char *name, int icon, char *idname, IDProperty *properties, int context) { uiBlock *block= layout->root->block; wmOperatorType *ot= WM_operatortype_find(idname); uiBut *but; int w; if(!ot) { ui_item_disabled(layout, idname); return; } if(!name) name= ot->name; if(layout->root->type == UI_LAYOUT_MENU && !icon) icon= ICON_BLANK1; /* create button */ uiBlockSetCurLayout(block, layout); w= ui_text_icon_width(layout, name, icon); if(icon && strcmp(name, "") != 0) but= uiDefIconTextButO(block, BUT, ot->idname, context, icon, (char*)name, 0, 0, w, UI_UNIT_Y, NULL); else if(icon) but= uiDefIconButO(block, BUT, ot->idname, context, icon, 0, 0, w, UI_UNIT_Y, NULL); else but= uiDefButO(block, BUT, ot->idname, context, (char*)name, 0, 0, w, UI_UNIT_Y, NULL); /* assign properties */ if(properties) { PointerRNA *opptr= uiButGetOperatorPtrRNA(but); opptr->data= properties; } } static char *ui_menu_enumpropname(char *opname, char *propname, int retval) { wmOperatorType *ot= WM_operatortype_find(opname); PointerRNA ptr; PropertyRNA *prop; if(!ot || !ot->srna) return ""; RNA_pointer_create(NULL, ot->srna, NULL, &ptr); prop= RNA_struct_find_property(&ptr, propname); if(prop) { const EnumPropertyItem *item; int totitem, i; RNA_property_enum_items(&ptr, prop, &item, &totitem); for (i=0; iroot->opcontext); } void uiItemsEnumO(uiLayout *layout, char *opname, char *propname) { wmOperatorType *ot= WM_operatortype_find(opname); PointerRNA ptr; PropertyRNA *prop; if(!ot || !ot->srna) { ui_item_disabled(layout, opname); return; } RNA_pointer_create(NULL, ot->srna, NULL, &ptr); prop= RNA_struct_find_property(&ptr, propname); if(prop && RNA_property_type(prop) == PROP_ENUM) { const EnumPropertyItem *item; int totitem, i; RNA_property_enum_items(&ptr, prop, &item, &totitem); for(i=0; iroot->opcontext); } void uiItemBooleanO(uiLayout *layout, char *name, int icon, char *opname, char *propname, int value) { PointerRNA ptr; WM_operator_properties_create(&ptr, opname); RNA_boolean_set(&ptr, propname, value); uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext); } void uiItemIntO(uiLayout *layout, char *name, int icon, char *opname, char *propname, int value) { PointerRNA ptr; WM_operator_properties_create(&ptr, opname); RNA_int_set(&ptr, propname, value); uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext); } void uiItemFloatO(uiLayout *layout, char *name, int icon, char *opname, char *propname, float value) { PointerRNA ptr; WM_operator_properties_create(&ptr, opname); RNA_float_set(&ptr, propname, value); uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext); } void uiItemStringO(uiLayout *layout, char *name, int icon, char *opname, char *propname, char *value) { PointerRNA ptr; WM_operator_properties_create(&ptr, opname); RNA_string_set(&ptr, propname, value); uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext); } void uiItemO(uiLayout *layout, char *name, int icon, char *opname) { uiItemFullO(layout, name, icon, opname, NULL, layout->root->opcontext); } /* RNA property items */ static void ui_item_rna_size(uiLayout *layout, char *name, int icon, PropertyRNA *prop, int index, int *r_w, int *r_h) { PropertyType type; PropertySubType subtype; int len, w, h; w= ui_text_icon_width(layout, name, icon); h= UI_UNIT_Y; /* arbitrary extended width by type */ type= RNA_property_type(prop); subtype= RNA_property_subtype(prop); len= RNA_property_array_length(prop); /* increase height for arrays */ if(index == RNA_NO_INDEX && len > 0) { if(strcmp(name, "") == 0 && icon == 0) h= 0; if(type == PROP_BOOLEAN && len == 20) h += 2*UI_UNIT_Y; else if(subtype == PROP_MATRIX) h += ceil(sqrt(len))*UI_UNIT_Y; else h += len*UI_UNIT_Y; } else if(ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) { if(type == PROP_BOOLEAN && strcmp(name, "") != 0) w += UI_UNIT_X; } *r_w= w; *r_h= h; } void uiItemFullR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int value, int expand, int slider, int toggle) { uiBlock *block= layout->root->block; uiBut *but; PropertyType type; char namestr[UI_MAX_NAME_STR]; int len, w, h; if(!ptr->data || !prop) return; uiBlockSetCurLayout(block, layout); /* retrieve info */ type= RNA_property_type(prop); len= RNA_property_array_length(prop); /* set name and icon */ if(!name) name= (char*)RNA_property_ui_name(prop); if(ELEM5(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_ENUM, PROP_POINTER)) name= ui_item_name_add_colon(name, namestr); if(type == PROP_BOOLEAN && len) name= ui_item_name_add_colon(name, namestr); if(layout->root->type == UI_LAYOUT_MENU) { if(type == PROP_BOOLEAN) icon= (RNA_property_boolean_get(ptr, prop))? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT; else if(type == PROP_ENUM && index == RNA_ENUM_VALUE) icon= (RNA_property_enum_get(ptr, prop) == value)? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT; } /* get size */ ui_item_rna_size(layout, name, icon, prop, index, &w, &h); /* array property */ if(index == RNA_NO_INDEX && len > 0) ui_item_array(layout, block, name, icon, ptr, prop, len, 0, 0, w, h, expand, slider); /* enum item */ else if(type == PROP_ENUM && index == RNA_ENUM_VALUE) { char *identifier= (char*)RNA_property_identifier(prop); if(icon && strcmp(name, "") != 0) uiDefIconTextButR(block, ROW, 0, icon, name, 0, 0, w, h, ptr, identifier, -1, 0, value, -1, -1, NULL); else if(icon) uiDefIconButR(block, ROW, 0, icon, 0, 0, w, h, ptr, identifier, -1, 0, value, -1, -1, NULL); else uiDefButR(block, ROW, 0, name, 0, 0, w, h, ptr, identifier, -1, 0, value, -1, -1, NULL); } /* expanded enum */ else if(type == PROP_ENUM && expand) ui_item_enum_row(layout, block, ptr, prop, 0, 0, w, h); /* property with separate label */ else if(type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h); /* single button */ else { but= uiDefAutoButR(block, ptr, prop, index, (char*)name, icon, 0, 0, w, h); if(slider && but->type==NUM) but->type= NUMSLI; if(toggle && but->type==OPTION) but->type= TOG; } } void uiItemR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, char *propname, int expand, int slider, int toggle) { PropertyRNA *prop; if(!ptr->data || !propname) return; prop= RNA_struct_find_property(ptr, propname); if(!prop) { ui_item_disabled(layout, propname); printf("uiItemR: property not found: %s\n", propname); return; } uiItemFullR(layout, name, icon, ptr, prop, RNA_NO_INDEX, 0, expand, slider, toggle); } void uiItemEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, int value) { PropertyRNA *prop; if(!ptr->data || !propname) return; prop= RNA_struct_find_property(ptr, propname); if(!prop) { ui_item_disabled(layout, propname); printf("uiItemEnumR: property not found: %s\n", propname); return; } uiItemFullR(layout, name, icon, ptr, prop, RNA_ENUM_VALUE, value, 0, 0, 0); } void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, char *propname) { PropertyRNA *prop; prop= RNA_struct_find_property(ptr, propname); if(!prop) { ui_item_disabled(layout, propname); return; } if(RNA_property_type(prop) == PROP_ENUM) { const EnumPropertyItem *item; int totitem, i; RNA_property_enum_items(ptr, prop, &item, &totitem); for(i=0; idraw(C, &menu); } static void ui_item_menu(uiLayout *layout, char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN) { uiBlock *block= layout->root->block; uiBut *but; int w, h; uiBlockSetCurLayout(block, layout); if(layout->root->type == UI_LAYOUT_HEADER) uiBlockSetEmboss(block, UI_EMBOSSP); if(!name) name= ""; if(layout->root->type == UI_LAYOUT_MENU && !icon) icon= ICON_BLANK1; w= ui_text_icon_width(layout, name, icon); h= UI_UNIT_Y; if(layout->root->type == UI_LAYOUT_HEADER) /* ugly .. */ w -= 3; if(icon) but= uiDefIconTextMenuBut(block, func, arg, icon, (char*)name, 0, 0, w, h, ""); else but= uiDefMenuBut(block, func, arg, (char*)name, 0, 0, w, h, ""); if(argN) { /* ugly .. */ but->poin= (char*)but; but->func_argN= argN; } if(layout->root->type == UI_LAYOUT_HEADER) uiBlockSetEmboss(block, UI_EMBOSS); else if(layout->root->type == UI_LAYOUT_PANEL) but->type= MENU; } void uiItemM(uiLayout *layout, bContext *C, char *name, int icon, char *menuname) { ARegion *ar= CTX_wm_region(C); MenuType *mt; if(!menuname) return; for(mt=ar->type->menutypes.first; mt; mt=mt->next) { if(strcmp(menuname, mt->idname) == 0) { if(!name) name= mt->label; if(layout->root->type == UI_LAYOUT_MENU && !icon) icon= ICON_BLANK1; ui_item_menu(layout, name, icon, ui_item_menutype_func, mt, NULL); break; } } } /* label item */ void uiItemL(uiLayout *layout, char *name, int icon) { uiBlock *block= layout->root->block; uiBut *but; int w; uiBlockSetCurLayout(block, layout); if(!name) name= ""; if(layout->root->type == UI_LAYOUT_MENU && !icon) icon= ICON_BLANK1; w= ui_text_icon_width(layout, name, icon); if(icon && strcmp(name, "") != 0) but= uiDefIconTextBut(block, LABEL, 0, icon, (char*)name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); else if(icon) but= uiDefIconBut(block, LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); else but= uiDefBut(block, LABEL, 0, (char*)name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); } /* value item */ void uiItemV(uiLayout *layout, char *name, int icon, int argval) { /* label */ uiBlock *block= layout->root->block; float *retvalue= (block->handle)? &block->handle->retvalue: NULL; int w; uiBlockSetCurLayout(block, layout); if(!name) name= ""; if(layout->root->type == UI_LAYOUT_MENU && !icon) icon= ICON_BLANK1; w= ui_text_icon_width(layout, name, icon); if(icon && strcmp(name, "") != 0) uiDefIconTextButF(block, BUTM, 0, icon, (char*)name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, ""); else if(icon) uiDefIconButF(block, BUTM, 0, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, ""); else uiDefButF(block, BUTM, 0, (char*)name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, ""); } /* separator item */ void uiItemS(uiLayout *layout) { uiBlock *block= layout->root->block; uiBlockSetCurLayout(block, layout); uiDefBut(block, SEPR, 0, "", 0, 0, EM_SEPR_X, EM_SEPR_Y, NULL, 0.0, 0.0, 0, 0, ""); } /* level items */ void uiItemMenuF(uiLayout *layout, char *name, int icon, uiMenuCreateFunc func) { if(!func) return; ui_item_menu(layout, name, icon, func, NULL, NULL); } typedef struct MenuItemLevel { int opcontext; char *opname; char *propname; PointerRNA rnapoin; } MenuItemLevel; static void menu_item_enum_opname_menu(bContext *C, uiLayout *layout, void *arg) { MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN); uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN); uiItemsEnumO(layout, lvl->opname, lvl->propname); } void uiItemMenuEnumO(uiLayout *layout, char *name, int icon, char *opname, char *propname) { wmOperatorType *ot= WM_operatortype_find(opname); MenuItemLevel *lvl; if(!ot || !ot->srna) { ui_item_disabled(layout, opname); return; } if(!name) name= ot->name; if(layout->root->type == UI_LAYOUT_MENU && !icon) icon= ICON_BLANK1; lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel"); lvl->opname= opname; lvl->propname= propname; lvl->opcontext= layout->root->opcontext; ui_item_menu(layout, name, icon, menu_item_enum_opname_menu, NULL, lvl); } static void menu_item_enum_rna_menu(bContext *C, uiLayout *layout, void *arg) { MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN); uiLayoutSetOperatorContext(layout, lvl->opcontext); uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname); } void uiItemMenuEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname) { MenuItemLevel *lvl; PropertyRNA *prop; prop= RNA_struct_find_property(ptr, propname); if(!prop) { ui_item_disabled(layout, propname); return; } if(!name) name= (char*)RNA_property_ui_name(prop); if(layout->root->type == UI_LAYOUT_MENU && !icon) icon= ICON_BLANK1; lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel"); lvl->rnapoin= *ptr; lvl->propname= propname; lvl->opcontext= layout->root->opcontext; ui_item_menu(layout, name, icon, menu_item_enum_rna_menu, NULL, lvl); } /**************************** Layout Items ***************************/ /* single-row layout */ static void ui_litem_estimate_row(uiLayout *litem) { uiItem *item; int itemw, itemh; litem->w= 0; litem->h= 0; for(item=litem->items.first; item; item=item->next) { ui_item_size(item, &itemw, &itemh); litem->w += itemw; litem->h= MAX2(itemh, litem->h); if(item->next) litem->w += litem->space; } } static int ui_litem_min_width(int itemw) { return MIN2(UI_UNIT_X, itemw); } static void ui_litem_layout_row(uiLayout *litem) { uiItem *item; int x, y, w, tot, totw, neww, itemw, minw, itemh, offset; int fixedw, freew, fixedx, freex, flag= 0, lastw= 0; x= litem->x; y= litem->y; w= litem->w; totw= 0; tot= 0; for(item=litem->items.first; item; item=item->next) { ui_item_size(item, &itemw, &itemh); totw += itemw; tot++; } if(totw == 0) return; if(w != 0) w -= (tot-1)*litem->space; fixedw= 0; /* keep clamping items to fixed minimum size until all are done */ do { freew= 0; x= 0; flag= 0; for(item=litem->items.first; item; item=item->next) { if(item->flag) continue; ui_item_size(item, &itemw, &itemh); minw= ui_litem_min_width(itemw); if(w - lastw > 0) neww= ui_item_fit(itemw, x, totw, w-lastw, !item->next, litem->alignment, NULL); else neww= 0; /* no space left, all will need clamping to minimum size */ x += neww; if((neww < minw || itemw == minw) && w != 0) { /* fixed size */ item->flag= 1; fixedw += minw; flag= 1; totw -= itemw; } else { /* keep free size */ item->flag= 0; freew += itemw; } } lastw= fixedw; } while(flag); freex= 0; fixedx= 0; x= litem->x; for(item=litem->items.first; item; item=item->next) { ui_item_size(item, &itemw, &itemh); minw= ui_litem_min_width(itemw); if(item->flag) { /* fixed minimum size items */ itemw= ui_item_fit(minw, fixedx, fixedw, MIN2(w, fixedw), !item->next, litem->alignment, NULL); fixedx += itemw; } else { /* free size item */ itemw= ui_item_fit(itemw, freex, freew, w-fixedw, !item->next, litem->alignment, NULL); freex += itemw; } /* align right/center */ offset= 0; if(litem->alignment == UI_LAYOUT_ALIGN_RIGHT) { if(fixedw == 0 && freew < w-fixedw) offset= (w - fixedw) - freew; } else if(litem->alignment == UI_LAYOUT_ALIGN_CENTER) { if(fixedw == 0 && freew < w-fixedw) offset= ((w - fixedw) - freew)/2; } /* position item */ ui_item_position(item, x+offset, y-itemh, itemw, itemh); x += itemw; if(item->next) x += litem->space; } litem->w= x - litem->x; litem->h= litem->y - y; litem->x= x; litem->y= y; } /* single-column layout */ static void ui_litem_estimate_column(uiLayout *litem) { uiItem *item; int itemw, itemh; litem->w= 0; litem->h= 0; for(item=litem->items.first; item; item=item->next) { ui_item_size(item, &itemw, &itemh); litem->w= MAX2(litem->w, itemw); litem->h += itemh; if(item->next) litem->h += litem->space; } } static void ui_litem_layout_column(uiLayout *litem) { uiItem *item; int itemh, x, y; x= litem->x; y= litem->y; for(item=litem->items.first; item; item=item->next) { ui_item_size(item, NULL, &itemh); y -= itemh; ui_item_position(item, x, y, litem->w, itemh); if(item->next) y -= litem->space; } litem->h= litem->y - y; litem->x= x; litem->y= y; } /* root layout */ static void ui_litem_estimate_root(uiLayout *litem) { /* nothing to do */ } static void ui_litem_layout_root(uiLayout *litem) { if(litem->root->type == UI_LAYOUT_HEADER) ui_litem_layout_row(litem); else ui_litem_layout_column(litem); } /* box layout */ static void ui_litem_estimate_box(uiLayout *litem) { uiStyle *style= litem->root->style; ui_litem_estimate_column(litem); litem->w += 2*style->boxspace; litem->h += style->boxspace; } static void ui_litem_layout_box(uiLayout *litem) { uiLayoutItemBx *box= (uiLayoutItemBx*)litem; uiStyle *style= litem->root->style; uiBut *but; int w, h; w= litem->w; h= litem->h; litem->x += style->boxspace; litem->y -= style->boxspace; if(w != 0) litem->w -= 2*style->boxspace; if(h != 0) litem->h -= 2*style->boxspace; ui_litem_layout_column(litem); litem->x -= style->boxspace; litem->y -= style->boxspace; if(w != 0) litem->w += 2*style->boxspace; if(h != 0) litem->h += style->boxspace; /* roundbox around the sublayout */ but= box->roundbox; but->x1= litem->x; but->y1= litem->y; but->x2= litem->x+litem->w; but->y2= litem->y+litem->h; } /* multi-column layout, automatically flowing to the next */ static void ui_litem_estimate_column_flow(uiLayout *litem) { uiStyle *style= litem->root->style; uiLayoutItemFlow *flow= (uiLayoutItemFlow*)litem; uiItem *item; int col, x, y, emh, emy, miny, itemw, itemh, maxw=0; int toth, totitem; /* compute max needed width and total height */ toth= 0; totitem= 0; for(item=litem->items.first; item; item=item->next) { ui_item_size(item, &itemw, &itemh); maxw= MAX2(maxw, itemw); toth += itemh; totitem++; } if(flow->number <= 0) { /* auto compute number of columns, not very good */ if(maxw == 0) { flow->totcol= 1; return; } flow->totcol= MAX2(litem->root->emw/maxw, 1); flow->totcol= MIN2(flow->totcol, totitem); } else flow->totcol= flow->number; /* compute sizes */ x= 0; y= 0; emy= 0; miny= 0; maxw= 0; emh= toth/flow->totcol; /* create column per column */ col= 0; for(item=litem->items.first; item; item=item->next) { ui_item_size(item, &itemw, &itemh); y -= itemh + style->buttonspacey; miny= MIN2(miny, y); emy -= itemh; maxw= MAX2(itemw, maxw); /* decide to go to next one */ if(col < flow->totcol-1 && emy <= -emh) { x += maxw + litem->space; maxw= 0; y= 0; col++; } } litem->h= litem->y - miny; } static void ui_litem_layout_column_flow(uiLayout *litem) { uiStyle *style= litem->root->style; uiLayoutItemFlow *flow= (uiLayoutItemFlow*)litem; uiItem *item; int col, x, y, w, emh, emy, miny, itemw, itemh; int toth, totitem, offset; /* compute max needed width and total height */ toth= 0; totitem= 0; for(item=litem->items.first; item; item=item->next) { ui_item_size(item, &itemw, &itemh); toth += itemh; totitem++; } /* compute sizes */ x= litem->x; y= litem->y; emy= 0; miny= 0; w= litem->w - (flow->totcol-1)*style->columnspace; emh= toth/flow->totcol; /* create column per column */ col= 0; for(item=litem->items.first; item; item=item->next) { ui_item_size(item, NULL, &itemh); itemw= ui_item_fit(1, x-litem->x, flow->totcol, w, col == flow->totcol-1, litem->alignment, &offset); y -= itemh; emy -= itemh; ui_item_position(item, x+offset, y, itemw, itemh); y -= style->buttonspacey; miny= MIN2(miny, y); /* decide to go to next one */ if(col < flow->totcol-1 && emy <= -emh) { x += itemw + style->columnspace; y= litem->y; col++; } } litem->h= litem->y - miny; litem->x= x; litem->y= miny; } /* free layout */ static void ui_litem_estimate_free(uiLayout *litem) { uiItem *item; int itemx, itemy, itemw, itemh, minx, miny; minx= 1e6; miny= 1e6; litem->w= 0; litem->h= 0; for(item=litem->items.first; item; item=item->next) { ui_item_offset(item, &itemx, &itemy); ui_item_size(item, &itemw, &itemh); minx= MIN2(minx, itemx); miny= MIN2(miny, itemy); litem->w= MAX2(litem->w, itemx+itemw); litem->h= MAX2(litem->h, itemy+itemh); } litem->w -= minx; litem->h -= miny; } static void ui_litem_layout_free(uiLayout *litem) { uiItem *item; float scalex=1.0f, scaley=1.0f; int x, y, newx, newy, itemx, itemy, itemh, itemw, minx, miny, totw, toth; minx= 1e6; miny= 1e6; totw= 0; toth= 0; for(item=litem->items.first; item; item=item->next) { ui_item_offset(item, &itemx, &itemy); ui_item_size(item, &itemw, &itemh); minx= MIN2(minx, itemx); miny= MIN2(miny, itemy); totw= MAX2(totw, itemx+itemw); toth= MAX2(toth, itemy+itemh); } totw -= minx; toth -= miny; if(litem->w && totw > litem->w) scalex= (float)litem->w/(float)totw; if(litem->h && toth > litem->h) scaley= (float)litem->h/(float)toth; x= litem->x; y= litem->y - scaley*toth; for(item=litem->items.first; item; item=item->next) { ui_item_offset(item, &itemx, &itemy); ui_item_size(item, &itemw, &itemh); if(scalex != 1.0f) { newx= itemx*scalex; itemw= (itemx + itemw)*scalex - newx; itemx= newx; } if(scaley != 1.0f) { newy= itemy*scaley; itemh= (itemy + itemh)*scaley - newy; itemy= newy; } ui_item_position(item, x+itemx-minx, y+itemy-miny, itemw, itemh); } litem->w= scalex*totw; litem->h= litem->y - y; litem->x= x + litem->w; litem->y= y; } /* split layout */ static void ui_litem_estimate_split(uiLayout *litem) { ui_litem_estimate_row(litem); } static void ui_litem_layout_split(uiLayout *litem) { uiLayoutItemSplt *split= (uiLayoutItemSplt*)litem; uiItem *item; int itemh, x, y, w, tot=0, colw=0; x= litem->x; y= litem->y; for(item=litem->items.first; item; item=item->next) tot++; if(tot == 0) return; w= (litem->w - (tot-1)*litem->space); colw= w*split->percentage; colw= MAX2(colw, 0); for(item=litem->items.first; item; item=item->next) { ui_item_size(item, NULL, &itemh); ui_item_position(item, x, y-itemh, colw, itemh); x += colw; if(item->next) { colw= (w - (w*split->percentage))/(tot-1); colw= MAX2(colw, 0); x += litem->space; } } litem->w= x - litem->x; litem->h= litem->y - y; litem->x= x; litem->y= y; } /* layout create functions */ uiLayout *uiLayoutRow(uiLayout *layout, int align) { uiLayout *litem; litem= MEM_callocN(sizeof(uiLayout), "uiLayoutRow"); litem->item.type= ITEM_LAYOUT_ROW; litem->root= layout->root; litem->align= align; litem->active= 1; litem->enabled= 1; litem->context= layout->context; litem->space= (align)? 0: layout->root->style->buttonspacex; BLI_addtail(&layout->items, litem); uiBlockSetCurLayout(layout->root->block, litem); return litem; } uiLayout *uiLayoutColumn(uiLayout *layout, int align) { uiLayout *litem; litem= MEM_callocN(sizeof(uiLayout), "uiLayoutColumn"); litem->item.type= ITEM_LAYOUT_COLUMN; litem->root= layout->root; litem->align= align; litem->active= 1; litem->enabled= 1; litem->context= layout->context; litem->space= (litem->align)? 0: layout->root->style->buttonspacey; BLI_addtail(&layout->items, litem); uiBlockSetCurLayout(layout->root->block, litem); return litem; } uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align) { uiLayoutItemFlow *flow; flow= MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow"); flow->litem.item.type= ITEM_LAYOUT_COLUMN_FLOW; flow->litem.root= layout->root; flow->litem.align= align; flow->litem.active= 1; flow->litem.enabled= 1; flow->litem.context= layout->context; flow->litem.space= (flow->litem.align)? 0: layout->root->style->columnspace; flow->number= number; BLI_addtail(&layout->items, flow); uiBlockSetCurLayout(layout->root->block, &flow->litem); return &flow->litem; } uiLayout *uiLayoutBox(uiLayout *layout) { uiLayoutItemBx *box; box= MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx"); box->litem.item.type= ITEM_LAYOUT_BOX; box->litem.root= layout->root; box->litem.active= 1; box->litem.enabled= 1; box->litem.context= layout->context; box->litem.space= layout->root->style->columnspace; BLI_addtail(&layout->items, box); uiBlockSetCurLayout(layout->root->block, &box->litem); box->roundbox= uiDefBut(layout->root->block, ROUNDBOX, 0, "", 0, 0, 0, 0, NULL, 0.0, 0.0, 0, 0, ""); return &box->litem; } uiLayout *uiLayoutFree(uiLayout *layout, int align) { uiLayout *litem; litem= MEM_callocN(sizeof(uiLayout), "uiLayoutFree"); litem->item.type= ITEM_LAYOUT_FREE; litem->root= layout->root; litem->align= align; litem->active= 1; litem->enabled= 1; litem->context= layout->context; BLI_addtail(&layout->items, litem); uiBlockSetCurLayout(layout->root->block, litem); return litem; } uiBlock *uiLayoutFreeBlock(uiLayout *layout) { uiBlock *block; block= uiLayoutGetBlock(layout); uiLayoutFree(layout, 0); return block; } uiLayout *uiLayoutSplit(uiLayout *layout, float percentage) { uiLayoutItemSplt *split; split= MEM_callocN(sizeof(uiLayoutItemSplt), "uiLayoutItemSplt"); split->litem.item.type= ITEM_LAYOUT_SPLIT; split->litem.root= layout->root; split->litem.active= 1; split->litem.enabled= 1; split->litem.context= layout->context; split->litem.space= layout->root->style->columnspace; split->percentage= (percentage == 0.0f)? 0.5f: percentage; BLI_addtail(&layout->items, split); uiBlockSetCurLayout(layout->root->block, &split->litem); return &split->litem; } void uiLayoutSetActive(uiLayout *layout, int active) { layout->active= active; } void uiLayoutSetEnabled(uiLayout *layout, int enabled) { layout->enabled= enabled; } void uiLayoutSetRedAlert(uiLayout *layout, int redalert) { layout->redalert= redalert; } void uiLayoutSetKeepAspect(uiLayout *layout, int keepaspect) { layout->keepaspect= keepaspect; } void uiLayoutSetAlignment(uiLayout *layout, int alignment) { layout->alignment= alignment; } void uiLayoutSetScaleX(uiLayout *layout, float scale) { layout->scale[0]= scale; } void uiLayoutSetScaleY(uiLayout *layout, float scale) { layout->scale[1]= scale; } int uiLayoutGetActive(uiLayout *layout) { return layout->active; } int uiLayoutGetEnabled(uiLayout *layout) { return layout->enabled; } int uiLayoutGetRedAlert(uiLayout *layout) { return layout->redalert; } int uiLayoutGetKeepAspect(uiLayout *layout) { return layout->keepaspect; } int uiLayoutGetAlignment(uiLayout *layout) { return layout->alignment; } float uiLayoutGetScaleX(uiLayout *layout) { return layout->scale[0]; } float uiLayoutGetScaleY(uiLayout *layout) { return layout->scale[0]; } /********************** Layout *******************/ static void ui_item_scale(uiLayout *litem, float scale[2]) { uiItem *item; int x, y, w, h; for(item=litem->items.last; item; item=item->prev) { ui_item_size(item, &w, &h); ui_item_offset(item, &x, &y); if(scale[0] != 0.0f) { x *= scale[0]; w *= scale[0]; } if(scale[1] != 0.0f) { y *= scale[1]; h *= scale[1]; } ui_item_position(item, x, y, w, h); } } static void ui_item_estimate(uiItem *item) { uiItem *subitem; if(item->type != ITEM_BUTTON) { uiLayout *litem= (uiLayout*)item; for(subitem=litem->items.first; subitem; subitem=subitem->next) ui_item_estimate(subitem); if(litem->items.first == NULL) return; if(litem->scale[0] != 0.0f || litem->scale[1] != 0.0f) ui_item_scale(litem, litem->scale); switch(litem->item.type) { case ITEM_LAYOUT_COLUMN: ui_litem_estimate_column(litem); break; case ITEM_LAYOUT_COLUMN_FLOW: ui_litem_estimate_column_flow(litem); break; case ITEM_LAYOUT_ROW: ui_litem_estimate_row(litem); break; case ITEM_LAYOUT_BOX: ui_litem_estimate_box(litem); break; case ITEM_LAYOUT_ROOT: ui_litem_estimate_root(litem); break; case ITEM_LAYOUT_FREE: ui_litem_estimate_free(litem); break; case ITEM_LAYOUT_SPLIT: ui_litem_estimate_split(litem); break; default: break; } } } static void ui_item_align(uiLayout *litem, int nr) { uiItem *item; uiButtonItem *bitem; uiLayoutItemBx *box; for(item=litem->items.last; item; item=item->prev) { if(item->type == ITEM_BUTTON) { bitem= (uiButtonItem*)item; if(ui_but_can_align(bitem->but)) if(!bitem->but->alignnr) bitem->but->alignnr= nr; } else if(item->type == ITEM_LAYOUT_FREE); else if(item->type == ITEM_LAYOUT_BOX) { box= (uiLayoutItemBx*)item; box->roundbox->alignnr= nr; BLI_remlink(&litem->root->block->buttons, box->roundbox); BLI_addhead(&litem->root->block->buttons, box->roundbox); } else ui_item_align((uiLayout*)item, nr); } } static void ui_item_flag(uiLayout *litem, int flag) { uiItem *item; uiButtonItem *bitem; for(item=litem->items.last; item; item=item->prev) { if(item->type == ITEM_BUTTON) { bitem= (uiButtonItem*)item; bitem->but->flag |= flag; } else ui_item_flag((uiLayout*)item, flag); } } static void ui_item_layout(uiItem *item) { uiItem *subitem; if(item->type != ITEM_BUTTON) { uiLayout *litem= (uiLayout*)item; if(litem->items.first == NULL) return; if(litem->align) ui_item_align(litem, ++litem->root->block->alignnr); if(!litem->active) ui_item_flag(litem, UI_BUT_INACTIVE); if(!litem->enabled) ui_item_flag(litem, UI_BUT_DISABLED); switch(litem->item.type) { case ITEM_LAYOUT_COLUMN: ui_litem_layout_column(litem); break; case ITEM_LAYOUT_COLUMN_FLOW: ui_litem_layout_column_flow(litem); break; case ITEM_LAYOUT_ROW: ui_litem_layout_row(litem); break; case ITEM_LAYOUT_BOX: ui_litem_layout_box(litem); break; case ITEM_LAYOUT_ROOT: ui_litem_layout_root(litem); break; case ITEM_LAYOUT_FREE: ui_litem_layout_free(litem); break; case ITEM_LAYOUT_SPLIT: ui_litem_layout_split(litem); break; default: break; } for(subitem=litem->items.first; subitem; subitem=subitem->next) ui_item_layout(subitem); } } static void ui_layout_items(const bContext *C, uiBlock *block, uiLayout *layout) { ui_item_estimate(&layout->item); ui_item_layout(&layout->item); } static void ui_layout_end(const bContext *C, uiBlock *block, uiLayout *layout, int *x, int *y) { if(layout->root->handlefunc) uiBlockSetButmFunc(block, layout->root->handlefunc, layout->root->argv); ui_layout_items(C, block, layout); if(x) *x= layout->x; if(y) *y= layout->y; } static void ui_layout_free(uiLayout *layout) { uiItem *item, *next; for(item=layout->items.first; item; item=next) { next= item->next; if(item->type == ITEM_BUTTON) MEM_freeN(item); else ui_layout_free((uiLayout*)item); } MEM_freeN(layout); } uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int size, int em, uiStyle *style) { uiLayout *layout; uiLayoutRoot *root; root= MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot"); root->type= type; root->style= style; root->block= block; root->opcontext= WM_OP_INVOKE_REGION_WIN; layout= MEM_callocN(sizeof(uiLayout), "uiLayout"); layout->item.type= ITEM_LAYOUT_ROOT; layout->x= x; layout->y= y; layout->root= root; layout->space= style->templatespace; layout->active= 1; layout->enabled= 1; layout->context= NULL; if(type == UI_LAYOUT_MENU) layout->space= 0; if(dir == UI_LAYOUT_HORIZONTAL) { layout->h= size; layout->root->emh= em*UI_UNIT_Y; } else { layout->w= size; layout->root->emw= em*UI_UNIT_X; } block->curlayout= layout; root->layout= layout; BLI_addtail(&block->layouts, root); return layout; } uiBlock *uiLayoutGetBlock(uiLayout *layout) { return layout->root->block; } void uiBlockSetCurLayout(uiBlock *block, uiLayout *layout) { block->curlayout= layout; } void ui_layout_add_but(uiLayout *layout, uiBut *but) { uiButtonItem *bitem; bitem= MEM_callocN(sizeof(uiButtonItem), "uiButtonItem"); bitem->item.type= ITEM_BUTTON; bitem->but= but; BLI_addtail(&layout->items, bitem); if(layout->context) { but->context= layout->context; but->context->used= 1; } } void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext) { layout->root->opcontext= opcontext; } void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv) { layout->root->handlefunc= handlefunc; layout->root->argv= argv; } void uiBlockLayoutResolve(const bContext *C, uiBlock *block, int *x, int *y) { uiLayoutRoot *root; if(x) *x= 0; if(y) *y= 0; block->curlayout= NULL; for(root=block->layouts.first; root; root=root->next) { /* NULL in advance so we don't interfere when adding button */ ui_layout_end(C, block, root->layout, x, y); ui_layout_free(root->layout); } BLI_freelistN(&block->layouts); /* XXX silly trick, interface_templates.c doesn't get linked * because it's not used by other files in this module? */ { void ui_template_fix_linking(); ui_template_fix_linking(); } } void uiLayoutSetContextPointer(uiLayout *layout, char *name, PointerRNA *ptr) { uiBlock *block= layout->root->block; layout->context= CTX_store_add(&block->contexts, name, ptr); }