Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/interface/interface_layout.c')
-rw-r--r--source/blender/editors/interface/interface_layout.c2013
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);
+}
+