Blender V2.61 - r43446
|
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 }