diff options
Diffstat (limited to 'source/blender/editors/interface/interface_layout.c')
-rw-r--r-- | source/blender/editors/interface/interface_layout.c | 2013 |
1 files changed, 2013 insertions, 0 deletions
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c new file mode 100644 index 00000000000..e112ca704bb --- /dev/null +++ b/source/blender/editors/interface/interface_layout.c @@ -0,0 +1,2013 @@ +/** + * $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 <limits.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#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; a<len; a++) { + col= a%len; + row= a/len; + + but= uiDefAutoButR(block, ptr, prop, a, "", 0, x + w*col, y+(row-a-1)*UI_UNIT_Y, w, UI_UNIT_Y); + if(slider && but->type==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; a<len; a++) { + if(len == 4 && subtype == PROP_ROTATION) + str[0]= quatitem[a]; + else if(subtype == PROP_VECTOR || subtype == PROP_ROTATION) + str[0]= vectoritem[a]; + else + str[0]= coloritem[a]; + + if(type == PROP_BOOLEAN) { + str[1]= '\0'; + } + else { + str[1]= ':'; + str[2]= '\0'; + } + + but= uiDefAutoButR(block, ptr, prop, a, str, 0, 0, 0, w, UI_UNIT_Y); + if(slider && but->type==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; a<len; a++) { + but= uiDefAutoButR(block, ptr, prop, a, "", 0, 0, 0, w, UI_UNIT_Y); + if(slider && but->type==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; a<totitem; a++) { + itemw= ui_text_icon_width(block->curlayout, (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; i<totitem; i++) { + if(item[i].value==retval) + return (char*)item[i].name; + } + } + + return ""; +} + +void uiItemEnumO(uiLayout *layout, char *name, int icon, char *opname, char *propname, int value) +{ + PointerRNA ptr; + + WM_operator_properties_create(&ptr, opname); + RNA_enum_set(&ptr, propname, value); + + if(!name) + name= ui_menu_enumpropname(opname, propname, value); + + uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->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; i<totitem; i++) + uiItemEnumO(layout, NULL, 0, opname, propname, item[i].value); + } +} + +/* for use in cases where we have */ +void uiItemEnumO_string(uiLayout *layout, char *name, int icon, char *opname, char *propname, char *value_str) +{ + PointerRNA ptr; + + /* for getting the enum */ + PropertyRNA *prop; + const EnumPropertyItem *item; + int totitem; + int value; + + WM_operator_properties_create(&ptr, opname); + + /*RNA_enum_set(&ptr, propname, value);*/ + if((prop= RNA_struct_find_property(&ptr, propname))) { + RNA_property_enum_items(&ptr, prop, &item, &totitem); + if(RNA_enum_value_from_id(item, value_str, &value)==0) { + printf("uiItemEnumO_string: %s.%s, enum %s not found.\n", RNA_struct_identifier(ptr.type), propname, value_str); + return; + } + } + else { + printf("uiItemEnumO_string: %s.%s not found.\n", RNA_struct_identifier(ptr.type), propname); + return; + } + + /* same as uiItemEnumO */ + if(!name) + name= ui_menu_enumpropname(opname, propname, value); + + uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->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; i<totitem; i++) + uiItemEnumR(layout, (char*)item[i].name, 0, ptr, propname, item[i].value); + } +} + +/* menu item */ +static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt) +{ + MenuType *mt= (MenuType*)arg_mt; + Menu menu = {0}; + + menu.type= mt; + menu.layout= layout; + mt->draw(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); +} + |