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