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