Blender V2.61 - r43446

interface_layout.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * Contributor(s): Blender Foundation 2009.
00019  *
00020  * ***** END GPL LICENSE BLOCK *****
00021  */
00022 
00028 #include <limits.h>
00029 #include <math.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <assert.h>
00033 
00034 #include "MEM_guardedalloc.h"
00035 
00036 #include "DNA_screen_types.h"
00037 #include "DNA_armature_types.h"
00038 #include "DNA_userdef_types.h"
00039 
00040 #include "BLI_listbase.h"
00041 #include "BLI_string.h"
00042 #include "BLI_utildefines.h"
00043 
00044 #include "BLF_translation.h"
00045 
00046 #include "BKE_context.h"
00047 #include "BKE_global.h"
00048 #include "BKE_idprop.h"
00049 #include "BKE_screen.h"
00050 
00051 #include "RNA_access.h"
00052 
00053 #include "UI_interface.h"
00054 
00055 
00056 #include "WM_api.h"
00057 #include "WM_types.h"
00058 
00059 #include "interface_intern.h"
00060 
00061 /************************ Structs and Defines *************************/
00062 
00063 #define RNA_NO_INDEX    -1
00064 #define RNA_ENUM_VALUE  -2
00065 
00066 #define EM_SEPR_X       6
00067 #define EM_SEPR_Y       6
00068 
00069 /* uiLayoutRoot */
00070 
00071 typedef struct uiLayoutRoot {
00072     struct uiLayoutRoot *next, *prev;
00073 
00074     int type;
00075     int opcontext;
00076 
00077     int emw, emh;
00078 
00079     uiMenuHandleFunc handlefunc;
00080     void *argv;
00081 
00082     uiStyle *style;
00083     uiBlock *block;
00084     uiLayout *layout;
00085 } uiLayoutRoot;
00086 
00087 /* Item */
00088 
00089 typedef enum uiItemType {
00090     ITEM_BUTTON,
00091 
00092     ITEM_LAYOUT_ROW,
00093     ITEM_LAYOUT_COLUMN,
00094     ITEM_LAYOUT_COLUMN_FLOW,
00095     ITEM_LAYOUT_ROW_FLOW,
00096     ITEM_LAYOUT_BOX,
00097     ITEM_LAYOUT_ABSOLUTE,
00098     ITEM_LAYOUT_SPLIT,
00099     ITEM_LAYOUT_OVERLAP,
00100 
00101     ITEM_LAYOUT_ROOT
00102 #if 0
00103     TEMPLATE_COLUMN_FLOW,
00104     TEMPLATE_SPLIT,
00105     TEMPLATE_BOX,
00106 
00107     TEMPLATE_HEADER,
00108     TEMPLATE_HEADER_ID
00109 #endif
00110 } uiItemType;
00111 
00112 typedef struct uiItem {
00113     void *next, *prev;
00114     uiItemType type;
00115     int flag;
00116 } uiItem;
00117 
00118 typedef struct uiButtonItem {
00119     uiItem item;
00120     uiBut *but;
00121 } uiButtonItem;
00122 
00123 struct uiLayout {
00124     uiItem item;
00125 
00126     uiLayoutRoot *root;
00127     bContextStore *context;
00128     ListBase items;
00129 
00130     int x, y, w, h;
00131     float scale[2];
00132     short space;
00133     char align;
00134     char active;
00135     char enabled;
00136     char redalert;
00137     char keepaspect;
00138     char alignment;
00139 };
00140 
00141 typedef struct uiLayoutItemFlow {
00142     uiLayout litem;
00143     int number;
00144     int totcol;
00145 } uiLayoutItemFlow;
00146 
00147 typedef struct uiLayoutItemBx {
00148     uiLayout litem;
00149     uiBut *roundbox;
00150 } uiLayoutItemBx;
00151 
00152 typedef struct uiLayoutItemSplit {
00153     uiLayout litem;
00154     float percentage;
00155 } uiLayoutItemSplit;
00156 
00157 typedef struct uiLayoutItemRoot {
00158     uiLayout litem;
00159 } uiLayoutItemRoot;
00160 
00161 /************************** Item ***************************/
00162 
00163 static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_NAME_STR])
00164 {
00165     int len= strlen(name);
00166 
00167     if(len != 0 && len+1 < UI_MAX_NAME_STR) {
00168         BLI_strncpy(namestr, name, UI_MAX_NAME_STR);
00169         namestr[len]= ':';
00170         namestr[len+1]= '\0';
00171         return namestr;
00172     }
00173 
00174     return name;
00175 }
00176 
00177 static int ui_item_fit(int item, int pos, int all, int available, int last, int alignment, int *offset)
00178 {
00179     /* available == 0 is unlimited */
00180     if(available == 0)
00181         return item;
00182     
00183     if(offset)
00184         *offset= 0;
00185     
00186     if(all > available) {
00187         /* contents is bigger than available space */
00188         if(last)
00189             return available-pos;
00190         else
00191             return (item*available)/all;
00192     }
00193     else {
00194         /* contents is smaller or equal to available space */
00195         if(alignment == UI_LAYOUT_ALIGN_EXPAND) {
00196             if(last)
00197                 return available-pos;
00198             else
00199                 return (item*available)/all;
00200         }
00201         else
00202             return item;
00203     }
00204 }
00205 
00206 /* variable button size in which direction? */
00207 #define UI_ITEM_VARY_X  1
00208 #define UI_ITEM_VARY_Y  2
00209 
00210 static int ui_layout_vary_direction(uiLayout *layout)
00211 {
00212     return (layout->root->type == UI_LAYOUT_HEADER || layout->alignment != UI_LAYOUT_ALIGN_EXPAND)? UI_ITEM_VARY_X: UI_ITEM_VARY_Y;
00213 }
00214 
00215 /* estimated size of text + icon */
00216 static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, int compact)
00217 {
00218     int variable = ui_layout_vary_direction(layout) == UI_ITEM_VARY_X;
00219 
00220     if(icon && !name[0])
00221         return UI_UNIT_X; /* icon only */
00222     else if(icon)
00223         return (variable)? UI_GetStringWidth(name) + (compact? 5: 10) + UI_UNIT_X: 10*UI_UNIT_X; /* icon + text */
00224     else
00225         return (variable)? UI_GetStringWidth(name) + (compact? 5: 10) + UI_UNIT_X: 10*UI_UNIT_X; /* text only */
00226 }
00227 
00228 static void ui_item_size(uiItem *item, int *r_w, int *r_h)
00229 {
00230     if(item->type == ITEM_BUTTON) {
00231         uiButtonItem *bitem= (uiButtonItem*)item;
00232 
00233         if(r_w) *r_w= bitem->but->x2 - bitem->but->x1;
00234         if(r_h) *r_h= bitem->but->y2 - bitem->but->y1;
00235     }
00236     else {
00237         uiLayout *litem= (uiLayout*)item;
00238 
00239         if(r_w) *r_w= litem->w;
00240         if(r_h) *r_h= litem->h;
00241     }
00242 }
00243 
00244 static void ui_item_offset(uiItem *item, int *r_x, int *r_y)
00245 {
00246     if(item->type == ITEM_BUTTON) {
00247         uiButtonItem *bitem= (uiButtonItem*)item;
00248 
00249         if(r_x) *r_x= bitem->but->x1;
00250         if(r_y) *r_y= bitem->but->y1;
00251     }
00252     else {
00253         if(r_x) *r_x= 0;
00254         if(r_y) *r_y= 0;
00255     }
00256 }
00257 
00258 static void ui_item_position(uiItem *item, int x, int y, int w, int h)
00259 {
00260     if(item->type == ITEM_BUTTON) {
00261         uiButtonItem *bitem= (uiButtonItem*)item;
00262 
00263         bitem->but->x1= x;
00264         bitem->but->y1= y;
00265         bitem->but->x2= x+w;
00266         bitem->but->y2= y+h;
00267         
00268         ui_check_but(bitem->but); /* for strlen */
00269     }
00270     else {
00271         uiLayout *litem= (uiLayout*)item;
00272 
00273         litem->x= x;
00274         litem->y= y+h;
00275         litem->w= w;
00276         litem->h= h;
00277     }
00278 }
00279 
00280 /******************** Special RNA Items *********************/
00281 
00282 static int ui_layout_local_dir(uiLayout *layout)
00283 {
00284     switch(layout->item.type) {
00285         case ITEM_LAYOUT_ROW:
00286         case ITEM_LAYOUT_ROOT:
00287         case ITEM_LAYOUT_OVERLAP:
00288             return UI_LAYOUT_HORIZONTAL;
00289         case ITEM_LAYOUT_COLUMN:
00290         case ITEM_LAYOUT_COLUMN_FLOW:
00291         case ITEM_LAYOUT_SPLIT:
00292         case ITEM_LAYOUT_ABSOLUTE:
00293         case ITEM_LAYOUT_BOX:
00294         default:
00295             return UI_LAYOUT_VERTICAL;
00296     }
00297 }
00298 
00299 static uiLayout *ui_item_local_sublayout(uiLayout *test, uiLayout *layout, int align)
00300 {
00301     uiLayout *sub;
00302 
00303     if(ui_layout_local_dir(test) == UI_LAYOUT_HORIZONTAL)
00304         sub= uiLayoutRow(layout, align);
00305     else
00306         sub= uiLayoutColumn(layout, align);
00307     
00308     sub->space= 0;
00309     return sub;
00310 }
00311 
00312 static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
00313 {
00314     wmWindow *win= CTX_wm_window(C);
00315     uiBut *but= arg_but, *cbut;
00316     PointerRNA *ptr= &but->rnapoin;
00317     PropertyRNA *prop= but->rnaprop;
00318     int i, index= GET_INT_FROM_POINTER(arg_index);
00319     int shift= win->eventstate->shift;
00320     int len= RNA_property_array_length(ptr, prop);
00321 
00322     if(!shift) {
00323         RNA_property_boolean_set_index(ptr, prop, index, TRUE);
00324 
00325         for(i=0; i<len; i++)
00326             if(i != index)
00327                 RNA_property_boolean_set_index(ptr, prop, i, 0);
00328 
00329         RNA_property_update(C, ptr, prop);
00330 
00331         for(cbut=but->block->buttons.first; cbut; cbut=cbut->next)
00332             ui_check_but(cbut);
00333     }
00334 }
00335 
00336 /* create buttons for an item with an RNA array */
00337 static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h), int expand, int slider, int toggle, int icon_only)
00338 {
00339     uiStyle *style= layout->root->style;
00340     uiBut *but;
00341     PropertyType type;
00342     PropertySubType subtype;
00343     uiLayout *sub;
00344     int a, b;
00345 
00346     /* retrieve type and subtype */
00347     type= RNA_property_type(prop);
00348     subtype= RNA_property_subtype(prop);
00349 
00350     sub= ui_item_local_sublayout(layout, layout, 1);
00351     uiBlockSetCurLayout(block, sub);
00352 
00353     /* create label */
00354     if(name[0])
00355         uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
00356 
00357     /* create buttons */
00358     if(type == PROP_BOOLEAN && ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
00359         /* special check for layer layout */
00360         int butw, buth, unit;
00361         int cols= (len >= 20)? 2: 1;
00362         int colbuts= len/(2*cols);
00363         int layer_used= 0;
00364 
00365         uiBlockSetCurLayout(block, uiLayoutAbsolute(layout, 0));
00366 
00367         unit= UI_UNIT_X*0.75;
00368         butw= unit;
00369         buth= unit;
00370 
00371         if(ptr->type == &RNA_Armature) {
00372             bArmature *arm= (bArmature *)ptr->data;
00373             layer_used= arm->layer_used;
00374         }
00375 
00376         for(b=0; b<cols; b++) {
00377             uiBlockBeginAlign(block);
00378 
00379             for(a=0; a<colbuts; a++) {
00380                 if(layer_used & (1<<(a+b*colbuts))) icon= ICON_LAYER_USED;
00381                 else icon= ICON_BLANK1;
00382 
00383                 but= uiDefAutoButR(block, ptr, prop, a+b*colbuts, "", icon, x + butw*a, y+buth, butw, buth);
00384                 if(subtype == PROP_LAYER_MEMBER)
00385                     uiButSetFunc(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(a+b*colbuts));
00386             }
00387             for(a=0; a<colbuts; a++) {
00388                 if(layer_used & (1<<(a+len/2+b*colbuts))) icon= ICON_LAYER_USED;
00389                 else icon= ICON_BLANK1;
00390 
00391                 but= uiDefAutoButR(block, ptr, prop, a+len/2+b*colbuts, "", icon, x + butw*a, y, butw, buth);
00392                 if(subtype == PROP_LAYER_MEMBER)
00393                     uiButSetFunc(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(a+len/2+b*colbuts));
00394             }
00395             uiBlockEndAlign(block);
00396 
00397             x += colbuts*butw + style->buttonspacex;
00398         }
00399     }
00400     else if(subtype == PROP_MATRIX) {
00401         int totdim, dim_size[3];    /* 3 == RNA_MAX_ARRAY_DIMENSION */
00402         int row, col;
00403 
00404         uiBlockSetCurLayout(block, uiLayoutAbsolute(layout, 1));
00405 
00406         totdim= RNA_property_array_dimension(ptr, prop, dim_size);
00407         if (totdim != 2) return;    /* only 2D matrices supported in UI so far */
00408         
00409         w /= dim_size[0];
00410         /* h /= dim_size[1]; */ /* UNUSED */
00411 
00412         for(a=0; a<len; a++) {
00413             col= a % dim_size[0];
00414             row= a / dim_size[0];
00415             
00416             but= uiDefAutoButR(block, ptr, prop, a, "", ICON_NONE, x + w*col, y+(dim_size[1]*UI_UNIT_Y)-(row*UI_UNIT_Y), w, UI_UNIT_Y);
00417             if(slider && but->type==NUM)
00418                 but->type= NUMSLI;
00419         }
00420     }
00421     else if(subtype == PROP_DIRECTION) {
00422         uiDefButR_prop(block, BUT_NORMAL, 0, name, x, y, UI_UNIT_X*3, UI_UNIT_Y*3, ptr, prop, 0, 0, 0, -1, -1, NULL);
00423     }
00424     else {
00425         /* note, this block of code is a bit arbitrary and has just been made
00426          * to work with common cases, but may need to be re-worked */
00427 
00428         /* special case, boolean array in a menu, this could be used in a more generic way too */
00429         if(ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) && !expand) {
00430             uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, 0, 0, w, UI_UNIT_Y);
00431         }
00432         else {
00433             int *boolarr= NULL;
00434 
00435             /* even if 'expand' is fale, expanding anyway */
00436 
00437             /* layout for known array subtypes */
00438             char str[3]= {'\0'};
00439 
00440             if(!icon_only) {
00441                 if(type != PROP_BOOLEAN) {
00442                     str[1]= ':';
00443                 }
00444             }
00445 
00446             /* show checkboxes for rna on a non-emboss block (menu for eg) */
00447             if(type == PROP_BOOLEAN && ELEM(layout->root->block->dt, UI_EMBOSSN, UI_EMBOSSP)) {
00448                 boolarr= MEM_callocN(sizeof(int)*len, "ui_item_array");
00449                 RNA_property_boolean_get_array(ptr, prop, boolarr);
00450             }
00451 
00452             for(a=0; a<len; a++) {
00453                 if(!icon_only) str[0]= RNA_property_array_item_char(prop, a);
00454                 if(boolarr) icon= boolarr[a] ? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT;
00455                 but= uiDefAutoButR(block, ptr, prop, a, str, icon, 0, 0, w, UI_UNIT_Y);
00456                 if(slider && but->type==NUM)
00457                     but->type= NUMSLI;
00458                 if(toggle && but->type==OPTION)
00459                     but->type= TOG;
00460             }
00461 
00462             if(boolarr) {
00463                 MEM_freeN(boolarr);
00464             }
00465         }
00466     }
00467 
00468     uiBlockSetCurLayout(block, layout);
00469 }
00470 
00471 static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, const char *uiname, int h, int icon_only)
00472 {
00473     uiBut *but;
00474     EnumPropertyItem *item;
00475     const char *name;
00476     int a, totitem, itemw, icon, value, free;
00477 
00478     RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item, &totitem, &free);
00479 
00480     uiBlockSetCurLayout(block, ui_item_local_sublayout(layout, layout, 1));
00481     for(a=0; a<totitem; a++) {
00482         if(!item[a].identifier[0])
00483             continue;
00484 
00485         name= (!uiname || uiname[0])? item[a].name: "";
00486         icon= item[a].icon;
00487         value= item[a].value;
00488         itemw= ui_text_icon_width(block->curlayout, name, icon, 0);
00489 
00490         if(icon && name[0] && !icon_only)
00491             but= uiDefIconTextButR_prop(block, ROW, 0, icon, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
00492         else if(icon)
00493             but= uiDefIconButR_prop(block, ROW, 0, icon, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
00494         else
00495             but= uiDefButR_prop(block, ROW, 0, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
00496 
00497         if(ui_layout_local_dir(layout) != UI_LAYOUT_HORIZONTAL)
00498             but->flag |= UI_TEXT_LEFT;
00499     }
00500     uiBlockSetCurLayout(block, layout);
00501 
00502     if(free)
00503         MEM_freeN(item);
00504 }
00505 
00506 /* callback for keymap item change button */
00507 static void ui_keymap_but_cb(bContext *UNUSED(C), void *but_v, void *UNUSED(key_v))
00508 {
00509     uiBut *but= but_v;
00510 
00511     RNA_boolean_set(&but->rnapoin, "shift", (but->modifier_key & KM_SHIFT) != 0);
00512     RNA_boolean_set(&but->rnapoin, "ctrl", (but->modifier_key & KM_CTRL) != 0);
00513     RNA_boolean_set(&but->rnapoin, "alt", (but->modifier_key & KM_ALT) != 0);
00514     RNA_boolean_set(&but->rnapoin, "oskey", (but->modifier_key & KM_OSKEY) != 0);
00515 }
00516 
00517 /* create label + button for RNA property */
00518 static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int x, int y, int w, int h, int flag)
00519 {
00520     uiLayout *sub;
00521     uiBut *but=NULL;
00522     PropertyType type;
00523     PropertySubType subtype;
00524     int labelw;
00525 
00526     sub= uiLayoutRow(layout, 0);
00527     uiBlockSetCurLayout(block, sub);
00528 
00529     if(name[0]) {
00530         /* XXX UI_GetStringWidth is not accurate
00531         labelw= UI_GetStringWidth(name);
00532         CLAMP(labelw, w/4, 3*w/4);*/
00533         labelw= w/3;
00534         uiDefBut(block, LABEL, 0, name, x, y, labelw, h, NULL, 0.0, 0.0, 0, 0, "");
00535         w= w-labelw;
00536     }
00537 
00538     type= RNA_property_type(prop);
00539     subtype= RNA_property_subtype(prop);
00540 
00541     if(subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) {
00542         uiBlockSetCurLayout(block, uiLayoutRow(sub, 1));
00543         uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, w-UI_UNIT_X, h);
00544 
00545         /* BUTTONS_OT_file_browse calls uiFileBrowseContextProperty */
00546         but= uiDefIconButO(block, BUT, subtype==PROP_DIRPATH ?
00547                                "BUTTONS_OT_directory_browse" :
00548                                "BUTTONS_OT_file_browse",
00549                            WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, NULL);
00550     }
00551     else if(flag & UI_ITEM_R_EVENT) {
00552         uiDefButR_prop(block, KEYEVT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL);
00553     }
00554     else if(flag & UI_ITEM_R_FULL_EVENT) {
00555         if(RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) {
00556             char buf[128];
00557 
00558             WM_keymap_item_to_string(ptr->data, buf, sizeof(buf));
00559 
00560             but= uiDefButR_prop(block, HOTKEYEVT, 0, buf, x, y, w, h, ptr, prop, 0, 0, 0, -1, -1, NULL);
00561             uiButSetFunc(but, ui_keymap_but_cb, but, NULL);
00562             if (flag & UI_ITEM_R_IMMEDIATE)
00563                 uiButSetFlag(but, UI_BUT_IMMEDIATE);
00564         }
00565     }
00566     else
00567         but= uiDefAutoButR(block, ptr, prop, index, (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY))? NULL: "", icon, x, y, w, h);
00568 
00569     uiBlockSetCurLayout(block, layout);
00570     return but;
00571 }
00572 
00573 void uiFileBrowseContextProperty(const bContext *C, PointerRNA *ptr, PropertyRNA **prop)
00574 {
00575     ARegion *ar= CTX_wm_region(C);
00576     uiBlock *block;
00577     uiBut *but, *prevbut;
00578 
00579     memset(ptr, 0, sizeof(*ptr));
00580     *prop= NULL;
00581 
00582     if(!ar)
00583         return;
00584 
00585     for(block=ar->uiblocks.first; block; block=block->next) {
00586         for(but=block->buttons.first; but; but= but->next) {
00587             prevbut= but->prev;
00588 
00589             /* find the button before the active one */
00590             if((but->flag & UI_BUT_LAST_ACTIVE) && prevbut && prevbut->rnapoin.data) {
00591                 if(RNA_property_type(prevbut->rnaprop) == PROP_STRING) {
00592                     *ptr= prevbut->rnapoin;
00593                     *prop= prevbut->rnaprop;
00594                     return;
00595                 }
00596             }
00597         }
00598     }
00599 }
00600 
00601 /********************* Button Items *************************/
00602 
00603 /* disabled item */
00604 static void ui_item_disabled(uiLayout *layout, const char *name)
00605 {
00606     uiBlock *block= layout->root->block;
00607     uiBut *but;
00608     int w;
00609 
00610     uiBlockSetCurLayout(block, layout);
00611 
00612     if(!name)
00613         name= "";
00614 
00615     w= ui_text_icon_width(layout, name, 0, 0);
00616 
00617     but= uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
00618     but->flag |= UI_BUT_DISABLED;
00619     but->lock = 1;
00620     but->lockstr = "";
00621 }
00622 
00623 /* operator items */
00624 PointerRNA uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, IDProperty *properties, int context, int flag)
00625 {
00626     uiBlock *block= layout->root->block;
00627     wmOperatorType *ot= WM_operatortype_find(opname, 1);
00628     uiBut *but;
00629     int w;
00630 
00631     if(!ot) {
00632         ui_item_disabled(layout, opname);
00633         RNA_warning("unknown operator '%s'", opname);
00634         return PointerRNA_NULL;
00635     }
00636 
00637     if(!name) {
00638         name= IFACE_(ot->name);
00639     }
00640 
00641     if(layout->root->type == UI_LAYOUT_MENU && !icon)
00642         icon= ICON_BLANK1;
00643 
00644     /* create button */
00645     uiBlockSetCurLayout(block, layout);
00646 
00647     w= ui_text_icon_width(layout, name, icon, 0);
00648 
00649     if (flag & UI_ITEM_R_NO_BG)
00650         uiBlockSetEmboss(block, UI_EMBOSSN);
00651 
00652     if(icon && name[0])
00653         but= uiDefIconTextButO(block, BUT, ot->idname, context, icon, name, 0, 0, w, UI_UNIT_Y, NULL);
00654     else if(icon)
00655         but= uiDefIconButO(block, BUT, ot->idname, context, icon, 0, 0, w, UI_UNIT_Y, NULL);
00656     else
00657         but= uiDefButO(block, BUT, ot->idname, context, name, 0, 0, w, UI_UNIT_Y, NULL);
00658 
00659     assert(but->optype != NULL);
00660 
00661     /* text alignment for toolbar buttons */
00662     if((layout->root->type == UI_LAYOUT_TOOLBAR) && !icon)
00663         but->flag |= UI_TEXT_LEFT;
00664 
00665     if (flag & UI_ITEM_R_NO_BG)
00666         uiBlockSetEmboss(block, UI_EMBOSS);
00667 
00668     if(layout->redalert)
00669         uiButSetFlag(but, UI_BUT_REDALERT);
00670 
00671     /* assign properties */
00672     if(properties || (flag & UI_ITEM_O_RETURN_PROPS)) {
00673         PointerRNA *opptr= uiButGetOperatorPtrRNA(but);
00674 
00675         if(properties) {
00676             opptr->data= properties;
00677         }
00678         else {
00679             IDPropertyTemplate val = {0};
00680             opptr->data= IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
00681         }
00682 
00683         return *opptr;
00684     }
00685 
00686     return PointerRNA_NULL;
00687 }
00688 
00689 static const char *ui_menu_enumpropname(uiLayout *layout, const char *opname, const char *propname, int retval)
00690 {
00691     wmOperatorType *ot= WM_operatortype_find(opname, 0);
00692     PointerRNA ptr;
00693     PropertyRNA *prop;
00694 
00695     if(!ot || !ot->srna)
00696         return "";
00697 
00698     RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
00699     prop= RNA_struct_find_property(&ptr, propname);
00700 
00701     if(prop) {
00702         EnumPropertyItem *item;
00703         int totitem, free;
00704         const char *name;
00705 
00706         RNA_property_enum_items_gettexted(layout->root->block->evil_C, &ptr, prop, &item, &totitem, &free);
00707         if(RNA_enum_name(item, retval, &name)) {
00708             if(free) MEM_freeN(item);
00709             return name;
00710         }
00711         
00712         if(free)
00713             MEM_freeN(item);
00714     }
00715 
00716     return "";
00717 }
00718 
00719 void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int icon, const char *propname, int value)
00720 {
00721     PointerRNA ptr;
00722 
00723     WM_operator_properties_create(&ptr, opname);
00724     RNA_enum_set(&ptr, propname, value);
00725 
00726     if(!name)
00727         name= ui_menu_enumpropname(layout, opname, propname, value);
00728 
00729     uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
00730 }
00731 
00732 void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, IDProperty *properties, int context, int flag)
00733 {
00734     wmOperatorType *ot= WM_operatortype_find(opname, 1);
00735     PointerRNA ptr;
00736     PropertyRNA *prop;
00737     uiBut *bt;
00738     uiBlock *block= layout->root->block;
00739 
00740     if(!ot || !ot->srna) {
00741         ui_item_disabled(layout, opname);
00742         RNA_warning("%s '%s'", ot ? "unknown operator" : "operator missing srna", opname);
00743         return;
00744     }
00745 
00746     RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
00747     prop= RNA_struct_find_property(&ptr, propname);
00748 
00749     /* don't let bad properties slip through */
00750     BLI_assert((prop == NULL) || (RNA_property_type(prop) == PROP_ENUM));
00751 
00752     if(prop && RNA_property_type(prop) == PROP_ENUM) {
00753         EnumPropertyItem *item;
00754         int totitem, i, free;
00755         uiLayout *split= uiLayoutSplit(layout, 0, 0);
00756         uiLayout *column= uiLayoutColumn(split, 0);
00757 
00758         RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item, &totitem, &free);
00759 
00760         for(i=0; i<totitem; i++) {
00761             if(item[i].identifier[0]) {
00762                 if(properties) {
00763                     PointerRNA tptr;
00764 
00765                     WM_operator_properties_create_ptr(&tptr, ot);
00766                     if(tptr.data) {
00767                         IDP_FreeProperty(tptr.data);
00768                         MEM_freeN(tptr.data);
00769                     }
00770                     tptr.data= IDP_CopyProperty(properties);
00771                     RNA_enum_set(&tptr, propname, item[i].value);
00772 
00773                     uiItemFullO(column, opname, item[i].name, item[i].icon, tptr.data, context, flag);
00774                 }
00775                 else
00776                     uiItemEnumO(column, opname, item[i].name, item[i].icon, propname, item[i].value);
00777             }
00778             else {
00779                 if(item[i].name) {
00780                     if(i != 0) {
00781                         column= uiLayoutColumn(split, 0);
00782                         /* inconsistent, but menus with labels do not look good flipped */
00783                         block->flag |= UI_BLOCK_NO_FLIP;
00784                     }
00785 
00786                     uiItemL(column, item[i].name, ICON_NONE);
00787                     bt= block->buttons.last;
00788                     bt->flag= UI_TEXT_LEFT;
00789                 }
00790                 else /* XXX bug here, collums draw bottom item badly */
00791                     uiItemS(column);
00792             }
00793         }
00794 
00795         if(free)
00796             MEM_freeN(item);
00797     }
00798 }
00799 
00800 void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
00801 {
00802     uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0);
00803 }
00804 
00805 /* for use in cases where we have */
00806 void uiItemEnumO_value(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
00807 {
00808     PointerRNA ptr;
00809 
00810     /* for getting the enum */
00811     PropertyRNA *prop;
00812 
00813     WM_operator_properties_create(&ptr, opname);
00814 
00815     /* enum lookup */
00816     if((prop= RNA_struct_find_property(&ptr, propname))) {
00817         /* pass */
00818     }
00819     else {
00820         RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
00821         return;
00822     }
00823 
00824     RNA_property_enum_set(&ptr, prop, value);
00825 
00826     /* same as uiItemEnumO */
00827     if(!name)
00828         name= ui_menu_enumpropname(layout, opname, propname, value);
00829 
00830     uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
00831 }
00832 
00833 void uiItemEnumO_string(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, const char *value_str)
00834 {
00835     PointerRNA ptr;
00836     
00837     /* for getting the enum */
00838     PropertyRNA *prop;
00839     EnumPropertyItem *item;
00840     int value, free;
00841 
00842     WM_operator_properties_create(&ptr, opname);
00843     
00844     /* enum lookup */
00845     if((prop= RNA_struct_find_property(&ptr, propname))) {
00846         RNA_property_enum_items_gettexted(layout->root->block->evil_C, &ptr, prop, &item, NULL, &free);
00847         if(item==NULL || RNA_enum_value_from_id(item, value_str, &value)==0) {
00848             if(free) MEM_freeN(item);
00849             RNA_warning("%s.%s, enum %s not found", RNA_struct_identifier(ptr.type), propname, value_str);
00850             return;
00851         }
00852 
00853         if(free)
00854             MEM_freeN(item);
00855     }
00856     else {
00857         RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
00858         return;
00859     }
00860     
00861     RNA_property_enum_set(&ptr, prop, value);
00862     
00863     /* same as uiItemEnumO */
00864     if(!name)
00865         name= ui_menu_enumpropname(layout, opname, propname, value);
00866 
00867     uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
00868 }
00869 
00870 void uiItemBooleanO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
00871 {
00872     PointerRNA ptr;
00873 
00874     WM_operator_properties_create(&ptr, opname);
00875     RNA_boolean_set(&ptr, propname, value);
00876 
00877     uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
00878 }
00879 
00880 void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
00881 {
00882     PointerRNA ptr;
00883 
00884     WM_operator_properties_create(&ptr, opname);
00885     RNA_int_set(&ptr, propname, value);
00886 
00887     uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
00888 }
00889 
00890 void uiItemFloatO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, float value)
00891 {
00892     PointerRNA ptr;
00893 
00894     WM_operator_properties_create(&ptr, opname);
00895     RNA_float_set(&ptr, propname, value);
00896 
00897     uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
00898 }
00899 
00900 void uiItemStringO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, const char *value)
00901 {
00902     PointerRNA ptr;
00903 
00904     WM_operator_properties_create(&ptr, opname);
00905     RNA_string_set(&ptr, propname, value);
00906 
00907     uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
00908 }
00909 
00910 void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
00911 {
00912     uiItemFullO(layout, opname, name, icon, NULL, layout->root->opcontext, 0);
00913 }
00914 
00915 /* RNA property items */
00916 
00917 static void ui_item_rna_size(uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int icon_only, int *r_w, int *r_h)
00918 {
00919     PropertyType type;
00920     PropertySubType subtype;
00921     int len, w, h;
00922 
00923     /* arbitrary extended width by type */
00924     type= RNA_property_type(prop);
00925     subtype= RNA_property_subtype(prop);
00926     len= RNA_property_array_length(ptr, prop);
00927 
00928     if(ELEM3(type, PROP_STRING, PROP_POINTER, PROP_ENUM) && !name[0] && !icon_only)
00929         name= "non-empty text";
00930     else if(type == PROP_BOOLEAN && !name[0] && !icon_only)
00931         icon= ICON_DOT;
00932 
00933     w= ui_text_icon_width(layout, name, icon, 0);
00934     h= UI_UNIT_Y;
00935 
00936     /* increase height for arrays */
00937     if(index == RNA_NO_INDEX && len > 0) {
00938         if(!name[0] && icon == ICON_NONE)
00939             h= 0;
00940 
00941         if(ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER))
00942             h += 2*UI_UNIT_Y;
00943         else if(subtype == PROP_MATRIX)
00944             h += ceil(sqrt(len))*UI_UNIT_Y;
00945         else
00946             h += len*UI_UNIT_Y;
00947     }
00948     else if(ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) {
00949         if(type == PROP_BOOLEAN && name[0])
00950             w += UI_UNIT_X/5;
00951         else if(type == PROP_ENUM)
00952             w += UI_UNIT_X/4;
00953         else if(type == PROP_FLOAT || type == PROP_INT)
00954             w += UI_UNIT_X*3;
00955     }
00956 
00957     *r_w= w;
00958     *r_h= h;
00959 }
00960 
00961 void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index, int value, int flag, const char *name, int icon)
00962 {
00963     uiBlock *block= layout->root->block;
00964     uiBut *but;
00965     PropertyType type;
00966     char namestr[UI_MAX_NAME_STR];
00967     int len, is_array, w, h, slider, toggle, expand, icon_only, no_bg;
00968 
00969     uiBlockSetCurLayout(block, layout);
00970 
00971     /* retrieve info */
00972     type= RNA_property_type(prop);
00973     is_array= RNA_property_array_check(prop);
00974     len= (is_array) ? RNA_property_array_length(ptr, prop) : 0;
00975 
00976     /* set name and icon */
00977     if(!name)
00978         name= RNA_property_ui_name(prop);
00979     if(icon == ICON_NONE)
00980         icon= RNA_property_ui_icon(prop);
00981     
00982     if(ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER))
00983         name= ui_item_name_add_colon(name, namestr);
00984     else if(type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX)
00985         name= ui_item_name_add_colon(name, namestr);
00986     else if(type == PROP_ENUM && index != RNA_ENUM_VALUE)
00987         name= ui_item_name_add_colon(name, namestr);
00988 
00989     if(layout->root->type == UI_LAYOUT_MENU) {
00990         if(type == PROP_BOOLEAN && ((is_array == FALSE) || (index != RNA_NO_INDEX))) {
00991             if(is_array) icon= (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT;
00992             else         icon= (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT;
00993         }
00994         else if(type == PROP_ENUM && index == RNA_ENUM_VALUE) {
00995             int enum_value= RNA_property_enum_get(ptr, prop);
00996             if(RNA_property_flag(prop) & PROP_ENUM_FLAG) {
00997                 icon= (enum_value & value)? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT;
00998             }
00999             else {
01000                 icon= (enum_value == value)? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT;
01001             }
01002         }
01003     }
01004 
01005     slider= (flag & UI_ITEM_R_SLIDER);
01006     toggle= (flag & UI_ITEM_R_TOGGLE);
01007     expand= (flag & UI_ITEM_R_EXPAND);
01008     icon_only= (flag & UI_ITEM_R_ICON_ONLY);
01009     no_bg= (flag & UI_ITEM_R_NO_BG);
01010 
01011     /* get size */
01012     ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, &w, &h);
01013 
01014     if (no_bg)
01015         uiBlockSetEmboss(block, UI_EMBOSSN);
01016     
01017     /* array property */
01018     if(index == RNA_NO_INDEX && is_array)
01019         ui_item_array(layout, block, name, icon, ptr, prop, len, 0, 0, w, h, expand, slider, toggle, icon_only);
01020     /* enum item */
01021     else if(type == PROP_ENUM && index == RNA_ENUM_VALUE) {
01022         if(icon && name[0] && !icon_only)
01023             uiDefIconTextButR_prop(block, ROW, 0, icon, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
01024         else if(icon)
01025             uiDefIconButR_prop(block, ROW, 0, icon, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
01026         else
01027             uiDefButR_prop(block, ROW, 0, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
01028     }
01029     /* expanded enum */
01030     else if(type == PROP_ENUM && (expand || RNA_property_flag(prop) & PROP_ENUM_FLAG))
01031         ui_item_enum_expand(layout, block, ptr, prop, name, h, icon_only);
01032     /* property with separate label */
01033     else if(type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) {
01034         but= ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag);
01035         ui_but_add_search(but, ptr, prop, NULL, NULL);
01036         
01037         if(layout->redalert)
01038             uiButSetFlag(but, UI_BUT_REDALERT);
01039     }
01040     /* single button */
01041     else {
01042         but= uiDefAutoButR(block, ptr, prop, index, name, icon, 0, 0, w, h);
01043 
01044         if(slider && but->type==NUM)
01045             but->type= NUMSLI;
01046 
01047         if(toggle && but->type==OPTION)
01048             but->type= TOG;
01049         
01050         if(layout->redalert)
01051             uiButSetFlag(but, UI_BUT_REDALERT);
01052     }
01053     
01054     if (no_bg)
01055         uiBlockSetEmboss(block, UI_EMBOSS);
01056 }
01057 
01058 void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
01059 {
01060     PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
01061 
01062     if(!prop) {
01063         ui_item_disabled(layout, propname);
01064         RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
01065         return;
01066     }
01067 
01068     uiItemFullR(layout, ptr, prop, RNA_NO_INDEX, 0, flag, name, icon);
01069 }
01070 
01071 void uiItemEnumR(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, const char *propname, int value)
01072 {
01073     PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
01074 
01075     if(!prop || RNA_property_type(prop) != PROP_ENUM) {
01076         ui_item_disabled(layout, propname);
01077         RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
01078         return;
01079     }
01080 
01081     uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, value, 0, name, icon);
01082 }
01083 
01084 void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value, const char *name, int icon)
01085 {
01086     PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
01087     EnumPropertyItem *item;
01088     int ivalue, a, free;
01089 
01090     if(!prop || RNA_property_type(prop) != PROP_ENUM) {
01091         ui_item_disabled(layout, propname);
01092         RNA_warning("enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
01093         return;
01094     }
01095 
01096     RNA_property_enum_items_gettexted(layout->root->block->evil_C, ptr, prop, &item, NULL, &free);
01097 
01098     if(!RNA_enum_value_from_id(item, value, &ivalue)) {
01099         if(free) MEM_freeN(item);
01100         ui_item_disabled(layout, propname);
01101         RNA_warning("enum property value not found: %s", value);
01102         return;
01103     }
01104 
01105     for(a=0; item[a].identifier; a++) {
01106         if(item[a].value == ivalue) {
01107             uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, name ? name : item[a].name, icon ? icon : item[a].icon);
01108             break;
01109         }
01110     }
01111 
01112     if(free)
01113         MEM_freeN(item);
01114 }
01115 
01116 void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname)
01117 {
01118     PropertyRNA *prop;
01119     uiBlock *block= layout->root->block;
01120     uiBut *bt;
01121 
01122     prop= RNA_struct_find_property(ptr, propname);
01123 
01124     if(!prop) {
01125         ui_item_disabled(layout, propname);
01126         RNA_warning("enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
01127         return;
01128     }
01129 
01130     if(RNA_property_type(prop) != PROP_ENUM) {
01131         RNA_warning("not an enum property: %s.%s", RNA_struct_identifier(ptr->type), propname);
01132         return;
01133     }
01134     else {
01135         EnumPropertyItem *item;
01136         int totitem, i, free;
01137         uiLayout *split= uiLayoutSplit(layout, 0, 0);
01138         uiLayout *column= uiLayoutColumn(split, 0);
01139 
01140         RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item, &totitem, &free);
01141 
01142         for(i=0; i<totitem; i++) {
01143             if(item[i].identifier[0]) {
01144                 uiItemEnumR(column, item[i].name, ICON_NONE, ptr, propname, item[i].value);
01145             }
01146             else {
01147                 if(item[i].name) {
01148                     if(i != 0) {
01149                         column= uiLayoutColumn(split, 0);
01150                         /* inconsistent, but menus with labels do not look good flipped */
01151                         block->flag |= UI_BLOCK_NO_FLIP;
01152                     }
01153 
01154                     uiItemL(column, item[i].name, ICON_NONE);
01155                     bt= block->buttons.last;
01156                     bt->flag= UI_TEXT_LEFT;
01157                 }
01158                 else
01159                     uiItemS(column);
01160             }
01161         }
01162 
01163         if(free)
01164             MEM_freeN(item);
01165     }
01166 }
01167 
01168 /* Pointer RNA button with search */
01169 
01170 typedef struct CollItemSearch {
01171     struct CollItemSearch *next, *prev;
01172     char *name;
01173     int index;
01174     int iconid;
01175 } CollItemSearch;
01176 
01177 static int sort_search_items_list(void *a, void *b)
01178 {
01179     CollItemSearch *cis1 = (CollItemSearch *)a;
01180     CollItemSearch *cis2 = (CollItemSearch *)b;
01181     
01182     if (BLI_strcasecmp(cis1->name, cis2->name)>0)
01183         return 1;
01184     else
01185         return 0;
01186 }
01187 
01188 static void rna_search_cb(const struct bContext *C, void *arg_but, const char *str, uiSearchItems *items)
01189 {
01190     uiBut *but= arg_but;
01191     char *name;
01192     int i=0, iconid=0, flag= RNA_property_flag(but->rnaprop);
01193     ListBase *items_list= MEM_callocN(sizeof(ListBase), "items_list");
01194     CollItemSearch *cis;
01195     const int skip_filter= !but->changed;
01196 
01197     /* build a temporary list of relevant items first */
01198     RNA_PROP_BEGIN(&but->rnasearchpoin, itemptr, but->rnasearchprop) {
01199         if(flag & PROP_ID_SELF_CHECK)
01200             if(itemptr.data == but->rnapoin.id.data)
01201                 continue;
01202 
01203         /* use filter */
01204         if(RNA_property_type(but->rnaprop)==PROP_POINTER) {
01205             if(RNA_property_pointer_poll(&but->rnapoin, but->rnaprop, &itemptr)==0)
01206                 continue;
01207         }
01208 
01209         if(itemptr.type && RNA_struct_is_ID(itemptr.type)) {
01210             ID *id= itemptr.data;
01211             char name_ui[MAX_ID_NAME];
01212 
01213 #if 0       /* this name is used for a string comparison and can't be modified, TODO */
01214             name_uiprefix_id(name_ui, id);
01215 #else
01216             BLI_strncpy(name_ui, id->name+2, sizeof(name_ui));
01217 #endif
01218             name= BLI_strdup(name_ui);
01219             iconid= ui_id_icon_get((bContext*)C, id, 1);
01220         }
01221         else {
01222             name= RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); /* could use the string length here */
01223             iconid = 0;
01224         }
01225 
01226         if(name) {
01227             if(skip_filter || BLI_strcasestr(name, str)) {
01228                 cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch");
01229                 cis->name = MEM_dupallocN(name);
01230                 cis->index = i;
01231                 cis->iconid = iconid;
01232                 BLI_addtail(items_list, cis);
01233             }
01234             MEM_freeN(name);
01235         }           
01236 
01237         i++;
01238     }
01239     RNA_PROP_END;
01240     
01241     BLI_sortlist(items_list, sort_search_items_list);
01242     
01243     /* add search items from temporary list */
01244     for (cis=items_list->first; cis; cis=cis->next) {
01245         if (!uiSearchItemAdd(items, cis->name, SET_INT_IN_POINTER(cis->index), cis->iconid)) {
01246             break;
01247         }
01248     }
01249 
01250     for (cis=items_list->first; cis; cis=cis->next) {
01251         MEM_freeN(cis->name);
01252     }
01253     BLI_freelistN(items_list);
01254     MEM_freeN(items_list);
01255 }
01256 
01257 static void search_id_collection(StructRNA *ptype, PointerRNA *ptr, PropertyRNA **prop)
01258 {
01259     StructRNA *srna;
01260 
01261     /* look for collection property in Main */
01262     RNA_main_pointer_create(G.main, ptr);
01263 
01264     *prop= NULL;
01265 
01266     RNA_STRUCT_BEGIN(ptr, iprop) {
01267         /* if it's a collection and has same pointer type, we've got it */
01268         if(RNA_property_type(iprop) == PROP_COLLECTION) {
01269             srna= RNA_property_pointer_type(ptr, iprop);
01270 
01271             if(ptype == srna) {
01272                 *prop= iprop;
01273                 break;
01274             }
01275         }
01276     }
01277     RNA_STRUCT_END;
01278 }
01279 
01280 void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop)
01281 {
01282     StructRNA *ptype;
01283     PointerRNA sptr;
01284 
01285     /* for ID's we do automatic lookup */
01286     if(!searchprop) {
01287         if(RNA_property_type(prop) == PROP_POINTER) {
01288             ptype= RNA_property_pointer_type(ptr, prop);
01289             search_id_collection(ptype, &sptr, &searchprop);
01290             searchptr= &sptr;
01291         }
01292     }
01293 
01294     /* turn button into search button */
01295     if(searchprop) {
01296         but->type= SEARCH_MENU;
01297         but->hardmax= MAX2(but->hardmax, 256);
01298         but->rnasearchpoin= *searchptr;
01299         but->rnasearchprop= searchprop;
01300         but->flag |= UI_ICON_LEFT|UI_TEXT_LEFT;
01301 
01302         uiButSetSearchFunc(but, rna_search_cb, but, NULL, NULL);
01303     }
01304 }
01305 
01306 void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
01307 {
01308     PropertyRNA *prop, *searchprop;
01309     PropertyType type;
01310     uiBut *but;
01311     uiBlock *block;
01312     StructRNA *icontype;
01313     int w, h;
01314     
01315     /* validate arguments */
01316     prop= RNA_struct_find_property(ptr, propname);
01317 
01318     if(!prop) {
01319         RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
01320         return;
01321     }
01322     
01323     type= RNA_property_type(prop);
01324     if(!ELEM(type, PROP_POINTER, PROP_STRING)) {
01325         RNA_warning("Property %s must be a pointer or string", propname);
01326         return;
01327     }
01328 
01329     searchprop= RNA_struct_find_property(searchptr, searchpropname);
01330 
01331 
01332     if(!searchprop) {
01333         RNA_warning("search collection property not found: %s.%s", RNA_struct_identifier(ptr->type), searchpropname);
01334         return;
01335     }
01336     else if (RNA_property_type(searchprop) != PROP_COLLECTION) {
01337         RNA_warning("search collection property is not a collection type: %s.%s", RNA_struct_identifier(ptr->type), searchpropname);
01338         return;
01339     }
01340 
01341     /* get icon & name */
01342     if(icon==ICON_NONE) {
01343         if(type == PROP_POINTER)
01344             icontype= RNA_property_pointer_type(ptr, prop);
01345         else
01346             icontype= RNA_property_pointer_type(searchptr, searchprop);
01347 
01348         icon= RNA_struct_ui_icon(icontype);
01349     }
01350     if(!name)
01351         name= RNA_property_ui_name(prop);
01352 
01353     /* create button */
01354     block= uiLayoutGetBlock(layout);
01355 
01356     ui_item_rna_size(layout, name, icon, ptr, prop, 0, 0, &w, &h);
01357     but= ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0);
01358 
01359     ui_but_add_search(but, ptr, prop, searchptr, searchprop);
01360 }
01361 
01362 /* menu item */
01363 static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
01364 {
01365     MenuType *mt= (MenuType*)arg_mt;
01366     Menu menu = {NULL};
01367 
01368     menu.type= mt;
01369     menu.layout= layout;
01370     mt->draw(C, &menu);
01371 }
01372 
01373 static void ui_item_menu(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN, const char *tip)
01374 {
01375     uiBlock *block= layout->root->block;
01376     uiBut *but;
01377     int w, h;
01378 
01379     uiBlockSetCurLayout(block, layout);
01380 
01381     if(layout->root->type == UI_LAYOUT_HEADER)
01382         uiBlockSetEmboss(block, UI_EMBOSS);
01383 
01384     if(!name)
01385         name= "";
01386     if(layout->root->type == UI_LAYOUT_MENU && !icon)
01387         icon= ICON_BLANK1;
01388 
01389     w= ui_text_icon_width(layout, name, icon, 1);
01390     h= UI_UNIT_Y;
01391 
01392     if(layout->root->type == UI_LAYOUT_HEADER) /* ugly .. */
01393         w -= 10;
01394 
01395     if(name[0] && icon)
01396         but= uiDefIconTextMenuBut(block, func, arg, icon, name, 0, 0, w, h, tip);
01397     else if(icon)
01398         but= uiDefIconMenuBut(block, func, arg, icon, 0, 0, w, h, tip);
01399     else
01400         but= uiDefMenuBut(block, func, arg, name, 0, 0, w, h, tip);
01401 
01402     if(argN) { /* ugly .. */
01403         but->poin= (char*)but;
01404         but->func_argN= argN;
01405     }
01406 
01407     if(layout->root->type == UI_LAYOUT_HEADER)
01408         uiBlockSetEmboss(block, UI_EMBOSS);
01409     else if(ELEM(layout->root->type, UI_LAYOUT_PANEL, UI_LAYOUT_TOOLBAR)) {
01410         but->type= MENU;
01411         but->flag |= UI_TEXT_LEFT;
01412     }
01413 }
01414 
01415 void uiItemM(uiLayout *layout, bContext *UNUSED(C), const char *menuname, const char *name, int icon)
01416 {
01417     MenuType *mt;
01418 
01419     mt= WM_menutype_find(menuname, FALSE);
01420 
01421     if(mt==NULL) {
01422         RNA_warning("not found %s", menuname);
01423         return;
01424     }
01425 
01426     if(!name) {
01427         name= IFACE_(mt->label);
01428     }
01429 
01430     if(layout->root->type == UI_LAYOUT_MENU && !icon)
01431         icon= ICON_BLANK1;
01432 
01433     ui_item_menu(layout, name, icon, ui_item_menutype_func, mt, NULL, mt->description);
01434 }
01435 
01436 /* label item */
01437 static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
01438 {
01439     uiBlock *block= layout->root->block;
01440     uiBut *but;
01441     int w;
01442 
01443     uiBlockSetCurLayout(block, layout);
01444 
01445     if(!name)
01446         name= "";
01447     if(layout->root->type == UI_LAYOUT_MENU && !icon)
01448         icon= ICON_BLANK1;
01449 
01450     w= ui_text_icon_width(layout, name, icon, 0);
01451 
01452     if(icon && name[0])
01453         but= uiDefIconTextBut(block, LABEL, 0, icon, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
01454     else if(icon)
01455         but= uiDefIconBut(block, LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
01456     else
01457         but= uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
01458     
01459     return but;
01460 }
01461 
01462 void uiItemL(uiLayout *layout, const char *name, int icon)
01463 {
01464     uiItemL_(layout, name, icon);
01465 }
01466 
01467 void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, const char *name, int icon)
01468 {
01469     uiBut *but= uiItemL_(layout, name, icon);
01470 
01471     if(ptr && ptr->type)
01472         if(RNA_struct_is_ID(ptr->type))
01473             uiButSetDragID(but, ptr->id.data);
01474 }
01475 
01476 
01477 /* value item */
01478 void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
01479 {
01480     /* label */
01481     uiBlock *block= layout->root->block;
01482     float *retvalue= (block->handle)? &block->handle->retvalue: NULL;
01483     int w;
01484 
01485     uiBlockSetCurLayout(block, layout);
01486 
01487     if(!name)
01488         name= "";
01489     if(layout->root->type == UI_LAYOUT_MENU && !icon)
01490         icon= ICON_BLANK1;
01491 
01492     w= ui_text_icon_width(layout, name, icon, 0);
01493 
01494     if(icon && name[0])
01495         uiDefIconTextButF(block, BUT, argval, icon, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, 0, "");
01496     else if(icon)
01497         uiDefIconButF(block, BUT, argval, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, 0, "");
01498     else
01499         uiDefButF(block, BUT, argval, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, 0, "");
01500 }
01501 
01502 /* separator item */
01503 void uiItemS(uiLayout *layout)
01504 {
01505     uiBlock *block= layout->root->block;
01506 
01507     uiBlockSetCurLayout(block, layout);
01508     uiDefBut(block, SEPR, 0, "", 0, 0, EM_SEPR_X, EM_SEPR_Y, NULL, 0.0, 0.0, 0, 0, "");
01509 }
01510 
01511 /* level items */
01512 void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
01513 {
01514     if(!func)
01515         return;
01516 
01517     ui_item_menu(layout, name, icon, func, arg, NULL, "");
01518 }
01519 
01520 typedef struct MenuItemLevel {
01521     int opcontext;
01522     /* dont use pointers to the strings because python can dynamically
01523      * allocate strings and free before the menu draws, see [#27304] */
01524     char opname[OP_MAX_TYPENAME];
01525     char propname[MAX_IDPROP_NAME];
01526     PointerRNA rnapoin;
01527 } MenuItemLevel;
01528 
01529 static void menu_item_enum_opname_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
01530 {
01531     MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
01532 
01533     uiLayoutSetOperatorContext(layout, lvl->opcontext);
01534     uiItemsEnumO(layout, lvl->opname, lvl->propname);
01535 }
01536 
01537 void uiItemMenuEnumO(uiLayout *layout, const char *opname, const char *propname, const char *name, int icon)
01538 {
01539     wmOperatorType *ot= WM_operatortype_find(opname, 1);
01540     MenuItemLevel *lvl;
01541 
01542     if(!ot) {
01543         ui_item_disabled(layout, opname);
01544         RNA_warning("unknown operator '%s'", opname);
01545         return;
01546     }
01547     if(!ot->srna) {
01548         ui_item_disabled(layout, opname);
01549         RNA_warning("operator missing srna '%s'", opname);
01550         return;
01551     }
01552 
01553     if(!name)
01554         name= ot->name;
01555     if(layout->root->type == UI_LAYOUT_MENU && !icon)
01556         icon= ICON_BLANK1;
01557 
01558     lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
01559     BLI_strncpy(lvl->opname, opname, sizeof(lvl->opname));
01560     BLI_strncpy(lvl->propname, propname, sizeof(lvl->propname));
01561     lvl->opcontext= layout->root->opcontext;
01562 
01563     ui_item_menu(layout, name, icon, menu_item_enum_opname_menu, NULL, lvl, ot->description);
01564 }
01565 
01566 static void menu_item_enum_rna_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
01567 {
01568     MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
01569 
01570     uiLayoutSetOperatorContext(layout, lvl->opcontext);
01571     uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
01572 }
01573 
01574 void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon)
01575 {
01576     MenuItemLevel *lvl;
01577     PropertyRNA *prop;
01578 
01579     prop= RNA_struct_find_property(ptr, propname);
01580     if(!prop) {
01581         ui_item_disabled(layout, propname);
01582         RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
01583         return;
01584     }
01585 
01586     if(!name)
01587         name= RNA_property_ui_name(prop);
01588     if(layout->root->type == UI_LAYOUT_MENU && !icon)
01589         icon= ICON_BLANK1;
01590 
01591     lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
01592     lvl->rnapoin= *ptr;
01593     BLI_strncpy(lvl->propname, propname, sizeof(lvl->propname));
01594     lvl->opcontext= layout->root->opcontext;
01595 
01596     ui_item_menu(layout, name, icon, menu_item_enum_rna_menu, NULL, lvl, RNA_property_description(prop));
01597 }
01598 
01599 /**************************** Layout Items ***************************/
01600 
01601 /* single-row layout */
01602 static void ui_litem_estimate_row(uiLayout *litem)
01603 {
01604     uiItem *item;
01605     int itemw, itemh;
01606 
01607     litem->w= 0;
01608     litem->h= 0;
01609 
01610     for(item=litem->items.first; item; item=item->next) {
01611         ui_item_size(item, &itemw, &itemh);
01612 
01613         litem->w += itemw;
01614         litem->h= MAX2(itemh, litem->h);
01615 
01616         if(item->next)
01617             litem->w += litem->space;
01618     }
01619 }
01620 
01621 static int ui_litem_min_width(int itemw)
01622 {
01623     return MIN2(2*UI_UNIT_X, itemw);
01624 }
01625 
01626 static void ui_litem_layout_row(uiLayout *litem)
01627 {
01628     uiItem *item;
01629     int x, y, w, tot, totw, neww, itemw, minw, itemh, offset;
01630     int fixedw, freew, fixedx, freex, flag= 0, lastw= 0;
01631 
01632     /* x= litem->x; */ /* UNUSED */
01633     y= litem->y;
01634     w= litem->w;
01635     totw= 0;
01636     tot= 0;
01637 
01638     for(item=litem->items.first; item; item=item->next) {
01639         ui_item_size(item, &itemw, &itemh);
01640         totw += itemw;
01641         tot++;
01642     }
01643 
01644     if(totw == 0)
01645         return;
01646     
01647     if(w != 0)
01648         w -= (tot-1)*litem->space;
01649     fixedw= 0;
01650 
01651     /* keep clamping items to fixed minimum size until all are done */
01652     do {
01653         freew= 0;
01654         x= 0;
01655         flag= 0;
01656 
01657         for(item=litem->items.first; item; item=item->next) {
01658             if(item->flag)
01659                 continue;
01660 
01661             ui_item_size(item, &itemw, &itemh);
01662             minw= ui_litem_min_width(itemw);
01663 
01664             if(w - lastw > 0)
01665                 neww= ui_item_fit(itemw, x, totw, w-lastw, !item->next, litem->alignment, NULL);
01666             else
01667                 neww= 0; /* no space left, all will need clamping to minimum size */
01668 
01669             x += neww;
01670 
01671             if((neww < minw || itemw == minw) && w != 0) {
01672                 /* fixed size */
01673                 item->flag= 1;
01674                 fixedw += minw;
01675                 flag= 1;
01676                 totw -= itemw;
01677             }
01678             else {
01679                 /* keep free size */
01680                 item->flag= 0;
01681                 freew += itemw;
01682             }
01683         }
01684 
01685         lastw= fixedw;
01686     } while(flag);
01687 
01688     freex= 0;
01689     fixedx= 0;
01690     x= litem->x;
01691 
01692     for(item=litem->items.first; item; item=item->next) {
01693         ui_item_size(item, &itemw, &itemh);
01694         minw= ui_litem_min_width(itemw);
01695 
01696         if(item->flag) {
01697             /* fixed minimum size items */
01698             itemw= ui_item_fit(minw, fixedx, fixedw, MIN2(w, fixedw), !item->next, litem->alignment, NULL);
01699             fixedx += itemw;
01700         }
01701         else {
01702             /* free size item */
01703             itemw= ui_item_fit(itemw, freex, freew, w-fixedw, !item->next, litem->alignment, NULL);
01704             freex += itemw;
01705         }
01706 
01707         /* align right/center */
01708         offset= 0;
01709         if(litem->alignment == UI_LAYOUT_ALIGN_RIGHT) {
01710             if(freew > 0 && freew < w-fixedw)
01711                 offset= (w - fixedw) - freew;
01712         }
01713         else if(litem->alignment == UI_LAYOUT_ALIGN_CENTER) {
01714             if(freew > 0 && freew < w-fixedw)
01715                 offset= ((w - fixedw) - freew)/2;
01716         }
01717 
01718         /* position item */
01719         ui_item_position(item, x+offset, y-itemh, itemw, itemh);
01720 
01721         x += itemw;
01722         if(item->next)
01723             x += litem->space;
01724     }
01725 
01726     litem->w= x - litem->x;
01727     litem->h= litem->y - y;
01728     litem->x= x;
01729     litem->y= y;
01730 }
01731 
01732 /* single-column layout */
01733 static void ui_litem_estimate_column(uiLayout *litem)
01734 {
01735     uiItem *item;
01736     int itemw, itemh;
01737 
01738     litem->w= 0;
01739     litem->h= 0;
01740 
01741     for(item=litem->items.first; item; item=item->next) {
01742         ui_item_size(item, &itemw, &itemh);
01743 
01744         litem->w= MAX2(litem->w, itemw);
01745         litem->h += itemh;
01746 
01747         if(item->next)
01748             litem->h += litem->space;
01749     }
01750 }
01751 
01752 static void ui_litem_layout_column(uiLayout *litem)
01753 {
01754     uiItem *item;
01755     int itemh, x, y;
01756 
01757     x= litem->x;
01758     y= litem->y;
01759 
01760     for(item=litem->items.first; item; item=item->next) {
01761         ui_item_size(item, NULL, &itemh);
01762 
01763         y -= itemh;
01764         ui_item_position(item, x, y, litem->w, itemh);
01765 
01766         if(item->next)
01767             y -= litem->space;
01768     }
01769 
01770     litem->h= litem->y - y;
01771     litem->x= x;
01772     litem->y= y;
01773 }
01774 
01775 /* root layout */
01776 static void ui_litem_estimate_root(uiLayout *UNUSED(litem))
01777 {
01778     /* nothing to do */
01779 }
01780 
01781 static void ui_litem_layout_root(uiLayout *litem)
01782 {
01783     if(litem->root->type == UI_LAYOUT_HEADER)
01784         ui_litem_layout_row(litem);
01785     else
01786         ui_litem_layout_column(litem);
01787 }
01788 
01789 /* box layout */
01790 static void ui_litem_estimate_box(uiLayout *litem)
01791 {
01792     uiStyle *style= litem->root->style;
01793 
01794     ui_litem_estimate_column(litem);
01795     litem->w += 2*style->boxspace;
01796     litem->h += style->boxspace;
01797 }
01798 
01799 static void ui_litem_layout_box(uiLayout *litem)
01800 {
01801     uiLayoutItemBx *box= (uiLayoutItemBx*)litem;
01802     uiStyle *style= litem->root->style;
01803     uiBut *but;
01804     int w, h;
01805 
01806     w= litem->w;
01807     h= litem->h;
01808 
01809     litem->x += style->boxspace;
01810 
01811     if(w != 0) litem->w -= 2*style->boxspace;
01812     if(h != 0) litem->h -= 2*style->boxspace;
01813 
01814     ui_litem_layout_column(litem);
01815 
01816     litem->x -= style->boxspace;
01817     litem->y -= style->boxspace;
01818 
01819     if(w != 0) litem->w += 2*style->boxspace;
01820     if(h != 0) litem->h += style->boxspace;
01821 
01822     /* roundbox around the sublayout */
01823     but= box->roundbox;
01824     but->x1= litem->x;
01825     but->y1= litem->y;
01826     but->x2= litem->x+litem->w;
01827     but->y2= litem->y+litem->h;
01828 }
01829 
01830 /* multi-column layout, automatically flowing to the next */
01831 static void ui_litem_estimate_column_flow(uiLayout *litem)
01832 {
01833     uiStyle *style= litem->root->style;
01834     uiLayoutItemFlow *flow= (uiLayoutItemFlow*)litem;
01835     uiItem *item;
01836     int col, x, y, emh, emy, miny, itemw, itemh, maxw=0;
01837     int toth, totitem;
01838 
01839     /* compute max needed width and total height */
01840     toth= 0;
01841     totitem= 0;
01842     for(item=litem->items.first; item; item=item->next) {
01843         ui_item_size(item, &itemw, &itemh);
01844         maxw= MAX2(maxw, itemw);
01845         toth += itemh;
01846         totitem++;
01847     }
01848 
01849     if(flow->number <= 0) {
01850         /* auto compute number of columns, not very good */
01851         if(maxw == 0) {
01852             flow->totcol= 1;
01853             return;
01854         }
01855 
01856         flow->totcol= MAX2(litem->root->emw/maxw, 1);
01857         flow->totcol= MIN2(flow->totcol, totitem);
01858     }
01859     else
01860         flow->totcol= flow->number;
01861 
01862     /* compute sizes */
01863     x= 0;
01864     y= 0;
01865     emy= 0;
01866     miny= 0;
01867 
01868     maxw= 0;
01869     emh= toth/flow->totcol;
01870 
01871     /* create column per column */
01872     col= 0;
01873     for(item=litem->items.first; item; item=item->next) {
01874         ui_item_size(item, &itemw, &itemh);
01875 
01876         y -= itemh + style->buttonspacey;
01877         miny= MIN2(miny, y);
01878         emy -= itemh;
01879         maxw= MAX2(itemw, maxw);
01880 
01881         /* decide to go to next one */
01882         if(col < flow->totcol-1 && emy <= -emh) {
01883             x += maxw + litem->space;
01884             maxw= 0;
01885             y= 0;
01886             col++;
01887         }
01888     }
01889 
01890     litem->w= x;
01891     litem->h= litem->y - miny;
01892 }
01893 
01894 static void ui_litem_layout_column_flow(uiLayout *litem)
01895 {
01896     uiStyle *style= litem->root->style;
01897     uiLayoutItemFlow *flow= (uiLayoutItemFlow*)litem;
01898     uiItem *item;
01899     int col, x, y, w, emh, emy, miny, itemw, itemh;
01900     int toth, totitem, offset;
01901 
01902     /* compute max needed width and total height */
01903     toth= 0;
01904     totitem= 0;
01905     for(item=litem->items.first; item; item=item->next) {
01906         ui_item_size(item, &itemw, &itemh);
01907         toth += itemh;
01908         totitem++;
01909     }
01910 
01911     /* compute sizes */
01912     x= litem->x;
01913     y= litem->y;
01914     emy= 0;
01915     miny= 0;
01916 
01917     w= litem->w - (flow->totcol-1)*style->columnspace;
01918     emh= toth/flow->totcol;
01919 
01920     /* create column per column */
01921     col= 0;
01922     for(item=litem->items.first; item; item=item->next) {
01923         ui_item_size(item, NULL, &itemh);
01924         itemw= ui_item_fit(1, x-litem->x, flow->totcol, w, col == flow->totcol-1, litem->alignment, &offset);
01925     
01926         y -= itemh;
01927         emy -= itemh;
01928         ui_item_position(item, x+offset, y, itemw, itemh);
01929         y -= style->buttonspacey;
01930         miny= MIN2(miny, y);
01931 
01932         /* decide to go to next one */
01933         if(col < flow->totcol-1 && emy <= -emh) {
01934             x += itemw + style->columnspace;
01935             y= litem->y;
01936             col++;
01937         }
01938     }
01939 
01940     litem->h= litem->y - miny;
01941     litem->x= x;
01942     litem->y= miny;
01943 }
01944 
01945 /* free layout */
01946 static void ui_litem_estimate_absolute(uiLayout *litem)
01947 {
01948     uiItem *item;
01949     int itemx, itemy, itemw, itemh, minx, miny;
01950 
01951     minx= 1e6;
01952     miny= 1e6;
01953     litem->w= 0;
01954     litem->h= 0;
01955 
01956     for(item=litem->items.first; item; item=item->next) {
01957         ui_item_offset(item, &itemx, &itemy);
01958         ui_item_size(item, &itemw, &itemh);
01959 
01960         minx= MIN2(minx, itemx);
01961         miny= MIN2(miny, itemy);
01962 
01963         litem->w= MAX2(litem->w, itemx+itemw);
01964         litem->h= MAX2(litem->h, itemy+itemh);
01965     }
01966 
01967     litem->w -= minx;
01968     litem->h -= miny;
01969 }
01970 
01971 static void ui_litem_layout_absolute(uiLayout *litem)
01972 {
01973     uiItem *item;
01974     float scalex=1.0f, scaley=1.0f;
01975     int x, y, newx, newy, itemx, itemy, itemh, itemw, minx, miny, totw, toth;
01976 
01977     minx= 1e6;
01978     miny= 1e6;
01979     totw= 0;
01980     toth= 0;
01981 
01982     for(item=litem->items.first; item; item=item->next) {
01983         ui_item_offset(item, &itemx, &itemy);
01984         ui_item_size(item, &itemw, &itemh);
01985 
01986         minx= MIN2(minx, itemx);
01987         miny= MIN2(miny, itemy);
01988 
01989         totw= MAX2(totw, itemx+itemw);
01990         toth= MAX2(toth, itemy+itemh);
01991     }
01992 
01993     totw -= minx;
01994     toth -= miny;
01995 
01996     if(litem->w && totw > 0)
01997         scalex= (float)litem->w/(float)totw;
01998     if(litem->h && toth > 0)
01999         scaley= (float)litem->h/(float)toth;
02000     
02001     x= litem->x;
02002     y= litem->y - scaley*toth;
02003 
02004     for(item=litem->items.first; item; item=item->next) {
02005         ui_item_offset(item, &itemx, &itemy);
02006         ui_item_size(item, &itemw, &itemh);
02007 
02008         if(scalex != 1.0f) {
02009             newx= (itemx - minx)*scalex;
02010             itemw= (itemx - minx + itemw)*scalex - newx;
02011             itemx= minx + newx;
02012         }
02013 
02014         if(scaley != 1.0f) {
02015             newy= (itemy - miny)*scaley;
02016             itemh= (itemy - miny + itemh)*scaley - newy;
02017             itemy= miny + newy;
02018         }
02019 
02020         ui_item_position(item, x+itemx-minx, y+itemy-miny, itemw, itemh);
02021     }
02022 
02023     litem->w= scalex*totw;
02024     litem->h= litem->y - y;
02025     litem->x= x + litem->w;
02026     litem->y= y;
02027 }
02028 
02029 /* split layout */
02030 static void ui_litem_estimate_split(uiLayout *litem)
02031 {
02032     ui_litem_estimate_row(litem);
02033 }
02034 
02035 static void ui_litem_layout_split(uiLayout *litem)
02036 {
02037     uiLayoutItemSplit *split= (uiLayoutItemSplit*)litem;
02038     uiItem *item;
02039     float percentage;
02040     const int tot= BLI_countlist(&litem->items);
02041     int itemh, x, y, w, colw=0;
02042 
02043     if(tot == 0)
02044         return;
02045 
02046     x= litem->x;
02047     y= litem->y;
02048 
02049     percentage= (split->percentage == 0.0f)? 1.0f/(float)tot: split->percentage;
02050     
02051     w= (litem->w - (tot-1)*litem->space);
02052     colw= w*percentage;
02053     colw= MAX2(colw, 0);
02054 
02055     for(item=litem->items.first; item; item=item->next) {
02056         ui_item_size(item, NULL, &itemh);
02057 
02058         ui_item_position(item, x, y-itemh, colw, itemh);
02059         x += colw;
02060 
02061         if(item->next) {
02062             colw= (w - (int)(w*percentage))/(tot-1);
02063             colw= MAX2(colw, 0);
02064 
02065             x += litem->space;
02066         }
02067     }
02068 
02069     litem->w= x - litem->x;
02070     litem->h= litem->y - y;
02071     litem->x= x;
02072     litem->y= y;
02073 }
02074 
02075 /* overlap layout */
02076 static void ui_litem_estimate_overlap(uiLayout *litem)
02077 {
02078     uiItem *item;
02079     int itemw, itemh;
02080 
02081     litem->w= 0;
02082     litem->h= 0;
02083 
02084     for(item=litem->items.first; item; item=item->next) {
02085         ui_item_size(item, &itemw, &itemh);
02086 
02087         litem->w= MAX2(itemw, litem->w);
02088         litem->h= MAX2(itemh, litem->h);
02089     }
02090 }
02091 
02092 static void ui_litem_layout_overlap(uiLayout *litem)
02093 {
02094     uiItem *item;
02095     int itemw, itemh, x, y;
02096 
02097     x= litem->x;
02098     y= litem->y;
02099 
02100     for(item=litem->items.first; item; item=item->next) {
02101         ui_item_size(item, &itemw, &itemh);
02102         ui_item_position(item, x, y-itemh, litem->w, itemh);
02103 
02104         litem->h= MAX2(litem->h, itemh);
02105     }
02106 
02107     litem->x= x;
02108     litem->y= y - litem->h;
02109 }
02110 
02111 /* layout create functions */
02112 uiLayout *uiLayoutRow(uiLayout *layout, int align)
02113 {
02114     uiLayout *litem;
02115 
02116     litem= MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
02117     litem->item.type= ITEM_LAYOUT_ROW;
02118     litem->root= layout->root;
02119     litem->align= align;
02120     litem->active= 1;
02121     litem->enabled= 1;
02122     litem->context= layout->context;
02123     litem->space= (align)? 0: layout->root->style->buttonspacex;
02124     litem->w = layout->w;
02125     BLI_addtail(&layout->items, litem);
02126 
02127     uiBlockSetCurLayout(layout->root->block, litem);
02128 
02129     return litem;
02130 }
02131 
02132 uiLayout *uiLayoutColumn(uiLayout *layout, int align)
02133 {
02134     uiLayout *litem;
02135 
02136     litem= MEM_callocN(sizeof(uiLayout), "uiLayoutColumn");
02137     litem->item.type= ITEM_LAYOUT_COLUMN;
02138     litem->root= layout->root;
02139     litem->align= align;
02140     litem->active= 1;
02141     litem->enabled= 1;
02142     litem->context= layout->context;
02143     litem->space= (litem->align)? 0: layout->root->style->buttonspacey;
02144     litem->w = layout->w;
02145     BLI_addtail(&layout->items, litem);
02146 
02147     uiBlockSetCurLayout(layout->root->block, litem);
02148 
02149     return litem;
02150 }
02151 
02152 uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align)
02153 {
02154     uiLayoutItemFlow *flow;
02155 
02156     flow= MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow");
02157     flow->litem.item.type= ITEM_LAYOUT_COLUMN_FLOW;
02158     flow->litem.root= layout->root;
02159     flow->litem.align= align;
02160     flow->litem.active= 1;
02161     flow->litem.enabled= 1;
02162     flow->litem.context= layout->context;
02163     flow->litem.space= (flow->litem.align)? 0: layout->root->style->columnspace;
02164     flow->litem.w = layout->w;
02165     flow->number= number;
02166     BLI_addtail(&layout->items, flow);
02167 
02168     uiBlockSetCurLayout(layout->root->block, &flow->litem);
02169 
02170     return &flow->litem;
02171 }
02172 
02173 static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
02174 {
02175     uiLayoutItemBx *box;
02176 
02177     box= MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx");
02178     box->litem.item.type= ITEM_LAYOUT_BOX;
02179     box->litem.root= layout->root;
02180     box->litem.active= 1;
02181     box->litem.enabled= 1;
02182     box->litem.context= layout->context;
02183     box->litem.space= layout->root->style->columnspace;
02184     box->litem.w = layout->w;
02185     BLI_addtail(&layout->items, box);
02186 
02187     uiBlockSetCurLayout(layout->root->block, &box->litem);
02188 
02189     box->roundbox= uiDefBut(layout->root->block, type, 0, "", 0, 0, 0, 0, NULL, 0.0, 0.0, 0, 0, "");
02190 
02191     return box;
02192 }
02193 
02194 uiLayout *uiLayoutBox(uiLayout *layout)
02195 {
02196     return (uiLayout*)ui_layout_box(layout, ROUNDBOX);
02197 }
02198 
02199 uiLayout *uiLayoutListBox(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr, PropertyRNA *actprop)
02200 {
02201     uiLayoutItemBx *box= ui_layout_box(layout, LISTBOX);
02202     uiBut *but= box->roundbox;
02203 
02204     but->rnasearchpoin= *ptr;
02205     but->rnasearchprop= prop;
02206     but->rnapoin= *actptr;
02207     but->rnaprop= actprop;
02208 
02209     return (uiLayout*)box;
02210 }
02211 
02212 uiLayout *uiLayoutAbsolute(uiLayout *layout, int align)
02213 {
02214     uiLayout *litem;
02215 
02216     litem= MEM_callocN(sizeof(uiLayout), "uiLayoutAbsolute");
02217     litem->item.type= ITEM_LAYOUT_ABSOLUTE;
02218     litem->root= layout->root;
02219     litem->align= align;
02220     litem->active= 1;
02221     litem->enabled= 1;
02222     litem->context= layout->context;
02223     BLI_addtail(&layout->items, litem);
02224 
02225     uiBlockSetCurLayout(layout->root->block, litem);
02226 
02227     return litem;
02228 }
02229 
02230 uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout)
02231 {
02232     uiBlock *block;
02233 
02234     block= uiLayoutGetBlock(layout);
02235     uiLayoutAbsolute(layout, 0);
02236 
02237     return block;
02238 }
02239 
02240 uiLayout *uiLayoutOverlap(uiLayout *layout)
02241 {
02242     uiLayout *litem;
02243 
02244     litem= MEM_callocN(sizeof(uiLayout), "uiLayoutOverlap");
02245     litem->item.type= ITEM_LAYOUT_OVERLAP;
02246     litem->root= layout->root;
02247     litem->active= 1;
02248     litem->enabled= 1;
02249     litem->context= layout->context;
02250     BLI_addtail(&layout->items, litem);
02251 
02252     uiBlockSetCurLayout(layout->root->block, litem);
02253 
02254     return litem;
02255 }
02256 
02257 uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align)
02258 {
02259     uiLayoutItemSplit *split;
02260 
02261     split= MEM_callocN(sizeof(uiLayoutItemSplit), "uiLayoutItemSplit");
02262     split->litem.item.type= ITEM_LAYOUT_SPLIT;
02263     split->litem.root= layout->root;
02264     split->litem.align= align;
02265     split->litem.active= 1;
02266     split->litem.enabled= 1;
02267     split->litem.context= layout->context;
02268     split->litem.space= layout->root->style->columnspace;
02269     split->litem.w= layout->w;
02270     split->percentage= percentage;
02271     BLI_addtail(&layout->items, split);
02272 
02273     uiBlockSetCurLayout(layout->root->block, &split->litem);
02274 
02275     return &split->litem;
02276 }
02277 
02278 void uiLayoutSetActive(uiLayout *layout, int active)
02279 {
02280     layout->active= active;
02281 }
02282 
02283 void uiLayoutSetEnabled(uiLayout *layout, int enabled)
02284 {
02285     layout->enabled= enabled;
02286 }
02287 
02288 void uiLayoutSetRedAlert(uiLayout *layout, int redalert)
02289 {
02290     layout->redalert= redalert;
02291 }
02292 
02293 void uiLayoutSetKeepAspect(uiLayout *layout, int keepaspect)
02294 {
02295     layout->keepaspect= keepaspect;
02296 }
02297 
02298 void uiLayoutSetAlignment(uiLayout *layout, int alignment)
02299 {
02300     layout->alignment= alignment;
02301 }
02302 
02303 void uiLayoutSetScaleX(uiLayout *layout, float scale)
02304 {
02305     layout->scale[0]= scale;
02306 }
02307 
02308 void uiLayoutSetScaleY(uiLayout *layout, float scale)
02309 {
02310     layout->scale[1]= scale;
02311 }
02312 
02313 int uiLayoutGetActive(uiLayout *layout)
02314 {
02315     return layout->active;
02316 }
02317 
02318 int uiLayoutGetEnabled(uiLayout *layout)
02319 {
02320     return layout->enabled;
02321 }
02322 
02323 int uiLayoutGetRedAlert(uiLayout *layout)
02324 {
02325     return layout->redalert;
02326 }
02327 
02328 int uiLayoutGetKeepAspect(uiLayout *layout)
02329 {
02330     return layout->keepaspect;
02331 }
02332 
02333 int uiLayoutGetAlignment(uiLayout *layout)
02334 {
02335     return layout->alignment;
02336 }
02337 
02338 int uiLayoutGetWidth(uiLayout *layout)
02339 {
02340     return layout->w;
02341 }
02342 
02343 float uiLayoutGetScaleX(uiLayout *layout)
02344 {
02345     return layout->scale[0];
02346 }
02347 
02348 float uiLayoutGetScaleY(uiLayout *layout)
02349 {
02350     return layout->scale[0];
02351 }
02352 
02353 /********************** Layout *******************/
02354 
02355 static void ui_item_scale(uiLayout *litem, float scale[2])
02356 {
02357     uiItem *item;
02358     int x, y, w, h;
02359 
02360     for(item=litem->items.last; item; item=item->prev) {
02361         ui_item_size(item, &w, &h);
02362         ui_item_offset(item, &x, &y);
02363 
02364         if(scale[0] != 0.0f) {
02365             x *= scale[0];
02366             w *= scale[0];
02367         }
02368 
02369         if(scale[1] != 0.0f) {
02370             y *= scale[1];
02371             h *= scale[1];
02372         }
02373 
02374         ui_item_position(item, x, y, w, h);
02375     }
02376 }
02377 
02378 static void ui_item_estimate(uiItem *item)
02379 {
02380     uiItem *subitem;
02381 
02382     if(item->type != ITEM_BUTTON) {
02383         uiLayout *litem= (uiLayout*)item;
02384 
02385         for(subitem=litem->items.first; subitem; subitem=subitem->next)
02386             ui_item_estimate(subitem);
02387 
02388         if(litem->items.first == NULL)
02389             return;
02390 
02391         if(litem->scale[0] != 0.0f || litem->scale[1] != 0.0f)
02392             ui_item_scale(litem, litem->scale);
02393 
02394         switch(litem->item.type) {
02395             case ITEM_LAYOUT_COLUMN:
02396                 ui_litem_estimate_column(litem);
02397                 break;
02398             case ITEM_LAYOUT_COLUMN_FLOW:
02399                 ui_litem_estimate_column_flow(litem);
02400                 break;
02401             case ITEM_LAYOUT_ROW:
02402                 ui_litem_estimate_row(litem);
02403                 break;
02404             case ITEM_LAYOUT_BOX:
02405                 ui_litem_estimate_box(litem);
02406                 break;
02407             case ITEM_LAYOUT_ROOT:
02408                 ui_litem_estimate_root(litem);
02409                 break;
02410             case ITEM_LAYOUT_ABSOLUTE:
02411                 ui_litem_estimate_absolute(litem);
02412                 break;
02413             case ITEM_LAYOUT_SPLIT:
02414                 ui_litem_estimate_split(litem);
02415                 break;
02416             case ITEM_LAYOUT_OVERLAP:
02417                 ui_litem_estimate_overlap(litem);
02418                 break;
02419             default:
02420                 break;
02421         }
02422     }
02423 }
02424 
02425 static void ui_item_align(uiLayout *litem, short nr)
02426 {
02427     uiItem *item;
02428     uiButtonItem *bitem;
02429     uiLayoutItemBx *box;
02430 
02431     for(item=litem->items.last; item; item=item->prev) {
02432         if(item->type == ITEM_BUTTON) {
02433             bitem= (uiButtonItem*)item;
02434             if(ui_but_can_align(bitem->but))
02435                 if(!bitem->but->alignnr)
02436                     bitem->but->alignnr= nr;
02437         }
02438         else if(item->type == ITEM_LAYOUT_ABSOLUTE);
02439         else if(item->type == ITEM_LAYOUT_OVERLAP);
02440         else if(item->type == ITEM_LAYOUT_BOX) {
02441             box= (uiLayoutItemBx*)item;
02442             box->roundbox->alignnr= nr;
02443             BLI_remlink(&litem->root->block->buttons, box->roundbox);
02444             BLI_addhead(&litem->root->block->buttons, box->roundbox);
02445         }
02446         else
02447             ui_item_align((uiLayout*)item, nr);
02448     }
02449 }
02450 
02451 static void ui_item_flag(uiLayout *litem, int flag)
02452 {
02453     uiItem *item;
02454     uiButtonItem *bitem;
02455 
02456     for(item=litem->items.last; item; item=item->prev) {
02457         if(item->type == ITEM_BUTTON) {
02458             bitem= (uiButtonItem*)item;
02459             bitem->but->flag |= flag;
02460         }
02461         else
02462             ui_item_flag((uiLayout*)item, flag);
02463     }
02464 }
02465 
02466 static void ui_item_layout(uiItem *item)
02467 {
02468     uiItem *subitem;
02469 
02470     if(item->type != ITEM_BUTTON) {
02471         uiLayout *litem= (uiLayout*)item;
02472 
02473         if(litem->items.first == NULL)
02474             return;
02475 
02476         if(litem->align)
02477             ui_item_align(litem, ++litem->root->block->alignnr);
02478         if(!litem->active)
02479             ui_item_flag(litem, UI_BUT_INACTIVE);
02480         if(!litem->enabled)
02481             ui_item_flag(litem, UI_BUT_DISABLED);
02482 
02483         switch(litem->item.type) {
02484             case ITEM_LAYOUT_COLUMN:
02485                 ui_litem_layout_column(litem);
02486                 break;
02487             case ITEM_LAYOUT_COLUMN_FLOW:
02488                 ui_litem_layout_column_flow(litem);
02489                 break;
02490             case ITEM_LAYOUT_ROW:
02491                 ui_litem_layout_row(litem);
02492                 break;
02493             case ITEM_LAYOUT_BOX:
02494                 ui_litem_layout_box(litem);
02495                 break;
02496             case ITEM_LAYOUT_ROOT:
02497                 ui_litem_layout_root(litem);
02498                 break;
02499             case ITEM_LAYOUT_ABSOLUTE:
02500                 ui_litem_layout_absolute(litem);
02501                 break;
02502             case ITEM_LAYOUT_SPLIT:
02503                 ui_litem_layout_split(litem);
02504                 break;
02505             case ITEM_LAYOUT_OVERLAP:
02506                 ui_litem_layout_overlap(litem);
02507                 break;
02508             default:
02509                 break;
02510         }
02511 
02512         for(subitem=litem->items.first; subitem; subitem=subitem->next)
02513             ui_item_layout(subitem);
02514     }
02515 }
02516 
02517 static void ui_layout_end(uiBlock *block, uiLayout *layout, int *x, int *y)
02518 {
02519     if(layout->root->handlefunc)
02520         uiBlockSetHandleFunc(block, layout->root->handlefunc, layout->root->argv);
02521 
02522     ui_item_estimate(&layout->item);
02523     ui_item_layout(&layout->item);
02524 
02525     if(x) *x= layout->x;
02526     if(y) *y= layout->y;
02527 }
02528 
02529 static void ui_layout_free(uiLayout *layout)
02530 {
02531     uiItem *item, *next;
02532 
02533     for(item=layout->items.first; item; item=next) {
02534         next= item->next;
02535 
02536         if(item->type == ITEM_BUTTON)
02537             MEM_freeN(item);
02538         else
02539             ui_layout_free((uiLayout*)item);
02540     }
02541 
02542     MEM_freeN(layout);
02543 }
02544 
02545 uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int size, int em, uiStyle *style)
02546 {
02547     uiLayout *layout;
02548     uiLayoutRoot *root;
02549 
02550     root= MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot");
02551     root->type= type;
02552     root->style= style;
02553     root->block= block;
02554     root->opcontext= WM_OP_INVOKE_REGION_WIN;
02555 
02556     layout= MEM_callocN(sizeof(uiLayout), "uiLayout");
02557     layout->item.type= ITEM_LAYOUT_ROOT;
02558 
02559     layout->x= x;
02560     layout->y= y;
02561     layout->root= root;
02562     layout->space= style->templatespace;
02563     layout->active= 1;
02564     layout->enabled= 1;
02565     layout->context= NULL;
02566 
02567     if(type == UI_LAYOUT_MENU)
02568         layout->space= 0;
02569 
02570     if(dir == UI_LAYOUT_HORIZONTAL) {
02571         layout->h= size;
02572         layout->root->emh= em*UI_UNIT_Y;
02573     }
02574     else {
02575         layout->w= size;
02576         layout->root->emw= em*UI_UNIT_X;
02577     }
02578 
02579     block->curlayout= layout;
02580     root->layout= layout;
02581     BLI_addtail(&block->layouts, root);
02582     
02583     return layout;
02584 }
02585 
02586 uiBlock *uiLayoutGetBlock(uiLayout *layout)
02587 {
02588     return layout->root->block;
02589 }
02590 
02591 int uiLayoutGetOperatorContext(uiLayout *layout)
02592 {
02593     return layout->root->opcontext;
02594 }
02595 
02596 
02597 void uiBlockSetCurLayout(uiBlock *block, uiLayout *layout)
02598 {
02599     block->curlayout= layout;
02600 }
02601 
02602 void ui_layout_add_but(uiLayout *layout, uiBut *but)
02603 {
02604     uiButtonItem *bitem;
02605     
02606     bitem= MEM_callocN(sizeof(uiButtonItem), "uiButtonItem");
02607     bitem->item.type= ITEM_BUTTON;
02608     bitem->but= but;
02609     BLI_addtail(&layout->items, bitem);
02610 
02611     if(layout->context) {
02612         but->context= layout->context;
02613         but->context->used= 1;
02614     }
02615 }
02616 
02617 void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
02618 {
02619     layout->root->opcontext= opcontext;
02620 }
02621 
02622 void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
02623 {
02624     layout->root->handlefunc= handlefunc;
02625     layout->root->argv= argv;
02626 }
02627 
02628 void uiBlockLayoutResolve(uiBlock *block, int *x, int *y)
02629 {
02630     uiLayoutRoot *root;
02631 
02632     if(x) *x= 0;
02633     if(y) *y= 0;
02634 
02635     block->curlayout= NULL;
02636 
02637     for(root=block->layouts.first; root; root=root->next) {
02638         /* NULL in advance so we don't interfere when adding button */
02639         ui_layout_end(block, root->layout, x, y);
02640         ui_layout_free(root->layout);
02641     }
02642 
02643     BLI_freelistN(&block->layouts);
02644 
02645     /* XXX silly trick, interface_templates.c doesn't get linked
02646      * because it's not used by other files in this module? */
02647     {
02648         UI_template_fix_linking();
02649     }
02650 }
02651 
02652 void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
02653 {
02654     uiBlock *block= layout->root->block;
02655     layout->context= CTX_store_add(&block->contexts, name, ptr);
02656 }
02657 
02658 
02659 /* introspect funcs */
02660 #include "BLI_dynstr.h"
02661 
02662 static void ui_intro_button(DynStr *ds, uiButtonItem *bitem)
02663 {
02664     uiBut *but = bitem->but;
02665     BLI_dynstr_appendf(ds, "'type':%d, ", but->type); /* see ~ UI_interface.h:200 */
02666     BLI_dynstr_appendf(ds, "'draw_string':'''%s''', ", but->drawstr);
02667     BLI_dynstr_appendf(ds, "'tip':'''%s''', ", but->tip ? but->tip : ""); // not exactly needed, rna has this
02668 
02669     if(but->optype) {
02670         char *opstr = WM_operator_pystring(but->block->evil_C, but->optype, but->opptr, 0);
02671         BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr ? opstr : "");
02672         MEM_freeN(opstr);
02673     }
02674 
02675     if(but->rnaprop) {
02676         BLI_dynstr_appendf(ds, "'rna':'%s.%s[%d]', ", RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop), but->rnaindex);
02677     }
02678 
02679 }
02680 
02681 static void ui_intro_items(DynStr *ds, ListBase *lb)
02682 {
02683     uiItem *item;
02684 
02685     BLI_dynstr_append(ds, "[");
02686 
02687     for(item=lb->first; item; item=item->next) {
02688 
02689         BLI_dynstr_append(ds, "{");
02690 
02691         /* could also use the INT but this is nicer*/
02692         switch(item->type) {
02693         case ITEM_BUTTON:           BLI_dynstr_append(ds, "'type':'BUTTON', ");break;
02694         case ITEM_LAYOUT_ROW:       BLI_dynstr_append(ds, "'type':'ROW', "); break;
02695         case ITEM_LAYOUT_COLUMN:    BLI_dynstr_append(ds, "'type':'COLUMN', "); break;
02696         case ITEM_LAYOUT_COLUMN_FLOW:BLI_dynstr_append(ds, "'type':'COLUMN_FLOW', "); break;
02697         case ITEM_LAYOUT_ROW_FLOW:  BLI_dynstr_append(ds, "'type':'ROW_FLOW', "); break;
02698         case ITEM_LAYOUT_BOX:       BLI_dynstr_append(ds, "'type':'BOX', "); break;
02699         case ITEM_LAYOUT_ABSOLUTE:  BLI_dynstr_append(ds, "'type':'ABSOLUTE', "); break;
02700         case ITEM_LAYOUT_SPLIT:     BLI_dynstr_append(ds, "'type':'SPLIT', "); break;
02701         case ITEM_LAYOUT_OVERLAP:   BLI_dynstr_append(ds, "'type':'OVERLAP', "); break;
02702         case ITEM_LAYOUT_ROOT:      BLI_dynstr_append(ds, "'type':'ROOT', "); break;
02703         default:                    BLI_dynstr_append(ds, "'type':'UNKNOWN', "); break;
02704         }
02705 
02706         switch(item->type) {
02707         case ITEM_BUTTON:
02708             ui_intro_button(ds, (uiButtonItem *)item);
02709             break;
02710         default:
02711             BLI_dynstr_append(ds, "'items':");
02712             ui_intro_items(ds, &((uiLayout*)item)->items);
02713             break;
02714         }
02715 
02716         BLI_dynstr_append(ds, "}");
02717 
02718         if(item != lb->last)
02719             BLI_dynstr_append(ds, ", ");
02720     }
02721     BLI_dynstr_append(ds, "], ");
02722 }
02723 
02724 static void ui_intro_uiLayout(DynStr *ds, uiLayout *layout)
02725 {
02726     ui_intro_items(ds, &layout->items);
02727 }
02728 
02729 static char *str = NULL; // XXX, constant re-freeing, far from ideal.
02730 const char *uiLayoutIntrospect(uiLayout *layout)
02731 {
02732     DynStr *ds= BLI_dynstr_new();
02733 
02734     if(str)
02735         MEM_freeN(str);
02736 
02737     ui_intro_uiLayout(ds, layout);
02738 
02739     str = BLI_dynstr_get_cstring(ds);
02740     BLI_dynstr_free(ds);
02741 
02742     return str;
02743 }
02744 
02745 static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C), void *op_pt, void *UNUSED(arg_dummy2))
02746 {
02747     WM_operator_properties_reset((wmOperator *)op_pt);
02748 }
02749 
02750 /* this function does not initialize the layout, functions can be called on the layout before and after */
02751 void uiLayoutOperatorButs(const bContext *C, uiLayout *layout, wmOperator *op,int (*check_prop)(struct PointerRNA *, struct PropertyRNA *), const char label_align, const short flag)
02752 {
02753     if(!op->properties) {
02754         IDPropertyTemplate val = {0};
02755         op->properties= IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
02756     }
02757 
02758     if(flag & UI_LAYOUT_OP_SHOW_TITLE) {
02759         uiItemL(layout, op->type->name, ICON_NONE);
02760     }
02761 
02762     /* poll() on this operator may still fail, at the moment there is no nice feedback when this happens
02763      * just fails silently */
02764     if(!WM_operator_repeat_check(C, op)) {
02765         uiBlockSetButLock(uiLayoutGetBlock(layout), TRUE, "Operator cannot redo");
02766         uiItemL(layout, "* Redo Unsupported *", ICON_NONE); // XXX, could give some nicer feedback or not show redo panel at all?
02767     }
02768 
02769     /* menu */
02770     if(op->type->flag & OPTYPE_PRESET) {
02771         /* XXX, no simple way to get WM_MT_operator_presets.bl_label from python! Label remains the same always! */
02772         PointerRNA op_ptr;
02773         uiLayout *row;
02774 
02775         uiLayoutGetBlock(layout)->ui_operator= op;
02776 
02777         row= uiLayoutRow(layout, TRUE);
02778         uiItemM(row, (bContext *)C, "WM_MT_operator_presets", NULL, ICON_NONE);
02779 
02780         WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add");
02781         RNA_string_set(&op_ptr, "operator", op->type->idname);
02782         op_ptr= uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMIN, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
02783 
02784         WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add");
02785         RNA_string_set(&op_ptr, "operator", op->type->idname);
02786         RNA_boolean_set(&op_ptr, "remove_active", TRUE);
02787         op_ptr= uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMOUT, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
02788     }
02789 
02790     if(op->type->ui) {
02791         op->layout= layout;
02792         op->type->ui((bContext*)C, op);
02793         op->layout= NULL;
02794 
02795         /* UI_LAYOUT_OP_SHOW_EMPTY ignored */
02796     }
02797     else {
02798         wmWindowManager *wm= CTX_wm_manager(C);
02799         PointerRNA ptr;
02800         int empty;
02801 
02802         RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
02803 
02804         /* main draw call */
02805         empty= uiDefAutoButsRNA(layout, &ptr, check_prop, label_align) == 0;
02806 
02807         if(empty && (flag & UI_LAYOUT_OP_SHOW_EMPTY)) {
02808             uiItemL(layout, IFACE_("No Properties"), ICON_NONE);
02809         }
02810     }
02811 
02812     /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled
02813      * but this is not so important if this button is drawn in those cases
02814      * (which isn't all that likely anyway) - campbell */
02815     if (op->properties->len) {
02816         uiBlock *block;
02817         uiBut *but;
02818         uiLayout *col; /* needed to avoid alignment errors with previous buttons */
02819 
02820         col= uiLayoutColumn(layout, 0);
02821         block= uiLayoutGetBlock(col);
02822         but = uiDefIconTextBut(block , BUT, 0, ICON_FILE_REFRESH, "Reset", 0, 0, 18, 20, NULL, 0.0, 0.0, 0.0, 0.0,
02823                                "Reset operator defaults");
02824         uiButSetFunc(but, ui_layout_operator_buts__reset_cb, op, NULL);
02825     }
02826 
02827     /* set various special settings for buttons */
02828     {
02829         uiBut *but;
02830         
02831         for(but= uiLayoutGetBlock(layout)->buttons.first; but; but= but->next) {
02832             /* no undo for buttons for operator redo panels */
02833             uiButClearFlag(but, UI_BUT_UNDO);
02834             
02835             /* if button is operator's default property, and a text-field, enable focus for it
02836              *  - this is used for allowing operators with popups to rename stuff with fewer clicks
02837              */
02838             if ((but->rnaprop == op->type->prop) && (but->type == TEX)) {
02839                 uiButSetFocusOnEnter(CTX_wm_window(C), but);
02840             }
02841         }
02842     }
02843 }
02844 
02845 /* this is a bit of a hack but best keep it in one place at least */
02846 MenuType *uiButGetMenuType(uiBut *but)
02847 {
02848     if(but->menu_create_func == ui_item_menutype_func) {
02849         return (MenuType *)but->poin;
02850     }
02851     else {
02852         return NULL;
02853     }
02854 }