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 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * Contributor(s): Blender Foundation 2002-2008, full recode. 00022 * 00023 * ***** END GPL LICENSE BLOCK ***** 00024 */ 00025 00031 #include <float.h> 00032 #include <limits.h> 00033 #include <math.h> 00034 #include <string.h> 00035 #include <ctype.h> 00036 00037 #include "MEM_guardedalloc.h" 00038 00039 #include "DNA_scene_types.h" 00040 #include "DNA_screen_types.h" 00041 #include "DNA_userdef_types.h" 00042 00043 #include "BLI_math.h" 00044 #include "BLI_blenlib.h" 00045 #include "BLI_dynstr.h" 00046 #include "BLI_utildefines.h" 00047 00048 #include "BKE_context.h" 00049 #include "BKE_library.h" 00050 #include "BKE_unit.h" 00051 #include "BKE_screen.h" 00052 #include "BKE_idprop.h" 00053 #include "BKE_utildefines.h" /* FILE_MAX */ 00054 00055 #include "BIF_gl.h" 00056 00057 #include "BLF_api.h" 00058 #include "BLF_translation.h" 00059 00060 #include "UI_interface.h" 00061 00062 #include "IMB_imbuf.h" 00063 00064 #include "WM_api.h" 00065 #include "WM_types.h" 00066 #include "wm_subwindow.h" 00067 #include "wm_window.h" 00068 00069 #include "RNA_access.h" 00070 00071 #include "BPY_extern.h" 00072 00073 #include "interface_intern.h" 00074 00075 #define MENU_WIDTH 120 00076 #define MENU_ITEM_HEIGHT 20 00077 #define MENU_SEP_HEIGHT 6 00078 00079 #define PRECISION_FLOAT_MAX 6 00080 #define PRECISION_FLOAT_MAX_POW 1000000 /* pow(10, PRECISION_FLOAT_MAX) */ 00081 00082 /* avoid unneeded calls to ui_get_but_val */ 00083 #define UI_BUT_VALUE_UNSET DBL_MAX 00084 #define UI_GET_BUT_VALUE_INIT(_but, _value) if(_value == DBL_MAX) { (_value)= ui_get_but_val(_but); } 00085 00086 /* 00087 * a full doc with API notes can be found in bf-blender/trunk/blender/doc/guides/interface_API.txt 00088 * 00089 * uiBlahBlah() external function 00090 * ui_blah_blah() internal function 00091 */ 00092 00093 static void ui_free_but(const bContext *C, uiBut *but); 00094 00095 /* ************* window matrix ************** */ 00096 00097 void ui_block_to_window_fl(const ARegion *ar, uiBlock *block, float *x, float *y) 00098 { 00099 float gx, gy; 00100 int sx, sy, getsizex, getsizey; 00101 00102 getsizex= ar->winrct.xmax-ar->winrct.xmin+1; 00103 getsizey= ar->winrct.ymax-ar->winrct.ymin+1; 00104 sx= ar->winrct.xmin; 00105 sy= ar->winrct.ymin; 00106 00107 gx= *x; 00108 gy= *y; 00109 00110 if(block->panel) { 00111 gx += block->panel->ofsx; 00112 gy += block->panel->ofsy; 00113 } 00114 00115 *x= ((float)sx) + ((float)getsizex)*(0.5f+ 0.5f*(gx*block->winmat[0][0]+ gy*block->winmat[1][0]+ block->winmat[3][0])); 00116 *y= ((float)sy) + ((float)getsizey)*(0.5f+ 0.5f*(gx*block->winmat[0][1]+ gy*block->winmat[1][1]+ block->winmat[3][1])); 00117 } 00118 00119 void ui_block_to_window(const ARegion *ar, uiBlock *block, int *x, int *y) 00120 { 00121 float fx, fy; 00122 00123 fx= *x; 00124 fy= *y; 00125 00126 ui_block_to_window_fl(ar, block, &fx, &fy); 00127 00128 *x= (int)(fx+0.5f); 00129 *y= (int)(fy+0.5f); 00130 } 00131 00132 void ui_block_to_window_rct(const ARegion *ar, uiBlock *block, rctf *graph, rcti *winr) 00133 { 00134 rctf tmpr; 00135 00136 tmpr= *graph; 00137 ui_block_to_window_fl(ar, block, &tmpr.xmin, &tmpr.ymin); 00138 ui_block_to_window_fl(ar, block, &tmpr.xmax, &tmpr.ymax); 00139 00140 winr->xmin= tmpr.xmin; 00141 winr->ymin= tmpr.ymin; 00142 winr->xmax= tmpr.xmax; 00143 winr->ymax= tmpr.ymax; 00144 } 00145 00146 void ui_window_to_block_fl(const ARegion *ar, uiBlock *block, float *x, float *y) /* for mouse cursor */ 00147 { 00148 float a, b, c, d, e, f, px, py; 00149 int sx, sy, getsizex, getsizey; 00150 00151 getsizex= ar->winrct.xmax-ar->winrct.xmin+1; 00152 getsizey= ar->winrct.ymax-ar->winrct.ymin+1; 00153 sx= ar->winrct.xmin; 00154 sy= ar->winrct.ymin; 00155 00156 a= 0.5f*((float)getsizex)*block->winmat[0][0]; 00157 b= 0.5f*((float)getsizex)*block->winmat[1][0]; 00158 c= 0.5f*((float)getsizex)*(1.0f+block->winmat[3][0]); 00159 00160 d= 0.5f*((float)getsizey)*block->winmat[0][1]; 00161 e= 0.5f*((float)getsizey)*block->winmat[1][1]; 00162 f= 0.5f*((float)getsizey)*(1.0f+block->winmat[3][1]); 00163 00164 px= *x - sx; 00165 py= *y - sy; 00166 00167 *y= (a*(py-f) + d*(c-px))/(a*e-d*b); 00168 *x= (px- b*(*y)- c)/a; 00169 00170 if(block->panel) { 00171 *x -= block->panel->ofsx; 00172 *y -= block->panel->ofsy; 00173 } 00174 } 00175 00176 void ui_window_to_block(const ARegion *ar, uiBlock *block, int *x, int *y) 00177 { 00178 float fx, fy; 00179 00180 fx= *x; 00181 fy= *y; 00182 00183 ui_window_to_block_fl(ar, block, &fx, &fy); 00184 00185 *x= (int)(fx+0.5f); 00186 *y= (int)(fy+0.5f); 00187 } 00188 00189 void ui_window_to_region(const ARegion *ar, int *x, int *y) 00190 { 00191 *x-= ar->winrct.xmin; 00192 *y-= ar->winrct.ymin; 00193 } 00194 00195 /* ******************* block calc ************************* */ 00196 00197 void ui_block_translate(uiBlock *block, int x, int y) 00198 { 00199 uiBut *bt; 00200 00201 for(bt= block->buttons.first; bt; bt=bt->next) { 00202 bt->x1 += x; 00203 bt->y1 += y; 00204 bt->x2 += x; 00205 bt->y2 += y; 00206 } 00207 00208 block->minx += x; 00209 block->miny += y; 00210 block->maxx += x; 00211 block->maxy += y; 00212 } 00213 00214 static void ui_text_bounds_block(uiBlock *block, float offset) 00215 { 00216 uiStyle *style=UI_GetStyle(); 00217 uiBut *bt; 00218 int i = 0, j, x1addval= offset, nextcol; 00219 int lastcol= 0, col= 0; 00220 00221 uiStyleFontSet(&style->widget); 00222 00223 for(bt= block->buttons.first; bt; bt= bt->next) { 00224 if(bt->type!=SEPR) { 00225 j= BLF_width(style->widget.uifont_id, bt->drawstr); 00226 00227 if(j > i) i = j; 00228 } 00229 00230 if(bt->next && bt->x1 < bt->next->x1) 00231 lastcol++; 00232 } 00233 00234 /* cope with multi collumns */ 00235 bt= block->buttons.first; 00236 while(bt) { 00237 if(bt->next && bt->x1 < bt->next->x1) { 00238 nextcol= 1; 00239 col++; 00240 } 00241 else nextcol= 0; 00242 00243 bt->x1 = x1addval; 00244 bt->x2 = bt->x1 + i + block->bounds; 00245 00246 if(col == lastcol) 00247 bt->x2= MAX2(bt->x2, offset + block->minbounds); 00248 00249 ui_check_but(bt); // clips text again 00250 00251 if(nextcol) 00252 x1addval+= i + block->bounds; 00253 00254 bt= bt->next; 00255 } 00256 } 00257 00258 void ui_bounds_block(uiBlock *block) 00259 { 00260 uiBut *bt; 00261 int xof; 00262 00263 if(block->buttons.first==NULL) { 00264 if(block->panel) { 00265 block->minx= 0.0; block->maxx= block->panel->sizex; 00266 block->miny= 0.0; block->maxy= block->panel->sizey; 00267 } 00268 } 00269 else { 00270 00271 block->minx= block->miny= 10000; 00272 block->maxx= block->maxy= -10000; 00273 00274 bt= block->buttons.first; 00275 while(bt) { 00276 if(bt->x1 < block->minx) block->minx= bt->x1; 00277 if(bt->y1 < block->miny) block->miny= bt->y1; 00278 00279 if(bt->x2 > block->maxx) block->maxx= bt->x2; 00280 if(bt->y2 > block->maxy) block->maxy= bt->y2; 00281 00282 bt= bt->next; 00283 } 00284 00285 block->minx -= block->bounds; 00286 block->miny -= block->bounds; 00287 block->maxx += block->bounds; 00288 block->maxy += block->bounds; 00289 } 00290 00291 block->maxx= block->minx + MAX2(block->maxx - block->minx, block->minbounds); 00292 00293 /* hardcoded exception... but that one is annoying with larger safety */ 00294 bt= block->buttons.first; 00295 if(bt && strncmp(bt->str, "ERROR", 5)==0) xof= 10; 00296 else xof= 40; 00297 00298 block->safety.xmin= block->minx-xof; 00299 block->safety.ymin= block->miny-xof; 00300 block->safety.xmax= block->maxx+xof; 00301 block->safety.ymax= block->maxy+xof; 00302 } 00303 00304 static void ui_centered_bounds_block(const bContext *C, uiBlock *block) 00305 { 00306 wmWindow *window= CTX_wm_window(C); 00307 int xmax, ymax; 00308 int startx, starty; 00309 int width, height; 00310 00311 /* note: this is used for the splash where window bounds event has not been 00312 * updated by ghost, get the window bounds from ghost directly */ 00313 00314 // wm_window_get_size(window, &xmax, &ymax); 00315 wm_window_get_size_ghost(window, &xmax, &ymax); 00316 00317 ui_bounds_block(block); 00318 00319 width= block->maxx - block->minx; 00320 height= block->maxy - block->miny; 00321 00322 startx = (xmax * 0.5f) - (width * 0.5f); 00323 starty = (ymax * 0.5f) - (height * 0.5f); 00324 00325 ui_block_translate(block, startx - block->minx, starty - block->miny); 00326 00327 /* now recompute bounds and safety */ 00328 ui_bounds_block(block); 00329 00330 } 00331 static void ui_popup_bounds_block(const bContext *C, uiBlock *block, int bounds_calc) 00332 { 00333 wmWindow *window= CTX_wm_window(C); 00334 int startx, starty, endx, endy, width, height, oldwidth, oldheight; 00335 int oldbounds, xmax, ymax; 00336 00337 oldbounds= block->bounds; 00338 00339 /* compute mouse position with user defined offset */ 00340 ui_bounds_block(block); 00341 00342 wm_window_get_size(window, &xmax, &ymax); 00343 00344 oldwidth= block->maxx - block->minx; 00345 oldheight= block->maxy - block->miny; 00346 00347 /* first we ensure wide enough text bounds */ 00348 if(bounds_calc==UI_BLOCK_BOUNDS_POPUP_MENU) { 00349 if(block->flag & UI_BLOCK_LOOP) { 00350 block->bounds= 50; 00351 ui_text_bounds_block(block, block->minx); 00352 } 00353 } 00354 00355 /* next we recompute bounds */ 00356 block->bounds= oldbounds; 00357 ui_bounds_block(block); 00358 00359 /* and we adjust the position to fit within window */ 00360 width= block->maxx - block->minx; 00361 height= block->maxy - block->miny; 00362 00363 /* avoid divide by zero below, caused by calling with no UI, but better not crash */ 00364 oldwidth= oldwidth > 0 ? oldwidth : MAX2(1, width); 00365 oldheight= oldheight > 0 ? oldheight : MAX2(1, height); 00366 00367 /* offset block based on mouse position, user offset is scaled 00368 * along in case we resized the block in ui_text_bounds_block */ 00369 startx= window->eventstate->x + block->minx + (block->mx*width)/oldwidth; 00370 starty= window->eventstate->y + block->miny + (block->my*height)/oldheight; 00371 00372 if(startx<10) 00373 startx= 10; 00374 if(starty<10) 00375 starty= 10; 00376 00377 endx= startx+width; 00378 endy= starty+height; 00379 00380 if(endx>xmax) { 00381 endx= xmax-10; 00382 startx= endx-width; 00383 } 00384 if(endy>ymax-20) { 00385 endy= ymax-20; 00386 starty= endy-height; 00387 } 00388 00389 ui_block_translate(block, startx - block->minx, starty - block->miny); 00390 00391 /* now recompute bounds and safety */ 00392 ui_bounds_block(block); 00393 } 00394 00395 /* used for various cases */ 00396 void uiBoundsBlock(uiBlock *block, int addval) 00397 { 00398 if(block==NULL) 00399 return; 00400 00401 block->bounds= addval; 00402 block->dobounds= UI_BLOCK_BOUNDS; 00403 } 00404 00405 /* used for pulldowns */ 00406 void uiTextBoundsBlock(uiBlock *block, int addval) 00407 { 00408 block->bounds= addval; 00409 block->dobounds= UI_BLOCK_BOUNDS_TEXT; 00410 } 00411 00412 /* used for block popups */ 00413 void uiPopupBoundsBlock(uiBlock *block, int addval, int mx, int my) 00414 { 00415 block->bounds= addval; 00416 block->dobounds= UI_BLOCK_BOUNDS_POPUP_MOUSE; 00417 block->mx= mx; 00418 block->my= my; 00419 } 00420 00421 /* used for menu popups */ 00422 void uiMenuPopupBoundsBlock(uiBlock *block, int addval, int mx, int my) 00423 { 00424 block->bounds= addval; 00425 block->dobounds= UI_BLOCK_BOUNDS_POPUP_MENU; 00426 block->mx= mx; 00427 block->my= my; 00428 } 00429 00430 /* used for centered popups, i.e. splash */ 00431 void uiCenteredBoundsBlock(uiBlock *block, int addval) 00432 { 00433 block->bounds= addval; 00434 block->dobounds= UI_BLOCK_BOUNDS_POPUP_CENTER; 00435 } 00436 00437 void uiExplicitBoundsBlock(uiBlock *block, int minx, int miny, int maxx, int maxy) 00438 { 00439 block->minx = minx; 00440 block->miny = miny; 00441 block->maxx = maxx; 00442 block->maxy = maxy; 00443 block->dobounds = 0; 00444 } 00445 00446 /* ************** LINK LINE DRAWING ************* */ 00447 00448 /* link line drawing is not part of buttons or theme.. so we stick with it here */ 00449 00450 static int ui_but_float_precision(uiBut *but, double value) 00451 { 00452 int prec; 00453 00454 /* first check if prec is 0 and fallback to a simple default */ 00455 if((prec= (int)but->a2) == 0) { 00456 prec= (but->hardmax < 10.001f) ? 3 : 2; 00457 } 00458 00459 /* check on the number of decimal places neede to display 00460 * the number, this is so 0.00001 is not displayed as 0.00, 00461 * _but_, this is only for small values si 10.0001 will not get 00462 * the same treatment */ 00463 if(value != 0.0 && (value= ABS(value)) < 0.1) { 00464 int value_i= (int)((value * PRECISION_FLOAT_MAX_POW) + 0.5); 00465 if(value_i != 0) { 00466 const int prec_span= 3; /* show: 0.01001, 5 would allow 0.0100001 for eg. */ 00467 int test_prec; 00468 int prec_min= -1; 00469 int dec_flag= 0; 00470 int i= PRECISION_FLOAT_MAX; 00471 while(i && value_i) { 00472 if(value_i % 10) { 00473 dec_flag |= 1<<i; 00474 prec_min= i; 00475 } 00476 value_i /= 10; 00477 i--; 00478 } 00479 00480 /* even though its a small value, if the second last digit is not 0, use it */ 00481 test_prec = prec_min; 00482 00483 dec_flag= (dec_flag >> (prec_min + 1)) & ((1 << prec_span) - 1); 00484 00485 while(dec_flag) { 00486 test_prec++; 00487 dec_flag = dec_flag >> 1; 00488 } 00489 00490 if(test_prec > prec) { 00491 prec= test_prec; 00492 } 00493 } 00494 } 00495 00496 CLAMP(prec, 1, PRECISION_FLOAT_MAX); 00497 00498 return prec; 00499 } 00500 00501 static void ui_draw_linkline(uiLinkLine *line) 00502 { 00503 rcti rect; 00504 00505 if(line->from==NULL || line->to==NULL) return; 00506 00507 rect.xmin= (line->from->x1+line->from->x2)/2.0f; 00508 rect.ymin= (line->from->y1+line->from->y2)/2.0f; 00509 rect.xmax= (line->to->x1+line->to->x2)/2.0f; 00510 rect.ymax= (line->to->y1+line->to->y2)/2.0f; 00511 00512 if(line->flag & UI_SELECT) 00513 glColor3ub(100,100,100); 00514 else 00515 glColor3ub(0,0,0); 00516 00517 ui_draw_link_bezier(&rect); 00518 } 00519 00520 static void ui_draw_links(uiBlock *block) 00521 { 00522 uiBut *but; 00523 uiLinkLine *line; 00524 00525 but= block->buttons.first; 00526 while(but) { 00527 if(but->type==LINK && but->link) { 00528 line= but->link->lines.first; 00529 while(line) { 00530 ui_draw_linkline(line); 00531 line= line->next; 00532 } 00533 } 00534 but= but->next; 00535 } 00536 } 00537 00538 /* ************** BLOCK ENDING FUNCTION ************* */ 00539 00540 /* NOTE: if but->poin is allocated memory for every defbut, things fail... */ 00541 static int ui_but_equals_old(uiBut *but, uiBut *oldbut) 00542 { 00543 /* various properties are being compared here, hopefully sufficient 00544 * to catch all cases, but it is simple to add more checks later */ 00545 if(but->retval != oldbut->retval) return 0; 00546 if(but->rnapoin.data != oldbut->rnapoin.data) return 0; 00547 if(but->rnaprop != oldbut->rnaprop) 00548 if(but->rnaindex != oldbut->rnaindex) return 0; 00549 if(but->func != oldbut->func) return 0; 00550 if(but->funcN != oldbut->funcN) return 0; 00551 if(oldbut->func_arg1 != oldbut && but->func_arg1 != oldbut->func_arg1) return 0; 00552 if(oldbut->func_arg2 != oldbut && but->func_arg2 != oldbut->func_arg2) return 0; 00553 if(!but->funcN && ((but->poin != oldbut->poin && (uiBut*)oldbut->poin != oldbut) || but->pointype != oldbut->pointype)) return 0; 00554 if(but->optype != oldbut->optype) return 0; 00555 00556 return 1; 00557 } 00558 00559 /* oldbut is being inserted in new block, so we use the lines from new button, and replace button pointers */ 00560 static void ui_but_update_linklines(uiBlock *block, uiBut *oldbut, uiBut *newbut) 00561 { 00562 uiLinkLine *line; 00563 uiBut *but; 00564 00565 /* if active button is LINK */ 00566 if(newbut->type==LINK && newbut->link) { 00567 00568 SWAP(uiLink *, oldbut->link, newbut->link); 00569 00570 for(line= oldbut->link->lines.first; line; line= line->next) { 00571 if(line->to==newbut) 00572 line->to= oldbut; 00573 if(line->from==newbut) 00574 line->from= oldbut; 00575 } 00576 } 00577 00578 /* check all other button links */ 00579 for(but= block->buttons.first; but; but= but->next) { 00580 if(but!=newbut && but->type==LINK && but->link) { 00581 for(line= but->link->lines.first; line; line= line->next) { 00582 if(line->to==newbut) 00583 line->to= oldbut; 00584 if(line->from==newbut) 00585 line->from= oldbut; 00586 } 00587 } 00588 } 00589 } 00590 00591 static int ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBut **butpp) 00592 { 00593 uiBlock *oldblock; 00594 uiBut *oldbut, *but= *butpp; 00595 int found= 0; 00596 00597 oldblock= block->oldblock; 00598 if(!oldblock) 00599 return found; 00600 00601 for(oldbut=oldblock->buttons.first; oldbut; oldbut=oldbut->next) { 00602 if(ui_but_equals_old(oldbut, but)) { 00603 if(oldbut->active) { 00604 #if 0 00605 // but->flag= oldbut->flag; 00606 #else 00607 /* exception! redalert flag can't be update from old button. 00608 * perhaps it should only copy specific flags rather than all. */ 00609 // but->flag= (oldbut->flag & ~UI_BUT_REDALERT) | (but->flag & UI_BUT_REDALERT); 00610 #endif 00611 // but->active= oldbut->active; 00612 // but->pos= oldbut->pos; 00613 // but->ofs= oldbut->ofs; 00614 // but->editstr= oldbut->editstr; 00615 // but->editval= oldbut->editval; 00616 // but->editvec= oldbut->editvec; 00617 // but->editcoba= oldbut->editcoba; 00618 // but->editcumap= oldbut->editcumap; 00619 // but->selsta= oldbut->selsta; 00620 // but->selend= oldbut->selend; 00621 // but->softmin= oldbut->softmin; 00622 // but->softmax= oldbut->softmax; 00623 // but->linkto[0]= oldbut->linkto[0]; 00624 // but->linkto[1]= oldbut->linkto[1]; 00625 found= 1; 00626 // oldbut->active= NULL; 00627 00628 /* move button over from oldblock to new block */ 00629 BLI_remlink(&oldblock->buttons, oldbut); 00630 BLI_insertlink(&block->buttons, but, oldbut); 00631 oldbut->block= block; 00632 *butpp= oldbut; 00633 00634 /* still stuff needs to be copied */ 00635 oldbut->x1= but->x1; oldbut->y1= but->y1; 00636 oldbut->x2= but->x2; oldbut->y2= but->y2; 00637 oldbut->context= but->context; /* set by Layout */ 00638 00639 /* typically the same pointers, but not on undo/redo */ 00640 /* XXX some menu buttons store button itself in but->poin. Ugly */ 00641 if(oldbut->poin != (char *)oldbut) { 00642 SWAP(char *, oldbut->poin, but->poin) 00643 SWAP(void *, oldbut->func_argN, but->func_argN) 00644 } 00645 00646 /* copy hardmin for list rows to prevent 'sticking' highlight to mouse position 00647 * when scrolling without moving mouse (see [#28432]) */ 00648 if(ELEM(oldbut->type, ROW, LISTROW)) 00649 oldbut->hardmax= but->hardmax; 00650 00651 ui_but_update_linklines(block, oldbut, but); 00652 00653 BLI_remlink(&block->buttons, but); 00654 ui_free_but(C, but); 00655 00656 /* note: if layout hasn't been applied yet, it uses old button pointers... */ 00657 } 00658 else { 00659 /* ensures one button can get activated, and in case the buttons 00660 * draw are the same this gives O(1) lookup for each button */ 00661 BLI_remlink(&oldblock->buttons, oldbut); 00662 ui_free_but(C, oldbut); 00663 } 00664 00665 break; 00666 } 00667 } 00668 00669 return found; 00670 } 00671 00672 /* needed for temporarily rename buttons, such as in outliner or fileselect, 00673 * they should keep calling uiDefButs to keep them alive */ 00674 /* returns 0 when button removed */ 00675 int uiButActiveOnly(const bContext *C, uiBlock *block, uiBut *but) 00676 { 00677 uiBlock *oldblock; 00678 uiBut *oldbut; 00679 int activate= 0, found= 0, isactive= 0; 00680 00681 oldblock= block->oldblock; 00682 if(!oldblock) 00683 activate= 1; 00684 else { 00685 for(oldbut=oldblock->buttons.first; oldbut; oldbut=oldbut->next) { 00686 if(ui_but_equals_old(oldbut, but)) { 00687 found= 1; 00688 00689 if(oldbut->active) 00690 isactive= 1; 00691 00692 break; 00693 } 00694 } 00695 } 00696 if(activate || found==0) { 00697 ui_button_activate_do( (bContext *)C, CTX_wm_region(C), but); 00698 } 00699 else if(found && isactive==0) { 00700 00701 BLI_remlink(&block->buttons, but); 00702 ui_free_but(C, but); 00703 return 0; 00704 } 00705 00706 return 1; 00707 } 00708 00709 /* use to check if we need to disable undo, but dont make any changes 00710 * returns FALSE if undo needs to be disabled. */ 00711 static int ui_but_is_rna_undo(uiBut *but) 00712 { 00713 if(but->rnapoin.id.data) { 00714 /* avoid undo push for buttons who's ID are screen or wm level 00715 * we could disable undo for buttons with no ID too but may have 00716 * unforeseen consequences, so best check for ID's we _know_ are not 00717 * handled by undo - campbell */ 00718 ID *id= but->rnapoin.id.data; 00719 if(ID_CHECK_UNDO(id) == FALSE) { 00720 return FALSE; 00721 } 00722 else { 00723 return TRUE; 00724 } 00725 } 00726 else if (but->rnapoin.type && !RNA_struct_undo_check(but->rnapoin.type)) { 00727 return FALSE; 00728 } 00729 00730 return TRUE; 00731 } 00732 00733 /* assigns automatic keybindings to menu items for fast access 00734 * (underline key in menu) */ 00735 static void ui_menu_block_set_keyaccels(uiBlock *block) 00736 { 00737 uiBut *but; 00738 00739 unsigned int menu_key_mask= 0; 00740 unsigned char menu_key; 00741 const char *str_pt; 00742 int pass; 00743 int tot_missing= 0; 00744 00745 /* only do it before bounding */ 00746 if(block->minx != block->maxx) 00747 return; 00748 00749 for(pass=0; pass<2; pass++) { 00750 /* 2 Passes, on for first letter only, second for any letter if first fails 00751 * fun first pass on all buttons so first word chars always get first priority */ 00752 00753 for(but=block->buttons.first; but; but=but->next) { 00754 if(!ELEM4(but->type, BUT, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) { 00755 /* pass */ 00756 } 00757 else if(but->menu_key=='\0') { 00758 if(but->str) { 00759 for(str_pt= but->str; *str_pt; ) { 00760 menu_key= tolower(*str_pt); 00761 if((menu_key >= 'a' && menu_key <= 'z') && !(menu_key_mask & 1<<(menu_key-'a'))) { 00762 menu_key_mask |= 1<<(menu_key-'a'); 00763 break; 00764 } 00765 00766 if(pass==0) { 00767 /* Skip to next delimeter on first pass (be picky) */ 00768 while(isalpha(*str_pt)) 00769 str_pt++; 00770 00771 if(*str_pt) 00772 str_pt++; 00773 } 00774 else { 00775 /* just step over every char second pass and find first usable key */ 00776 str_pt++; 00777 } 00778 } 00779 00780 if(*str_pt) { 00781 but->menu_key= menu_key; 00782 } 00783 else { 00784 /* run second pass */ 00785 tot_missing++; 00786 } 00787 00788 /* if all keys have been used just exit, unlikely */ 00789 if(menu_key_mask == (1<<26)-1) { 00790 return; 00791 } 00792 } 00793 } 00794 } 00795 00796 /* check if second pass is needed */ 00797 if(!tot_missing) { 00798 break; 00799 } 00800 } 00801 } 00802 00803 00804 static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) 00805 { 00806 uiBut *but; 00807 char buf[512]; 00808 00809 /* for menu's */ 00810 MenuType *mt; 00811 IDProperty *prop_menu= NULL; 00812 IDProperty *prop_menu_name= NULL; 00813 00814 /* only do it before bounding */ 00815 if(block->minx != block->maxx) 00816 return; 00817 00818 00819 #define UI_MENU_KEY_STR_CAT \ 00820 char *butstr_orig= BLI_strdup(but->str); \ 00821 BLI_snprintf(but->strdata, \ 00822 sizeof(but->strdata), \ 00823 "%s|%s", \ 00824 butstr_orig, buf); \ 00825 MEM_freeN(butstr_orig); \ 00826 but->str= but->strdata; \ 00827 ui_check_but(but); \ 00828 00829 00830 for(but=block->buttons.first; but; but=but->next) { 00831 if(but->optype) { 00832 IDProperty *prop= (but->opptr)? but->opptr->data: NULL; 00833 00834 if(WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, TRUE, 00835 buf, sizeof(buf))) 00836 { 00837 UI_MENU_KEY_STR_CAT 00838 } 00839 } 00840 else if ((mt= uiButGetMenuType(but))) { 00841 /* only allocate menu property once */ 00842 if (prop_menu == NULL) { 00843 /* annoying, create a property */ 00844 IDPropertyTemplate val = {0}; 00845 prop_menu= IDP_New(IDP_GROUP, &val, __func__); /* dummy, name is unimportant */ 00846 IDP_AddToGroup(prop_menu, (prop_menu_name= IDP_NewString("", "name", sizeof(mt->idname)))); 00847 } 00848 00849 IDP_AssignString(prop_menu_name, mt->idname, sizeof(mt->idname)); 00850 00851 if(WM_key_event_operator_string(C, "WM_OT_call_menu", WM_OP_INVOKE_REGION_WIN, prop_menu, FALSE, 00852 buf, sizeof(buf))) 00853 { 00854 UI_MENU_KEY_STR_CAT 00855 } 00856 } 00857 } 00858 00859 if (prop_menu) { 00860 IDP_FreeProperty(prop_menu); 00861 MEM_freeN(prop_menu); 00862 } 00863 00864 #undef UI_MENU_KEY_STR_CAT 00865 00866 } 00867 00868 void uiEndBlock(const bContext *C, uiBlock *block) 00869 { 00870 uiBut *but; 00871 Scene *scene= CTX_data_scene(C); 00872 00873 /* inherit flags from 'old' buttons that was drawn here previous, based 00874 * on matching buttons, we need this to make button event handling non 00875 * blocking, while still allowing buttons to be remade each redraw as it 00876 * is expected by blender code */ 00877 for(but=block->buttons.first; but; but=but->next) { 00878 if(ui_but_update_from_old_block(C, block, &but)) 00879 ui_check_but(but); 00880 00881 /* temp? Proper check for greying out */ 00882 if(but->optype) { 00883 wmOperatorType *ot= but->optype; 00884 00885 if(but->context) 00886 CTX_store_set((bContext*)C, but->context); 00887 00888 if(ot == NULL || WM_operator_poll_context((bContext*)C, ot, but->opcontext)==0) { 00889 but->flag |= UI_BUT_DISABLED; 00890 but->lock = 1; 00891 } 00892 00893 if(but->context) 00894 CTX_store_set((bContext*)C, NULL); 00895 } 00896 00897 ui_but_anim_flag(but, (scene)? scene->r.cfra: 0.0f); 00898 } 00899 00900 if(block->oldblock) { 00901 block->auto_open= block->oldblock->auto_open; 00902 block->auto_open_last= block->oldblock->auto_open_last; 00903 block->tooltipdisabled= block->oldblock->tooltipdisabled; 00904 00905 block->oldblock= NULL; 00906 } 00907 00908 /* handle pending stuff */ 00909 if(block->layouts.first) uiBlockLayoutResolve(block, NULL, NULL); 00910 ui_block_do_align(block); 00911 if((block->flag & UI_BLOCK_LOOP) && (block->flag & UI_BLOCK_NUMSELECT)) { 00912 ui_menu_block_set_keyaccels(block); /* could use a different flag to check */ 00913 } 00914 if(block->flag & UI_BLOCK_LOOP) ui_menu_block_set_keymaps(C, block); 00915 00916 /* after keymaps! */ 00917 if(block->dobounds == UI_BLOCK_BOUNDS) ui_bounds_block(block); 00918 else if(block->dobounds == UI_BLOCK_BOUNDS_TEXT) ui_text_bounds_block(block, 0.0f); 00919 else if(block->dobounds == UI_BLOCK_BOUNDS_POPUP_CENTER) ui_centered_bounds_block(C, block); 00920 else if(block->dobounds) ui_popup_bounds_block(C, block, block->dobounds); 00921 00922 if(block->minx==0.0f && block->maxx==0.0f) uiBoundsBlock(block, 0); 00923 if(block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block); 00924 00925 block->endblock= 1; 00926 } 00927 00928 /* ************** BLOCK DRAWING FUNCTION ************* */ 00929 00930 void ui_fontscale(short *points, float aspect) 00931 { 00932 if(aspect < 0.9f || aspect > 1.1f) { 00933 float pointsf= *points; 00934 00935 /* for some reason scaling fonts goes too fast compared to widget size */ 00936 aspect= sqrt(aspect); 00937 pointsf /= aspect; 00938 00939 if(aspect > 1.0f) 00940 *points= ceilf(pointsf); 00941 else 00942 *points= floorf(pointsf); 00943 } 00944 } 00945 00946 /* project button or block (but==NULL) to pixels in regionspace */ 00947 static void ui_but_to_pixelrect(rcti *rect, const ARegion *ar, uiBlock *block, uiBut *but) 00948 { 00949 float gx, gy; 00950 float getsizex, getsizey; 00951 00952 getsizex= ar->winx; 00953 getsizey= ar->winy; 00954 00955 gx= (but?but->x1:block->minx) + (block->panel?block->panel->ofsx:0.0f); 00956 gy= (but?but->y1:block->miny) + (block->panel?block->panel->ofsy:0.0f); 00957 00958 rect->xmin= floorf(getsizex*(0.5f+ 0.5f*(gx*block->winmat[0][0]+ gy*block->winmat[1][0]+ block->winmat[3][0]))); 00959 rect->ymin= floorf(getsizey*(0.5f+ 0.5f*(gx*block->winmat[0][1]+ gy*block->winmat[1][1]+ block->winmat[3][1]))); 00960 00961 gx= (but?but->x2:block->maxx) + (block->panel?block->panel->ofsx:0.0f); 00962 gy= (but?but->y2:block->maxy) + (block->panel?block->panel->ofsy:0.0f); 00963 00964 rect->xmax= floorf(getsizex*(0.5f+ 0.5f*(gx*block->winmat[0][0]+ gy*block->winmat[1][0]+ block->winmat[3][0]))); 00965 rect->ymax= floorf(getsizey*(0.5f+ 0.5f*(gx*block->winmat[0][1]+ gy*block->winmat[1][1]+ block->winmat[3][1]))); 00966 00967 } 00968 00969 /* uses local copy of style, to scale things down, and allow widgets to change stuff */ 00970 void uiDrawBlock(const bContext *C, uiBlock *block) 00971 { 00972 uiStyle style= *UI_GetStyle(); // XXX pass on as arg 00973 ARegion *ar; 00974 uiBut *but; 00975 rcti rect; 00976 int multisample_enabled; 00977 00978 /* get menu region or area region */ 00979 ar= CTX_wm_menu(C); 00980 if(!ar) 00981 ar= CTX_wm_region(C); 00982 00983 if(!block->endblock) 00984 uiEndBlock(C, block); 00985 00986 /* disable AA, makes widgets too blurry */ 00987 multisample_enabled= glIsEnabled(GL_MULTISAMPLE_ARB); 00988 if(multisample_enabled) 00989 glDisable(GL_MULTISAMPLE_ARB); 00990 00991 /* we set this only once */ 00992 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 00993 00994 /* scale fonts */ 00995 ui_fontscale(&style.paneltitle.points, block->aspect); 00996 ui_fontscale(&style.grouplabel.points, block->aspect); 00997 ui_fontscale(&style.widgetlabel.points, block->aspect); 00998 ui_fontscale(&style.widget.points, block->aspect); 00999 01000 /* scale block min/max to rect */ 01001 ui_but_to_pixelrect(&rect, ar, block, NULL); 01002 01003 /* pixel space for AA widgets */ 01004 glMatrixMode(GL_PROJECTION); 01005 glPushMatrix(); 01006 glMatrixMode(GL_MODELVIEW); 01007 glPushMatrix(); 01008 glLoadIdentity(); 01009 01010 wmOrtho2(-0.01f, ar->winx-0.01f, -0.01f, ar->winy-0.01f); 01011 01012 /* back */ 01013 if(block->flag & UI_BLOCK_LOOP) 01014 ui_draw_menu_back(&style, block, &rect); 01015 else if(block->panel) 01016 ui_draw_aligned_panel(&style, block, &rect); 01017 01018 /* widgets */ 01019 for(but= block->buttons.first; but; but= but->next) { 01020 if(!(but->flag & (UI_HIDDEN|UI_SCROLLED))) { 01021 ui_but_to_pixelrect(&rect, ar, block, but); 01022 01023 /* XXX: figure out why invalid coordinates happen when closing render window */ 01024 /* and material preview is redrawn in main window (temp fix for bug #23848) */ 01025 if(rect.xmin < rect.xmax && rect.ymin < rect.ymax) 01026 ui_draw_but(C, ar, &style, but, &rect); 01027 } 01028 } 01029 01030 /* restore matrix */ 01031 glMatrixMode(GL_PROJECTION); 01032 glPopMatrix(); 01033 glMatrixMode(GL_MODELVIEW); 01034 glPopMatrix(); 01035 01036 if(multisample_enabled) 01037 glEnable(GL_MULTISAMPLE_ARB); 01038 01039 ui_draw_links(block); 01040 } 01041 01042 /* ************* EVENTS ************* */ 01043 01044 static void ui_is_but_sel(uiBut *but, double *value) 01045 { 01046 short is_push=0, is_true=1; 01047 01048 if(ELEM3(but->type, TOGN, ICONTOGN, OPTIONN)) is_true= 0; 01049 01050 if( but->bit ) { 01051 int lvalue; 01052 UI_GET_BUT_VALUE_INIT(but, *value) 01053 lvalue= (int)*value; 01054 if( BTST(lvalue, (but->bitnr)) ) is_push= is_true; 01055 else is_push= !is_true; 01056 } 01057 else { 01058 switch(but->type) { 01059 case BUT: 01060 is_push= 2; 01061 break; 01062 case HOTKEYEVT: 01063 case KEYEVT: 01064 is_push= 2; 01065 break; 01066 case TOGBUT: 01067 case TOG: 01068 case TOGR: 01069 case TOG3: 01070 case BUT_TOGDUAL: 01071 case ICONTOG: 01072 case OPTION: 01073 UI_GET_BUT_VALUE_INIT(but, *value) 01074 if(*value != (double)but->hardmin) is_push= 1; 01075 break; 01076 case ICONTOGN: 01077 case TOGN: 01078 case OPTIONN: 01079 UI_GET_BUT_VALUE_INIT(but, *value) 01080 if(*value==0.0) is_push= 1; 01081 break; 01082 case ROW: 01083 case LISTROW: 01084 UI_GET_BUT_VALUE_INIT(but, *value) 01085 /* support for rna enum buts */ 01086 if(but->rnaprop && (RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG)) { 01087 if((int)*value & (int)but->hardmax) is_push= 1; 01088 } 01089 else { 01090 if(*value == (double)but->hardmax) is_push= 1; 01091 } 01092 break; 01093 case COL: 01094 is_push= 2; 01095 break; 01096 default: 01097 is_push= 2; 01098 break; 01099 } 01100 } 01101 01102 if(is_push==2); 01103 else if(is_push==1) but->flag |= UI_SELECT; 01104 else but->flag &= ~UI_SELECT; 01105 } 01106 01107 static uiBut *ui_find_inlink(uiBlock *block, void *poin) 01108 { 01109 uiBut *but; 01110 01111 but= block->buttons.first; 01112 while(but) { 01113 if(but->type==INLINK) { 01114 if(but->poin == poin) return but; 01115 } 01116 but= but->next; 01117 } 01118 return NULL; 01119 } 01120 01121 static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt) 01122 { 01123 uiLinkLine *line; 01124 01125 line= MEM_callocN(sizeof(uiLinkLine), "linkline"); 01126 BLI_addtail(listb, line); 01127 line->from= but; 01128 line->to= bt; 01129 } 01130 01131 uiBut *uiFindInlink(uiBlock *block, void *poin) 01132 { 01133 return ui_find_inlink(block, poin); 01134 } 01135 01136 void uiComposeLinks(uiBlock *block) 01137 { 01138 uiBut *but, *bt; 01139 uiLink *link; 01140 void ***ppoin; 01141 int a; 01142 01143 but= block->buttons.first; 01144 while(but) { 01145 if(but->type==LINK) { 01146 link= but->link; 01147 01148 /* for all pointers in the array */ 01149 if(link) { 01150 if(link->ppoin) { 01151 ppoin= link->ppoin; 01152 for(a=0; a < *(link->totlink); a++) { 01153 bt= ui_find_inlink(block, (*ppoin)[a] ); 01154 if(bt) { 01155 ui_add_link_line(&link->lines, but, bt); 01156 } 01157 } 01158 } 01159 else if(link->poin) { 01160 bt= ui_find_inlink(block, *(link->poin) ); 01161 if(bt) { 01162 ui_add_link_line(&link->lines, but, bt); 01163 } 01164 } 01165 } 01166 } 01167 but= but->next; 01168 } 01169 } 01170 01171 01172 /* ************************************************ */ 01173 01174 void uiBlockSetButLock(uiBlock *block, int val, const char *lockstr) 01175 { 01176 if(val) { 01177 block->lock= val ? 1:0; 01178 block->lockstr= lockstr; 01179 } 01180 } 01181 01182 void uiBlockClearButLock(uiBlock *block) 01183 { 01184 block->lock= 0; 01185 block->lockstr= NULL; 01186 } 01187 01188 /* *************************************************************** */ 01189 01190 void ui_delete_linkline(uiLinkLine *line, uiBut *but) 01191 { 01192 uiLink *link; 01193 int a, b; 01194 01195 BLI_remlink(&but->link->lines, line); 01196 01197 link= line->from->link; 01198 01199 /* are there more pointers allowed? */ 01200 if(link->ppoin) { 01201 01202 if(*(link->totlink)==1) { 01203 *(link->totlink)= 0; 01204 MEM_freeN(*(link->ppoin)); 01205 *(link->ppoin)= NULL; 01206 } 01207 else { 01208 b= 0; 01209 for(a=0; a< (*(link->totlink)); a++) { 01210 01211 if( (*(link->ppoin))[a] != line->to->poin ) { 01212 (*(link->ppoin))[b]= (*(link->ppoin))[a]; 01213 b++; 01214 } 01215 } 01216 (*(link->totlink))--; 01217 } 01218 } 01219 else { 01220 *(link->poin)= NULL; 01221 } 01222 01223 MEM_freeN(line); 01224 //REDRAW 01225 } 01226 01227 /* *********************** data get/set *********************** 01228 * this either works with the pointed to data, or can work with 01229 * an edit override pointer while dragging for example */ 01230 01231 /* for buttons pointing to color for example */ 01232 void ui_get_but_vectorf(uiBut *but, float vec[3]) 01233 { 01234 PropertyRNA *prop; 01235 int a, tot; 01236 01237 if(but->editvec) { 01238 copy_v3_v3(vec, but->editvec); 01239 } 01240 01241 if(but->rnaprop) { 01242 prop= but->rnaprop; 01243 01244 vec[0]= vec[1]= vec[2]= 0.0f; 01245 01246 if(RNA_property_type(prop) == PROP_FLOAT) { 01247 tot= RNA_property_array_length(&but->rnapoin, prop); 01248 tot= MIN2(tot, 3); 01249 01250 for(a=0; a<tot; a++) 01251 vec[a]= RNA_property_float_get_index(&but->rnapoin, prop, a); 01252 } 01253 } 01254 else if(but->pointype == CHA) { 01255 char *cp= (char *)but->poin; 01256 vec[0]= ((float)cp[0])/255.0f; 01257 vec[1]= ((float)cp[1])/255.0f; 01258 vec[2]= ((float)cp[2])/255.0f; 01259 } 01260 else if(but->pointype == FLO) { 01261 float *fp= (float *)but->poin; 01262 copy_v3_v3(vec, fp); 01263 } 01264 else { 01265 if (but->editvec==NULL) { 01266 fprintf(stderr, "ui_get_but_vectorf: can't get color, should never happen\n"); 01267 vec[0]= vec[1]= vec[2]= 0.0f; 01268 } 01269 } 01270 01271 if (but->type == BUT_NORMAL) { 01272 normalize_v3(vec); 01273 } 01274 } 01275 01276 /* for buttons pointing to color for example */ 01277 void ui_set_but_vectorf(uiBut *but, const float vec[3]) 01278 { 01279 PropertyRNA *prop; 01280 01281 if(but->editvec) { 01282 copy_v3_v3(but->editvec, vec); 01283 } 01284 01285 if(but->rnaprop) { 01286 prop= but->rnaprop; 01287 01288 if(RNA_property_type(prop) == PROP_FLOAT) { 01289 int tot; 01290 int a; 01291 01292 tot= RNA_property_array_length(&but->rnapoin, prop); 01293 tot= MIN2(tot, 3); 01294 01295 for (a=0; a<tot; a++) { 01296 RNA_property_float_set_index(&but->rnapoin, prop, a, vec[a]); 01297 } 01298 } 01299 } 01300 else if(but->pointype == CHA) { 01301 char *cp= (char *)but->poin; 01302 cp[0]= (char)(0.5f + vec[0]*255.0f); 01303 cp[1]= (char)(0.5f + vec[1]*255.0f); 01304 cp[2]= (char)(0.5f + vec[2]*255.0f); 01305 } 01306 else if(but->pointype == FLO) { 01307 float *fp= (float *)but->poin; 01308 copy_v3_v3(fp, vec); 01309 } 01310 } 01311 01312 int ui_is_but_float(uiBut *but) 01313 { 01314 if(but->pointype==FLO && but->poin) 01315 return 1; 01316 01317 if(but->rnaprop && RNA_property_type(but->rnaprop) == PROP_FLOAT) 01318 return 1; 01319 01320 return 0; 01321 } 01322 01323 int ui_is_but_unit(uiBut *but) 01324 { 01325 UnitSettings *unit= but->block->unit; 01326 const int unit_type= uiButGetUnitType(but); 01327 01328 if(unit_type == PROP_UNIT_NONE) 01329 return 0; 01330 01331 #if 1 // removed so angle buttons get correct snapping 01332 if (unit->system_rotation == USER_UNIT_ROT_RADIANS && unit_type == PROP_UNIT_ROTATION) 01333 return 0; 01334 #endif 01335 01336 /* for now disable time unit conversion */ 01337 if (unit_type == PROP_UNIT_TIME) 01338 return 0; 01339 01340 if (unit->system == USER_UNIT_NONE) { 01341 if (unit_type != PROP_UNIT_ROTATION) { 01342 return 0; 01343 } 01344 } 01345 01346 return 1; 01347 } 01348 01349 int ui_is_but_rna_valid(uiBut *but) 01350 { 01351 if (but->rnaprop==NULL || RNA_struct_contains_property(&but->rnapoin, but->rnaprop)) { 01352 return TRUE; 01353 } 01354 else { 01355 printf("property removed %s: %p\n", but->drawstr, but->rnaprop); 01356 return FALSE; 01357 } 01358 } 01359 01360 double ui_get_but_val(uiBut *but) 01361 { 01362 PropertyRNA *prop; 01363 double value = 0.0; 01364 01365 if(but->editval) { return *(but->editval); } 01366 if(but->poin==NULL && but->rnapoin.data==NULL) return 0.0; 01367 01368 if(but->rnaprop) { 01369 prop= but->rnaprop; 01370 01371 switch(RNA_property_type(prop)) { 01372 case PROP_BOOLEAN: 01373 if(RNA_property_array_check(prop)) 01374 value= RNA_property_boolean_get_index(&but->rnapoin, prop, but->rnaindex); 01375 else 01376 value= RNA_property_boolean_get(&but->rnapoin, prop); 01377 break; 01378 case PROP_INT: 01379 if(RNA_property_array_check(prop)) 01380 value= RNA_property_int_get_index(&but->rnapoin, prop, but->rnaindex); 01381 else 01382 value= RNA_property_int_get(&but->rnapoin, prop); 01383 break; 01384 case PROP_FLOAT: 01385 if(RNA_property_array_check(prop)) 01386 value= RNA_property_float_get_index(&but->rnapoin, prop, but->rnaindex); 01387 else 01388 value= RNA_property_float_get(&but->rnapoin, prop); 01389 break; 01390 case PROP_ENUM: 01391 value= RNA_property_enum_get(&but->rnapoin, prop); 01392 break; 01393 default: 01394 value= 0.0; 01395 break; 01396 } 01397 } 01398 else if(but->type== HSVSLI) { 01399 float h, s, v, *fp; 01400 01401 fp= (but->editvec)? but->editvec: (float *)but->poin; 01402 rgb_to_hsv(fp[0], fp[1], fp[2], &h, &s, &v); 01403 01404 switch(but->str[0]) { 01405 case 'H': value= h; break; 01406 case 'S': value= s; break; 01407 case 'V': value= v; break; 01408 } 01409 } 01410 else if( but->pointype == CHA ) { 01411 value= *(char *)but->poin; 01412 } 01413 else if( but->pointype == SHO ) { 01414 value= *(short *)but->poin; 01415 } 01416 else if( but->pointype == INT ) { 01417 value= *(int *)but->poin; 01418 } 01419 else if( but->pointype == FLO ) { 01420 value= *(float *)but->poin; 01421 } 01422 01423 return value; 01424 } 01425 01426 void ui_set_but_val(uiBut *but, double value) 01427 { 01428 PropertyRNA *prop; 01429 01430 /* value is a hsv value: convert to rgb */ 01431 if(but->rnaprop) { 01432 prop= but->rnaprop; 01433 01434 if(RNA_property_editable(&but->rnapoin, prop)) { 01435 switch(RNA_property_type(prop)) { 01436 case PROP_BOOLEAN: 01437 if(RNA_property_array_length(&but->rnapoin, prop)) 01438 RNA_property_boolean_set_index(&but->rnapoin, prop, but->rnaindex, value); 01439 else 01440 RNA_property_boolean_set(&but->rnapoin, prop, value); 01441 break; 01442 case PROP_INT: 01443 if(RNA_property_array_length(&but->rnapoin, prop)) 01444 RNA_property_int_set_index(&but->rnapoin, prop, but->rnaindex, (int)value); 01445 else 01446 RNA_property_int_set(&but->rnapoin, prop, (int)value); 01447 break; 01448 case PROP_FLOAT: 01449 if(RNA_property_array_length(&but->rnapoin, prop)) 01450 RNA_property_float_set_index(&but->rnapoin, prop, but->rnaindex, value); 01451 else 01452 RNA_property_float_set(&but->rnapoin, prop, value); 01453 break; 01454 case PROP_ENUM: 01455 if(RNA_property_flag(prop) & PROP_ENUM_FLAG) { 01456 int ivalue= (int)value; 01457 ivalue ^= RNA_property_enum_get(&but->rnapoin, prop); /* toggle for enum/flag buttons */ 01458 RNA_property_enum_set(&but->rnapoin, prop, ivalue); 01459 } 01460 else { 01461 RNA_property_enum_set(&but->rnapoin, prop, value); 01462 } 01463 break; 01464 default: 01465 break; 01466 } 01467 } 01468 01469 /* we can't be sure what RNA set functions actually do, 01470 * so leave this unset */ 01471 value= UI_BUT_VALUE_UNSET; 01472 } 01473 else if(but->pointype==0); 01474 else if(but->type==HSVSLI ) { 01475 float h, s, v, *fp; 01476 01477 fp= (but->editvec)? but->editvec: (float *)but->poin; 01478 rgb_to_hsv(fp[0], fp[1], fp[2], &h, &s, &v); 01479 01480 switch(but->str[0]) { 01481 case 'H': h= value; break; 01482 case 'S': s= value; break; 01483 case 'V': v= value; break; 01484 } 01485 01486 hsv_to_rgb(h, s, v, fp, fp+1, fp+2); 01487 01488 } 01489 else { 01490 /* first do rounding */ 01491 if(but->pointype==CHA) 01492 value= (char)floor(value+0.5); 01493 else if(but->pointype==SHO ) { 01494 /* gcc 3.2.1 seems to have problems 01495 * casting a double like 32772.0 to 01496 * a short so we cast to an int, then 01497 to a short */ 01498 int gcckludge; 01499 gcckludge = (int) floor(value+0.5); 01500 value= (short)gcckludge; 01501 } 01502 else if(but->pointype==INT ) 01503 value= (int)floor(value+0.5); 01504 else if(but->pointype==FLO ) { 01505 float fval= (float)value; 01506 if(fval>= -0.00001f && fval<= 0.00001f) fval= 0.0f; /* prevent negative zero */ 01507 value= fval; 01508 } 01509 01510 /* then set value with possible edit override */ 01511 if(but->editval) 01512 value= *but->editval= value; 01513 else if(but->pointype==CHA) 01514 value= *((char *)but->poin)= (char)value; 01515 else if(but->pointype==SHO) 01516 value= *((short *)but->poin)= (short)value; 01517 else if(but->pointype==INT) 01518 value= *((int *)but->poin)= (int)value; 01519 else if(but->pointype==FLO) 01520 value= *((float *)but->poin)= (float)value; 01521 } 01522 01523 /* update select flag */ 01524 ui_is_but_sel(but, &value); 01525 } 01526 01527 int ui_get_but_string_max_length(uiBut *but) 01528 { 01529 if(ELEM(but->type, TEX, SEARCH_MENU)) 01530 return but->hardmax; 01531 else if(but->type == IDPOIN) 01532 return MAX_ID_NAME-2; 01533 else 01534 return UI_MAX_DRAW_STR; 01535 } 01536 01537 static double ui_get_but_scale_unit(uiBut *but, double value) 01538 { 01539 UnitSettings *unit= but->block->unit; 01540 int unit_type= uiButGetUnitType(but); 01541 01542 if(unit_type == PROP_UNIT_LENGTH) { 01543 return value * (double)unit->scale_length; 01544 } 01545 else if(unit_type == PROP_UNIT_AREA) { 01546 return value * pow(unit->scale_length, 2); 01547 } 01548 else if(unit_type == PROP_UNIT_VOLUME) { 01549 return value * pow(unit->scale_length, 3); 01550 } 01551 else if(unit_type == PROP_UNIT_TIME) { /* WARNING - using evil_C :| */ 01552 Scene *scene= CTX_data_scene(but->block->evil_C); 01553 return FRA2TIME(value); 01554 } 01555 else { 01556 return value; 01557 } 01558 } 01559 01560 /* str will be overwritten */ 01561 void ui_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen) 01562 { 01563 if(ui_is_but_unit(but)) { 01564 UnitSettings *unit= but->block->unit; 01565 int unit_type= uiButGetUnitType(but); 01566 char *orig_str; 01567 01568 orig_str= MEM_callocN(sizeof(char)*maxlen + 1, "textedit sub str"); 01569 memcpy(orig_str, str, maxlen); 01570 01571 bUnit_ToUnitAltName(str, maxlen, orig_str, unit->system, unit_type>>16); 01572 01573 MEM_freeN(orig_str); 01574 } 01575 } 01576 01577 static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double value, int pad) 01578 { 01579 UnitSettings *unit= but->block->unit; 01580 int do_split= unit->flag & USER_UNIT_OPT_SPLIT; 01581 int unit_type= uiButGetUnitType(but); 01582 int precision= but->a2; 01583 01584 if(unit->scale_length<0.0001f) unit->scale_length= 1.0f; // XXX do_versions 01585 01586 /* Sanity checks */ 01587 if(precision > PRECISION_FLOAT_MAX) precision= PRECISION_FLOAT_MAX; 01588 else if(precision==0) precision= 2; 01589 01590 bUnit_AsString(str, len_max, ui_get_but_scale_unit(but, value), precision, unit->system, unit_type>>16, do_split, pad); 01591 } 01592 01593 static float ui_get_but_step_unit(uiBut *but, float step_default) 01594 { 01595 int unit_type= uiButGetUnitType(but)>>16; 01596 float step; 01597 01598 step = bUnit_ClosestScalar(ui_get_but_scale_unit(but, step_default), but->block->unit->system, unit_type); 01599 01600 if(step > 0.0f) { /* -1 is an error value */ 01601 return (float)((double)step/ui_get_but_scale_unit(but, 1.0))*100.0f; 01602 } 01603 else { 01604 return step_default; 01605 } 01606 } 01607 01608 01609 void ui_get_but_string(uiBut *but, char *str, size_t maxlen) 01610 { 01611 if(but->rnaprop && ELEM3(but->type, TEX, IDPOIN, SEARCH_MENU)) { 01612 PropertyType type; 01613 char *buf= NULL; 01614 int buf_len; 01615 01616 type= RNA_property_type(but->rnaprop); 01617 01618 if(type == PROP_STRING) { 01619 /* RNA string */ 01620 buf= RNA_property_string_get_alloc(&but->rnapoin, but->rnaprop, str, maxlen, &buf_len); 01621 } 01622 else if(type == PROP_POINTER) { 01623 /* RNA pointer */ 01624 PointerRNA ptr= RNA_property_pointer_get(&but->rnapoin, but->rnaprop); 01625 buf= RNA_struct_name_get_alloc(&ptr, str, maxlen, &buf_len); 01626 } 01627 01628 if(!buf) { 01629 str[0] = '\0'; 01630 } 01631 else if(buf && buf != str) { 01632 /* string was too long, we have to truncate */ 01633 memcpy(str, buf, MIN2(maxlen, buf_len+1)); 01634 MEM_freeN(buf); 01635 } 01636 } 01637 else if(but->type == IDPOIN) { 01638 /* ID pointer */ 01639 if(but->idpoin_idpp) { /* Can be NULL for ID properties by python */ 01640 ID *id= *(but->idpoin_idpp); 01641 if(id) { 01642 BLI_strncpy(str, id->name+2, maxlen); 01643 return; 01644 } 01645 } 01646 str[0] = '\0'; 01647 return; 01648 } 01649 else if(but->type == TEX) { 01650 /* string */ 01651 BLI_strncpy(str, but->poin, maxlen); 01652 return; 01653 } 01654 else if(but->type == SEARCH_MENU) { 01655 /* string */ 01656 BLI_strncpy(str, but->poin, maxlen); 01657 return; 01658 } 01659 else if(ui_but_anim_expression_get(but, str, maxlen)) 01660 ; /* driver expression */ 01661 else { 01662 /* number editing */ 01663 double value; 01664 01665 value= ui_get_but_val(but); 01666 01667 if(ui_is_but_float(but)) { 01668 if(ui_is_but_unit(but)) { 01669 ui_get_but_string_unit(but, str, maxlen, value, 0); 01670 } 01671 else { 01672 const int prec= ui_but_float_precision(but, value); 01673 BLI_snprintf(str, maxlen, "%.*f", prec, value); 01674 } 01675 } 01676 else 01677 BLI_snprintf(str, maxlen, "%d", (int)value); 01678 } 01679 } 01680 01681 #ifdef WITH_PYTHON 01682 01683 static int ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char *str, double *value) 01684 { 01685 char str_unit_convert[256]; 01686 const int unit_type= uiButGetUnitType(but); 01687 01688 BLI_strncpy(str_unit_convert, str, sizeof(str_unit_convert)); 01689 01690 /* ugly, use the draw string to get the value, this could cause problems if it includes some text which resolves to a unit */ 01691 bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), but->drawstr, ui_get_but_scale_unit(but, 1.0), but->block->unit->system, unit_type>>16); 01692 01693 return (BPY_button_exec(C, str_unit_convert, value, TRUE) != -1); 01694 } 01695 01696 static int ui_set_but_string_eval_num(bContext *C, uiBut *but, const char *str, double *value) 01697 { 01698 int ok= FALSE; 01699 01700 if(str[0] != '\0') { 01701 int is_unit_but= ui_is_but_unit(but); 01702 /* only enable verbose if we won't run again with units */ 01703 if(BPY_button_exec(C, str, value, is_unit_but==FALSE) != -1) { 01704 /* if the value parsed ok without unit conversion this button may still need a unit multiplier */ 01705 if(is_unit_but) { 01706 char str_new[128]; 01707 01708 BLI_snprintf(str_new, sizeof(str_new), "%f", *value); 01709 ok= ui_set_but_string_eval_num_unit(C, but, str_new, value); 01710 } 01711 else { 01712 ok= TRUE; /* parse normal string via py (no unit conversion needed) */ 01713 } 01714 } 01715 else if(is_unit_but) { 01716 /* parse failed, this is a unit but so run replacements and parse again */ 01717 ok= ui_set_but_string_eval_num_unit(C, but, str, value); 01718 } 01719 } 01720 01721 return ok; 01722 } 01723 01724 #endif // WITH_PYTHON 01725 01726 int ui_set_but_string(bContext *C, uiBut *but, const char *str) 01727 { 01728 if(but->rnaprop && ELEM3(but->type, TEX, IDPOIN, SEARCH_MENU)) { 01729 if(RNA_property_editable(&but->rnapoin, but->rnaprop)) { 01730 PropertyType type; 01731 01732 type= RNA_property_type(but->rnaprop); 01733 01734 if(type == PROP_STRING) { 01735 /* RNA string */ 01736 RNA_property_string_set(&but->rnapoin, but->rnaprop, str); 01737 return 1; 01738 } 01739 else if(type == PROP_POINTER) { 01740 /* RNA pointer */ 01741 PointerRNA ptr, rptr; 01742 PropertyRNA *prop; 01743 01744 if(str == NULL || str[0] == '\0') { 01745 RNA_property_pointer_set(&but->rnapoin, but->rnaprop, PointerRNA_NULL); 01746 return 1; 01747 } 01748 else { 01749 ptr= but->rnasearchpoin; 01750 prop= but->rnasearchprop; 01751 01752 if(prop && RNA_property_collection_lookup_string(&ptr, prop, str, &rptr)) 01753 RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr); 01754 01755 return 1; 01756 } 01757 01758 return 0; 01759 } 01760 } 01761 } 01762 else if(but->type == IDPOIN) { 01763 /* ID pointer */ 01764 but->idpoin_func(C, str, but->idpoin_idpp); 01765 return 1; 01766 } 01767 else if(but->type == TEX) { 01768 /* string */ 01769 if(ui_is_but_utf8(but)) BLI_strncpy_utf8(but->poin, str, but->hardmax); 01770 else BLI_strncpy(but->poin, str, but->hardmax); 01771 01772 return 1; 01773 } 01774 else if(but->type == SEARCH_MENU) { 01775 /* string */ 01776 BLI_strncpy(but->poin, str, but->hardmax); 01777 return 1; 01778 } 01779 else if(ui_but_anim_expression_set(but, str)) { 01780 /* driver expression */ 01781 return 1; 01782 } 01783 else if(str[0]=='#') { 01784 /* shortcut to create new driver expression (versus immediate Py-execution) */ 01785 return ui_but_anim_expression_create(but, str+1); 01786 } 01787 else { 01788 /* number editing */ 01789 double value; 01790 01791 #ifdef WITH_PYTHON 01792 if(ui_set_but_string_eval_num(C, but, str, &value) == FALSE) { 01793 return 0; 01794 } 01795 #else 01796 value= atof(str); 01797 #endif // WITH_PYTHON 01798 01799 if(!ui_is_but_float(but)) value= (int)floor(value + 0.5); 01800 if(but->type==NUMABS) value= fabs(value); 01801 01802 /* not that we use hard limits here */ 01803 if(value < (double)but->hardmin) value= but->hardmin; 01804 if(value > (double)but->hardmax) value= but->hardmax; 01805 01806 ui_set_but_val(but, value); 01807 return 1; 01808 } 01809 01810 return 0; 01811 } 01812 01813 void ui_set_but_default(bContext *C, short all) 01814 { 01815 PointerRNA ptr; 01816 01817 WM_operator_properties_create(&ptr, "UI_OT_reset_default_button"); 01818 RNA_boolean_set(&ptr, "all", all); 01819 WM_operator_name_call(C, "UI_OT_reset_default_button", WM_OP_EXEC_DEFAULT, &ptr); 01820 WM_operator_properties_free(&ptr); 01821 } 01822 01823 static double soft_range_round_up(double value, double max) 01824 { 01825 /* round up to .., 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, .. */ 01826 double newmax= pow(10.0, ceil(log(value)/M_LN10)); 01827 01828 if(newmax*0.2 >= max && newmax*0.2 >= value) 01829 return newmax*0.2; 01830 else if(newmax*0.5 >= max && newmax*0.5 >= value) 01831 return newmax*0.5; 01832 else 01833 return newmax; 01834 } 01835 01836 static double soft_range_round_down(double value, double max) 01837 { 01838 /* round down to .., 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, .. */ 01839 double newmax= pow(10.0, floor(log(value)/M_LN10)); 01840 01841 if(newmax*5.0 <= max && newmax*5.0 <= value) 01842 return newmax*5.0; 01843 else if(newmax*2.0 <= max && newmax*2.0 <= value) 01844 return newmax*2.0; 01845 else 01846 return newmax; 01847 } 01848 01849 void ui_set_but_soft_range(uiBut *but, double value) 01850 { 01851 /* ideally we would not limit this but practially, its more then 01852 * enough worst case is very long vectors wont use a smart soft-range 01853 * which isnt so bad. */ 01854 01855 if(but->rnaprop) { 01856 const PropertyType type= RNA_property_type(but->rnaprop); 01857 double softmin, softmax /*, step, precision*/; 01858 double value_min= value; 01859 double value_max= value; 01860 01861 /* clamp button range to something reasonable in case 01862 * we get -inf/inf from RNA properties */ 01863 if(type == PROP_INT) { 01864 int imin, imax, istep; 01865 const int array_len= RNA_property_array_length(&but->rnapoin, but->rnaprop); 01866 01867 RNA_property_int_ui_range(&but->rnapoin, but->rnaprop, &imin, &imax, &istep); 01868 softmin= (imin == INT_MIN)? -1e4: imin; 01869 softmax= (imin == INT_MAX)? 1e4: imax; 01870 /*step= istep;*/ /*UNUSED*/ 01871 /*precision= 1;*/ /*UNUSED*/ 01872 01873 if(array_len >= 2) { 01874 int value_range[2]; 01875 RNA_property_int_get_array_range(&but->rnapoin, but->rnaprop, value_range); 01876 value_min= (double)value_range[0]; 01877 value_max= (double)value_range[1]; 01878 } 01879 } 01880 else if(type == PROP_FLOAT) { 01881 float fmin, fmax, fstep, fprecision; 01882 const int array_len= RNA_property_array_length(&but->rnapoin, but->rnaprop); 01883 01884 RNA_property_float_ui_range(&but->rnapoin, but->rnaprop, &fmin, &fmax, &fstep, &fprecision); 01885 softmin= (fmin == -FLT_MAX)? (float)-1e4: fmin; 01886 softmax= (fmax == FLT_MAX)? (float)1e4: fmax; 01887 /*step= fstep;*/ /*UNUSED*/ 01888 /*precision= fprecision;*/ /*UNUSED*/ 01889 01890 if(array_len >= 2) { 01891 float value_range[2]; 01892 RNA_property_float_get_array_range(&but->rnapoin, but->rnaprop, value_range); 01893 value_min= (double)value_range[0]; 01894 value_max= (double)value_range[1]; 01895 } 01896 } 01897 else 01898 return; 01899 01900 /* if the value goes out of the soft/max range, adapt the range */ 01901 if(value_min+1e-10 < softmin) { 01902 if(value_min < 0.0) 01903 softmin= -soft_range_round_up(-value_min, -softmin); 01904 else 01905 softmin= soft_range_round_down(value_min, softmin); 01906 01907 if(softmin < (double)but->hardmin) 01908 softmin= (double)but->hardmin; 01909 } 01910 if(value_max-1e-10 > softmax) { 01911 if(value_max < 0.0) 01912 softmax= -soft_range_round_down(-value_max, -softmax); 01913 else 01914 softmax= soft_range_round_up(value_max, softmax); 01915 01916 if(softmax > (double)but->hardmax) 01917 softmax= but->hardmax; 01918 } 01919 01920 but->softmin= softmin; 01921 but->softmax= softmax; 01922 } 01923 } 01924 01925 /* ******************* Free ********************/ 01926 01927 static void ui_free_link(uiLink *link) 01928 { 01929 if(link) { 01930 BLI_freelistN(&link->lines); 01931 MEM_freeN(link); 01932 } 01933 } 01934 01935 /* can be called with C==NULL */ 01936 static void ui_free_but(const bContext *C, uiBut *but) 01937 { 01938 if(but->opptr) { 01939 WM_operator_properties_free(but->opptr); 01940 MEM_freeN(but->opptr); 01941 } 01942 if(but->func_argN) MEM_freeN(but->func_argN); 01943 if(but->active) { 01944 /* XXX solve later, buttons should be free-able without context ideally, 01945 * however they may have open tooltips or popup windows, which need to 01946 * be closed using a context pointer */ 01947 if(C) 01948 ui_button_active_free(C, but); 01949 else 01950 if(but->active) 01951 MEM_freeN(but->active); 01952 } 01953 if(but->str && but->str != but->strdata) MEM_freeN(but->str); 01954 ui_free_link(but->link); 01955 01956 if((but->type == BUT_IMAGE) && but->poin) IMB_freeImBuf((struct ImBuf *)but->poin); 01957 01958 MEM_freeN(but); 01959 } 01960 01961 /* can be called with C==NULL */ 01962 void uiFreeBlock(const bContext *C, uiBlock *block) 01963 { 01964 uiBut *but; 01965 01966 while( (but= block->buttons.first) ) { 01967 BLI_remlink(&block->buttons, but); 01968 ui_free_but(C, but); 01969 } 01970 01971 if(block->unit) 01972 MEM_freeN(block->unit); 01973 01974 if(block->func_argN) 01975 MEM_freeN(block->func_argN); 01976 01977 CTX_store_free_list(&block->contexts); 01978 01979 BLI_freelistN(&block->saferct); 01980 01981 MEM_freeN(block); 01982 } 01983 01984 /* can be called with C==NULL */ 01985 void uiFreeBlocks(const bContext *C, ListBase *lb) 01986 { 01987 uiBlock *block; 01988 01989 while( (block= lb->first) ) { 01990 BLI_remlink(lb, block); 01991 uiFreeBlock(C, block); 01992 } 01993 } 01994 01995 void uiFreeInactiveBlocks(const bContext *C, ListBase *lb) 01996 { 01997 uiBlock *block, *nextblock; 01998 01999 for(block=lb->first; block; block=nextblock) { 02000 nextblock= block->next; 02001 02002 if(!block->handle) { 02003 if(!block->active) { 02004 BLI_remlink(lb, block); 02005 uiFreeBlock(C, block); 02006 } 02007 else 02008 block->active= 0; 02009 } 02010 } 02011 } 02012 02013 void uiBlockSetRegion(uiBlock *block, ARegion *region) 02014 { 02015 ListBase *lb= ®ion->uiblocks; 02016 uiBlock *oldblock= NULL; 02017 02018 /* each listbase only has one block with this name, free block 02019 * if is already there so it can be rebuilt from scratch */ 02020 if(lb) { 02021 oldblock= BLI_findstring(lb, block->name, offsetof(uiBlock, name)); 02022 02023 if (oldblock) { 02024 oldblock->active= 0; 02025 oldblock->panel= NULL; 02026 } 02027 02028 /* at the beginning of the list! for dynamical menus/blocks */ 02029 BLI_addhead(lb, block); 02030 } 02031 02032 block->oldblock= oldblock; 02033 } 02034 02035 uiBlock *uiBeginBlock(const bContext *C, ARegion *region, const char *name, short dt) 02036 { 02037 uiBlock *block; 02038 wmWindow *window; 02039 Scene *scn; 02040 int getsizex, getsizey; 02041 02042 window= CTX_wm_window(C); 02043 scn = CTX_data_scene(C); 02044 02045 block= MEM_callocN(sizeof(uiBlock), "uiBlock"); 02046 block->active= 1; 02047 block->dt= dt; 02048 block->evil_C= (void*)C; // XXX 02049 02050 if (scn) { 02051 block->color_profile= (scn->r.color_mgt_flag & R_COLOR_MANAGEMENT); 02052 02053 /* copy to avoid crash when scene gets deleted with ui still open */ 02054 block->unit= MEM_mallocN(sizeof(scn->unit), "UI UnitSettings"); 02055 memcpy(block->unit, &scn->unit, sizeof(scn->unit)); 02056 } 02057 02058 BLI_strncpy(block->name, name, sizeof(block->name)); 02059 02060 if(region) 02061 uiBlockSetRegion(block, region); 02062 02063 /* window matrix and aspect */ 02064 if(region && region->swinid) { 02065 wm_subwindow_getmatrix(window, region->swinid, block->winmat); 02066 wm_subwindow_getsize(window, region->swinid, &getsizex, &getsizey); 02067 02068 /* TODO - investigate why block->winmat[0][0] is negative 02069 * in the image view when viewRedrawForce is called */ 02070 block->aspect= 2.0/fabs( (getsizex)*block->winmat[0][0]); 02071 } 02072 else { 02073 /* no subwindow created yet, for menus for example, so we 02074 * use the main window instead, since buttons are created 02075 * there anyway */ 02076 wm_subwindow_getmatrix(window, window->screen->mainwin, block->winmat); 02077 wm_subwindow_getsize(window, window->screen->mainwin, &getsizex, &getsizey); 02078 02079 block->aspect= 2.0/fabs(getsizex*block->winmat[0][0]); 02080 block->auto_open= TRUE; 02081 block->flag |= UI_BLOCK_LOOP; /* tag as menu */ 02082 } 02083 02084 return block; 02085 } 02086 02087 uiBlock *uiGetBlock(const char *name, ARegion *ar) 02088 { 02089 return BLI_findstring(&ar->uiblocks, name, offsetof(uiBlock, name)); 02090 } 02091 02092 void uiBlockSetEmboss(uiBlock *block, char dt) 02093 { 02094 block->dt= dt; 02095 } 02096 02097 void ui_check_but(uiBut *but) 02098 { 02099 /* if something changed in the button */ 02100 double value= UI_BUT_VALUE_UNSET; 02101 // float okwidth; // UNUSED 02102 02103 ui_is_but_sel(but, &value); 02104 02105 /* only update soft range while not editing */ 02106 if(but->rnaprop && !(but->editval || but->editstr || but->editvec)) { 02107 UI_GET_BUT_VALUE_INIT(but, value) 02108 ui_set_but_soft_range(but, value); 02109 } 02110 02111 /* test for min and max, icon sliders, etc */ 02112 switch( but->type ) { 02113 case NUM: 02114 case SLI: 02115 case SCROLL: 02116 case NUMSLI: 02117 case HSVSLI: 02118 UI_GET_BUT_VALUE_INIT(but, value) 02119 if(value < (double)but->hardmin) ui_set_but_val(but, but->hardmin); 02120 else if(value > (double)but->hardmax) ui_set_but_val(but, but->hardmax); 02121 break; 02122 02123 case NUMABS: 02124 { 02125 double value_abs; 02126 UI_GET_BUT_VALUE_INIT(but, value) 02127 value_abs= fabs(value); 02128 if(value_abs < (double)but->hardmin) ui_set_but_val(but, but->hardmin); 02129 else if(value_abs > (double)but->hardmax) ui_set_but_val(but, but->hardmax); 02130 break; 02131 } 02132 case ICONTOG: 02133 case ICONTOGN: 02134 if(!but->rnaprop || (RNA_property_flag(but->rnaprop) & PROP_ICONS_CONSECUTIVE)) { 02135 if(but->flag & UI_SELECT) but->iconadd= 1; 02136 else but->iconadd= 0; 02137 } 02138 break; 02139 02140 case ICONROW: 02141 if(!but->rnaprop || (RNA_property_flag(but->rnaprop) & PROP_ICONS_CONSECUTIVE)) { 02142 UI_GET_BUT_VALUE_INIT(but, value) 02143 but->iconadd= (int)value- (int)(but->hardmin); 02144 } 02145 break; 02146 02147 case ICONTEXTROW: 02148 if(!but->rnaprop || (RNA_property_flag(but->rnaprop) & PROP_ICONS_CONSECUTIVE)) { 02149 UI_GET_BUT_VALUE_INIT(but, value) 02150 but->iconadd= (int)value- (int)(but->hardmin); 02151 } 02152 break; 02153 } 02154 02155 02156 /* safety is 4 to enable small number buttons (like 'users') */ 02157 // okwidth= -4 + (but->x2 - but->x1); // UNUSED 02158 02159 /* name: */ 02160 switch( but->type ) { 02161 02162 case MENU: 02163 case ICONTEXTROW: 02164 02165 if(but->x2 - but->x1 > 24) { 02166 UI_GET_BUT_VALUE_INIT(but, value) 02167 ui_set_name_menu(but, (int)value); 02168 } 02169 break; 02170 02171 case NUM: 02172 case NUMSLI: 02173 case HSVSLI: 02174 case NUMABS: 02175 02176 UI_GET_BUT_VALUE_INIT(but, value) 02177 02178 if(ui_is_but_float(but)) { 02179 if(value == (double) FLT_MAX) BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%sinf", but->str); 02180 else if(value == (double) -FLT_MAX) BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s-inf", but->str); 02181 /* support length type buttons */ 02182 else if(ui_is_but_unit(but)) { 02183 char new_str[sizeof(but->drawstr)]; 02184 ui_get_but_string_unit(but, new_str, sizeof(new_str), value, TRUE); 02185 BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%s", but->str, new_str); 02186 } 02187 else { 02188 const int prec= ui_but_float_precision(but, value); 02189 BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%.*f", but->str, prec, value); 02190 } 02191 } 02192 else { 02193 BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%d", but->str, (int)value); 02194 } 02195 02196 if(but->rnaprop) { 02197 PropertySubType pstype = RNA_property_subtype(but->rnaprop); 02198 02199 if (pstype == PROP_PERCENTAGE) 02200 strcat(but->drawstr, "%"); 02201 } 02202 break; 02203 02204 case LABEL: 02205 if(ui_is_but_float(but)) { 02206 int prec; 02207 UI_GET_BUT_VALUE_INIT(but, value) 02208 prec= ui_but_float_precision(but, value); 02209 BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%.*f", but->str, prec, value); 02210 } 02211 else { 02212 BLI_strncpy(but->drawstr, but->str, UI_MAX_DRAW_STR); 02213 } 02214 02215 break; 02216 02217 case IDPOIN: 02218 case TEX: 02219 case SEARCH_MENU: 02220 if(!but->editstr) { 02221 char str[UI_MAX_DRAW_STR]; 02222 02223 ui_get_but_string(but, str, UI_MAX_DRAW_STR-strlen(but->str)); 02224 02225 BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%s", but->str, str); 02226 } 02227 break; 02228 02229 case KEYEVT: 02230 BLI_strncpy(but->drawstr, but->str, UI_MAX_DRAW_STR); 02231 if (but->flag & UI_SELECT) { 02232 strcat(but->drawstr, "Press a key"); 02233 } 02234 else { 02235 UI_GET_BUT_VALUE_INIT(but, value) 02236 strcat(but->drawstr, WM_key_event_string((short)value)); 02237 } 02238 break; 02239 02240 case HOTKEYEVT: 02241 if (but->flag & UI_SELECT) { 02242 but->drawstr[0]= '\0'; 02243 02244 if(but->modifier_key) { 02245 char *str= but->drawstr; 02246 02247 if(but->modifier_key & KM_SHIFT) 02248 str= strcat(str, "Shift "); 02249 if(but->modifier_key & KM_CTRL) 02250 str= strcat(str, "Ctrl "); 02251 if(but->modifier_key & KM_ALT) 02252 str= strcat(str, "Alt "); 02253 if(but->modifier_key & KM_OSKEY) 02254 str= strcat(str, "Cmd "); 02255 02256 (void)str; /* UNUSED */ 02257 } 02258 else 02259 strcat(but->drawstr, "Press a key "); 02260 } 02261 else 02262 BLI_strncpy(but->drawstr, but->str, UI_MAX_DRAW_STR); 02263 02264 break; 02265 02266 case BUT_TOGDUAL: 02267 /* trying to get the dual-icon to left of text... not very nice */ 02268 if(but->str[0]) { 02269 BLI_strncpy(but->drawstr, " ", UI_MAX_DRAW_STR); 02270 BLI_strncpy(but->drawstr+2, but->str, UI_MAX_DRAW_STR-2); 02271 } 02272 break; 02273 02274 case HSVCUBE: 02275 case HSVCIRCLE: 02276 break; 02277 default: 02278 BLI_strncpy(but->drawstr, but->str, UI_MAX_DRAW_STR); 02279 02280 } 02281 02282 /* if we are doing text editing, this will override the drawstr */ 02283 if(but->editstr) 02284 BLI_strncpy(but->drawstr, but->editstr, UI_MAX_DRAW_STR); 02285 02286 /* text clipping moved to widget drawing code itself */ 02287 } 02288 02289 02290 void uiBlockBeginAlign(uiBlock *block) 02291 { 02292 /* if other align was active, end it */ 02293 if(block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block); 02294 02295 block->flag |= UI_BUT_ALIGN_DOWN; 02296 block->alignnr++; 02297 02298 /* buttons declared after this call will get this align nr */ // XXX flag? 02299 } 02300 02301 static int buts_are_horiz(uiBut *but1, uiBut *but2) 02302 { 02303 float dx, dy; 02304 02305 dx= fabs( but1->x2 - but2->x1); 02306 dy= fabs( but1->y1 - but2->y2); 02307 02308 if(dx > dy) return 0; 02309 return 1; 02310 } 02311 02312 void uiBlockEndAlign(uiBlock *block) 02313 { 02314 block->flag &= ~UI_BUT_ALIGN; // all 4 flags 02315 } 02316 02317 int ui_but_can_align(uiBut *but) 02318 { 02319 return !ELEM3(but->type, LABEL, OPTION, OPTIONN); 02320 } 02321 02322 static void ui_block_do_align_but(uiBut *first, short nr) 02323 { 02324 uiBut *prev, *but=NULL, *next; 02325 int flag= 0, cols=0, rows=0; 02326 02327 /* auto align */ 02328 02329 for(but=first; but && but->alignnr == nr; but=but->next) { 02330 if(but->next && but->next->alignnr == nr) { 02331 if(buts_are_horiz(but, but->next)) cols++; 02332 else rows++; 02333 } 02334 } 02335 02336 /* rows==0: 1 row, cols==0: 1 collumn */ 02337 02338 /* note; how it uses 'flag' in loop below (either set it, or OR it) is confusing */ 02339 for(but=first, prev=NULL; but && but->alignnr == nr; prev=but, but=but->next) { 02340 next= but->next; 02341 if(next && next->alignnr != nr) 02342 next= NULL; 02343 02344 /* clear old flag */ 02345 but->flag &= ~UI_BUT_ALIGN; 02346 02347 if(flag==0) { /* first case */ 02348 if(next) { 02349 if(buts_are_horiz(but, next)) { 02350 if(rows==0) 02351 flag= UI_BUT_ALIGN_RIGHT; 02352 else 02353 flag= UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT; 02354 } 02355 else { 02356 flag= UI_BUT_ALIGN_DOWN; 02357 } 02358 } 02359 } 02360 else if(next==NULL) { /* last case */ 02361 if(prev) { 02362 if(buts_are_horiz(prev, but)) { 02363 if(rows==0) 02364 flag= UI_BUT_ALIGN_LEFT; 02365 else 02366 flag= UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT; 02367 } 02368 else flag= UI_BUT_ALIGN_TOP; 02369 } 02370 } 02371 else if(buts_are_horiz(but, next)) { 02372 /* check if this is already second row */ 02373 if( prev && buts_are_horiz(prev, but)==0) { 02374 flag &= ~UI_BUT_ALIGN_LEFT; 02375 flag |= UI_BUT_ALIGN_TOP; 02376 /* exception case: bottom row */ 02377 if(rows>0) { 02378 uiBut *bt= but; 02379 while(bt && bt->alignnr == nr) { 02380 if(bt->next && bt->next->alignnr == nr && buts_are_horiz(bt, bt->next)==0 ) break; 02381 bt= bt->next; 02382 } 02383 if(bt==NULL || bt->alignnr != nr) flag= UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT; 02384 } 02385 } 02386 else flag |= UI_BUT_ALIGN_LEFT; 02387 } 02388 else { 02389 if(cols==0) { 02390 flag |= UI_BUT_ALIGN_TOP; 02391 } 02392 else { /* next button switches to new row */ 02393 02394 if(prev && buts_are_horiz(prev, but)) 02395 flag |= UI_BUT_ALIGN_LEFT; 02396 else { 02397 flag &= ~UI_BUT_ALIGN_LEFT; 02398 flag |= UI_BUT_ALIGN_TOP; 02399 } 02400 02401 if( (flag & UI_BUT_ALIGN_TOP)==0) { /* stil top row */ 02402 if(prev) { 02403 if(next && buts_are_horiz(but, next)) 02404 flag = UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT|UI_BUT_ALIGN_RIGHT; 02405 else { 02406 /* last button in top row */ 02407 flag = UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT; 02408 } 02409 } 02410 else 02411 flag |= UI_BUT_ALIGN_DOWN; 02412 } 02413 else 02414 flag |= UI_BUT_ALIGN_TOP; 02415 } 02416 } 02417 02418 but->flag |= flag; 02419 02420 /* merge coordinates */ 02421 if(prev) { 02422 // simple cases 02423 if(rows==0) { 02424 but->x1= (prev->x2+but->x1)/2.0f; 02425 prev->x2= but->x1; 02426 } 02427 else if(cols==0) { 02428 but->y2= (prev->y1+but->y2)/2.0f; 02429 prev->y1= but->y2; 02430 } 02431 else { 02432 if(buts_are_horiz(prev, but)) { 02433 but->x1= (prev->x2+but->x1)/2.0f; 02434 prev->x2= but->x1; 02435 /* copy height too */ 02436 but->y2= prev->y2; 02437 } 02438 else if(prev->prev && buts_are_horiz(prev->prev, prev)==0) { 02439 /* the previous button is a single one in its row */ 02440 but->y2= (prev->y1+but->y2)/2.0f; 02441 prev->y1= but->y2; 02442 02443 but->x1= prev->x1; 02444 if(next && buts_are_horiz(but, next)==0) 02445 but->x2= prev->x2; 02446 } 02447 else { 02448 /* the previous button is not a single one in its row */ 02449 but->y2= prev->y1; 02450 } 02451 } 02452 } 02453 } 02454 } 02455 02456 void ui_block_do_align(uiBlock *block) 02457 { 02458 uiBut *but; 02459 short nr; 02460 02461 /* align buttons with same align nr */ 02462 for(but=block->buttons.first; but;) { 02463 if(but->alignnr) { 02464 nr= but->alignnr; 02465 ui_block_do_align_but(but, nr); 02466 02467 /* skip with same number */ 02468 for(; but && but->alignnr == nr; but=but->next); 02469 02470 if(!but) 02471 break; 02472 } 02473 else 02474 but= but->next; 02475 } 02476 } 02477 02478 /* 02479 * ui_def_but is the function that draws many button types 02480 02481 * for float buttons: 02482 * "a1" Click Step (how much to change the value each click) 02483 * "a2" Number of decimal point values to display. 0 defaults to 3 (0.000) 02484 * 1,2,3, and a maximum of 4, all greater values will be clamped to 4. 02485 */ 02486 static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, int x1, int y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, const char *tip) 02487 { 02488 uiBut *but; 02489 int slen; 02490 02491 if(type & BUTPOIN) { /* a pointer is required */ 02492 if(poin==NULL) 02493 return NULL; 02494 } 02495 02496 but= MEM_callocN(sizeof(uiBut), "uiBut"); 02497 02498 but->type= type & BUTTYPE; 02499 but->pointype= type & BUTPOIN; 02500 but->bit= type & BIT; 02501 but->bitnr= type & 31; 02502 but->icon = ICON_NONE; 02503 but->iconadd=0; 02504 02505 but->retval= retval; 02506 02507 slen= strlen(str); 02508 if(slen >= UI_MAX_NAME_STR-1) { 02509 but->str= MEM_mallocN(slen+2, "ui_def_but str"); /* why +2 ? */ 02510 } 02511 else { 02512 but->str= but->strdata; 02513 } 02514 memcpy(but->str, str, slen+1); 02515 02516 but->x1= x1; 02517 but->y1= y1; 02518 but->x2= (x1+x2); 02519 but->y2= (y1+y2); 02520 02521 but->poin= poin; 02522 but->hardmin= but->softmin= min; 02523 but->hardmax= but->softmax= max; 02524 but->a1= a1; 02525 but->a2= a2; 02526 but->tip= tip; 02527 02528 but->lock= block->lock; 02529 but->lockstr= block->lockstr; 02530 but->dt= block->dt; 02531 02532 but->aspect= 1.0f; //XXX block->aspect; 02533 but->block= block; // pointer back, used for frontbuffer status, and picker 02534 02535 if((block->flag & UI_BUT_ALIGN) && ui_but_can_align(but)) 02536 but->alignnr= block->alignnr; 02537 02538 but->func= block->func; 02539 but->func_arg1= block->func_arg1; 02540 but->func_arg2= block->func_arg2; 02541 02542 but->funcN= block->funcN; 02543 if(block->func_argN) 02544 but->func_argN= MEM_dupallocN(block->func_argN); 02545 02546 but->pos= -1; /* cursor invisible */ 02547 02548 if(ELEM4(but->type, NUM, NUMABS, NUMSLI, HSVSLI)) { /* add a space to name */ 02549 /* slen remains unchanged from previous assignment, ensure this stays true */ 02550 if(slen>0 && slen<UI_MAX_NAME_STR-2) { 02551 if(but->str[slen-1]!=' ') { 02552 but->str[slen]= ' '; 02553 but->str[slen+1]= 0; 02554 } 02555 } 02556 } 02557 02558 if((block->flag & UI_BLOCK_LOOP) || ELEM8(but->type, MENU, TEX, LABEL, IDPOIN, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR)) 02559 but->flag |= (UI_TEXT_LEFT|UI_ICON_LEFT); 02560 else if(but->type==BUT_TOGDUAL) 02561 but->flag |= UI_ICON_LEFT; 02562 02563 but->flag |= (block->flag & UI_BUT_ALIGN); 02564 02565 if (but->lock) { 02566 if (but->lockstr) { 02567 but->flag |= UI_BUT_DISABLED; 02568 } 02569 } 02570 02571 /* keep track of UI_interface.h */ 02572 if(ELEM7(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM)); 02573 else if(ELEM3(but->type, SCROLL, SEPR, FTPREVIEW)); 02574 else if(but->type >= SEARCH_MENU); 02575 else but->flag |= UI_BUT_UNDO; 02576 02577 BLI_addtail(&block->buttons, but); 02578 02579 if(block->curlayout) 02580 ui_layout_add_but(block->curlayout, but); 02581 02582 #ifdef WITH_PYTHON 02583 /* if the 'UI_OT_editsource' is running, extract the source info from the button */ 02584 if (UI_editsource_enable_check()) { 02585 UI_editsource_active_but_test(but); 02586 } 02587 #endif 02588 02589 return but; 02590 } 02591 02592 /* ui_def_but_rna_propname and ui_def_but_rna 02593 * both take the same args except for propname vs prop, this is done so we can 02594 * avoid an extra lookup on 'prop' when its already available. 02595 * 02596 * When this kind of change won't disrupt branches, best look into making more 02597 * of our UI functions take prop rather then propname. 02598 */ 02599 02600 #define UI_DEF_BUT_RNA_DISABLE(but) \ 02601 but->flag |= UI_BUT_DISABLED; \ 02602 but->lock = 1; \ 02603 but->lockstr = "" 02604 02605 02606 static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *str, int x1, int y1, short x2, short y2, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, float a1, float a2, const char *tip) 02607 { 02608 const PropertyType proptype= RNA_property_type(prop); 02609 uiBut *but; 02610 int freestr= 0, icon= 0; 02611 02612 /* use rna values if parameters are not specified */ 02613 if(!str) { 02614 if(type == MENU && proptype == PROP_ENUM) { 02615 EnumPropertyItem *item; 02616 DynStr *dynstr; 02617 int i, totitem, value, free; 02618 02619 RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item, &totitem, &free); 02620 value= RNA_property_enum_get(ptr, prop); 02621 02622 dynstr= BLI_dynstr_new(); 02623 BLI_dynstr_appendf(dynstr, "%s%%t", RNA_property_ui_name(prop)); 02624 for(i=0; i<totitem; i++) { 02625 if(!item[i].identifier[0]) { 02626 if(item[i].name) 02627 BLI_dynstr_appendf(dynstr, "|%s%%l", item[i].name); 02628 else 02629 BLI_dynstr_append(dynstr, "|%l"); 02630 } 02631 else if(item[i].icon) 02632 BLI_dynstr_appendf(dynstr, "|%s %%i%d %%x%d", item[i].name, item[i].icon, item[i].value); 02633 else 02634 BLI_dynstr_appendf(dynstr, "|%s %%x%d", item[i].name, item[i].value); 02635 02636 if(value == item[i].value) 02637 icon= item[i].icon; 02638 } 02639 str= BLI_dynstr_get_cstring(dynstr); 02640 BLI_dynstr_free(dynstr); 02641 02642 if(free) 02643 MEM_freeN(item); 02644 02645 freestr= 1; 02646 } 02647 else if(ELEM(type, ROW, LISTROW) && proptype == PROP_ENUM) { 02648 EnumPropertyItem *item; 02649 int i, totitem, free; 02650 02651 RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item, &totitem, &free); 02652 for(i=0; i<totitem; i++) { 02653 if(item[i].identifier[0] && item[i].value == (int)max) { 02654 str= item[i].name; 02655 icon= item[i].icon; 02656 } 02657 } 02658 02659 if(!str) 02660 str= RNA_property_ui_name(prop); 02661 if(free) 02662 MEM_freeN(item); 02663 } 02664 else { 02665 str= RNA_property_ui_name(prop); 02666 icon= RNA_property_ui_icon(prop); 02667 } 02668 } 02669 02670 if(!tip && proptype != PROP_ENUM) 02671 tip= RNA_property_ui_description(prop); 02672 02673 if(min == max || a1 == -1 || a2 == -1) { 02674 if(proptype == PROP_INT) { 02675 int hardmin, hardmax, softmin, softmax, step; 02676 02677 RNA_property_int_range(ptr, prop, &hardmin, &hardmax); 02678 RNA_property_int_ui_range(ptr, prop, &softmin, &softmax, &step); 02679 02680 if(!ELEM(type, ROW, LISTROW) && min == max) { 02681 min= hardmin; 02682 max= hardmax; 02683 } 02684 if(a1 == -1) 02685 a1= step; 02686 if(a2 == -1) 02687 a2= 0; 02688 } 02689 else if(proptype == PROP_FLOAT) { 02690 float hardmin, hardmax, softmin, softmax, step, precision; 02691 02692 RNA_property_float_range(ptr, prop, &hardmin, &hardmax); 02693 RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision); 02694 02695 if(!ELEM(type, ROW, LISTROW) && min == max) { 02696 min= hardmin; 02697 max= hardmax; 02698 } 02699 if(a1 == -1) 02700 a1= step; 02701 if(a2 == -1) 02702 a2= precision; 02703 } 02704 else if(proptype == PROP_STRING) { 02705 min= 0; 02706 max= RNA_property_string_maxlength(prop); 02707 if(max == 0) /* interface code should ideally support unlimited length */ 02708 max= UI_MAX_DRAW_STR; 02709 } 02710 } 02711 02712 /* now create button */ 02713 but= ui_def_but(block, type, retval, str, x1, y1, x2, y2, NULL, min, max, a1, a2, tip); 02714 02715 but->rnapoin= *ptr; 02716 but->rnaprop= prop; 02717 02718 if(RNA_property_array_length(&but->rnapoin, but->rnaprop)) 02719 but->rnaindex= index; 02720 else 02721 but->rnaindex= 0; 02722 02723 if(icon) { 02724 but->icon= (BIFIconID)icon; 02725 but->flag |= UI_HAS_ICON; 02726 but->flag|= UI_ICON_LEFT; 02727 } 02728 02729 if (!RNA_property_editable(&but->rnapoin, prop)) { 02730 UI_DEF_BUT_RNA_DISABLE(but); 02731 } 02732 02733 if (but->flag & UI_BUT_UNDO && (ui_but_is_rna_undo(but) == FALSE)) { 02734 but->flag &= ~UI_BUT_UNDO; 02735 } 02736 02737 /* If this button uses units, calculate the step from this */ 02738 if((proptype == PROP_FLOAT) && ui_is_but_unit(but)) { 02739 but->a1= ui_get_but_step_unit(but, but->a1); 02740 } 02741 02742 if(freestr) 02743 MEM_freeN((void *)str); 02744 02745 return but; 02746 } 02747 02748 static uiBut *ui_def_but_rna_propname(uiBlock *block, int type, int retval, const char *str, int x1, int y1, short x2, short y2, PointerRNA *ptr, const char *propname, int index, float min, float max, float a1, float a2, const char *tip) 02749 { 02750 PropertyRNA *prop= RNA_struct_find_property(ptr, propname); 02751 uiBut *but; 02752 02753 if(prop) { 02754 but= ui_def_but_rna(block, type, retval, str, x1, y1, x2, y2, ptr, prop, index, min, max, a1, a2, tip); 02755 } 02756 else { 02757 but= ui_def_but(block, type, retval, propname, x1, y1, x2, y2, NULL, min, max, a1, a2, tip); 02758 02759 UI_DEF_BUT_RNA_DISABLE(but); 02760 } 02761 02762 return but; 02763 } 02764 02765 static uiBut *ui_def_but_operator(uiBlock *block, int type, const char *opname, int opcontext, const char *str, int x1, int y1, short x2, short y2, const char *tip) 02766 { 02767 uiBut *but; 02768 wmOperatorType *ot; 02769 02770 ot= WM_operatortype_find(opname, 0); 02771 02772 if(!str) { 02773 if(ot) str= ot->name; 02774 else str= opname; 02775 } 02776 02777 if ((!tip || tip[0]=='\0') && ot && ot->description) { 02778 tip= ot->description; 02779 02780 tip = TIP_(tip); 02781 } 02782 02783 but= ui_def_but(block, type, -1, str, x1, y1, x2, y2, NULL, 0, 0, 0, 0, tip); 02784 but->optype= ot; 02785 but->opcontext= opcontext; 02786 but->flag &= ~UI_BUT_UNDO; /* no need for ui_but_is_undo(), we never need undo here */ 02787 02788 if(!ot) { 02789 but->flag |= UI_BUT_DISABLED; 02790 but->lock = 1; 02791 but->lockstr = ""; 02792 } 02793 02794 return but; 02795 } 02796 02797 static uiBut *ui_def_but_operator_text(uiBlock *block, int type, const char *opname, int opcontext, const char *str, int x1, int y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, const char *tip) 02798 { 02799 uiBut *but; 02800 wmOperatorType *ot; 02801 02802 ot= WM_operatortype_find(opname, 0); 02803 02804 if(!str) { 02805 if(ot) str= ot->name; 02806 else str= opname; 02807 } 02808 02809 if ((!tip || tip[0]=='\0') && ot && ot->description) { 02810 tip= ot->description; 02811 } 02812 02813 but= ui_def_but(block, type, -1, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip); 02814 but->optype= ot; 02815 but->opcontext= opcontext; 02816 but->flag &= ~UI_BUT_UNDO; /* no need for ui_but_is_undo(), we never need undo here */ 02817 02818 if(!ot) { 02819 but->flag |= UI_BUT_DISABLED; 02820 but->lock = 1; 02821 but->lockstr = ""; 02822 } 02823 02824 return but; 02825 } 02826 02827 uiBut *uiDefBut(uiBlock *block, int type, int retval, const char *str, int x1, int y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, const char *tip) 02828 { 02829 uiBut *but= ui_def_but(block, type, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip); 02830 02831 ui_check_but(but); 02832 02833 return but; 02834 } 02835 02836 /* if _x_ is a power of two (only one bit) return the power, 02837 * otherwise return -1. 02838 * (1<<findBitIndex(x))==x for powers of two. 02839 */ 02840 static int findBitIndex(unsigned int x) 02841 { 02842 if (!x || !is_power_of_2_i(x)) { /* is_power_of_2_i(x) strips lowest bit */ 02843 return -1; 02844 } else { 02845 int idx= 0; 02846 02847 if (x&0xFFFF0000) idx+=16, x>>=16; 02848 if (x&0xFF00) idx+=8, x>>=8; 02849 if (x&0xF0) idx+=4, x>>=4; 02850 if (x&0xC) idx+=2, x>>=2; 02851 if (x&0x2) idx+=1; 02852 02853 return idx; 02854 } 02855 } 02856 02857 /* autocomplete helper functions */ 02858 struct AutoComplete { 02859 size_t maxlen; 02860 char *truncate; 02861 const char *startname; 02862 }; 02863 02864 AutoComplete *autocomplete_begin(const char *startname, size_t maxlen) 02865 { 02866 AutoComplete *autocpl; 02867 02868 autocpl= MEM_callocN(sizeof(AutoComplete), "AutoComplete"); 02869 autocpl->maxlen= maxlen; 02870 autocpl->truncate= MEM_callocN(sizeof(char)*maxlen, "AutoCompleteTruncate"); 02871 autocpl->startname= startname; 02872 02873 return autocpl; 02874 } 02875 02876 void autocomplete_do_name(AutoComplete *autocpl, const char *name) 02877 { 02878 char *truncate= autocpl->truncate; 02879 const char *startname= autocpl->startname; 02880 int a; 02881 02882 for(a=0; a<autocpl->maxlen-1; a++) { 02883 if(startname[a]==0 || startname[a]!=name[a]) 02884 break; 02885 } 02886 /* found a match */ 02887 if(startname[a]==0) { 02888 /* first match */ 02889 if(truncate[0]==0) 02890 BLI_strncpy(truncate, name, autocpl->maxlen); 02891 else { 02892 /* remove from truncate what is not in bone->name */ 02893 for(a=0; a<autocpl->maxlen-1; a++) { 02894 if(name[a] == 0) { 02895 truncate[a]= 0; 02896 break; 02897 } 02898 else if(truncate[a]!=name[a]) 02899 truncate[a]= 0; 02900 } 02901 } 02902 } 02903 } 02904 02905 void autocomplete_end(AutoComplete *autocpl, char *autoname) 02906 { 02907 if(autocpl->truncate[0]) 02908 BLI_strncpy(autoname, autocpl->truncate, autocpl->maxlen); 02909 else { 02910 if (autoname != autocpl->startname) /* dont copy a string over its self */ 02911 BLI_strncpy(autoname, autocpl->startname, autocpl->maxlen); 02912 } 02913 MEM_freeN(autocpl->truncate); 02914 MEM_freeN(autocpl); 02915 } 02916 02917 /* autocomplete callback for ID buttons */ 02918 static void autocomplete_id(bContext *C, char *str, void *arg_v) 02919 { 02920 int blocktype= (intptr_t)arg_v; 02921 ListBase *listb= which_libbase(CTX_data_main(C), blocktype); 02922 02923 if(listb==NULL) return; 02924 02925 /* search if str matches the beginning of an ID struct */ 02926 if(str[0]) { 02927 AutoComplete *autocpl= autocomplete_begin(str, MAX_ID_NAME-2); 02928 ID *id; 02929 02930 for(id= listb->first; id; id= id->next) 02931 autocomplete_do_name(autocpl, id->name+2); 02932 02933 autocomplete_end(autocpl, str); 02934 } 02935 } 02936 02937 static void ui_check_but_and_iconize(uiBut *but, int icon) 02938 { 02939 if(icon) { 02940 but->icon= (BIFIconID) icon; 02941 but->flag|= UI_HAS_ICON; 02942 } 02943 02944 ui_check_but(but); 02945 } 02946 02947 static uiBut *uiDefButBit(uiBlock *block, int type, int bit, int retval, const char *str, int x1, int y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, const char *tip) 02948 { 02949 int bitIdx= findBitIndex(bit); 02950 if (bitIdx==-1) { 02951 return NULL; 02952 } else { 02953 return uiDefBut(block, type|BIT|bitIdx, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip); 02954 } 02955 } 02956 uiBut *uiDefButF(uiBlock *block, int type, int retval, const char *str, int x1, int y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, const char *tip) 02957 { 02958 return uiDefBut(block, type|FLO, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 02959 } 02960 uiBut *uiDefButBitF(uiBlock *block, int type, int bit, int retval, const char *str, int x1, int y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, const char *tip) 02961 { 02962 return uiDefButBit(block, type|FLO, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 02963 } 02964 uiBut *uiDefButI(uiBlock *block, int type, int retval, const char *str, int x1, int y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, const char *tip) 02965 { 02966 return uiDefBut(block, type|INT, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 02967 } 02968 uiBut *uiDefButBitI(uiBlock *block, int type, int bit, int retval, const char *str, int x1, int y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, const char *tip) 02969 { 02970 return uiDefButBit(block, type|INT, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 02971 } 02972 uiBut *uiDefButS(uiBlock *block, int type, int retval, const char *str, int x1, int y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, const char *tip) 02973 { 02974 return uiDefBut(block, type|SHO, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 02975 } 02976 uiBut *uiDefButBitS(uiBlock *block, int type, int bit, int retval, const char *str, int x1, int y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, const char *tip) 02977 { 02978 return uiDefButBit(block, type|SHO, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 02979 } 02980 uiBut *uiDefButC(uiBlock *block, int type, int retval, const char *str, int x1, int y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, const char *tip) 02981 { 02982 return uiDefBut(block, type|CHA, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 02983 } 02984 uiBut *uiDefButBitC(uiBlock *block, int type, int bit, int retval, const char *str, int x1, int y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, const char *tip) 02985 { 02986 return uiDefButBit(block, type|CHA, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 02987 } 02988 uiBut *uiDefButR(uiBlock *block, int type, int retval, const char *str, int x1, int y1, short x2, short y2, PointerRNA *ptr, const char *propname, int index, float min, float max, float a1, float a2, const char *tip) 02989 { 02990 uiBut *but; 02991 but= ui_def_but_rna_propname(block, type, retval, str, x1, y1, x2, y2, ptr, propname, index, min, max, a1, a2, tip); 02992 ui_check_but(but); 02993 return but; 02994 } 02995 uiBut *uiDefButR_prop(uiBlock *block, int type, int retval, const char *str, int x1, int y1, short x2, short y2, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, float a1, float a2, const char *tip) 02996 { 02997 uiBut *but; 02998 but= ui_def_but_rna(block, type, retval, str, x1, y1, x2, y2, ptr, prop, index, min, max, a1, a2, tip); 02999 ui_check_but(but); 03000 return but; 03001 } 03002 uiBut *uiDefButO(uiBlock *block, int type, const char *opname, int opcontext, const char *str, int x1, int y1, short x2, short y2, const char *tip) 03003 { 03004 uiBut *but; 03005 but= ui_def_but_operator(block, type, opname, opcontext, str, x1, y1, x2, y2, tip); 03006 ui_check_but(but); 03007 return but; 03008 } 03009 03010 uiBut *uiDefButTextO(uiBlock *block, int type, const char *opname, int opcontext, const char *str, int x1, int y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, const char *tip) 03011 { 03012 uiBut *but= ui_def_but_operator_text(block, type, opname, opcontext, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip); 03013 ui_check_but(but); 03014 return but; 03015 } 03016 03017 /* if a1==1.0 then a2 is an extra icon blending factor (alpha 0.0 - 1.0) */ 03018 uiBut *uiDefIconBut(uiBlock *block, int type, int retval, int icon, int x1, int y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, const char *tip) 03019 { 03020 uiBut *but= ui_def_but(block, type, retval, "", x1, y1, x2, y2, poin, min, max, a1, a2, tip); 03021 ui_check_but_and_iconize(but, icon); 03022 return but; 03023 } 03024 static uiBut *uiDefIconButBit(uiBlock *block, int type, int bit, int retval, int icon, int x1, int y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, const char *tip) 03025 { 03026 int bitIdx= findBitIndex(bit); 03027 if (bitIdx==-1) { 03028 return NULL; 03029 } else { 03030 return uiDefIconBut(block, type|BIT|bitIdx, retval, icon, x1, y1, x2, y2, poin, min, max, a1, a2, tip); 03031 } 03032 } 03033 03034 uiBut *uiDefIconButF(uiBlock *block, int type, int retval, int icon, int x1, int y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, const char *tip) 03035 { 03036 return uiDefIconBut(block, type|FLO, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03037 } 03038 uiBut *uiDefIconButBitF(uiBlock *block, int type, int bit, int retval, int icon, int x1, int y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, const char *tip) 03039 { 03040 return uiDefIconButBit(block, type|FLO, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03041 } 03042 uiBut *uiDefIconButI(uiBlock *block, int type, int retval, int icon, int x1, int y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, const char *tip) 03043 { 03044 return uiDefIconBut(block, type|INT, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03045 } 03046 uiBut *uiDefIconButBitI(uiBlock *block, int type, int bit, int retval, int icon, int x1, int y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, const char *tip) 03047 { 03048 return uiDefIconButBit(block, type|INT, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03049 } 03050 uiBut *uiDefIconButS(uiBlock *block, int type, int retval, int icon, int x1, int y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, const char *tip) 03051 { 03052 return uiDefIconBut(block, type|SHO, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03053 } 03054 uiBut *uiDefIconButBitS(uiBlock *block, int type, int bit, int retval, int icon, int x1, int y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, const char *tip) 03055 { 03056 return uiDefIconButBit(block, type|SHO, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03057 } 03058 uiBut *uiDefIconButC(uiBlock *block, int type, int retval, int icon, int x1, int y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, const char *tip) 03059 { 03060 return uiDefIconBut(block, type|CHA, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03061 } 03062 uiBut *uiDefIconButBitC(uiBlock *block, int type, int bit, int retval, int icon, int x1, int y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, const char *tip) 03063 { 03064 return uiDefIconButBit(block, type|CHA, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03065 } 03066 uiBut *uiDefIconButR(uiBlock *block, int type, int retval, int icon, int x1, int y1, short x2, short y2, PointerRNA *ptr, const char *propname, int index, float min, float max, float a1, float a2, const char *tip) 03067 { 03068 uiBut *but; 03069 but= ui_def_but_rna_propname(block, type, retval, "", x1, y1, x2, y2, ptr, propname, index, min, max, a1, a2, tip); 03070 ui_check_but_and_iconize(but, icon); 03071 return but; 03072 } 03073 uiBut *uiDefIconButR_prop(uiBlock *block, int type, int retval, int icon, int x1, int y1, short x2, short y2, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, float a1, float a2, const char *tip) 03074 { 03075 uiBut *but; 03076 but= ui_def_but_rna(block, type, retval, "", x1, y1, x2, y2, ptr, prop, index, min, max, a1, a2, tip); 03077 ui_check_but_and_iconize(but, icon); 03078 return but; 03079 } 03080 uiBut *uiDefIconButO(uiBlock *block, int type, const char *opname, int opcontext, int icon, int x1, int y1, short x2, short y2, const char *tip) 03081 { 03082 uiBut *but; 03083 but= ui_def_but_operator(block, type, opname, opcontext, "", x1, y1, x2, y2, tip); 03084 ui_check_but_and_iconize(but, icon); 03085 return but; 03086 } 03087 03088 /* Button containing both string label and icon */ 03089 uiBut *uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, const char *str, int x1, int y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, const char *tip) 03090 { 03091 uiBut *but= ui_def_but(block, type, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip); 03092 ui_check_but_and_iconize(but, icon); 03093 but->flag|= UI_ICON_LEFT; 03094 return but; 03095 } 03096 static uiBut *uiDefIconTextButBit(uiBlock *block, int type, int bit, int retval, int icon, const char *str, int x1, int y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, const char *tip) 03097 { 03098 int bitIdx= findBitIndex(bit); 03099 if (bitIdx==-1) { 03100 return NULL; 03101 } else { 03102 return uiDefIconTextBut(block, type|BIT|bitIdx, retval, icon, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip); 03103 } 03104 } 03105 03106 uiBut *uiDefIconTextButF(uiBlock *block, int type, int retval, int icon, const char *str, int x1, int y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, const char *tip) 03107 { 03108 return uiDefIconTextBut(block, type|FLO, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03109 } 03110 uiBut *uiDefIconTextButBitF(uiBlock *block, int type, int bit, int retval, int icon, const char *str, int x1, int y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, const char *tip) 03111 { 03112 return uiDefIconTextButBit(block, type|FLO, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03113 } 03114 uiBut *uiDefIconTextButI(uiBlock *block, int type, int retval, int icon, const char *str, int x1, int y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, const char *tip) 03115 { 03116 return uiDefIconTextBut(block, type|INT, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03117 } 03118 uiBut *uiDefIconTextButBitI(uiBlock *block, int type, int bit, int retval, int icon, const char *str, int x1, int y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, const char *tip) 03119 { 03120 return uiDefIconTextButBit(block, type|INT, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03121 } 03122 uiBut *uiDefIconTextButS(uiBlock *block, int type, int retval, int icon, const char *str, int x1, int y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, const char *tip) 03123 { 03124 return uiDefIconTextBut(block, type|SHO, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03125 } 03126 uiBut *uiDefIconTextButBitS(uiBlock *block, int type, int bit, int retval, int icon, const char *str, int x1, int y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, const char *tip) 03127 { 03128 return uiDefIconTextButBit(block, type|SHO, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03129 } 03130 uiBut *uiDefIconTextButC(uiBlock *block, int type, int retval, int icon, const char *str, int x1, int y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, const char *tip) 03131 { 03132 return uiDefIconTextBut(block, type|CHA, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03133 } 03134 uiBut *uiDefIconTextButBitC(uiBlock *block, int type, int bit, int retval, int icon, const char *str, int x1, int y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, const char *tip) 03135 { 03136 return uiDefIconTextButBit(block, type|CHA, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); 03137 } 03138 uiBut *uiDefIconTextButR(uiBlock *block, int type, int retval, int icon, const char *str, int x1, int y1, short x2, short y2, PointerRNA *ptr, const char *propname, int index, float min, float max, float a1, float a2, const char *tip) 03139 { 03140 uiBut *but; 03141 but= ui_def_but_rna_propname(block, type, retval, str, x1, y1, x2, y2, ptr, propname, index, min, max, a1, a2, tip); 03142 ui_check_but_and_iconize(but, icon); 03143 but->flag|= UI_ICON_LEFT; 03144 return but; 03145 } 03146 uiBut *uiDefIconTextButR_prop(uiBlock *block, int type, int retval, int icon, const char *str, int x1, int y1, short x2, short y2, PointerRNA *ptr, PropertyRNA *prop, int index, float min, float max, float a1, float a2, const char *tip) 03147 { 03148 uiBut *but; 03149 but= ui_def_but_rna(block, type, retval, str, x1, y1, x2, y2, ptr, prop, index, min, max, a1, a2, tip); 03150 ui_check_but_and_iconize(but, icon); 03151 but->flag|= UI_ICON_LEFT; 03152 return but; 03153 } 03154 uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, int opcontext, int icon, const char *str, int x1, int y1, short x2, short y2, const char *tip) 03155 { 03156 uiBut *but; 03157 but= ui_def_but_operator(block, type, opname, opcontext, str, x1, y1, x2, y2, tip); 03158 ui_check_but_and_iconize(but, icon); 03159 but->flag|= UI_ICON_LEFT; 03160 return but; 03161 } 03162 03163 /* END Button containing both string label and icon */ 03164 03165 void uiSetButLink(uiBut *but, void **poin, void ***ppoin, short *tot, int from, int to) 03166 { 03167 uiLink *link; 03168 03169 link= but->link= MEM_callocN(sizeof(uiLink), "new uilink"); 03170 03171 link->poin= poin; 03172 link->ppoin= ppoin; 03173 link->totlink= tot; 03174 link->fromcode= from; 03175 link->tocode= to; 03176 } 03177 03178 /* cruft to make uiBlock and uiBut private */ 03179 03180 int uiBlocksGetYMin(ListBase *lb) 03181 { 03182 uiBlock *block; 03183 int min= 0; 03184 03185 for (block= lb->first; block; block= block->next) 03186 if (block==lb->first || block->miny<min) 03187 min= block->miny; 03188 03189 return min; 03190 } 03191 03192 void uiBlockSetDirection(uiBlock *block, int direction) 03193 { 03194 block->direction= direction; 03195 } 03196 03197 /* this call escapes if there's alignment flags */ 03198 void uiBlockFlipOrder(uiBlock *block) 03199 { 03200 ListBase lb; 03201 uiBut *but, *next; 03202 float centy, miny=10000, maxy= -10000; 03203 03204 if(U.uiflag & USER_MENUFIXEDORDER) 03205 return; 03206 else if(block->flag & UI_BLOCK_NO_FLIP) 03207 return; 03208 03209 for(but= block->buttons.first; but; but= but->next) { 03210 if(but->flag & UI_BUT_ALIGN) return; 03211 if(but->y1 < miny) miny= but->y1; 03212 if(but->y2 > maxy) maxy= but->y2; 03213 } 03214 /* mirror trick */ 03215 centy= (miny+maxy)/2.0f; 03216 for(but= block->buttons.first; but; but= but->next) { 03217 but->y1 = centy-(but->y1-centy); 03218 but->y2 = centy-(but->y2-centy); 03219 SWAP(float, but->y1, but->y2); 03220 } 03221 03222 /* also flip order in block itself, for example for arrowkey */ 03223 lb.first= lb.last= NULL; 03224 but= block->buttons.first; 03225 while(but) { 03226 next= but->next; 03227 BLI_remlink(&block->buttons, but); 03228 BLI_addtail(&lb, but); 03229 but= next; 03230 } 03231 block->buttons= lb; 03232 } 03233 03234 03235 void uiBlockSetFlag(uiBlock *block, int flag) 03236 { 03237 block->flag|= flag; 03238 } 03239 03240 void uiBlockClearFlag(uiBlock *block, int flag) 03241 { 03242 block->flag&= ~flag; 03243 } 03244 03245 void uiBlockSetXOfs(uiBlock *block, int xofs) 03246 { 03247 block->xofs= xofs; 03248 } 03249 03250 void uiButSetFlag(uiBut *but, int flag) 03251 { 03252 but->flag|= flag; 03253 } 03254 03255 void uiButClearFlag(uiBut *but, int flag) 03256 { 03257 but->flag&= ~flag; 03258 } 03259 03260 int uiButGetRetVal(uiBut *but) 03261 { 03262 return but->retval; 03263 } 03264 03265 void uiButSetDragID(uiBut *but, ID *id) 03266 { 03267 but->dragtype= WM_DRAG_ID; 03268 but->dragpoin= (void *)id; 03269 } 03270 03271 void uiButSetDragRNA(uiBut *but, PointerRNA *ptr) 03272 { 03273 but->dragtype= WM_DRAG_RNA; 03274 but->dragpoin= (void *)ptr; 03275 } 03276 03277 void uiButSetDragPath(uiBut *but, const char *path) 03278 { 03279 but->dragtype= WM_DRAG_PATH; 03280 but->dragpoin= (void *)path; 03281 } 03282 03283 void uiButSetDragName(uiBut *but, const char *name) 03284 { 03285 but->dragtype= WM_DRAG_NAME; 03286 but->dragpoin= (void *)name; 03287 } 03288 03289 /* value from button itself */ 03290 void uiButSetDragValue(uiBut *but) 03291 { 03292 but->dragtype= WM_DRAG_VALUE; 03293 } 03294 03295 void uiButSetDragImage(uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale) 03296 { 03297 but->dragtype= WM_DRAG_PATH; 03298 but->icon= icon; /* no flag UI_HAS_ICON, so icon doesnt draw in button */ 03299 but->dragpoin= (void *)path; 03300 but->imb= imb; 03301 but->imb_scale= scale; 03302 } 03303 03304 PointerRNA *uiButGetOperatorPtrRNA(uiBut *but) 03305 { 03306 if(but->optype && !but->opptr) { 03307 but->opptr= MEM_callocN(sizeof(PointerRNA), "uiButOpPtr"); 03308 WM_operator_properties_create_ptr(but->opptr, but->optype); 03309 } 03310 03311 return but->opptr; 03312 } 03313 03314 void uiButSetUnitType(uiBut *but, const int unit_type) 03315 { 03316 but->unit_type= (unsigned char)(unit_type>>16); 03317 } 03318 03319 int uiButGetUnitType(uiBut *but) 03320 { 03321 int ownUnit = (int)but->unit_type; 03322 03323 /* own unit define always takes precidence over RNA provided, allowing for overriding 03324 * default value provided in RNA in a few special cases (i.e. Active Keyframe in Graph Edit) 03325 */ 03326 // XXX: this doesn't allow clearing unit completely, though the same could be said for icons 03327 if ((ownUnit != 0) || (but->rnaprop == NULL)) { 03328 return ownUnit << 16; 03329 } 03330 else { 03331 return RNA_SUBTYPE_UNIT(RNA_property_subtype(but->rnaprop)); 03332 } 03333 } 03334 03335 void uiBlockSetHandleFunc(uiBlock *block, uiBlockHandleFunc func, void *arg) 03336 { 03337 block->handle_func= func; 03338 block->handle_func_arg= arg; 03339 } 03340 03341 void uiBlockSetButmFunc(uiBlock *block, uiMenuHandleFunc func, void *arg) 03342 { 03343 block->butm_func= func; 03344 block->butm_func_arg= arg; 03345 } 03346 03347 void uiBlockSetFunc(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2) 03348 { 03349 block->func= func; 03350 block->func_arg1= arg1; 03351 block->func_arg2= arg2; 03352 } 03353 03354 void uiBlockSetNFunc(uiBlock *block, uiButHandleFunc func, void *argN, void *arg2) 03355 { 03356 if(block->func_argN) 03357 MEM_freeN(block->func_argN); 03358 03359 block->funcN= func; 03360 block->func_argN= argN; 03361 block->func_arg2= arg2; 03362 } 03363 03364 void uiButSetRenameFunc(uiBut *but, uiButHandleRenameFunc func, void *arg1) 03365 { 03366 but->rename_func= func; 03367 but->rename_arg1= arg1; 03368 } 03369 03370 void uiBlockSetDrawExtraFunc(uiBlock *block, void (*func)(const bContext *C, void *idv, void *arg1, void *arg2, rcti *rect), void *arg1, void *arg2) 03371 { 03372 block->drawextra= func; 03373 block->drawextra_arg1= arg1; 03374 block->drawextra_arg2= arg2; 03375 } 03376 03377 void uiButSetFunc(uiBut *but, uiButHandleFunc func, void *arg1, void *arg2) 03378 { 03379 but->func= func; 03380 but->func_arg1= arg1; 03381 but->func_arg2= arg2; 03382 } 03383 03384 void uiButSetNFunc(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2) 03385 { 03386 if(but->func_argN) 03387 MEM_freeN(but->func_argN); 03388 03389 but->funcN= funcN; 03390 but->func_argN= argN; 03391 but->func_arg2= arg2; 03392 } 03393 03394 void uiButSetCompleteFunc(uiBut *but, uiButCompleteFunc func, void *arg) 03395 { 03396 but->autocomplete_func= func; 03397 but->autofunc_arg= arg; 03398 } 03399 03400 uiBut *uiDefIDPoinBut(uiBlock *block, uiIDPoinFuncFP func, short blocktype, int retval, const char *str, int x1, int y1, short x2, short y2, void *idpp, const char *tip) 03401 { 03402 uiBut *but= ui_def_but(block, IDPOIN, retval, str, x1, y1, x2, y2, NULL, 0.0, 0.0, 0.0, 0.0, tip); 03403 but->idpoin_func= func; 03404 but->idpoin_idpp= (ID**) idpp; 03405 ui_check_but(but); 03406 03407 if(blocktype) 03408 uiButSetCompleteFunc(but, autocomplete_id, (void *)(intptr_t)blocktype); 03409 03410 return but; 03411 } 03412 03413 uiBut *uiDefBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, const char *str, int x1, int y1, short x2, short y2, const char *tip) 03414 { 03415 uiBut *but= ui_def_but(block, BLOCK, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip); 03416 but->block_create_func= func; 03417 ui_check_but(but); 03418 return but; 03419 } 03420 03421 uiBut *uiDefBlockButN(uiBlock *block, uiBlockCreateFunc func, void *argN, const char *str, int x1, int y1, short x2, short y2, const char *tip) 03422 { 03423 uiBut *but= ui_def_but(block, BLOCK, 0, str, x1, y1, x2, y2, NULL, 0.0, 0.0, 0.0, 0.0, tip); 03424 but->block_create_func= func; 03425 if(but->func_argN) 03426 MEM_freeN(but->func_argN); 03427 but->func_argN= argN; 03428 ui_check_but(but); 03429 return but; 03430 } 03431 03432 03433 uiBut *uiDefPulldownBut(uiBlock *block, uiBlockCreateFunc func, void *arg, const char *str, int x1, int y1, short x2, short y2, const char *tip) 03434 { 03435 uiBut *but= ui_def_but(block, PULLDOWN, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip); 03436 but->block_create_func= func; 03437 ui_check_but(but); 03438 return but; 03439 } 03440 03441 uiBut *uiDefMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, const char *str, int x1, int y1, short x2, short y2, const char *tip) 03442 { 03443 uiBut *but= ui_def_but(block, PULLDOWN, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip); 03444 but->menu_create_func= func; 03445 ui_check_but(but); 03446 return but; 03447 } 03448 03449 uiBut *uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, const char *str, int x1, int y1, short x2, short y2, const char *tip) 03450 { 03451 uiBut *but= ui_def_but(block, PULLDOWN, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip); 03452 03453 but->icon= (BIFIconID) icon; 03454 but->flag|= UI_HAS_ICON; 03455 03456 but->flag|= UI_ICON_LEFT; 03457 but->flag|= UI_ICON_SUBMENU; 03458 03459 but->menu_create_func= func; 03460 ui_check_but(but); 03461 03462 return but; 03463 } 03464 03465 uiBut *uiDefIconMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, int x1, int y1, short x2, short y2, const char *tip) 03466 { 03467 uiBut *but= ui_def_but(block, PULLDOWN, 0, "", x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip); 03468 03469 but->icon= (BIFIconID) icon; 03470 but->flag |= UI_HAS_ICON; 03471 but->flag &=~ UI_ICON_LEFT; 03472 03473 but->menu_create_func= func; 03474 ui_check_but(but); 03475 03476 return but; 03477 } 03478 03479 /* Block button containing both string label and icon */ 03480 uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int icon, const char *str, int x1, int y1, short x2, short y2, const char *tip) 03481 { 03482 uiBut *but= ui_def_but(block, BLOCK, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip); 03483 03484 /* XXX temp, old menu calls pass on icon arrow, which is now UI_ICON_SUBMENU flag */ 03485 if(icon!=ICON_RIGHTARROW_THIN) { 03486 but->icon= (BIFIconID) icon; 03487 but->flag|= UI_ICON_LEFT; 03488 } 03489 but->flag|= UI_HAS_ICON; 03490 but->flag|= UI_ICON_SUBMENU; 03491 03492 but->block_create_func= func; 03493 ui_check_but(but); 03494 03495 return but; 03496 } 03497 03498 /* Block button containing icon */ 03499 uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int retval, int icon, int x1, int y1, short x2, short y2, const char *tip) 03500 { 03501 uiBut *but= ui_def_but(block, BLOCK, retval, "", x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip); 03502 03503 but->icon= (BIFIconID) icon; 03504 but->flag|= UI_HAS_ICON; 03505 03506 but->flag|= UI_ICON_LEFT; 03507 03508 but->block_create_func= func; 03509 ui_check_but(but); 03510 03511 return but; 03512 } 03513 03514 uiBut *uiDefKeyevtButS(uiBlock *block, int retval, const char *str, int x1, int y1, short x2, short y2, short *spoin, const char *tip) 03515 { 03516 uiBut *but= ui_def_but(block, KEYEVT|SHO, retval, str, x1, y1, x2, y2, spoin, 0.0, 0.0, 0.0, 0.0, tip); 03517 ui_check_but(but); 03518 return but; 03519 } 03520 03521 /* short pointers hardcoded */ 03522 /* modkeypoin will be set to KM_SHIFT, KM_ALT, KM_CTRL, KM_OSKEY bits */ 03523 uiBut *uiDefHotKeyevtButS(uiBlock *block, int retval, const char *str, int x1, int y1, short x2, short y2, short *keypoin, short *modkeypoin, const char *tip) 03524 { 03525 uiBut *but= ui_def_but(block, HOTKEYEVT|SHO, retval, str, x1, y1, x2, y2, keypoin, 0.0, 0.0, 0.0, 0.0, tip); 03526 but->modifier_key= *modkeypoin; 03527 ui_check_but(but); 03528 return but; 03529 } 03530 03531 03532 /* arg is pointer to string/name, use uiButSetSearchFunc() below to make this work */ 03533 /* here a1 and a2, if set, control thumbnail preview rows/cols */ 03534 uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, int x1, int y1, short x2, short y2, float a1, float a2, const char *tip) 03535 { 03536 uiBut *but= ui_def_but(block, SEARCH_MENU, retval, "", x1, y1, x2, y2, arg, 0.0, maxlen, a1, a2, tip); 03537 03538 but->icon= (BIFIconID) icon; 03539 but->flag|= UI_HAS_ICON; 03540 03541 but->flag|= UI_ICON_LEFT|UI_TEXT_LEFT; 03542 03543 ui_check_but(but); 03544 03545 return but; 03546 } 03547 03548 03549 /* arg is user value, searchfunc and handlefunc both get it as arg */ 03550 /* if active set, button opens with this item visible and selected */ 03551 void uiButSetSearchFunc(uiBut *but, uiButSearchFunc sfunc, void *arg, uiButHandleFunc bfunc, void *active) 03552 { 03553 but->search_func= sfunc; 03554 but->search_arg= arg; 03555 03556 uiButSetFunc(but, bfunc, arg, active); 03557 03558 /* search buttons show red-alert if item doesn't exist, not for menus */ 03559 if(0==(but->block->flag & UI_BLOCK_LOOP)) { 03560 /* skip empty buttons, not all buttons need input, we only show invalid */ 03561 if(but->drawstr[0]) 03562 ui_but_search_test(but); 03563 } 03564 } 03565 03566 /* push a new event onto event queue to activate the given button 03567 * (usually a text-field) upon entering a popup 03568 */ 03569 void uiButSetFocusOnEnter(wmWindow *win, uiBut *but) 03570 { 03571 wmEvent event; 03572 03573 event= *(win->eventstate); 03574 event.type= EVT_BUT_OPEN; 03575 event.val= KM_PRESS; 03576 event.customdata= but; 03577 event.customdatafree= FALSE; 03578 03579 wm_event_add(win, &event); 03580 } 03581 03582 /* Program Init/Exit */ 03583 03584 void UI_init(void) 03585 { 03586 ui_resources_init(); 03587 } 03588 03589 /* after reading userdef file */ 03590 void UI_init_userdef(void) 03591 { 03592 /* fix saved themes */ 03593 init_userdef_do_versions(); 03594 uiStyleInit(); 03595 } 03596 03597 void UI_reinit_font(void) 03598 { 03599 uiStyleInit(); 03600 } 03601 03602 void UI_exit(void) 03603 { 03604 ui_resources_free(); 03605 } 03606