Blender  V2.59
interface.c
Go to the documentation of this file.
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= &region->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