diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-11-11 21:31:32 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2008-11-11 21:31:32 +0300 |
commit | 78a1c27c4a6abe0ed31ca93ad21910f3df04da56 (patch) | |
tree | 48258a995237f8eb4e222784bf27ec41973ab6c2 /source/blender/editors/interface/interface.c | |
parent | 44f94f7927a2becf40e50a105b4c18f0a36f5341 (diff) |
Port of part of the Interface code to 2.50.
This is based on the current trunk version, so these files should not need
merges. There's two things (clipboard and intptr_t) that are missing in 2.50
and commented out with XXX 2.48, these can be enabled again once trunk is
merged into this branch.
Further this is not all interface code, there are many parts commented out:
* interface.c: nearly all button types, missing: links, chartab, keyevent.
* interface_draw.c: almost all code, with some small exceptions.
* interface_ops.c: this replaces ui_do_but and uiDoBlocks with two operators,
making it non-blocking.
* interface_regions: this is a part of interface.c, split off, contains code to
create regions for tooltips, menus, pupmenu (that one is crashing currently),
color chooser, basically regions with buttons which is fairly independent of
core interface code.
* interface_panel.c and interface_icons.c: not ported over, so no panels and
icons yet. Panels should probably become (free floating) regions?
* text.c: (formerly language.c) for drawing text and translation. this works
but is using bad globals still and could be cleaned up.
Header Files:
* ED_datafiles.h now has declarations for datatoc_ files, so those extern
declarations can be #included instead of repeated.
* The user interface code is in UI_interface.h and other UI_* files.
Core:
* The API for creating blocks, buttons, etc is nearly the same still. Blocks
are now created per region instead of per area.
* The code was made non-blocking, which means that any changes and redraws
should be possible while editing a button. That means though that we need
some sort of persistence even though the blender model is to recreate buttons
for each redraw. So when a new block is created, some matching happens to
find out which buttons correspond to buttons in the previously created block,
and for activated buttons some data is then copied over to the new button.
* Added UI_init/UI_init_userdef/UI_exit functions that should initialize code
in this module, instead of multiple function calls in the windowmanager.
* Removed most static/globals from interface.c.
* Removed UIafterfunc_ I don't think it's needed anymore, and not sure how it
would integrate here?
* Currently only full window redraws are used, this should become per region
and maybe per button later.
Operators:
* Events are currently handled through two operators: button activate and menu
handle. Operators may not be the best way to implement this, since there are
currently some issues with events being missed, but they can become a special
handler type instead, this should not be a big change.
* The button activate operator runs as long as a button is active, and will
handle all interaction with that button until the button is not activated
anymore. This means clicking, text editing, number dragging, opening menu
blocks, etc.
* Since this operator has to be non-blocking, the ui_do_but code needed to made
non-blocking. That means variables that were previously on the stack, now
need to be stored away in a struct such that they can be accessed again when
the operator receives more events.
* Additionally the place in the ui_do_but code indicated the state, now that
needs to be set explicit in order to handle the right events in the right
state. So an activated button can be in one of these states: init, highlight,
wait_flash, wait_release, wait_key_event, num_editing, text_editing,
text_selecting, block_open, exit.
* For each button type an ui_apply_but_* function has also been separated out
from ui_do_but. This makes it possible to continuously apply the button as
text is being typed for example, and there is an option in the code to enable
this. Since the code non-blocking and can deal with the button being deleted
even, it should be safe to do this.
* When editing text, dragging numbers, etc, the actual data (but->poin) is not
being edited, since that would mean data is being edited without correct
updates happening, while some other part of blender may be accessing that
data in the meantime. So data values, strings, vectors are written to a
temporary location and only flush in the apply function.
Regions:
* Menus, color chooser, tooltips etc all create screen level regions. Such menu
blocks give a handle to the button that creates it, which will contain the
results of the menu block once a MESSAGE event is received from that menu
block.
* For this type of menu block the coordinates used to be in window space. They
are still created that way and ui_positionblock still works with window
coordinates, but after that the block and buttons are brought back to region
coordinates since these are now contained in a region.
* The flush/overdraw frontbuffer drawing code was removed, the windowmanager
should have enough information with these screen level regions to have full
control over what gets drawn when and to then do correct compositing.
Testing:
* The header in the time space currently has some buttons to test the UI code.
Diffstat (limited to 'source/blender/editors/interface/interface.c')
-rw-r--r-- | source/blender/editors/interface/interface.c | 2573 |
1 files changed, 2573 insertions, 0 deletions
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c new file mode 100644 index 00000000000..7fa9615f64c --- /dev/null +++ b/source/blender/editors/interface/interface.c @@ -0,0 +1,2573 @@ +/** + * $Id: interface.c 16882 2008-10-02 12:29:45Z ton $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <math.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_ID.h" +#include "DNA_listBase.h" +#include "DNA_screen_types.h" +#include "DNA_texture_types.h" +#include "DNA_userdef_types.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" +#include "BLI_dynstr.h" + +#include "BKE_global.h" +#include "BKE_screen.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "UI_interface.h" +#include "UI_text.h" + +#include "BMF_Api.h" +#ifdef INTERNATIONAL +#include "FTF_Api.h" +#endif + +#include "ED_screen.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm_subwindow.h" +#include "wm_window.h" + +#include "RNA_access.h" +#include "RNA_types.h" + +#include "interface.h" + +/* + * a full doc with API notes can be found in bf-blender/blender/doc/interface_API.txt + * + * uiBlahBlah() external function + * ui_blah_blah() internal function + */ + +static void ui_free_but(uiBut *but); + +/* ************ GLOBALS ************* */ + +static uiFont UIfont[UI_ARRAY]; // no init needed + +/* ************* translation ************** */ + +/* XXX 2.50 missing from context */ +int ui_translate_buttons() +{ + return (U.transopts & USER_TR_BUTTONS); +} + +int ui_translate_menus() +{ + return (U.transopts & USER_TR_MENUS); +} + +int ui_translate_tooltips() +{ + return (U.transopts & USER_TR_TOOLTIPS); +} + +/* ************* window matrix ************** */ + +void ui_block_to_window_fl(const ARegion *ar, uiBlock *block, float *x, float *y) +{ + float gx, gy; + int sx, sy, getsizex, getsizey; + + getsizex= ar->winrct.xmax-ar->winrct.xmin; + getsizey= ar->winrct.ymax-ar->winrct.ymin; + sx= ar->winrct.xmin; + sy= ar->winrct.ymin; + + gx= *x; + gy= *y; + *x= ((float)sx) + ((float)getsizex)*(0.5+ 0.5*(gx*block->winmat[0][0]+ gy*block->winmat[1][0]+ block->winmat[3][0])); + *y= ((float)sy) + ((float)getsizey)*(0.5+ 0.5*(gx*block->winmat[0][1]+ gy*block->winmat[1][1]+ block->winmat[3][1])); +} + +void ui_block_to_window(const ARegion *ar, uiBlock *block, int *x, int *y) +{ + float fx, fy; + + fx= *x; + fy= *y; + + ui_block_to_window_fl(ar, block, &fx, &fy); + + *x= (int)(fx+0.5f); + *y= (int)(fy+0.5f); +} + +void ui_block_to_window_rct(const ARegion *ar, uiBlock *block, rctf *graph, rcti *winr) +{ + rctf tmpr; + + tmpr= *graph; + ui_block_to_window_fl(ar, block, &tmpr.xmin, &tmpr.ymin); + ui_block_to_window_fl(ar, block, &tmpr.xmax, &tmpr.ymax); + + winr->xmin= tmpr.xmin; + winr->ymin= tmpr.ymin; + winr->xmax= tmpr.xmax; + winr->ymax= tmpr.ymax; +} + +void ui_window_to_block_fl(const ARegion *ar, uiBlock *block, float *x, float *y) /* for mouse cursor */ +{ + float a, b, c, d, e, f, px, py; + int sx, sy, getsizex, getsizey; + + getsizex= ar->winrct.xmax-ar->winrct.xmin; + getsizey= ar->winrct.ymax-ar->winrct.ymin; + sx= ar->winrct.xmin; + sy= ar->winrct.ymin; + + a= .5*((float)getsizex)*block->winmat[0][0]; + b= .5*((float)getsizex)*block->winmat[1][0]; + c= .5*((float)getsizex)*(1.0+block->winmat[3][0]); + + d= .5*((float)getsizey)*block->winmat[0][1]; + e= .5*((float)getsizey)*block->winmat[1][1]; + f= .5*((float)getsizey)*(1.0+block->winmat[3][1]); + + px= *x - sx; + py= *y - sy; + + *y= (a*(py-f) + d*(c-px))/(a*e-d*b); + *x= (px- b*(*y)- c)/a; +} + +void ui_window_to_block(const ARegion *ar, uiBlock *block, int *x, int *y) +{ + float fx, fy; + + fx= *x; + fy= *y; + + ui_window_to_block_fl(ar, block, &fx, &fy); + + *x= (int)(fx+0.5f); + *y= (int)(fy+0.5f); +} + +/* ******************* block calc ************************* */ + +/* only for pulldowns */ +void uiTextBoundsBlock(uiBlock *block, int addval) +{ + uiBut *bt; + int i = 0, j, x1addval= 0, nextcol; + + bt= block->buttons.first; + while(bt) { + if(bt->type!=SEPR) { + int transopts= ui_translate_buttons(); + if(bt->type==TEX || bt->type==IDPOIN) transopts= 0; + j= UI_GetStringWidth(bt->font, bt->drawstr, transopts); + + if(j > i) i = j; + } + bt= bt->next; + } + + /* cope with multi collumns */ + bt= block->buttons.first; + while(bt) { + if(bt->next && bt->x1 < bt->next->x1) + nextcol= 1; + else nextcol= 0; + + bt->x1 = x1addval; + bt->x2 = bt->x1 + i + addval; + + ui_check_but(bt); // clips text again + + if(nextcol) + x1addval+= i + addval; + + bt= bt->next; + } +} + +void uiBoundsBlock(uiBlock *block, int addval) +{ + uiBut *bt; + int xof; + + if(block==NULL) + return; + + if(block->buttons.first==NULL) { + if(block->panel) { + block->minx= 0.0; block->maxx= block->panel->sizex; + block->miny= 0.0; block->maxy= block->panel->sizey; + } + } + else { + + block->minx= block->miny= 10000; + block->maxx= block->maxy= -10000; + + bt= block->buttons.first; + while(bt) { + if(bt->x1 < block->minx) block->minx= bt->x1; + if(bt->y1 < block->miny) block->miny= bt->y1; + + if(bt->x2 > block->maxx) block->maxx= bt->x2; + if(bt->y2 > block->maxy) block->maxy= bt->y2; + + bt= bt->next; + } + + block->minx -= addval; + block->miny -= addval; + block->maxx += addval; + block->maxy += addval; + } + + /* hardcoded exception... but that one is annoying with larger safety */ + bt= block->buttons.first; + if(bt && strncmp(bt->str, "ERROR", 5)==0) xof= 10; + else xof= 40; + + block->safety.xmin= block->minx-xof; + block->safety.ymin= block->miny-xof; + block->safety.xmax= block->maxx+xof; + block->safety.ymax= block->maxy+xof; +} + +void uiBlockTranslate(uiBlock *block, int x, int y) +{ + uiBut *bt; + + for(bt= block->buttons.first; bt; bt=bt->next) { + bt->x1 += x; + bt->y1 += y; + bt->x2 += x; + bt->y2 += y; + } + + block->minx += x; + block->miny += y; + block->maxx += x; + block->maxy += y; +} + +void uiBlockOrigin(uiBlock *block) +{ + uiBut *bt; + int minx= 10000, miny= 10000; + + for(bt= block->buttons.first; bt; bt=bt->next) { + if(bt->x1 < minx) minx= bt->x1; + if(bt->y1 < miny) miny= bt->y1; + } + + uiBlockTranslate(block, -minx, -miny); +} + +void ui_autofill(uiBlock *block) +{ + uiBut *but; + float *maxw, *maxh, startx = 0, starty, height = 0; + float totmaxh; + int rows=0, /* cols=0, */ i, lasti; + + /* first count rows */ + but= block->buttons.last; + rows= but->x1+1; + + /* calculate max width / height for each row */ + maxw= MEM_callocN(sizeof(float)*rows, "maxw"); + maxh= MEM_callocN(sizeof(float)*rows, "maxh"); + but= block->buttons.first; + while(but) { + i= but->x1; + if( maxh[i] < but->y2) maxh[i]= but->y2; + maxw[i] += but->x2; + but= but->next; + } + + totmaxh= 0.0; + for(i=0; i<rows; i++) totmaxh+= maxh[i]; + + /* apply widths/heights */ + starty= block->maxy; + but= block->buttons.first; + lasti= -1; + while(but) { + // signal for aligning code + but->flag |= UI_BUT_ALIGN_DOWN; + + i= but->x1; + + if(i!=lasti) { + startx= block->minx; + height= (maxh[i]*(block->maxy-block->miny))/totmaxh; + starty-= height; + lasti= i; + } + + but->y1= starty+but->aspect; + but->y2= but->y1+height-but->aspect; + + but->x2= (but->x2*(block->maxx-block->minx))/maxw[i]; + but->x1= startx+but->aspect; + + startx+= but->x2; + but->x2+= but->x1-but->aspect; + + ui_check_but(but); + + but= but->next; + } + + uiBlockEndAlign(block); + + MEM_freeN(maxw); MEM_freeN(maxh); + block->autofill= 0; +} + +/* ************** LINK LINE DRAWING ************* */ + +/* link line drawing is not part of buttons or theme.. so we stick with it here */ + +static void ui_draw_linkline(uiBut *but, uiLinkLine *line) +{ + float vec1[2], vec2[2]; + + if(line->from==NULL || line->to==NULL) return; + + vec1[0]= (line->from->x1+line->from->x2)/2.0; + vec1[1]= (line->from->y1+line->from->y2)/2.0; + vec2[0]= (line->to->x1+line->to->x2)/2.0; + vec2[1]= (line->to->y1+line->to->y2)/2.0; + + if(line->flag & UI_SELECT) UI_ThemeColorShade(but->themecol, 80); + else glColor3ub(0,0,0); + fdrawline(vec1[0], vec1[1], vec2[0], vec2[1]); +} + +static void ui_draw_links(uiBlock *block) +{ + uiBut *but; + uiLinkLine *line; + + but= block->buttons.first; + while(but) { + if(but->type==LINK && but->link) { + line= but->link->lines.first; + while(line) { + ui_draw_linkline(but, line); + line= line->next; + } + } + but= but->next; + } +} + +/* ************** BLOCK ENDING FUNCTION ************* */ + +static int ui_but_equals_old(uiBut *but, uiBut *oldbut) +{ + /* various properties are being compared here, hopfully sufficient + * to catch all cases, but it is simple to add more checks later */ + if(but->retval != oldbut->retval) return 0; + if(but->poin != oldbut->poin || but->pointype != oldbut->pointype) return 0; + if(but->rnapoin.data != oldbut->rnapoin.data) return 0; + if(but->rnaprop != oldbut->rnaprop) + if(but->rnaindex != oldbut->rnaindex) return 0; + if(but->func != oldbut->func) return 0; + if(but->func_arg1 != oldbut->func_arg1) return 0; + if(but->func_arg2 != oldbut->func_arg2) return 0; + if(but->func_arg3 != oldbut->func_arg3) return 0; + + return 1; +} + +static int ui_but_update_from_old_block(uiBlock *block, uiBut *but) +{ + uiBlock *oldblock; + uiBut *oldbut; + int found= 0; + + oldblock= block->oldblock; + if(!oldblock) + return found; + + for(oldbut=oldblock->buttons.first; oldbut; oldbut=oldbut->next) { + if(ui_but_equals_old(oldbut, but)) { + if(oldbut->activate) { + but->flag= oldbut->flag; + but->activate= oldbut->activate; + but->pos= oldbut->pos; + but->editstr= oldbut->editstr; + but->editval= oldbut->editval; + but->editvec= oldbut->editvec; + but->editcoba= oldbut->editcoba; + but->editcumap= oldbut->editcumap; + but->selsta= oldbut->selsta; + but->selend= oldbut->selend; + found= 1; + } + + /* ensures one button can get activated, and in case the buttons + * draw are the same this gives O(1) lookup for each button */ + BLI_remlink(&oldblock->buttons, oldbut); + ui_free_but(oldbut); + + break; + } + } + + return found; +} + +void uiEndBlock(uiBlock *block) +{ + uiBut *but; + + /* inherit flags from 'old' buttons that was drawn here previous, based + * on matching buttons, we need this to make button event handling non + * blocking, while still alowing buttons to be remade each redraw as it + * is expected by blender code */ + for(but=block->buttons.first; but; but=but->next) + if(ui_but_update_from_old_block(block, but)) + ui_check_but(but); + + if(block->oldblock) { + block->auto_open= block->oldblock->auto_open; + block->auto_open_last= block->oldblock->auto_open_last; + + uiFreeBlock(block->oldblock); + block->oldblock= NULL; + } + + /* handle pending stuff */ + if(block->autofill) ui_autofill(block); + if(block->minx==0.0 && block->maxx==0.0) uiBoundsBlock(block, 0); + if(block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block); +} + +/* ************** BLOCK DRAWING FUNCTION ************* */ + +void uiDrawBlock(uiBlock *block) +{ + uiBut *but; + + /* we set this only once */ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /* XXX 2.50 no panels yet */ + //uiPanelPush(block); // panel matrix + + if(block->flag & UI_BLOCK_LOOP) { + uiDrawMenuBox(block->minx, block->miny, block->maxx, block->maxy, block->flag); + } + else { + /* XXX 2.50 no panels yet */ + //if(block->panel) ui_draw_panel(block); + } + + /* XXX 2.50 need context here? */ + //if(block->drawextra) block->drawextra(curarea, block); + + for (but= block->buttons.first; but; but= but->next) + ui_draw_but(but); + + ui_draw_links(block); + + /* XXX 2.50 no panels yet */ + //uiPanelPop(block); // matrix restored +} + +/* ************* EVENTS ************* */ + +static void ui_is_but_sel(uiBut *but) +{ + double value; + int lvalue; + short push=0, true=1; + + value= ui_get_but_val(but); + + if( but->type==TOGN || but->type==ICONTOGN) true= 0; + + if( but->bit ) { + lvalue= (int)value; + if( BTST(lvalue, (but->bitnr)) ) push= true; + else push= !true; + } + else { + switch(but->type) { + case BUT: + push= 2; + break; + case KEYEVT: + if (value==-1) push= 1; + break; + case TOG: + case TOGR: + case TOG3: + case BUT_TOGDUAL: + case ICONTOG: + if(value!=but->min) push= 1; + break; + case ICONTOGN: + case TOGN: + if(value==0.0) push= 1; + break; + case ROW: + if(value == but->max) push= 1; + break; + case COL: + push= 1; + break; + default: + push= 2; + break; + } + } + + if(push==2); + else if(push==1) but->flag |= UI_SELECT; + else but->flag &= ~UI_SELECT; +} + +/* XXX 2.50 no links supported yet */ + +#if 0 +static uiBut *ui_get_valid_link_button(uiBlock *block, uiBut *but, short *mval) +{ + uiBut *bt; + + /* find button to link to */ + for (bt= block->buttons.first; bt; bt= bt->next) + if(bt!=but && uibut_contains_pt(bt, mval)) + break; + + if (bt) { + if (but->type==LINK && bt->type==INLINK) { + if( but->link->tocode == (int)bt->min ) { + return bt; + } + } + else if(but->type==INLINK && bt->type==LINK) { + if( bt->link->tocode == (int)but->min ) { + return bt; + } + } + } + + return NULL; +} + +static int ui_is_a_link(uiBut *from, uiBut *to) +{ + uiLinkLine *line; + uiLink *link; + + link= from->link; + if(link) { + line= link->lines.first; + while(line) { + if(line->from==from && line->to==to) return 1; + line= line->next; + } + } + return 0; +} + +static uiBut *ui_find_inlink(uiBlock *block, void *poin) +{ + uiBut *but; + + but= block->buttons.first; + while(but) { + if(but->type==INLINK) { + if(but->poin == poin) return but; + } + but= but->next; + } + return NULL; +} + +static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt) +{ + uiLinkLine *line; + + line= MEM_callocN(sizeof(uiLinkLine), "linkline"); + BLI_addtail(listb, line); + line->from= but; + line->to= bt; +} + +uiBut *uiFindInlink(uiBlock *block, void *poin) +{ + return ui_find_inlink(block, poin); +} + +void uiComposeLinks(uiBlock *block) +{ + uiBut *but, *bt; + uiLink *link; + void ***ppoin; + int a; + + but= block->buttons.first; + while(but) { + if(but->type==LINK) { + link= but->link; + + /* for all pointers in the array */ + if(link) { + if(link->ppoin) { + ppoin= link->ppoin; + for(a=0; a < *(link->totlink); a++) { + bt= ui_find_inlink(block, (*ppoin)[a] ); + if(bt) { + ui_add_link_line(&link->lines, but, bt); + } + } + } + else if(link->poin) { + bt= ui_find_inlink(block, *(link->poin) ); + if(bt) { + ui_add_link_line(&link->lines, but, bt); + } + } + } + } + but= but->next; + } +} + +static void ui_add_link(uiBut *from, uiBut *to) +{ + /* in 'from' we have to add a link to 'to' */ + uiLink *link; + void **oldppoin; + int a; + + if(ui_is_a_link(from, to)) { + printf("already exists\n"); + return; + } + + link= from->link; + + /* are there more pointers allowed? */ + if(link->ppoin) { + oldppoin= *(link->ppoin); + + (*(link->totlink))++; + *(link->ppoin)= MEM_callocN( *(link->totlink)*sizeof(void *), "new link"); + + for(a=0; a< (*(link->totlink))-1; a++) { + (*(link->ppoin))[a]= oldppoin[a]; + } + (*(link->ppoin))[a]= to->poin; + + if(oldppoin) MEM_freeN(oldppoin); + } + else { + *(link->poin)= to->poin; + } + +} + +static int ui_do_but_LINK(uiBlock *block, uiBut *but) +{ + /* + * This button only visualizes, the dobutton mode + * can add a new link, but then the whole system + * should be redrawn/initialized. + * + */ + uiBut *bt=0, *bto=NULL; + short sval[2], mval[2], mvalo[2], first= 1; + + uiGetMouse(curarea->win, sval); + mvalo[0]= sval[0]; + mvalo[1]= sval[1]; + + while (get_mbut() & L_MOUSE) { + uiGetMouse(curarea->win, mval); + + if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || first) { + /* clear completely, because of drawbuttons */ + bt= ui_get_valid_link_button(block, but, mval); + if(bt) { + bt->flag |= UI_ACTIVE; + ui_draw_but(bt); + } + if(bto && bto!=bt) { + bto->flag &= ~UI_ACTIVE; + ui_draw_but(bto); + } + bto= bt; + + if (!first) { + glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]); + } + glutil_draw_front_xor_line(sval[0], sval[1], mval[0], mval[1]); + + mvalo[0]= mval[0]; + mvalo[1]= mval[1]; + + first= 0; + } + else UI_wait_for_statechange(); + } + + if (!first) { + glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]); + } + + if(bt) { + if(but->type==LINK) ui_add_link(but, bt); + else ui_add_link(bt, but); + + scrarea_queue_winredraw(curarea); + } + + return 0; +} +#endif + +/* ************************************************ */ + +void uiBlockSetButLock(uiBlock *block, int val, char *lockstr) +{ + block->lock |= val; + if(val) block->lockstr= lockstr; +} + +void uiBlockClearButLock(uiBlock *block) +{ + block->lock= 0; + block->lockstr= NULL; +} + +/* *************************************************************** */ + +/* XXX 2.50 no button editing */ + +#if 0 +static void setup_file(uiBlock *block) +{ + uiBut *but; + FILE *fp; + + fp= fopen("butsetup","w"); + if(fp==NULL); + else { + but= block->buttons.first; + while(but) { + ui_check_but(but); + fprintf(fp,"%d,%d,%d,%d %s %s\n", (int)but->x1, (int)but->y1, (int)( but->x2-but->x1), (int)(but->y2-but->y1), but->str, but->tip); + but= but->next; + } + fclose(fp); + } +} + + +static void edit_but(uiBlock *block, uiBut *but, uiEvent *uevent) +{ + short dx, dy, mval[2], mvalo[2], didit=0; + + getmouseco_sc(mvalo); + while(TRUE) { + if( !(get_mbut() & L_MOUSE) ) break; + + getmouseco_sc(mval); + dx= (mval[0]-mvalo[0]); + dy= (mval[1]-mvalo[1]); + + if(dx!=0 || dy!=0) { + mvalo[0]= mval[0]; + mvalo[1]= mval[1]; + + cpack(0xc0c0c0); + glRectf(but->x1-2, but->y1-2, but->x2+2, but->y2+2); + + if((uevent->qual & LR_SHIFTKEY)==0) { + but->x1 += dx; + but->y1 += dy; + } + but->x2 += dx; + but->y2 += dy; + + ui_draw_but(but); + ui_block_flush_back(but->block); + didit= 1; + + } + /* idle for this poor code */ + else PIL_sleep_ms(30); + } + if(didit) setup_file(block); +} +#endif + +/* XXX 2.50 no links supported yet */ +#if 0 +static void ui_delete_active_linkline(uiBlock *block) +{ + uiBut *but; + uiLink *link; + uiLinkLine *line, *nline; + int a, b; + + but= block->buttons.first; + while(but) { + if(but->type==LINK && but->link) { + line= but->link->lines.first; + while(line) { + + nline= line->next; + + if(line->flag & UI_SELECT) { + BLI_remlink(&but->link->lines, line); + + link= line->from->link; + + /* are there more pointers allowed? */ + if(link->ppoin) { + + if(*(link->totlink)==1) { + *(link->totlink)= 0; + MEM_freeN(*(link->ppoin)); + *(link->ppoin)= NULL; + } + else { + b= 0; + for(a=0; a< (*(link->totlink)); a++) { + + if( (*(link->ppoin))[a] != line->to->poin ) { + (*(link->ppoin))[b]= (*(link->ppoin))[a]; + b++; + } + } + (*(link->totlink))--; + } + } + else { + *(link->poin)= NULL; + } + + MEM_freeN(line); + } + line= nline; + } + } + but= but->next; + } + + /* temporal! these buttons can be everywhere... */ + allqueue(REDRAWBUTSLOGIC, 0); +} + +static void ui_do_active_linklines(uiBlock *block, short *mval) +{ + uiBut *but; + uiLinkLine *line, *act= NULL; + float mindist= 12.0, fac, v1[2], v2[2], v3[3]; + int foundone= 0; + + if(mval) { + v1[0]= mval[0]; + v1[1]= mval[1]; + + /* find a line close to the mouse */ + but= block->buttons.first; + while(but) { + if(but->type==LINK && but->link) { + foundone= 1; + line= but->link->lines.first; + while(line) { + v2[0]= line->from->x2; + v2[1]= (line->from->y1+line->from->y2)/2.0; + v3[0]= line->to->x1; + v3[1]= (line->to->y1+line->to->y2)/2.0; + + fac= PdistVL2Dfl(v1, v2, v3); + if(fac < mindist) { + mindist= fac; + act= line; + } + line= line->next; + } + } + but= but->next; + } + } + + /* check for a 'found one' to prevent going to 'frontbuffer' mode. + this slows done gfx quite some, and at OSX the 'finish' forces a swapbuffer */ + if(foundone) { + glDrawBuffer(GL_FRONT); + + /* draw */ + but= block->buttons.first; + while(but) { + if(but->type==LINK && but->link) { + line= but->link->lines.first; + while(line) { + if(line==act) { + if((line->flag & UI_SELECT)==0) { + line->flag |= UI_SELECT; + ui_draw_linkline(but, line); + } + } + else if(line->flag & UI_SELECT) { + line->flag &= ~UI_SELECT; + ui_draw_linkline(but, line); + } + line= line->next; + } + } + but= but->next; + } + bglFlush(); + glDrawBuffer(GL_BACK); + } +} +#endif + +/* ******************************************************* */ + +/* XXX 2.50 no screendump supported yet */ + +#if 0 +/* nasty but safe way to store screendump rect */ +static int scr_x=0, scr_y=0, scr_sizex=0, scr_sizey=0; + +static void ui_set_screendump_bbox(uiBlock *block) +{ + if(block) { + scr_x= block->minx; + scr_y= block->miny; + scr_sizex= block->maxx - block->minx; + scr_sizey= block->maxy - block->miny; + } + else { + scr_sizex= scr_sizey= 0; + } +} + +/* used for making screenshots for menus, called in screendump.c */ +int uiIsMenu(int *x, int *y, int *sizex, int *sizey) +{ + if(scr_sizex!=0 && scr_sizey!=0) { + *x= scr_x; + *y= scr_y; + *sizex= scr_sizex; + *sizey= scr_sizey; + return 1; + } + + return 0; +} +#endif + +/* *********************** data get/set *********************** + * this either works with the pointed to data, or can work with + * an edit override pointer while dragging for example */ + +/* for buttons pointing to color for example */ +void ui_get_but_vectorf(uiBut *but, float *vec) +{ + void *poin; + int pointype; + + poin= (but->editvec)? (void*)but->editvec: but->poin; + pointype= (but->editvec)? FLO: but->pointype; + + if(!but->editvec && pointype == CHA) { + char *cp= (char *)poin; + vec[0]= ((float)cp[0])/255.0; + vec[1]= ((float)cp[1])/255.0; + vec[2]= ((float)cp[2])/255.0; + } + else if(pointype == FLO) { + float *fp= (float *)poin; + VECCOPY(vec, fp); + } +} + +/* for buttons pointing to color for example */ +void ui_set_but_vectorf(uiBut *but, float *vec) +{ + void *poin; + int pointype; + + poin= (but->editvec)? (void*)but->editvec: but->poin; + pointype= (but->editvec)? FLO: but->pointype; + + if(!but->editvec && but->pointype == CHA) { + char *cp= (char *)poin; + cp[0]= (char)(0.5 +vec[0]*255.0); + cp[1]= (char)(0.5 +vec[1]*255.0); + cp[2]= (char)(0.5 +vec[2]*255.0); + } + else if( but->pointype == FLO ) { + float *fp= (float *)poin; + VECCOPY(fp, vec); + } +} + +int ui_is_but_float(uiBut *but) +{ + if(but->pointype==FLO && but->poin) + return 1; + + if(but->rnaprop && but->rnaprop->type==PROP_FLOAT && but->rnapoin.data) + return 1; + + return 0; +} + +double ui_get_but_val(uiBut *but) +{ + PropertyRNA *prop; + double value = 0.0; + + if(but->editval) { return *(but->editval); } + if(but->poin==NULL && but->rnapoin.data==NULL) return 0.0; + + if(but->rnaprop) { + prop= but->rnaprop; + + switch(prop->type) { + case PROP_BOOLEAN: + if(prop->arraylength) + value= RNA_property_boolean_get_array(prop, &but->rnapoin, but->rnaindex); + else + value= RNA_property_boolean_get(prop, &but->rnapoin); + break; + case PROP_INT: + if(prop->arraylength) + value= RNA_property_int_get_array(prop, &but->rnapoin, but->rnaindex); + else + value= RNA_property_int_get(prop, &but->rnapoin); + break; + case PROP_FLOAT: + if(prop->arraylength) + value= RNA_property_float_get_array(prop, &but->rnapoin, but->rnaindex); + else + value= RNA_property_float_get(prop, &but->rnapoin); + break; + case PROP_ENUM: + value= RNA_property_enum_get(prop, &but->rnapoin); + break; + default: + value= 0.0; + break; + } + } + else if(but->type== HSVSLI) { + float h, s, v, *fp; + + fp= (but->editvec)? but->editvec: (float *)but->poin; + rgb_to_hsv(fp[0], fp[1], fp[2], &h, &s, &v); + + switch(but->str[0]) { + case 'H': value= h; break; + case 'S': value= s; break; + case 'V': value= v; break; + } + } + else if( but->pointype == CHA ) { + value= *(char *)but->poin; + } + else if( but->pointype == SHO ) { + value= *(short *)but->poin; + } + else if( but->pointype == INT ) { + value= *(int *)but->poin; + } + else if( but->pointype == FLO ) { + value= *(float *)but->poin; + } + + return value; +} + +void ui_set_but_val(uiBut *but, double value) +{ + PropertyRNA *prop; + + /* value is a hsv value: convert to rgb */ + if(but->rnaprop) { + prop= but->rnaprop; + + switch(prop->type) { + case PROP_BOOLEAN: + if(prop->arraylength) + RNA_property_boolean_set_array(prop, &but->rnapoin, but->rnaindex, value); + else + RNA_property_boolean_set(prop, &but->rnapoin, value); + break; + case PROP_INT: + if(prop->arraylength) + RNA_property_int_set_array(prop, &but->rnapoin, but->rnaindex, value); + else + RNA_property_int_set(prop, &but->rnapoin, value); + break; + case PROP_FLOAT: + if(prop->arraylength) + RNA_property_float_set_array(prop, &but->rnapoin, but->rnaindex, value); + else + RNA_property_float_set(prop, &but->rnapoin, value); + break; + case PROP_ENUM: + RNA_property_enum_set(prop, &but->rnapoin, value); + break; + default: + break; + } + } + else if(but->pointype==0); + else if(but->type==HSVSLI ) { + float h, s, v, *fp; + + fp= (but->editvec)? but->editvec: (float *)but->poin; + rgb_to_hsv(fp[0], fp[1], fp[2], &h, &s, &v); + + switch(but->str[0]) { + case 'H': h= value; break; + case 'S': s= value; break; + case 'V': v= value; break; + } + + hsv_to_rgb(h, s, v, fp, fp+1, fp+2); + + } + else { + /* first do rounding */ + if(but->pointype==CHA) + value= (char)floor(value+0.5); + else if(but->pointype==SHO ) { + /* gcc 3.2.1 seems to have problems + * casting a double like 32772.0 to + * a short so we cast to an int, then + to a short */ + int gcckludge; + gcckludge = (int) floor(value+0.5); + value= (short)gcckludge; + } + else if(but->pointype==INT ) + value= (int)floor(value+0.5); + else if(but->pointype==FLO ) { + float fval= (float)value; + if(fval>= -0.00001f && fval<= 0.00001f) fval= 0.0f; /* prevent negative zero */ + value= fval; + } + + /* then set value with possible edit override */ + if(but->editval) + *but->editval= value; + else if(but->pointype==CHA) + *((char *)but->poin)= (char)value; + else if(but->pointype==SHO) + *((short *)but->poin)= (short)value; + else if(but->pointype==INT) + *((int *)but->poin)= (int)value; + else if(but->pointype==FLO) + *((float *)but->poin)= (float)value; + } + + /* update select flag */ + ui_is_but_sel(but); +} + +void ui_get_but_string(uiBut *but, char *str, int maxlen) +{ + if(but->rnaprop) { + char *buf; + + buf= RNA_property_string_get_alloc(but->rnaprop, &but->rnapoin, str, maxlen); + + if(buf != str) { + /* string was too long, we have to truncate */ + BLI_strncpy(str, buf, maxlen); + MEM_freeN(buf); + } + } + else + BLI_strncpy(str, but->poin, maxlen); + +} + +void ui_set_but_string(uiBut *but, const char *str) +{ + if(but->rnaprop) + RNA_property_string_set(but->rnaprop, &but->rnapoin, str); + else + BLI_strncpy(but->poin, str, but->max); +} + +/* ******************* Font ********************/ + +static void ui_set_ftf_font(float aspect) +{ +#ifdef INTERNATIONAL + if(aspect<1.15) { + FTF_SetFontSize('l'); + } + else if(aspect<1.59) { + FTF_SetFontSize('m'); + } + else { + FTF_SetFontSize('s'); + } +#endif +} + +void uiSetCurFont(uiBlock *block, int index) +{ + ui_set_ftf_font(block->aspect); + + if(block->aspect<0.60) { + block->curfont= UIfont[index].xl; + } + else if(block->aspect<1.15) { + block->curfont= UIfont[index].large; + } + else if(block->aspect<1.59) { + block->curfont= UIfont[index].medium; + } + else { + block->curfont= UIfont[index].small; + } + + if(block->curfont==NULL) block->curfont= UIfont[index].large; + if(block->curfont==NULL) block->curfont= UIfont[index].medium; + if(block->curfont==NULL) printf("error block no font %s\n", block->name); + +} + +/* called by node editor */ +void *uiSetCurFont_ext(float aspect) +{ + void *curfont; + + ui_set_ftf_font(aspect); + + if(aspect<0.60) { + curfont= UIfont[0].xl; + } + else if(aspect<1.15) { + curfont= UIfont[0].large; + } + else if(aspect<1.59) { + curfont= UIfont[0].medium; + } + else { + curfont= UIfont[0].small; + } + + if(curfont==NULL) curfont= UIfont[0].large; + if(curfont==NULL) curfont= UIfont[0].medium; + + return curfont; +} + +void uiDefFont(unsigned int index, void *xl, void *large, void *medium, void *small) +{ + if(index>=UI_ARRAY) return; + + UIfont[index].xl= xl; + UIfont[index].large= large; + UIfont[index].medium= medium; + UIfont[index].small= small; +} + +/* ******************* Free ********************/ + +static void ui_free_link(uiLink *link) +{ + if(link) { + BLI_freelistN(&link->lines); + MEM_freeN(link); + } +} + +static void ui_free_but(uiBut *but) +{ + if(but->str && but->str != but->strdata) MEM_freeN(but->str); + ui_free_link(but->link); + + MEM_freeN(but); +} + +void uiFreeBlock(uiBlock *block) +{ + uiBut *but; + + while( (but= block->buttons.first) ) { + BLI_remlink(&block->buttons, but); + ui_free_but(but); + } + + if(block->panel) block->panel->active= 0; + BLI_freelistN(&block->saferct); + + + MEM_freeN(block); +} + +void uiFreeBlocks(ListBase *lb) +{ + uiBlock *block; + + while( (block= lb->first) ) { + BLI_remlink(lb, block); + uiFreeBlock(block); + } +} + +uiBlock *uiBeginBlock(wmWindow *window, ARegion *region, char *name, short dt, short font) +{ + ListBase *lb; + uiBlock *block, *oldblock= NULL; + int getsizex, getsizey; + + lb= ®ion->uiblocks; + + /* each listbase only has one block with this name, free block + * if is already there so it can be rebuilt from scratch */ + if(lb) { + for (oldblock= lb->first; oldblock; oldblock= oldblock->next) + if (BLI_streq(oldblock->name, name)) + break; + + if (oldblock) + BLI_remlink(lb, oldblock); + } + + block= MEM_callocN(sizeof(uiBlock), "uiBlock"); + block->oldblock= oldblock; + + /* at the beginning of the list! for dynamical menus/blocks */ + if(lb) + BLI_addhead(lb, block); + + BLI_strncpy(block->name, name, sizeof(block->name)); + +#if 0 + /* draw win */ + block->win= win; + /* window where queue event should be added, pretty weak this way! + this is because the 'mainwin' pup menu's */ + block->winq= mywinget(); +#endif + + block->dt= dt; + block->themecol= TH_AUTO; + + /* window matrix and aspect */ + if(region->swinid) { + wm_subwindow_getmatrix(window, region->swinid, block->winmat); + wm_subwindow_getsize(window, region->swinid, &getsizex, &getsizey); + + /* TODO - investigate why block->winmat[0][0] is negative + * in the image view when viewRedrawForce is called */ + block->aspect= 2.0/fabs( (getsizex)*block->winmat[0][0]); + } + else { + /* no subwindow created yet, for menus for example, so we + * use the main window instead, since buttons are created + * there anyway */ + wm_subwindow_getmatrix(window, window->winid, block->winmat); + wm_subwindow_getsize(window, window->winid, &getsizex, &getsizey); + + block->aspect= 2.0/fabs(getsizex*block->winmat[0][0]); + block->auto_open= 2; + } + + uiSetCurFont(block, font); + + return block; +} + +uiBlock *uiGetBlock(char *name, ARegion *ar) +{ + uiBlock *block= ar->uiblocks.first; + + while(block) { + if( strcmp(name, block->name)==0 ) return block; + block= block->next; + } + + return NULL; +} + +void ui_check_but(uiBut *but) +{ + /* if something changed in the button */ + ID *id; + double value; + float okwidth; + int transopts= ui_translate_buttons(); + short pos; + + ui_is_but_sel(but); + + if(but->type==TEX || but->type==IDPOIN) transopts= 0; + + /* test for min and max, icon sliders, etc */ + switch( but->type ) { + case NUM: + case SLI: + case SCROLL: + case NUMSLI: + case HSVSLI: + value= ui_get_but_val(but); + if(value < but->min) ui_set_but_val(but, but->min); + else if(value > but->max) ui_set_but_val(but, but->max); + break; + + case NUMABS: + value= fabs( ui_get_but_val(but) ); + if(value < but->min) ui_set_but_val(but, but->min); + else if(value > but->max) ui_set_but_val(but, but->max); + break; + + case ICONTOG: + case ICONTOGN: + if(but->flag & UI_SELECT) but->iconadd= 1; + else but->iconadd= 0; + break; + + case ICONROW: + value= ui_get_but_val(but); + but->iconadd= (int)value- (int)(but->min); + break; + + case ICONTEXTROW: + value= ui_get_but_val(but); + but->iconadd= (int)value- (int)(but->min); + break; + } + + + /* safety is 4 to enable small number buttons (like 'users') */ + if(but->type==NUMSLI || but->type==HSVSLI) + okwidth= -4 + (but->x2 - but->x1)/2.0; + else + okwidth= -4 + (but->x2 - but->x1); + + /* name: */ + switch( but->type ) { + + case MENU: + case ICONTEXTROW: + + if(but->x2 - but->x1 > 24) { + value= ui_get_but_val(but); + ui_set_name_menu(but, (int)value); + } + break; + + case NUM: + case NUMSLI: + case HSVSLI: + case NUMABS: + + value= ui_get_but_val(but); + + if(ui_is_but_float(but)) { + if(but->a2) { /* amount of digits defined */ + if(but->a2==1) sprintf(but->drawstr, "%s%.1f", but->str, value); + else if(but->a2==2) sprintf(but->drawstr, "%s%.2f", but->str, value); + else if(but->a2==3) sprintf(but->drawstr, "%s%.3f", but->str, value); + else sprintf(but->drawstr, "%s%.4f", but->str, value); + } + else { + if(but->max<10.001) sprintf(but->drawstr, "%s%.3f", but->str, value); + else sprintf(but->drawstr, "%s%.2f", but->str, value); + } + } + else { + sprintf(but->drawstr, "%s%d", but->str, (int)value); + } + break; + + case LABEL: + if(ui_is_but_float(but)) { + value= ui_get_but_val(but); + if(but->a2) { /* amount of digits defined */ + if(but->a2==1) sprintf(but->drawstr, "%s%.1f", but->str, value); + else if(but->a2==2) sprintf(but->drawstr, "%s%.2f", but->str, value); + else if(but->a2==3) sprintf(but->drawstr, "%s%.3f", but->str, value); + else sprintf(but->drawstr, "%s%.4f", but->str, value); + } + else { + sprintf(but->drawstr, "%s%.2f", but->str, value); + } + } + else strcpy(but->drawstr, but->str); + + break; + + case IDPOIN: + id= *(but->idpoin_idpp); + strcpy(but->drawstr, but->str); + if(id) strcat(but->drawstr, id->name+2); + break; + + case TEX: + if(!but->editstr) { + char str[UI_MAX_DRAW_STR]; + + ui_get_but_string(but, str, UI_MAX_DRAW_STR-strlen(but->str)); + + strcpy(but->drawstr, but->str); + strcat(but->drawstr, str); + } + break; + + case KEYEVT: + strcpy(but->drawstr, but->str); + if (but->flag & UI_SELECT) { + strcat(but->drawstr, "Press a key"); + } else { + /* XXX 2.50 function not supported */ + /* strcat(but->drawstr, key_event_to_string((short) ui_get_but_val(but))); */ + } + break; + + case BUT_TOGDUAL: + /* trying to get the dual-icon to left of text... not very nice */ + if(but->str[0]) { + strcpy(but->drawstr, " "); + strcpy(but->drawstr+2, but->str); + } + break; + default: + strcpy(but->drawstr, but->str); + + } + + /* if we are doing text editing, this will override the drawstr */ + if(but->editstr) { + strcpy(but->drawstr, but->str); + strcat(but->drawstr, but->editstr); + } + + if(but->drawstr[0]) { + but->strwidth= but->aspect*UI_GetStringWidth(but->font, but->drawstr, transopts); + // here should be check for less space for icon offsets... + if(but->type==MENU) okwidth -= 15; + } + else + but->strwidth= 0; + + /* automatic width */ + if(but->x2==0.0f && but->x1 > 0.0f) { + but->x2= (but->x1+but->strwidth+6); + } + + if(but->strwidth==0) but->drawstr[0]= 0; + else if(but->type==BUTM || but->type==BLOCK); // no clip string, uiTextBoundsBlock is used (hack!) + else { + + /* calc but->ofs, to draw the string shorter if too long */ + but->ofs= 0; + + while(but->strwidth > (int)okwidth ) { + + if ELEM3(but->type, NUM, NUMABS, TEX) { // only these cut off left + but->ofs++; + but->strwidth= but->aspect*UI_GetStringWidth(but->font, but->drawstr+but->ofs, transopts); + + /* textbut exception */ + if(but->editstr && but->pos != -1) { + pos= but->pos+strlen(but->str); + if(pos-1 < but->ofs) { + pos= but->ofs-pos+1; + but->ofs -= pos; + if(but->ofs<0) { + but->ofs= 0; + pos--; + } + but->drawstr[ strlen(but->drawstr)-pos ]= 0; + } + } + } + else { + but->drawstr[ strlen(but->drawstr)-1 ]= 0; + but->strwidth= but->aspect*UI_GetStringWidth(but->font, but->drawstr, transopts); + } + + if(but->strwidth < 10) break; + } + } +} + +static int ui_auto_themecol(uiBut *but) +{ + + switch(but->type) { + case BUT: + return TH_BUT_ACTION; + case ROW: + case TOG: + case TOG3: + case TOGR: + case TOGN: + case BUT_TOGDUAL: + return TH_BUT_SETTING; + case SLI: + case NUM: + case NUMSLI: + case NUMABS: + case HSVSLI: + return TH_BUT_NUM; + case TEX: + return TH_BUT_TEXTFIELD; + case PULLDOWN: + case BLOCK: + case MENU: + case BUTM: + // (weak!) detect if it is a blockloop + if(but->block->dt == UI_EMBOSSP) return TH_MENU_ITEM; + return TH_BUT_POPUP; + case ROUNDBOX: + return TH_PANEL; + default: + return TH_BUT_NEUTRAL; + } +} + +void uiBlockBeginAlign(uiBlock *block) +{ + /* if other align was active, end it */ + if(block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block); + + block->flag |= UI_BUT_ALIGN_DOWN; + /* buttons declared after this call will this align flag */ +} + +static int buts_are_horiz(uiBut *but1, uiBut *but2) +{ + float dx, dy; + + dx= fabs( but1->x2 - but2->x1); + dy= fabs( but1->y1 - but2->y2); + + if(dx > dy) return 0; + return 1; +} + +void uiBlockEndAlign(uiBlock *block) +{ + uiBut *prev, *but=NULL, *next; + int flag= 0, cols=0, rows=0; + int theme= UI_GetThemeValue(TH_BUT_DRAWTYPE); + + if ( !(ELEM3(theme, TH_MINIMAL, TH_SHADED, TH_ROUNDED)) ) { + block->flag &= ~UI_BUT_ALIGN; // all 4 flags + return; + } + + /* auto align: + - go back to first button of align start (ALIGN_DOWN) + - compare triples, and define flags + */ + prev= block->buttons.last; + while(prev) { + if( (prev->flag & UI_BUT_ALIGN_DOWN)) but= prev; + else break; + + if(but && but->next) { + if(buts_are_horiz(but, but->next)) cols++; + else rows++; + } + + prev= prev->prev; + } + if(but==NULL) return; + + /* rows==0: 1 row, cols==0: 1 collumn */ + + /* note; how it uses 'flag' in loop below (either set it, or OR it) is confusing */ + prev= NULL; + while(but) { + next= but->next; + + /* clear old flag */ + but->flag &= ~UI_BUT_ALIGN_DOWN; + + if(flag==0) { /* first case */ + if(next) { + if(buts_are_horiz(but, next)) { + if(rows==0) + flag= UI_BUT_ALIGN_RIGHT; + else + flag= UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT; + } + else { + flag= UI_BUT_ALIGN_DOWN; + } + } + } + else if(next==NULL) { /* last case */ + if(prev) { + if(buts_are_horiz(prev, but)) { + if(rows==0) + flag= UI_BUT_ALIGN_LEFT; + else + flag= UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT; + } + else flag= UI_BUT_ALIGN_TOP; + } + } + else if(buts_are_horiz(but, next)) { + /* check if this is already second row */ + if( prev && buts_are_horiz(prev, but)==0) { + flag |= UI_BUT_ALIGN_TOP; + /* exception case: bottom row */ + if(rows>0) { + uiBut *bt= but; + while(bt) { + if(bt->next && buts_are_horiz(bt, bt->next)==0 ) break; + bt= bt->next; + } + if(bt==0) flag= UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT; + } + } + else flag |= UI_BUT_ALIGN_LEFT; + } + else { + if(cols==0) { + flag |= UI_BUT_ALIGN_TOP; + } + else { /* next button switches to new row */ + if( (flag & UI_BUT_ALIGN_TOP)==0) { /* stil top row */ + if(prev) + flag= UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT; + else + flag |= UI_BUT_ALIGN_DOWN; + } + else + flag |= UI_BUT_ALIGN_TOP; + } + } + + but->flag |= flag; + + /* merge coordinates */ + if(prev) { + // simple cases + if(rows==0) { + but->x1= (prev->x2+but->x1)/2.0; + prev->x2= but->x1; + } + else if(cols==0) { + but->y2= (prev->y1+but->y2)/2.0; + prev->y1= but->y2; + } + else { + if(buts_are_horiz(prev, but)) { + but->x1= (prev->x2+but->x1)/2.0; + prev->x2= but->x1; + /* copy height too */ + but->y2= prev->y2; + } + else if(prev->prev && buts_are_horiz(prev->prev, prev)==0) { + /* the previous button is a single one in its row */ + but->y2= (prev->y1+but->y2)/2.0; + prev->y1= but->y2; + } + else { + /* the previous button is not a single one in its row */ + but->y2= prev->y1; + } + } + } + + prev= but; + but= next; + } + + block->flag &= ~UI_BUT_ALIGN; // all 4 flags +} + +#if 0 +static void uiBlockEndAligno(uiBlock *block) +{ + uiBut *but; + + /* correct last defined button */ + but= block->buttons.last; + if(but) { + /* vertical align case */ + if( (block->flag & UI_BUT_ALIGN) == (UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_DOWN) ) { + but->flag &= ~UI_BUT_ALIGN_DOWN; + } + /* horizontal align case */ + if( (block->flag & UI_BUT_ALIGN) == (UI_BUT_ALIGN_LEFT|UI_BUT_ALIGN_RIGHT) ) { + but->flag &= ~UI_BUT_ALIGN_RIGHT; + } + /* else do nothing, manually provided flags */ + } + block->flag &= ~UI_BUT_ALIGN; // all 4 flags +} +#endif + +/* +ui_def_but is the function that draws many button types + +for float buttons: + "a1" Click Step (how much to change the value each click) + "a2" Number of decimal point values to display. 0 defaults to 3 (0.000) 1,2,3, and a maximum of 4, + all greater values will be clamped to 4. + +*/ +static uiBut *ui_def_but(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip) +{ + uiBut *but; + short slen; + + if(type & BUTPOIN) { /* a pointer is required */ + if(poin==NULL) { + /* if pointer is zero, button is removed and not drawn */ + UI_ThemeColor(block->themecol); + glRects(x1, y1, x1+x2, y1+y2); + return NULL; + } + } + + but= MEM_callocN(sizeof(uiBut), "uiBut"); + + but->type= type & BUTTYPE; + but->pointype= type & BUTPOIN; + but->bit= type & BIT; + but->bitnr= type & 31; + but->icon = 0; + + BLI_addtail(&block->buttons, but); + + but->retval= retval; + if( strlen(str)>=UI_MAX_NAME_STR-1 ) { + but->str= MEM_callocN( strlen(str)+2, "uiDefBut"); + strcpy(but->str, str); + } + else { + but->str= but->strdata; + strcpy(but->str, str); + } + but->x1= x1; + but->y1= y1; + if(block->autofill) { + but->x2= x2; + but->y2= y2; + } + else { + but->x2= (x1+x2); + but->y2= (y1+y2); + } + but->poin= poin; + but->min= min; + but->max= max; + but->a1= a1; + but->a2= a2; + but->tip= tip; + + but->font= block->curfont; + + but->lock= block->lock; + but->lockstr= block->lockstr; + + but->aspect= block->aspect; + but->win= block->win; + but->block= block; // pointer back, used for frontbuffer status, and picker + + if(block->themecol==TH_AUTO) but->themecol= ui_auto_themecol(but); + else but->themecol= block->themecol; + + if (but->type==BUTM) { + but->butm_func= block->butm_func; + but->butm_func_arg= block->butm_func_arg; + } else { + but->func= block->func; + but->func_arg1= block->func_arg1; + but->func_arg2= block->func_arg2; + } + + ui_set_embossfunc(but, block->dt); + + but->pos= -1; /* cursor invisible */ + + if(ELEM(but->type, NUM, NUMABS)) { /* add a space to name */ + slen= strlen(but->str); + if(slen>0 && slen<UI_MAX_NAME_STR-2) { + if(but->str[slen-1]!=' ') { + but->str[slen]= ' '; + but->str[slen+1]= 0; + } + } + } + + if(but->type==HSVCUBE) { /* hsv buttons temp storage */ + float rgb[3]; + ui_get_but_vectorf(but, rgb); + rgb_to_hsv(rgb[0], rgb[1], rgb[2], but->hsv, but->hsv+1, but->hsv+2); + } + + if ELEM8(but->type, HSVSLI , NUMSLI, MENU, TEX, LABEL, IDPOIN, BLOCK, BUTM) { + but->flag |= UI_TEXT_LEFT; + } + + if(but->type==BUT_TOGDUAL) { + but->flag |= UI_ICON_LEFT; + } + + if(but->type==ROUNDBOX) + but->flag |= UI_NO_HILITE; + + but->flag |= (block->flag & UI_BUT_ALIGN); + if(block->flag & UI_BLOCK_NO_HILITE) + but->flag |= UI_NO_HILITE; + + return but; +} + +uiBut *uiDefBut(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip) +{ + uiBut *but= ui_def_but(block, type, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip); + + ui_check_but(but); + + return but; +} + + /* if _x_ is a power of two (only one bit) return the power, + * otherwise return -1. + * (1<<findBitIndex(x))==x for powers of two. + */ +static int findBitIndex(unsigned int x) { + if (!x || (x&(x-1))!=0) { /* x&(x-1) strips lowest bit */ + return -1; + } else { + int idx= 0; + + if (x&0xFFFF0000) idx+=16, x>>=16; + if (x&0xFF00) idx+=8, x>>=8; + if (x&0xF0) idx+=4, x>>=4; + if (x&0xC) idx+=2, x>>=2; + if (x&0x2) idx+=1; + + return idx; + } +} + +/* autocomplete helper functions */ +struct AutoComplete { + int maxlen; + char *truncate; + char *startname; +}; + +AutoComplete *autocomplete_begin(char *startname, int maxlen) +{ + AutoComplete *autocpl; + + autocpl= MEM_callocN(sizeof(AutoComplete), "AutoComplete"); + autocpl->maxlen= maxlen; + autocpl->truncate= MEM_callocN(sizeof(char)*maxlen, "AutoCompleteTruncate"); + autocpl->startname= startname; + + return autocpl; +} + +void autocomplete_do_name(AutoComplete *autocpl, const char *name) +{ + char *truncate= autocpl->truncate; + char *startname= autocpl->startname; + int a; + + for(a=0; a<autocpl->maxlen-1; a++) { + if(startname[a]==0 || startname[a]!=name[a]) + break; + } + /* found a match */ + if(startname[a]==0) { + /* first match */ + if(truncate[0]==0) + BLI_strncpy(truncate, name, autocpl->maxlen); + else { + /* remove from truncate what is not in bone->name */ + for(a=0; a<autocpl->maxlen-1; a++) { + if(truncate[a]!=name[a]) + truncate[a]= 0; + } + } + } +} + +void autocomplete_end(AutoComplete *autocpl, char *autoname) +{ + if(autocpl->truncate[0]) + BLI_strncpy(autoname, autocpl->truncate, autocpl->maxlen); + else + BLI_strncpy(autoname, autocpl->startname, autocpl->maxlen); + + MEM_freeN(autocpl->truncate); + MEM_freeN(autocpl); +} + +/* autocomplete callback for ID buttons */ +static void autocomplete_id(char *str, void *arg_v) +{ + /* XXX 2.48 int blocktype= (intptr_t)arg_v; */ + ListBase *listb= NULL /* XXX 2.50 needs context, wich_libbase(G.main, blocktype) */; + + if(listb==NULL) return; + + /* search if str matches the beginning of an ID struct */ + if(str[0]) { + AutoComplete *autocpl= autocomplete_begin(str, 22); + ID *id; + + for(id= listb->first; id; id= id->next) + autocomplete_do_name(autocpl, id->name+2); + + autocomplete_end(autocpl, str); + } +} + +static uiBut *uiDefButBit(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip) +{ + int bitIdx= findBitIndex(bit); + if (bitIdx==-1) { + return NULL; + } else { + return uiDefBut(block, type|BIT|bitIdx, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip); + } +} +uiBut *uiDefButF(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefBut(block, type|FLO, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefButBitF(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefButBit(block, type|FLO, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefButI(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefBut(block, type|INT, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefButBitI(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefButBit(block, type|INT, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefButS(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefBut(block, type|SHO, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefButBitS(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefButBit(block, type|SHO, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefButC(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefBut(block, type|CHA, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefButBitC(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefButBit(block, type|CHA, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} + +uiBut *uiDefIconBut(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip) +{ + uiBut *but= ui_def_but(block, type, retval, "", x1, y1, x2, y2, poin, min, max, a1, a2, tip); + + but->icon= (BIFIconID) icon; + but->flag|= UI_HAS_ICON; + + ui_check_but(but); + + return but; +} +static uiBut *uiDefIconButBit(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip) +{ + int bitIdx= findBitIndex(bit); + if (bitIdx==-1) { + return NULL; + } else { + return uiDefIconBut(block, type|BIT|bitIdx, retval, icon, x1, y1, x2, y2, poin, min, max, a1, a2, tip); + } +} + +uiBut *uiDefIconButF(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconBut(block, type|FLO, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconButBitF(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconButBit(block, type|FLO, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconButI(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconBut(block, type|INT, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconButBitI(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconButBit(block, type|INT, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconButS(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconBut(block, type|SHO, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconButBitS(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconButBit(block, type|SHO, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconButC(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconBut(block, type|CHA, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconButBitC(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconButBit(block, type|CHA, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} + +/* Button containing both string label and icon */ +uiBut *uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip) +{ + uiBut *but= ui_def_but(block, type, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip); + + but->icon= (BIFIconID) icon; + but->flag|= UI_HAS_ICON; + + but->flag|= UI_ICON_LEFT; + + ui_check_but(but); + + return but; +} +static uiBut *uiDefIconTextButBit(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip) +{ + int bitIdx= findBitIndex(bit); + if (bitIdx==-1) { + return NULL; + } else { + return uiDefIconTextBut(block, type|BIT|bitIdx, retval, icon, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip); + } +} + +uiBut *uiDefIconTextButF(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconTextBut(block, type|FLO, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconTextButBitF(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconTextButBit(block, type|FLO, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconTextButI(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconTextBut(block, type|INT, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconTextButBitI(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconTextButBit(block, type|INT, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconTextButS(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconTextBut(block, type|SHO, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconTextButBitS(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconTextButBit(block, type|SHO, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconTextButC(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconTextBut(block, type|CHA, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} +uiBut *uiDefIconTextButBitC(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip) +{ + return uiDefIconTextButBit(block, type|CHA, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip); +} + +uiBut *uiDefRNABut(uiBlock *block, int retval, PointerRNA *ptr, PropertyRNA *prop, int index, short x1, short y1, short x2, short y2) +{ + uiBut *but; + + switch(prop->type) { + case PROP_BOOLEAN: { + int value; + + if(prop->arraylength) + value= RNA_property_boolean_get_array(prop, ptr, index); + else + value= RNA_property_boolean_get(prop, ptr); + + but= ui_def_but(block, TOG, 0, (value)? "True": "False", x1, y1, x2, y2, NULL, 0, 0, 0, 0, (char*)prop->description); + break; + } + case PROP_INT: { + IntPropertyRNA *iprop= (IntPropertyRNA*)prop; + but= ui_def_but(block, NUM, 0, "", x1, y1, x2, y2, NULL, iprop->softmin, iprop->softmax, iprop->step, 0, (char*)prop->description); + break; + } + case PROP_FLOAT: { + FloatPropertyRNA *fprop= (FloatPropertyRNA*)prop; + but= ui_def_but(block, NUM, 0, "", x1, y1, x2, y2, NULL, fprop->softmin, fprop->softmax, fprop->step, fprop->precision, (char*)prop->description); + break; + } + case PROP_ENUM: { + EnumPropertyRNA *eprop= (EnumPropertyRNA*)prop; + DynStr *dynstr; + char *menu; + int i; + + dynstr= BLI_dynstr_new(); + BLI_dynstr_appendf(dynstr, "%s%%t", prop->name); + for(i=0; i<eprop->totitem; i++) + BLI_dynstr_appendf(dynstr, "|%s %%x%d", eprop->item[i].name, eprop->item[i].value); + menu= BLI_dynstr_get_cstring(dynstr); + BLI_dynstr_free(dynstr); + + but= ui_def_but(block, MENU, 0, menu, x1, y1, x2, y2, NULL, 0, 0, 0, 0, (char*)prop->description); + MEM_freeN(menu); + break; + } + case PROP_STRING: { + StringPropertyRNA *sprop= (StringPropertyRNA*)prop; + but= ui_def_but(block, TEX, 0, "", x1, y1, x2, y2, NULL, 0, sprop->maxlength, 0, 0, (char*)prop->description); + break; + } + case PROP_POINTER: { + PointerRNA pptr; + char name[256]= "", *nameptr= name; + + RNA_property_pointer_get(prop, ptr, &pptr); + + if(pptr.data) { + if(pptr.type && pptr.type->nameproperty) + nameptr= RNA_property_string_get_alloc(pptr.type->nameproperty, &pptr, name, sizeof(name)); + else + strcpy(nameptr, "unknown"); + } + + but= ui_def_but(block, BUT, 0, nameptr, x1, y1, x2, y2, NULL, 0, 0, 0, 0, (char*)prop->description); + but->flag |= UI_TEXT_LEFT; + + if(nameptr != name) + MEM_freeN(nameptr); + + break; + } + default: + but= NULL; + break; + } + + if(but) { + but->rnapoin= *ptr; + but->rnaprop= prop; + but->rnaindex= index; + + ui_check_but(but); + } + + return but; +} + +/* END Button containing both string label and icon */ + +void uiAutoBlock(uiBlock *block, float minx, float miny, float sizex, float sizey, int flag) +{ + block->minx= minx; + block->maxx= minx+sizex; + block->miny= miny; + block->maxy= miny+sizey; + + block->autofill= flag; /* also check for if it has to be done */ + +} + +void uiSetButLink(uiBut *but, void **poin, void ***ppoin, short *tot, int from, int to) +{ + uiLink *link; + + link= but->link= MEM_callocN(sizeof(uiLink), "new uilink"); + + link->poin= poin; + link->ppoin= ppoin; + link->totlink= tot; + link->fromcode= from; + link->tocode= to; +} + +/* cruft to make uiBlock and uiBut private */ + +int uiBlocksGetYMin(ListBase *lb) +{ + uiBlock *block; + int min= 0; + + for (block= lb->first; block; block= block->next) + if (block==lb->first || block->miny<min) + min= block->miny; + + return min; +} + +int uiBlockGetCol(uiBlock *block) +{ + return block->themecol; +} +void uiBlockSetCol(uiBlock *block, int col) +{ + block->themecol= col; +} +void uiBlockSetEmboss(uiBlock *block, int emboss) +{ + block->dt= emboss; +} +void uiBlockSetDirection(uiBlock *block, int direction) +{ + block->direction= direction; +} + +/* this call escapes if there's alignment flags */ +void uiBlockFlipOrder(uiBlock *block) +{ + ListBase lb; + uiBut *but, *next; + float centy, miny=10000, maxy= -10000; + +// if(U.uiflag & USER_PLAINMENUS) +// return; + + for(but= block->buttons.first; but; but= but->next) { + if(but->flag & UI_BUT_ALIGN) return; + if(but->y1 < miny) miny= but->y1; + if(but->y2 > maxy) maxy= but->y2; + } + /* mirror trick */ + centy= (miny+maxy)/2.0; + for(but= block->buttons.first; but; but= but->next) { + but->y1 = centy-(but->y1-centy); + but->y2 = centy-(but->y2-centy); + SWAP(float, but->y1, but->y2); + } + + /* also flip order in block itself, for example for arrowkey */ + lb.first= lb.last= NULL; + but= block->buttons.first; + while(but) { + next= but->next; + BLI_remlink(&block->buttons, but); + BLI_addtail(&lb, but); + but= next; + } + block->buttons= lb; +} + + +void uiBlockSetFlag(uiBlock *block, int flag) +{ + block->flag= flag; +} +void uiBlockSetXOfs(uiBlock *block, int xofs) +{ + block->xofs= xofs; +} +void* uiBlockGetCurFont(uiBlock *block) +{ + return block->curfont; +} + +void uiButSetFlag(uiBut *but, int flag) +{ + but->flag|= flag; +} +void uiButClearFlag(uiBut *but, int flag) +{ + but->flag&= ~flag; +} + +int uiButGetRetVal(uiBut *but) +{ + return but->retval; +} + +/* Call this function BEFORE adding buttons to the block */ +void uiBlockSetButmFunc(uiBlock *block, void (*menufunc)(void *arg, int event), void *arg) +{ + block->butm_func= menufunc; + block->butm_func_arg= arg; +} + +void uiBlockSetFunc(uiBlock *block, void (*func)(void *arg1, void *arg2), void *arg1, void *arg2) +{ + block->func= func; + block->func_arg1= arg1; + block->func_arg2= arg2; +} + +void uiBlockSetDrawExtraFunc(uiBlock *block, void (*func)()) +{ + block->drawextra= func; +} + +void uiButSetFunc(uiBut *but, void (*func)(void *arg1, void *arg2), void *arg1, void *arg2) +{ + but->func= func; + but->func_arg1= arg1; + but->func_arg2= arg2; +} + +void uiButSetFunc3(uiBut *but, void (*func)(void *arg1, void *arg2, void *arg3), void *arg1, void *arg2, void *arg3) +{ + but->func3= func; + but->func_arg1= arg1; + but->func_arg2= arg2; + but->func_arg3= arg3; +} + +void uiButSetCompleteFunc(uiBut *but, void (*func)(char *str, void *arg), void *arg) +{ + but->autocomplete_func= func; + but->autofunc_arg= arg; +} + +uiBut *uiDefIDPoinBut(uiBlock *block, uiIDPoinFuncFP func, short blocktype, int retval, char *str, short x1, short y1, short x2, short y2, void *idpp, char *tip) +{ + uiBut *but= ui_def_but(block, IDPOIN, retval, str, x1, y1, x2, y2, NULL, 0.0, 0.0, 0.0, 0.0, tip); + but->idpoin_func= func; + but->idpoin_idpp= (ID**) idpp; + ui_check_but(but); + + if(blocktype) + uiButSetCompleteFunc(but, autocomplete_id, 0 /* XXX 2.48 (void *)(intptr_t)blocktype*/); + + return but; +} + +uiBut *uiDefBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, char *str, short x1, short y1, short x2, short y2, char *tip) +{ + uiBut *but= ui_def_but(block, BLOCK, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip); + but->block_func= func; + ui_check_but(but); + return but; +} + +uiBut *uiDefPulldownBut(uiBlock *block, uiBlockFuncFP func, void *arg, char *str, short x1, short y1, short x2, short y2, char *tip) +{ + uiBut *but= ui_def_but(block, PULLDOWN, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip); + but->block_func= func; + ui_check_but(but); + return but; +} + +/* Block button containing both string label and icon */ +uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, int icon, char *str, short x1, short y1, short x2, short y2, char *tip) +{ + uiBut *but= ui_def_but(block, BLOCK, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip); + + but->icon= (BIFIconID) icon; + but->flag|= UI_HAS_ICON; + + but->flag|= UI_ICON_LEFT; + but->flag|= UI_ICON_RIGHT; + + but->block_func= func; + ui_check_but(but); + + return but; +} + +/* Block button containing icon */ +uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, int retval, int icon, short x1, short y1, short x2, short y2, char *tip) +{ + uiBut *but= ui_def_but(block, BLOCK, retval, "", x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip); + + but->icon= (BIFIconID) icon; + but->flag|= UI_HAS_ICON; + + but->flag|= UI_ICON_LEFT; + but->flag|= UI_ICON_RIGHT; + + but->block_func= func; + ui_check_but(but); + + return but; +} + +void uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip) +{ + uiBut *but= ui_def_but(block, KEYEVT|SHO, retval, str, x1, y1, x2, y2, spoin, 0.0, 0.0, 0.0, 0.0, tip); + ui_check_but(but); +} + +/* Program Init/Exit */ + +void UI_init(void) +{ + uiDefFont(UI_HELVB, + BMF_GetFont(BMF_kHelveticaBold14), + BMF_GetFont(BMF_kHelveticaBold12), + BMF_GetFont(BMF_kHelveticaBold10), + BMF_GetFont(BMF_kHelveticaBold8)); + uiDefFont(UI_HELV, + BMF_GetFont(BMF_kHelvetica12), + BMF_GetFont(BMF_kHelvetica12), + BMF_GetFont(BMF_kHelvetica10), + BMF_GetFont(BMF_kHelveticaBold8)); + + ui_resources_init(); +} + +void UI_init_userdef() +{ + ui_text_init_userdef(); + ui_theme_init_userdef(); +} + +void UI_exit(void) +{ + ui_resources_free(); +} + |