4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
31 a full doc with API notes can be found in bf-blender/blender/doc/interface_API.txt
51 #include "MEM_guardedalloc.h"
56 #include "BIF_language.h"
59 #endif // INTERNATIONAL
61 #include "BLI_blenlib.h"
62 #include "BLI_arithb.h"
64 #include "DNA_color_types.h"
65 #include "DNA_screen_types.h"
66 #include "DNA_space_types.h"
67 #include "DNA_userdef_types.h"
68 #include "DNA_vec_types.h"
69 #include "DNA_object_types.h"
70 #include "DNA_texture_types.h"
71 #include "DNA_vfont_types.h"
73 #include "BKE_blender.h"
74 #include "BKE_colortools.h"
75 #include "BKE_global.h"
76 #include "BKE_library.h"
77 #include "BKE_texture.h"
78 #include "BKE_utildefines.h"
80 #include "BIF_cursors.h"
82 #include "BIF_graphics.h"
83 #include "BIF_keyval.h"
84 #include "BIF_mainqueue.h"
85 #include "BIF_resources.h"
86 #include "BIF_screen.h"
87 #include "BIF_toolbox.h"
88 #include "BIF_mywindow.h"
89 #include "BIF_space.h"
90 #include "BIF_glutil.h"
91 #include "BIF_editfont.h"
92 #include "BIF_interface.h"
93 #include "BIF_interface_icons.h"
94 #include "BIF_butspace.h"
95 #include "BIF_previewrender.h"
99 #ifndef DISABLE_PYTHON
100 #include "BPY_extern.h" /* for BPY_button_eval */
103 #include "GHOST_Types.h" /* for tablet data */
105 #include "mydevice.h"
106 #include "interface.h"
110 #include "BLO_sys_types.h" // for intptr_t support
112 #define INSIDE_BLOCK 1
113 #define INSIDE_PANEL_HEADER 2
114 #define INSIDE_PANEL_SCALE 3
116 /* naming conventions:
118 * uiBlahBlah() external function
119 * ui_blah_blah() internal function
123 /* ************ GLOBALS ************* */
125 float UIwinmat[4][4];
126 static int UIlock= 0, UIafterval;
127 static char *UIlockstr=NULL;
129 static void (*UIafterfunc_butm)(void *arg, int event);
130 static void (*UIafterfunc_but)(void *arg1, void *arg2);
131 static void *UIafterfunc_arg1, *UIafterfunc_arg2;
133 static uiFont UIfont[UI_ARRAY]; // no init needed
136 static ColorBand but_copypaste_coba;
138 /* ************* PROTOTYPES ***************** */
140 static void ui_set_but_val(uiBut *but, double value);
141 static void ui_do_but_tip(uiBut *buttip);
143 /* ****************************** */
145 static int uibut_contains_pt(uiBut *but, short *pt)
147 return ((but->x1<pt[0] && but->x2>=pt[0]) &&
148 (but->y1<pt[1] && but->y2>=pt[1]));
151 static void uibut_do_func(uiBut *but)
154 but->func(but->func_arg1, but->func_arg2);
158 /* ************* window matrix ************** */
161 void ui_graphics_to_window(int win, float *x, float *y) /* for rectwrite */
165 int getsizex, getsizey;
167 bwin_getsize(win, &getsizex, &getsizey);
168 bwin_getsuborigin(win, &sx, &sy);
172 *x= ((float)sx) + ((float)getsizex)*(0.5+ 0.5*(gx*UIwinmat[0][0]+ gy*UIwinmat[1][0]+ UIwinmat[3][0]));
173 *y= ((float)sy) + ((float)getsizey)*(0.5+ 0.5*(gx*UIwinmat[0][1]+ gy*UIwinmat[1][1]+ UIwinmat[3][1]));
176 void ui_graphics_to_window_rct(int win, rctf *graph, rcti *winr)
180 int getsizex, getsizey;
182 bwin_getsize(win, &getsizex, &getsizey);
183 bwin_getsuborigin(win, &sx, &sy);
187 winr->xmin= (int)((float)sx) + ((float)getsizex)*(0.5+ 0.5*(gx*UIwinmat[0][0]+ gy*UIwinmat[1][0]+ UIwinmat[3][0]));
188 winr->ymin= (int)((float)sy) + ((float)getsizey)*(0.5+ 0.5*(gx*UIwinmat[0][1]+ gy*UIwinmat[1][1]+ UIwinmat[3][1]));
191 winr->xmax= (int)((float)sx) + ((float)getsizex)*(0.5+ 0.5*(gx*UIwinmat[0][0]+ gy*UIwinmat[1][0]+ UIwinmat[3][0]));
192 winr->ymax= (int)((float)sy) + ((float)getsizey)*(0.5+ 0.5*(gx*UIwinmat[0][1]+ gy*UIwinmat[1][1]+ UIwinmat[3][1]));
196 void ui_window_to_graphics(int win, float *x, float *y) /* for mouse cursor */
198 float a, b, c, d, e, f, px, py;
199 int getsizex, getsizey;
201 bwin_getsize(win, &getsizex, &getsizey);
203 a= .5*((float)getsizex)*UIwinmat[0][0];
204 b= .5*((float)getsizex)*UIwinmat[1][0];
205 c= .5*((float)getsizex)*(1.0+UIwinmat[3][0]);
207 d= .5*((float)getsizey)*UIwinmat[0][1];
208 e= .5*((float)getsizey)*UIwinmat[1][1];
209 f= .5*((float)getsizey)*(1.0+UIwinmat[3][1]);
214 *y= (a*(py-f) + d*(c-px))/(a*e-d*b);
215 *x= (px- b*(*y)- c)/a;
220 /* ************* SAVE UNDER ************ */
224 OverDraw *ui_begin_overdraw(int minx, int miny, int maxx, int maxy);
225 - enforces mainwindow to become active
226 - grabs copy from frontbuffer, pastes in back
228 void ui_flush_overdraw(OverDraw *od);
229 - copies backbuffer to front
231 void ui_refresh_overdraw(Overdraw *od);
232 - pastes in back copy of frontbuffer again for fresh drawing
234 void ui_end_overdraw(OverDraw *od);
235 - puts back on frontbuffer saved image
237 - sets back active blender area
238 - signals backbuffer to be corrupt (sel buffer!)
242 /* frontbuffer updates now glCopyPixels too, with block->flush rect */
244 /* new idea for frontbuffer updates:
246 - hilites: with blended poly?
248 - full updates... thats harder, but:
250 - before draw, always paste to backbuf
252 - always end with redraw event for full update
256 static void myglCopyPixels(int a, int b, int c, int d, int e)
259 unsigned int *buf= MEM_mallocN(4*c*d, "temp glcopypixels");
260 glReadPixels(a, b, c, d, GL_RGBA, GL_UNSIGNED_BYTE, buf);
261 glDrawPixels(c, d, GL_RGBA, GL_UNSIGNED_BYTE, buf);
264 else glCopyPixels(a, b, c, d, e);
268 short x, y, sx, sy, oldwin;
273 static uiOverDraw *ui_begin_overdraw(int minx, int miny, int maxx, int maxy)
277 // dirty patch removed for sun and sgi to mywindow.c commented out
279 /* clip with actual window size */
280 if(minx < 0) minx= 0;
281 if(miny < 0) miny= 0;
282 if(maxx >= G.curscreen->sizex) maxx= G.curscreen->sizex-1;
283 if(maxy >= G.curscreen->sizey) maxy= G.curscreen->sizey-1;
285 if(minx<maxx && miny<maxy) {
286 od= MEM_callocN(sizeof(uiOverDraw), "overdraw");
292 od->rect= MEM_mallocN(od->sx*od->sy*4, "temp_frontbuffer_image");
294 od->oldwin= mywinget();
295 mywinset(G.curscreen->mainwin);
297 glReadBuffer(GL_FRONT);
298 glReadPixels(od->x, od->y, od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
299 glReadBuffer(GL_BACK);
301 glDisable(GL_DITHER);
302 glRasterPos2f(od->x, od->y);
303 glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
310 static void ui_flush_overdraw(uiOverDraw *od)
314 glDisable(GL_DITHER);
315 glReadBuffer(GL_BACK);
316 glDrawBuffer(GL_FRONT);
317 glRasterPos2s(od->x, od->y);
318 myglCopyPixels(od->x, od->y, od->sx, od->sy, GL_COLOR);
321 glDrawBuffer(GL_BACK);
324 /* special flush version to enable transparent menus */
325 static void ui_block_flush_overdraw(uiBlock *block)
328 if(block->flag & UI_BLOCK_LOOP) {
331 BIF_GetThemeColor4ubv(TH_MENU_BACK, col);
334 uiOverDraw *od= block->overdraw;
336 /* completely draw all! */
337 glRasterPos2s(od->x, od->y);
338 glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
340 uiDrawMenuBox(block->minx, block->miny, block->maxx, block->maxy, block->flag);
341 for (bt= block->buttons.first; bt; bt= bt->next) {
347 ui_flush_overdraw(block->overdraw);
350 static void ui_end_overdraw(uiOverDraw *od)
354 glDisable(GL_DITHER);
357 glRasterPos2s(od->x, od->y);
358 glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
361 glDrawBuffer(GL_FRONT);
362 glRasterPos2s(od->x, od->y);
363 glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
366 glDrawBuffer(GL_BACK);
369 if(od->oldwin) mywinset(od->oldwin);
374 markdirty_all_back(); // sets flags only
377 /* ****************** live updates for hilites and button presses *********** */
379 void ui_block_flush_back(uiBlock *block)
381 int minx, miny, sizex, sizey;
383 /* note; this routine also has to work for block loop */
384 if(block->needflush==0) return;
386 /* exception, when we cannot use backbuffer for draw... */
387 if(block->flag & UI_BLOCK_FRONTBUFFER) {
389 glDrawBuffer(GL_BACK);
394 /* copy pixels works on window coords, so we move to window space */
396 ui_graphics_to_window(block->win, &block->flush.xmin, &block->flush.ymin);
397 ui_graphics_to_window(block->win, &block->flush.xmax, &block->flush.ymax);
398 minx= floor(block->flush.xmin);
399 miny= floor(block->flush.ymin);
400 sizex= ceil(block->flush.xmax-block->flush.xmin);
401 sizey= ceil(block->flush.ymax-block->flush.ymin);
403 if(sizex>0 && sizey>0) {
405 mywinset(G.curscreen->mainwin);
407 glDisable(GL_DITHER);
408 glReadBuffer(GL_BACK);
409 glDrawBuffer(GL_FRONT);
410 glRasterPos2i(minx, miny);
412 myglCopyPixels(minx, miny+1, sizex, sizey, GL_COLOR);
414 myglCopyPixels(minx, miny, sizex, sizey, GL_COLOR);
418 glDrawBuffer(GL_BACK);
420 mywinset(block->win);
423 markdirty_win_back(block->win);
429 /* merge info for live updates in frontbuf */
430 void ui_block_set_flush(uiBlock *block, uiBut *but)
436 block->flush.xmin= 0.0;
437 block->flush.xmax= 0.0;
440 /* exception, when we cannot use backbuffer for draw... */
441 if(block->flag & UI_BLOCK_FRONTBUFFER) {
442 glDrawBuffer(GL_FRONT);
444 else if(block->needflush==0) {
446 block->flush.xmin= but->x1;
447 block->flush.xmax= but->x2;
448 block->flush.ymin= but->y1;
449 block->flush.ymax= but->y2;
454 if(block->flush.xmin > but->x1) block->flush.xmin= but->x1;
455 if(block->flush.xmax < but->x2) block->flush.xmax= but->x2;
456 if(block->flush.ymin > but->y1) block->flush.ymin= but->y1;
457 if(block->flush.ymax < but->y2) block->flush.ymax= but->y2;
465 /* ******************* copy and paste ******************** */
467 /* c = copy, v = paste */
468 /* return 1 when something changed */
469 static int ui_but_copy_paste(uiBut *but, char mode)
472 char buf[UI_MAX_DRAW_STR+1]= {0};
476 if(mode=='v' && but->lock) return 0;
480 /* extract first line from clipboard in case of multi-line copies */
481 char *p = getClipboard(0);
484 while (*p && *p!='\r' && *p!='\n' && i<UI_MAX_DRAW_STR) {
493 if ELEM4(but->type, NUM, NUMABS, NUMSLI, HSVSLI) {
497 sprintf(buf, "%f", ui_get_but_val(but));
498 putClipboard(buf, 0);
501 if (sscanf(buf, " %lf ", &val) == 1) {
502 ui_set_but_val(but, val);
511 else if(but->type==COL) {
515 if(but->pointype==FLO) {
516 float *fp= (float *) poin;
517 sprintf(buf, "[%f, %f, %f]", fp[0], fp[1], fp[2]);
518 putClipboard(buf, 0);
520 else if (but->pointype==CHA) {
521 char *cp= (char *) poin;
522 f[0]= (float)(cp[0]/255.0);
523 f[1]= (float)(cp[1]/255.0);
524 f[2]= (float)(cp[2]/255.0);
525 sprintf(buf, "[%f, %f, %f]", f[0], f[1], f[2]);
526 putClipboard(buf, 0);
531 if(but->pointype==FLO) {
532 float *fp= (float *) poin;
533 if (sscanf(buf, "[%f, %f, %f]", &f[0], &f[1], &f[2]) == 3) {
540 else if (but->pointype==CHA) {
541 char *cp= (char *) poin;
542 if (sscanf(buf, "[%f, %f, %f]", &f[0], &f[1], &f[2]) == 3) {
543 cp[0]= (char)(f[0]*255.0);
544 cp[1]= (char)(f[1]*255.0);
545 cp[2]= (char)(f[2]*255.0);
553 /* text/string data */
554 else if(but->type==TEX) {
557 strncpy(buf, but->poin, but->max);
558 buf[(int)but->max]= 0;
559 putClipboard(buf, 0);
562 char backstr[UI_MAX_DRAW_STR];
563 /* give butfunc the original text too */
564 /* feature used for bone renaming, channels, etc */
565 if(but->func_arg2==NULL) {
566 strncpy(backstr, but->poin, UI_MAX_DRAW_STR);
567 but->func_arg2= backstr;
569 strncpy(but->poin, buf, but->max);
576 /* ID name string (eg. OB:Object = "Object") */
577 else if(but->type==IDPOIN) {
579 ID *id= *but->idpoin_idpp;
581 strncpy(buf, id->name+2, 22);
583 putClipboard(buf, 0);
587 but->idpoin_func(buf, but->idpoin_idpp);
593 /* colorband (not supported by system clipboard) */
594 else if(but->type==BUT_COLORBAND) {
599 memcpy( &but_copypaste_coba, but->poin, sizeof(ColorBand) );
601 if (but_copypaste_coba.tot==0) {
605 but->poin= MEM_callocN( sizeof(ColorBand), "colorband");
607 memcpy( but->poin, &but_copypaste_coba, sizeof(ColorBand) );
615 /* ******************* block calc ************************* */
617 /* only for pulldowns */
618 void uiTextBoundsBlock(uiBlock *block, int addval)
621 int i = 0, j, x1addval= 0, nextcol;
623 bt= block->buttons.first;
626 int transopts= (U.transopts & USER_TR_BUTTONS);
627 if(bt->type==TEX || bt->type==IDPOIN) transopts= 0;
628 j= BIF_GetStringWidth(bt->font, bt->drawstr, transopts);
635 /* cope with multi collumns */
636 bt= block->buttons.first;
638 if(bt->next && bt->x1 < bt->next->x1)
643 bt->x2 = bt->x1 + i + addval;
645 ui_check_but(bt); // clips text again
648 x1addval+= i + addval;
655 void uiBoundsBlock(uiBlock *block, int addval)
663 if(block->buttons.first==NULL) {
665 block->minx= 0.0; block->maxx= block->panel->sizex;
666 block->miny= 0.0; block->maxy= block->panel->sizey;
671 block->minx= block->miny= 10000;
672 block->maxx= block->maxy= -10000;
674 bt= block->buttons.first;
676 if(bt->x1 < block->minx) block->minx= bt->x1;
677 if(bt->y1 < block->miny) block->miny= bt->y1;
679 if(bt->x2 > block->maxx) block->maxx= bt->x2;
680 if(bt->y2 > block->maxy) block->maxy= bt->y2;
685 block->minx -= addval;
686 block->miny -= addval;
687 block->maxx += addval;
688 block->maxy += addval;
691 /* hardcoded exception... but that one is annoying with larger safety */
692 bt= block->buttons.first;
693 if(bt && strncmp(bt->str, "ERROR", 5)==0) xof= 10;
696 block->safety.xmin= block->minx-xof;
697 block->safety.ymin= block->miny-xof;
698 block->safety.xmax= block->maxx+xof;
699 block->safety.ymax= block->maxy+xof;
702 static void ui_positionblock(uiBlock *block, uiBut *but)
704 /* position block relative to but */
708 int xsize, ysize, xof=0, yof=0, center;
709 short dir1= 0, dir2=0;
711 /* first transform to screen coords, assuming matrix is stil OK */
712 /* the UIwinmat is in panelspace */
714 butrct.xmin= but->x1; butrct.xmax= but->x2;
715 butrct.ymin= but->y1; butrct.ymax= but->y2;
717 ui_graphics_to_window(block->win, &butrct.xmin, &butrct.ymin);
718 ui_graphics_to_window(block->win, &butrct.xmax, &butrct.ymax);
719 block->parentrct= butrct; // will use that for pulldowns later
721 /* calc block rect */
722 if(block->buttons.first) {
723 block->minx= block->miny= 10000;
724 block->maxx= block->maxy= -10000;
726 bt= block->buttons.first;
728 if(bt->x1 < block->minx) block->minx= bt->x1;
729 if(bt->y1 < block->miny) block->miny= bt->y1;
731 if(bt->x2 > block->maxx) block->maxx= bt->x2;
732 if(bt->y2 > block->maxy) block->maxy= bt->y2;
738 /* we're nice and allow empty blocks too */
739 block->minx= block->miny= 0;
740 block->maxx= block->maxy= 20;
743 aspect= (float)(block->maxx - block->minx + 4);
744 ui_graphics_to_window(block->win, &block->minx, &block->miny);
745 ui_graphics_to_window(block->win, &block->maxx, &block->maxy);
747 //block->minx-= 2.0; block->miny-= 2.0;
748 //block->maxx+= 2.0; block->maxy+= 2.0;
750 xsize= block->maxx - block->minx+4; // 4 for shadow
751 ysize= block->maxy - block->miny+4;
752 aspect/= (float)xsize;
755 short left=0, right=0, top=0, down=0;
757 if(block->direction & UI_CENTER) center= ysize/2;
760 if( butrct.xmin-xsize > 0.0) left= 1;
761 if( butrct.xmax+xsize < G.curscreen->sizex) right= 1;
762 if( butrct.ymin-ysize+center > 0.0) down= 1;
763 if( butrct.ymax+ysize-center < G.curscreen->sizey) top= 1;
765 dir1= block->direction & UI_DIRECTION;
767 /* secundary directions */
768 if(dir1 & (UI_TOP|UI_DOWN)) {
769 if(dir1 & UI_LEFT) dir2= UI_LEFT;
770 else if(dir1 & UI_RIGHT) dir2= UI_RIGHT;
771 dir1 &= (UI_TOP|UI_DOWN);
774 if(dir2==0) if(dir1==UI_LEFT || dir1==UI_RIGHT) dir2= UI_DOWN;
775 if(dir2==0) if(dir1==UI_TOP || dir1==UI_DOWN) dir2= UI_LEFT;
777 /* no space at all? dont change */
779 if(dir1==UI_LEFT && left==0) dir1= UI_RIGHT;
780 if(dir1==UI_RIGHT && right==0) dir1= UI_LEFT;
781 /* this is aligning, not append! */
782 if(dir2==UI_LEFT && right==0) dir2= UI_RIGHT;
783 if(dir2==UI_RIGHT && left==0) dir2= UI_LEFT;
786 if(dir1==UI_TOP && top==0) dir1= UI_DOWN;
787 if(dir1==UI_DOWN && down==0) dir1= UI_TOP;
788 if(dir2==UI_TOP && top==0) dir2= UI_DOWN;
789 if(dir2==UI_DOWN && down==0) dir2= UI_TOP;
793 xof= butrct.xmin - block->maxx;
794 if(dir2==UI_TOP) yof= butrct.ymin - block->miny-center;
795 else yof= butrct.ymax - block->maxy+center;
797 else if(dir1==UI_RIGHT) {
798 xof= butrct.xmax - block->minx;
799 if(dir2==UI_TOP) yof= butrct.ymin - block->miny-center;
800 else yof= butrct.ymax - block->maxy+center;
802 else if(dir1==UI_TOP) {
803 yof= butrct.ymax - block->miny;
804 if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
805 else xof= butrct.xmin - block->minx;
806 // changed direction?
807 if((dir1 & block->direction)==0) {
808 if(block->direction & UI_SHIFT_FLIPPED)
809 xof+= dir2==UI_LEFT?25:-25;
810 uiBlockFlipOrder(block);
813 else if(dir1==UI_DOWN) {
814 yof= butrct.ymin - block->maxy;
815 if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
816 else xof= butrct.xmin - block->minx;
817 // changed direction?
818 if((dir1 & block->direction)==0) {
819 if(block->direction & UI_SHIFT_FLIPPED)
820 xof+= dir2==UI_LEFT?25:-25;
821 uiBlockFlipOrder(block);
825 /* and now we handle the exception; no space below or to top */
826 if(top==0 && down==0) {
827 if(dir1==UI_LEFT || dir1==UI_RIGHT) {
828 // align with bottom of screen
833 /* or no space left or right */
834 if(left==0 && right==0) {
835 if(dir1==UI_TOP || dir1==UI_DOWN) {
836 // align with left size of screen
841 // apply requested offset in the block
842 xof += block->xofs/block->aspect;
843 yof += block->yofs/block->aspect;
849 for(bt= block->buttons.first; bt; bt= bt->next) {
851 ui_graphics_to_window(block->win, &bt->x1, &bt->y1);
852 ui_graphics_to_window(block->win, &bt->x2, &bt->y2);
860 // ui_check_but recalculates drawstring size in pixels
869 /* safety calculus */
871 float midx= (block->parentrct.xmin+block->parentrct.xmax)/2.0;
872 float midy= (block->parentrct.ymin+block->parentrct.ymax)/2.0;
874 /* when you are outside parent button, safety there should be smaller */
876 // parent button to left
877 if( midx < block->minx ) block->safety.xmin= block->minx-3;
878 else block->safety.xmin= block->minx-40;
879 // parent button to right
880 if( midx > block->maxx ) block->safety.xmax= block->maxx+3;
881 else block->safety.xmax= block->maxx+40;
883 // parent button on bottom
884 if( midy < block->miny ) block->safety.ymin= block->miny-3;
885 else block->safety.ymin= block->miny-40;
886 // parent button on top
887 if( midy > block->maxy ) block->safety.ymax= block->maxy+3;
888 else block->safety.ymax= block->maxy+40;
890 // exception for switched pulldowns...
891 if(dir1 && (dir1 & block->direction)==0) {
892 if(dir2==UI_RIGHT) block->safety.xmax= block->maxx+3;
893 if(dir2==UI_LEFT) block->safety.xmin= block->minx-3;
895 block->direction= dir1;
898 block->safety.xmin= block->minx-40;
899 block->safety.ymin= block->miny-40;
900 block->safety.xmax= block->maxx+40;
901 block->safety.ymax= block->maxy+40;
907 void ui_autofill(uiBlock *block)
910 float *maxw, *maxh, startx = 0, starty, height = 0;
912 int rows=0, /* cols=0, */ i, lasti;
914 /* first count rows */
915 but= block->buttons.last;
918 /* calculate max width / height for each row */
919 maxw= MEM_callocN(sizeof(float)*rows, "maxw");
920 maxh= MEM_callocN(sizeof(float)*rows, "maxh");
921 but= block->buttons.first;
924 if( maxh[i] < but->y2) maxh[i]= but->y2;
930 for(i=0; i<rows; i++) totmaxh+= maxh[i];
932 /* apply widths/heights */
934 but= block->buttons.first;
937 // signal for aligning code
938 but->flag |= UI_BUT_ALIGN_DOWN;
944 height= (maxh[i]*(block->maxy-block->miny))/totmaxh;
949 but->y1= starty+but->aspect;
950 but->y2= but->y1+height-but->aspect;
952 but->x2= (but->x2*(block->maxx-block->minx))/maxw[i];
953 but->x1= startx+but->aspect;
956 but->x2+= but->x1-but->aspect;
963 uiBlockEndAlign(block);
965 MEM_freeN(maxw); MEM_freeN(maxh);
969 /* ************** LINK LINE DRAWING ************* */
971 /* link line drawing is not part of buttons or theme.. so we stick with it here */
973 static void ui_draw_linkline(uiBut *but, uiLinkLine *line)
975 float vec1[2], vec2[2];
977 if(line->from==NULL || line->to==NULL) return;
979 vec1[0]= (line->from->x1+line->from->x2)/2.0;
980 vec1[1]= (line->from->y1+line->from->y2)/2.0;
981 vec2[0]= (line->to->x1+line->to->x2)/2.0;
982 vec2[1]= (line->to->y1+line->to->y2)/2.0;
984 if(line->flag & UI_SELECT) BIF_ThemeColorShade(but->themecol, 80);
985 else glColor3ub(0,0,0);
986 fdrawline(vec1[0], vec1[1], vec2[0], vec2[1]);
989 static void ui_draw_links(uiBlock *block)
994 but= block->buttons.first;
996 if(but->type==LINK && but->link) {
997 line= but->link->lines.first;
999 ui_draw_linkline(but, line);
1007 /* ************** BLOCK DRAWING FUNCTION ************* */
1010 void uiDrawBlock(uiBlock *block)
1013 short testmouse=0, mouse[2];
1015 /* we set this only once */
1016 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1018 /* handle pending stuff */
1019 if(block->autofill) ui_autofill(block);
1020 if(block->minx==0.0 && block->maxx==0.0) uiBoundsBlock(block, 0);
1021 if(block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block);
1023 /* we set active flag on a redraw again */
1024 if((block->flag & UI_BLOCK_LOOP)==0) {
1026 Mat4CpyMat4(UIwinmat, block->winmat);
1029 uiPanelPush(block); // panel matrix
1031 if(block->flag & UI_BLOCK_LOOP) {
1032 uiDrawMenuBox(block->minx, block->miny, block->maxx, block->maxy, block->flag);
1035 if(block->panel) ui_draw_panel(block);
1038 if(block->drawextra) block->drawextra(curarea, block);
1040 if(testmouse) /* do it after panel push, otherwise coords are wrong */
1041 uiGetMouse(block->win, mouse);
1043 for (but= block->buttons.first; but; but= but->next) {
1045 if(testmouse && uibut_contains_pt(but, mouse))
1046 but->flag |= UI_ACTIVE;
1051 ui_draw_links(block);
1053 uiPanelPop(block); // matrix restored
1056 /* ************* MENUBUTS *********** */
1070 int nitems, itemssize;
1073 static MenuData *menudata_new(char *instr) {
1074 MenuData *md= MEM_mallocN(sizeof(*md), "MenuData");
1080 md->nitems= md->itemssize= 0;
1085 static void menudata_set_title(MenuData *md, char *title, int titleicon) {
1089 md->titleicon= titleicon;
1092 static void menudata_add_item(MenuData *md, char *str, int retval, int icon) {
1093 if (md->nitems==md->itemssize) {
1094 int nsize= md->itemssize?(md->itemssize<<1):1;
1095 MenuEntry *oitems= md->items;
1097 md->items= MEM_mallocN(nsize*sizeof(*md->items), "md->items");
1099 memcpy(md->items, oitems, md->nitems*sizeof(*md->items));
1103 md->itemssize= nsize;
1106 md->items[md->nitems].str= str;
1107 md->items[md->nitems].retval= retval;
1108 md->items[md->nitems].icon= icon;
1112 static void menudata_free(MenuData *md) {
1113 MEM_freeN(md->instr);
1115 MEM_freeN(md->items);
1120 * Parse menu description strings, string is of the
1121 * form "[sss%t|]{(sss[%xNN]|), (%l|)}", ssss%t indicates the
1122 * menu title, sss or sss%xNN indicates an option,
1123 * if %xNN is given then NN is the return value if
1124 * that option is selected otherwise the return value
1125 * is the index of the option (starting with 1). %l
1126 * indicates a seperator.
1128 * @param str String to be parsed.
1129 * @retval new menudata structure, free with menudata_free()
1131 static MenuData *decompose_menu_string(char *str)
1133 char *instr= BLI_strdup(str);
1134 MenuData *md= menudata_new(instr);
1135 char *nitem= NULL, *s= instr;
1136 int nicon=0, nretval= 1, nitem_is_title= 0;
1147 } else if (s[1]=='t') {
1152 } else if (s[1]=='l') {
1155 } else if (s[1]=='i') {
1161 } else if (c=='|' || c=='\0') {
1165 if (nitem_is_title) {
1166 menudata_set_title(md, nitem, nicon);
1169 /* prevent separator to get a value */
1170 if(nitem[0]=='%' && nitem[1]=='l')
1171 menudata_add_item(md, nitem, -1, nicon);
1173 menudata_add_item(md, nitem, nretval, nicon);
1174 nretval= md->nitems+1;
1192 static void ui_set_name_menu(uiBut *but, int value)
1197 md= decompose_menu_string(but->str);
1198 for (i=0; i<md->nitems; i++)
1199 if (md->items[i].retval==value)
1200 strcpy(but->drawstr, md->items[i].str);
1205 static void ui_warp_pointer(short x, short y)
1207 /* OSX has very poor mousewarp support, it sends events;
1208 this causes a menu being pressed immediately ... */
1215 static int ui_do_but_MENU(uiBut *but)
1219 ListBase listb={NULL, NULL}, lb;
1221 int width, height=0, a, xmax, starty;
1223 int columns=1, rows=0, boxh, event;
1224 short x1, y1, active= -1;
1228 but->flag |= UI_SELECT;
1230 ui_block_flush_back(but->block); // flush because this button creates own blocks loop
1232 block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
1233 block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
1234 block->themecol= TH_MENU_ITEM;
1236 md= decompose_menu_string(but->str);
1238 /* columns and row calculation */
1239 columns= (md->nitems+20)/20;
1240 if (columns<1) columns= 1;
1242 if(columns>8) columns= (md->nitems+25)/25;
1244 rows= (int) md->nitems/columns;
1245 if (rows<1) rows= 1;
1247 while (rows*columns<md->nitems) rows++;
1249 /* prevent scaling up of pupmenu */
1250 if (but->aspect < 1.0f) but->aspect = 1.0f;
1252 /* size and location */
1254 width= 1.5*but->aspect*strlen(md->title)+BIF_GetStringWidth(block->curfont, md->title, (U.transopts & USER_TR_MENUS));
1258 for(a=0; a<md->nitems; a++) {
1259 xmax= but->aspect*BIF_GetStringWidth(block->curfont, md->items[a].str, (U.transopts & USER_TR_MENUS));
1260 if ( md->items[a].icon) xmax += 20*but->aspect;
1261 if(xmax>width) width= xmax;
1265 if (width < (but->x2 - but->x1)) width = (but->x2 - but->x1);
1266 if (width<50) width=50;
1271 if (md->title) height+= boxh;
1273 getmouseco_sc(mval);
1275 /* find active item */
1276 fvalue= ui_get_but_val(but);
1277 for(active=0; active<md->nitems; active++) {
1278 if( md->items[active].retval== (int)fvalue ) break;
1280 /* no active item? */
1281 if(active==md->nitems) {
1282 if(md->title) active= -1;
1286 /* for now disabled... works confusing because you think it's a title or so.... */
1295 uiSetCurFont(block, block->font+1);
1296 if (md->titleicon) {
1297 uiDefIconTextBut(block, LABEL, 0, md->titleicon, md->title, startx, (short)(starty+rows*boxh), (short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
1299 bt= uiDefBut(block, LABEL, 0, md->title, startx, (short)(starty+rows*boxh), (short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
1300 bt->flag= UI_TEXT_LEFT;
1302 uiSetCurFont(block, block->font);
1306 for(a=0; a<md->nitems; a++) {
1308 x1= but->x1 + width*((int)(md->nitems-a-1)/rows);
1309 y1= but->y1 - boxh*(rows - ((md->nitems - a - 1)%rows)) + (rows*boxh);
1311 if (strcmp(md->items[md->nitems-a-1].str, "%l")==0) {
1312 uiDefBut(block, SEPR, B_NOP, "", x1, y1,(short)(width-(rows>1)), (short)(boxh-1), NULL, 0.0, 0.0, 0, 0, "");
1314 else if(md->items[md->nitems-a-1].icon) {
1315 uiBut *bt= uiDefIconTextBut(block, BUTM|but->pointype, but->retval, md->items[md->nitems-a-1].icon ,md->items[md->nitems-a-1].str, x1, y1,(short)(width-(rows>1)), (short)(boxh-1), but->poin, (float) md->items[md->nitems-a-1].retval, 0.0, 0, 0, "");
1316 if(active==a) bt->flag |= UI_ACTIVE;
1319 uiBut *bt= uiDefBut(block, BUTM|but->pointype, but->retval, md->items[md->nitems-a-1].str, x1, y1,(short)(width-(rows>1)), (short)(boxh-1), but->poin, (float) md->items[md->nitems-a-1].retval, 0.0, 0, 0, "");
1320 if(active==a) bt->flag |= UI_ACTIVE;
1324 /* the code up here has flipped locations, because of change of preferred order */
1325 /* thats why we have to switch list order too, to make arrowkeys work */
1327 lb.first= lb.last= NULL;
1328 bt= block->buttons.first;
1330 uiBut *next= bt->next;
1331 BLI_remlink(&block->buttons, bt);
1332 BLI_addhead(&lb, bt);
1338 block->direction= UI_TOP;
1339 ui_positionblock(block, but);
1341 /* blocks can come (and get scaled) from a normal window, now we go to screenspace */
1342 block->win= G.curscreen->mainwin;
1343 for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
1344 bwin_getsinglematrix(block->win, block->winmat);
1346 event= uiDoBlocks(&listb, 0, 1);
1350 but->flag &= ~UI_SELECT;
1352 /* no draw of button now, for floating panels the matrix now is invalid...
1353 the button still is active, and will be redrawn in main loop to de-activate it */
1354 /* but, if no hilites, we send redraw to queue */
1355 if(but->flag & UI_NO_HILITE)
1356 addqueue(but->block->winq, REDRAW, 1);
1360 /* return no existing event, because the menu sends events instead */
1364 /* ********************** NEXT/PREV for arrowkeys etc ************** */
1366 static uiBut *ui_but_prev(uiBut *but)
1370 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
1375 static uiBut *ui_but_next(uiBut *but)
1379 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
1384 static uiBut *ui_but_first(uiBlock *block)
1388 but= block->buttons.first;
1390 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
1396 static uiBut *ui_but_last(uiBlock *block)
1400 but= block->buttons.last;
1402 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
1409 /* ************* IN-BUTTON TEXT SELECTION/EDITING ************* */
1411 static short ui_delete_selection_edittext(uiBut *but)
1414 short deletedwidth=0;
1417 str= (char *)but->poin;
1419 deletedwidth = (but->selend - but->selsta);
1421 for(x=0; x< strlen(str); x++) {
1422 if (but->selend + x <= strlen(str) ) {
1423 str[but->selsta + x]= str[but->selend + x];
1425 str[but->selsta + x]= '\0';
1429 but->pos = but->selend = but->selsta;
1431 return deletedwidth;
1434 static void ui_set_cursor_pos_edittext(uiBut *but, short sx)
1436 char backstr[UI_MAX_DRAW_STR];
1438 BLI_strncpy(backstr, but->drawstr, UI_MAX_DRAW_STR);
1439 but->pos= strlen(backstr)-but->ofs;
1441 while((but->aspect*BIF_GetStringWidth(but->font, backstr+but->ofs, 0) + but->x1) > sx) {
1442 if (but->pos <= 0) break;
1444 backstr[but->pos+but->ofs] = 0;
1447 but->pos -= strlen(but->str);
1448 but->pos += but->ofs;
1449 if(but->pos<0) but->pos= 0;
1453 /* ************* EVENTS ************* */
1455 void uiGetMouse(int win, short *adr)
1461 if (win == G.curscreen->mainwin) return;
1463 bwin_getsuborigin(win, &x, &y);
1471 ui_window_to_graphics(win, &xwin, &ywin);
1473 adr[0]= (short)(xwin+0.5);
1474 adr[1]= (short)(ywin+0.5);
1477 static void ui_is_but_sel(uiBut *but)
1481 short push=0, true=1;
1483 value= ui_get_but_val(but);
1485 if( but->type==TOGN || but->type==ICONTOGN) true= 0;
1489 if( BTST(lvalue, (but->bitnr)) ) push= true;
1498 if (value==-1) push= 1;
1505 if(value!=but->min) push= 1;
1509 if(value==0.0) push= 1;
1512 if(value == but->max) push= 1;
1524 else if(push==1) but->flag |= UI_SELECT;
1525 else but->flag &= ~UI_SELECT;
1528 static int ui_do_but_BUT(uiBut *but)
1533 int oflag= but->flag;
1536 uiGetMouse(mywinget(), mval);
1538 if (uibut_contains_pt(but, mval))
1539 but->flag |= UI_SELECT;
1541 but->flag &= ~UI_SELECT;
1543 if (but->flag != oflag) {
1545 ui_block_flush_back(but->block);
1549 } while (get_mbut() & L_MOUSE);
1551 activated= (but->flag & UI_SELECT);
1554 UIafterfunc_but= but->func;
1555 UIafterfunc_arg1= but->func_arg1;
1556 UIafterfunc_arg2= but->func_arg2;
1557 /* no more uibut_do_func(but); this button calls fileselecting windows */
1560 but->flag &= ~UI_SELECT;
1563 return activated?but->retval:0;
1566 static int ui_do_but_KEYEVT(uiBut *but)
1568 unsigned short event= 0;
1571 /* flag for ui_check_but */
1572 ui_set_but_val(but, -1);
1575 ui_block_flush_back(but->block);
1578 event= extern_qread(&val);
1579 } while (!event || !val || ELEM(event, MOUSEX, MOUSEY));
1581 if (!key_event_to_string(event)[0]) event= 0;
1583 ui_set_but_val(but, (double) event);
1590 static int ui_do_but_TOG(uiBlock *block, uiBut *but, int qual)
1594 int w, lvalue, push;
1597 if(but->type==BUT_TOGDUAL && qual==LR_CTRLKEY) {
1598 if(but->pointype==SHO)
1600 else if(but->pointype==INT)
1604 value= ui_get_but_val(but);
1608 w= BTST(lvalue, but->bitnr);
1609 if(w) lvalue = BCLR(lvalue, but->bitnr);
1610 else lvalue = BSET(lvalue, but->bitnr);
1612 if(but->type==TOGR) {
1613 if( (get_qual() & LR_SHIFTKEY)==0 ) {
1614 lvalue= 1<<(but->bitnr);
1616 ui_set_but_val(but, (double)lvalue);
1618 bt= block->buttons.first;
1620 if( bt!=but && bt->poin==but->poin ) {
1628 if(lvalue==0) lvalue= 1<<(but->bitnr);
1632 ui_set_but_val(but, (double)lvalue);
1633 if(but->type==ICONTOG || but->type==ICONTOGN) ui_check_but(but);
1634 // no frontbuffer draw for this one
1635 if(but->type==BUT_TOGDUAL);
1636 else if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
1640 if(value==0.0) push= 1;
1643 if(but->type==TOGN || but->type==ICONTOGN) push= !push;
1644 ui_set_but_val(but, (double)push);
1645 if(but->type==ICONTOG || but->type==ICONTOGN) ui_check_but(but);
1646 // no frontbuffer draw for this one
1647 if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
1650 /* end local hack... */
1651 if(but->type==BUT_TOGDUAL && qual==LR_CTRLKEY) {
1652 if(but->pointype==SHO)
1654 else if(but->pointype==INT)
1658 /* no while loop...this button is used for viewmove */
1665 static int ui_do_but_ROW(uiBlock *block, uiBut *but)
1669 ui_set_but_val(but, but->max);
1672 bt= block->buttons.first;
1674 if( bt!=but && bt->type==ROW ) {
1675 if(bt->min==but->min) {
1685 /* return 1 if char ch is special character otherwise
1687 static short test_special_char(char ch)
1729 static int ui_do_but_TEX(uiBut *but)
1732 short x, y, mval[2], len=0, dodraw, selextend=0;
1733 char *str, backstr[UI_MAX_DRAW_STR];
1734 short capturing, sx, sy, prevx;
1736 str= (char *)but->poin;
1738 but->flag |= UI_SELECT;
1740 uiGetMouse(mywinget(), mval);
1742 /* set cursor pos to the end of the text */
1743 but->pos = strlen(str);
1745 but->selend = strlen(but->drawstr) - strlen(but->str);
1748 BLI_strncpy(backstr, but->poin, UI_MAX_DRAW_STR);
1751 ui_block_flush_back(but->block);
1753 while (get_mbut() & L_MOUSE) BIF_wait_for_statechange();
1764 dev = extern_qread_ext(&val, &ascii);
1766 if(dev==INPUTCHANGE) break;
1767 else if(get_mbut() & R_MOUSE) break;
1768 else if(get_mbut() & L_MOUSE) {
1769 uiGetMouse(mywinget(), mval);
1770 sx = mval[0]; sy = mval[1];
1772 if ((but->y1 <= sy) && (sy <= but->y2) && (but->x1 <= sx) && (sx <= but->x2)) {
1773 ui_set_cursor_pos_edittext(but, mval[0]);
1775 but->selsta = but->selend = but->pos;
1777 /* drag text select */
1779 while (get_mbut() & L_MOUSE) {
1780 uiGetMouse(mywinget(), mval);
1782 if(prevx!=mval[0]) {
1784 if (mval[0] > sx) selextend = EXTEND_RIGHT;
1785 else if (mval[0] < sx) selextend = EXTEND_LEFT;
1787 ui_set_cursor_pos_edittext(but, mval[0]);
1789 if (selextend == EXTEND_RIGHT) but->selend = but->pos;
1790 if (selextend == EXTEND_LEFT) but->selsta = but->pos;
1794 ui_block_flush_back(but->block);
1801 else if(dev==ESCKEY) break;
1802 else if(dev==MOUSEX) val= 0;
1803 else if(dev==MOUSEY) val= 0;
1805 /* cut, copy, paste selected text */
1806 /* mainqread discards ascii values < 32, so can't do this cleanly within the if(ascii) block*/
1808 ((G.qual & LR_COMMANDKEY) || (G.qual & LR_CTRLKEY)) &&
1809 ((dev==XKEY) || (dev==CKEY) || (dev==VKEY)) ) {
1811 char buf[UI_MAX_DRAW_STR]={0};
1816 /* extract the first line from the clipboard */
1817 char *p = getClipboard(0);
1820 while (*p && *p!='\r' && *p!='\n' && i<UI_MAX_DRAW_STR) {
1826 /* paste over the current selection */
1827 if ((but->selend - but->selsta) > 0) {
1828 len -= ui_delete_selection_edittext(but);
1831 for (y=0; y<strlen(buf); y++)
1833 /* add contents of buffer */
1834 if(len < but->max) {
1835 for(x= but->max; x>but->pos; x--)
1837 str[but->pos]= buf[y];
1843 if (strlen(buf) > 0) dodraw= 1;
1847 else if ( (dev==XKEY) || (dev==CKEY) ) {
1848 /* copy the contents to the clipboard */
1849 for(x= but->selsta; x <= but->selend; x++) {
1853 buf[(x - but->selsta)] = str[x];
1855 putClipboard(buf, 0);
1857 /* for cut only, delete the selection afterwards */
1859 if ((but->selend - but->selsta) > 0) {
1860 len -= ui_delete_selection_edittext(but);
1862 if (len < 0) len = 0;
1870 if(len-(but->selend - but->selsta)+1 <= but->max) {
1872 /* type over the current selection */
1873 if ((but->selend - but->selsta) > 0) {
1874 len -= ui_delete_selection_edittext(but);
1877 if(len < but->max) {
1878 for(x= but->max; x>but->pos; x--)
1880 str[but->pos]= ascii;
1893 /* if there's a selection */
1894 if ((but->selend - but->selsta) > 0) {
1895 /* extend the selection based on the first direction taken */
1896 if(G.qual & LR_SHIFTKEY) {
1898 selextend = EXTEND_RIGHT;
1900 if (selextend == EXTEND_RIGHT) {
1902 if (but->selend > len) but->selend = len;
1903 } else if (selextend == EXTEND_LEFT) {
1905 /* if the selection start has gone past the end,
1906 * flip them so they're in sync again */
1907 if (but->selsta == but->selend) {
1908 but->pos = but->selsta;
1909 selextend = EXTEND_RIGHT;
1913 but->selsta = but->pos = but->selend;
1917 if(G.qual & LR_SHIFTKEY) {
1918 /* make a selection, starting from the cursor position */
1919 but->selsta = but->pos;
1922 if(but->pos>strlen(str)) but->pos= strlen(str);
1924 but->selend = but->pos;
1925 } else if(G.qual & LR_CTRLKEY) {
1926 /* jump betweenn special characters (/,\,_,-, etc.),
1927 * look at function test_special_char() for complete
1928 * list of special character, ctr -> */
1929 while(but->pos < len) {
1931 if(test_special_char(str[but->pos])) break;
1935 if(but->pos>strlen(str)) but->pos= strlen(str);
1942 /* if there's a selection */
1943 if ((but->selend - but->selsta) > 0) {
1944 /* extend the selection based on the first direction taken */
1945 if(G.qual & LR_SHIFTKEY) {
1947 selextend = EXTEND_LEFT;
1949 if (selextend == EXTEND_LEFT) {
1951 if (but->selsta < 0) but->selsta = 0;
1952 } else if (selextend == EXTEND_RIGHT) {
1954 /* if the selection start has gone past the end,
1955 * flip them so they're in sync again */
1956 if (but->selsta == but->selend) {
1957 but->pos = but->selsta;
1958 selextend = EXTEND_LEFT;
1962 but->pos = but->selend = but->selsta;
1966 if(G.qual & LR_SHIFTKEY) {
1967 /* make a selection, starting from the cursor position */
1968 but->selend = but->pos;
1971 if(but->pos<0) but->pos= 0;
1973 but->selsta = but->pos;
1974 } else if(G.qual & LR_CTRLKEY) {
1975 /* jump betweenn special characters (/,\,_,-, etc.),
1976 * look at function test_special_char() for complete
1977 * list of special character, ctr -> */
1978 while(but->pos > 0){
1980 if(test_special_char(str[but->pos])) break;
1983 if(but->pos>0) but->pos--;
1991 if(G.qual & LR_SHIFTKEY) {
1992 but->selsta = but->pos;
1993 but->selend = strlen(str);
1994 selextend = EXTEND_RIGHT;
1996 but->selsta = but->selend = but->pos= strlen(str);
2003 if(G.qual & LR_SHIFTKEY) {
2004 but->selend = but->pos;
2006 selextend = EXTEND_LEFT;
2008 but->selsta = but->selend = but->pos= 0;
2019 if ((but->selend - but->selsta) > 0) {
2020 len -= ui_delete_selection_edittext(but);
2022 if (len < 0) len = 0;
2025 else if(but->pos>=0 && but->pos<strlen(str)) {
2026 for(x=but->pos; x<=strlen(str); x++)
2035 if ((but->selend - but->selsta) > 0) {
2036 len -= ui_delete_selection_edittext(but);
2038 if (len < 0) len = 0;
2041 else if(get_qual() & LR_SHIFTKEY) {
2047 else if(but->pos>0) {
2048 for(x=but->pos; x<=strlen(str); x++)
2058 if(but->autocomplete_func) {
2059 but->autocomplete_func(str, but->autofunc_arg);
2060 but->pos= strlen(str);
2064 else capturing= FALSE;
2074 ui_block_flush_back(but->block);
2078 if(dev==ESCKEY) strcpy(but->poin, backstr);
2080 but->flag &= ~UI_SELECT;
2083 /* give butfunc the original text too */
2084 /* feature used for bone renaming, channels, etc */
2085 if(but->func_arg2==NULL) but->func_arg2= backstr;
2092 if(dev==TABKEY) addqueue(but->win, G.qual?BUT_PREV:BUT_NEXT, 1);
2094 if(dev!=ESCKEY) return but->retval;
2095 else return B_NOP; // prevent event to be passed on
2099 static int ui_act_as_text_but(uiBut *but)
2104 int temp, retval, textleft;
2105 char str[UI_MAX_DRAW_STR], *point;
2107 /* this function is abused for tab-cycling */
2109 return ui_do_but_TEX(but);
2111 value= ui_get_but_val(but);
2112 if( but->pointype==FLO ) {
2113 if(but->a2) { /* amount of digits defined */
2114 if(but->a2==1) sprintf(str, "%.1f", value);
2115 else if(but->a2==2) sprintf(str, "%.2f", value);
2116 else if(but->a2==3) sprintf(str, "%.3f", value);
2117 else sprintf(str, "%.4f", value);
2119 else sprintf(str, "%.3f", value);
2122 sprintf(str, "%d", (int)value);
2124 /* store values before calling as text button */
2127 but_func= but->func;
2132 but->max= UI_MAX_DRAW_STR - 1; /* for py strings evaluation */
2135 textleft= but->flag & UI_TEXT_LEFT;
2136 but->flag |= UI_TEXT_LEFT;
2139 retval= ui_do_but_TEX(but);
2141 /* restore values */
2144 but->func= but_func;
2147 if(textleft==0) but->flag &= ~UI_TEXT_LEFT;
2149 #ifndef DISABLE_PYTHON
2150 if(BPY_button_eval(str, &value)) {
2151 /* Uncomment this if you want to see an error message (and annoy users) */
2152 /* error("Invalid Python expression, check console");*/
2153 value = 0.0f; /* Zero out value on error */
2156 retval = 0; /* invalidate return value if eval failed, except when string was null */
2162 if(but->pointype!=FLO) value= (int)value;
2164 if(but->type==NUMABS) value= fabs(value);
2165 if(value<min) value= min;
2166 if(value>max) value= max;
2168 ui_set_but_val(but, value);
2175 static int ui_do_but_NUM(uiBut *but)
2177 double value, butrange;
2178 float deler, fstart, f, tempf, pressure;
2179 int lvalue, temp, orig_x; /* , firsttime=1; */
2180 short retval=0, qual, sx, mval[2], pos=0;
2182 but->flag |= UI_SELECT;
2184 ui_block_flush_back(but->block);
2186 uiGetMouse(mywinget(), mval);
2187 value= ui_get_but_val(but);
2190 orig_x = sx; /* Store so we can scale the rate of change by the dist the mouse is from its original xlocation */
2191 butrange= (but->max - but->min);
2192 fstart= (butrange == 0.0)? 0.0f: (value - but->min)/butrange;
2198 if(get_qual() & LR_SHIFTKEY) { /* make it textbut */
2199 if( ui_act_as_text_but(but) ) retval= but->retval;
2202 retval= but->retval;
2203 /* firsttime: this button can be approached with enter as well */
2205 /* drag-lock - prevent unwanted scroll adjustments */
2206 /* change last value (now 3) to adjust threshold in pixels */
2207 while (get_mbut() & L_MOUSE & ( abs(mval[0]-sx) <= 3) ) {
2208 uiGetMouse(mywinget(), mval);
2210 sx = mval[0]; /* ignore mouse movement within drag-lock */
2212 while (get_mbut() & L_MOUSE) {
2214 pressure = get_pressure();
2216 uiGetMouse(mywinget(), mval);
2219 if( but->pointype!=FLO ) {
2221 if( (but->max-but->min)<100 ) deler= 200.0;
2222 if( (but->max-but->min)<25 ) deler= 50.0;
2225 if(qual & LR_SHIFTKEY) deler*= 10.0;
2226 if(qual & LR_ALTKEY) deler*= 20.0;
2228 /* de-sensitise based on tablet pressure */
2229 if (ELEM(get_activedevice(), DEV_STYLUS, DEV_ERASER)) deler /= pressure;
2232 if( but->pointype==FLO && but->max-but->min > 11) {
2233 /* non linear change in mouse input- good for high precicsion */
2234 f+= (((float)(mval[0]-sx))/deler) * (fabs(orig_x-mval[0])*0.002);
2235 } else if ( but->pointype!=FLO && but->max-but->min > 129) { /* only scale large int buttons */
2236 /* non linear change in mouse input- good for high precicsionm ints need less fine tuning */
2237 f+= (((float)(mval[0]-sx))/deler) * (fabs(orig_x-mval[0])*0.004);
2240 f+= ((float)(mval[0]-sx))/deler ;
2246 tempf= ( but->min + f*(but->max-but->min));
2248 if( but->pointype!=FLO ) {
2250 temp= floor(tempf+.5);
2252 if(tempf==but->min || tempf==but->max);
2253 else if(qual & LR_CTRLKEY) {
2254 if(qual & LR_SHIFTKEY) temp= 100*(temp/100);
2255 else temp= 10*(temp/10);
2257 if( temp>=but->min && temp<=but->max) {
2259 value= ui_get_but_val(but);
2262 if(temp != lvalue ) {
2264 ui_set_but_val(but, (double)temp);
2267 ui_block_flush_back(but->block);
2276 if(qual & LR_CTRLKEY) {
2277 if(qual & LR_SHIFTKEY) {
2278 if(tempf==but->min || tempf==but->max);
2279 else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
2280 else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
2281 else tempf= floor(tempf);
2284 if(tempf==but->min || tempf==but->max);
2285 else if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
2286 else if(but->max-but->min < 21.0) tempf= floor(tempf);
2287 else tempf= 10.0*floor(tempf/10.0);
2291 if( tempf>=but->min && tempf<=but->max) {
2292 value= ui_get_but_val(but);
2294 if(tempf != value ) {
2296 ui_set_but_val(but, tempf);
2299 ui_block_flush_back(but->block);
2305 BIF_wait_for_statechange();
2308 /* click on the side arrows to increment/decrement, click inside
2309 * to edit the value directly */
2310 if(pos==0) { /* plus 1 or minus 1 */
2311 if( but->pointype!=FLO ) {
2313 if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
2315 if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
2317 else if(sx > (but->x1 + (2*(but->x2 - but->x1)/3) + 3)) {
2319 if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
2322 if( ui_act_as_text_but(but) ); else retval= 0;
2327 if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
2328 tempf-= 0.01*but->a1;
2329 if (tempf < but->min) tempf = but->min;
2330 ui_set_but_val(but, tempf);
2332 else if(sx > but->x1 + (2*((but->x2 - but->x1)/3) + 3)) {
2333 tempf+= 0.01*but->a1;
2334 if (tempf < but->min) tempf = but->min;
2335 ui_set_but_val(but, tempf);
2338 if( ui_act_as_text_but(but) ); else retval= 0;
2344 but->flag &= ~UI_SELECT;
2347 ui_block_flush_back(but->block);
2354 static int ui_do_but_TOG3(uiBut *but)
2357 if( but->pointype==SHO ) {
2358 short *sp= (short *)but->poin;
2360 if( BTST(sp[1], but->bitnr)) {
2361 sp[1]= BCLR(sp[1], but->bitnr);
2362 sp[0]= BCLR(sp[0], but->bitnr);
2364 else if( BTST(sp[0], but->bitnr)) {
2365 sp[1]= BSET(sp[1], but->bitnr);
2367 sp[0]= BSET(sp[0], but->bitnr);
2371 if( BTST(*(but->poin+2), but->bitnr)) {
2372 *(but->poin+2)= BCLR(*(but->poin+2), but->bitnr);
2373 *(but->poin)= BCLR(*(but->poin), but->bitnr);
2375 else if( BTST(*(but->poin), but->bitnr)) {
2376 *(but->poin+2)= BSET(*(but->poin+2), but->bitnr);
2378 *(but->poin)= BSET(*(but->poin), but->bitnr);
2388 static int ui_do_but_ICONROW(uiBut *but)
2390 ListBase listb= {NULL, NULL};
2395 but->flag |= UI_SELECT;
2397 ui_block_flush_back(but->block); // flush because this button creates own blocks loop
2400 block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
2401 block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
2402 block->themecol= TH_MENU_ITEM;
2404 for(a=(int)but->min; a<=(int)but->max; a++) {
2405 uiDefIconBut(block, BUTM|but->pointype, but->retval, but->icon+(a-but->min), 0, (short)(18*a), (short)(but->x2-but->x1-4), 18, but->poin, (float)a, 0.0, 0, 0, "");
2407 block->direction= UI_TOP;
2408 ui_positionblock(block, but);
2410 /* the block is made with but-win, but is handled in mainwin space...
2411 this is needs better implementation */
2412 block->win= G.curscreen->mainwin;
2414 event= uiDoBlocks(&listb, 0, 1);
2416 but->flag &= ~UI_SELECT;
2420 if (event & UI_RETURN_OK) {
2427 static int ui_do_but_ICONTEXTROW(uiBut *but)
2430 ListBase listb={NULL, NULL};
2431 int width, a, xmax, ypos;
2434 but->flag |= UI_SELECT;
2436 ui_block_flush_back(but->block); // flush because this button creates own blocks loop
2438 block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
2439 block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
2440 block->themecol= TH_MENU_ITEM;
2442 md= decompose_menu_string(but->str);
2444 /* size and location */
2445 /* expand menu width to fit labels */
2447 width= 2*strlen(md->title)+BIF_GetStringWidth(block->curfont, md->title, (U.transopts & USER_TR_MENUS));
2451 for(a=0; a<md->nitems; a++) {
2452 xmax= BIF_GetStringWidth(block->curfont, md->items[a].str, (U.transopts & USER_TR_MENUS));
2453 if(xmax>width) width= xmax;
2457 if (width<50) width=50;
2461 /* loop through the menu options and draw them out with icons & text labels */
2462 for(a=0; a<md->nitems; a++) {
2464 /* add a space if there's a separator (%l) */
2465 if (strcmp(md->items[a].str, "%l")==0) {
2469 uiDefIconTextBut(block, BUTM|but->pointype, but->retval, (short)((but->icon)+(md->items[a].retval-but->min)), md->items[a].str, 0, ypos,(short)width, 19, but->poin, (float) md->items[a].retval, 0.0, 0, 0, "");
2476 uiSetCurFont(block, block->font+1);
2477 bt= uiDefBut(block, LABEL, 0, md->title, 0, ypos, (short)width, 19, NULL, 0.0, 0.0, 0, 0, "");
2478 uiSetCurFont(block, block->font);
2479 bt->flag= UI_TEXT_LEFT;
2482 block->direction= UI_TOP;
2483 ui_positionblock(block, but);
2485 /* the block is made with but-win, but is handled in mainwin space...
2486 this is needs better implementation */
2487 block->win= G.curscreen->mainwin;
2489 uiBoundsBlock(block, 3);
2491 event = uiDoBlocks(&listb, 0, 1);
2495 but->flag &= ~UI_SELECT;
2499 if (event & UI_RETURN_OK) {
2507 static int ui_do_but_IDPOIN(uiBut *but)
2509 char str[UI_MAX_DRAW_STR];
2512 id= *but->idpoin_idpp;
2513 if(id) strcpy(str, id->name+2);
2525 but->idpoin_func(str, but->idpoin_idpp);
2532 static int ui_do_but_SLI(uiBut *but)
2534 float f, fstart, tempf = 0.0, deler, value;
2535 int sx, h, temp, pos=0, lvalue, redraw;
2536 short mval[2], qual;
2538 value= ui_get_but_val(but);
2539 uiGetMouse(mywinget(), mval);
2543 fstart= but->max-but->min;
2544 fstart= (value - but->min)/fstart;
2547 if( but->type==NUMSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
2548 else if( but->type==HSVSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
2549 else deler= (but->x2-but->x1- 5.0*but->aspect);
2552 while (get_mbut() & L_MOUSE) {
2555 uiGetMouse(mywinget(), mval);
2557 f= (float)(mval[0]-sx)/deler +fstart;
2559 if (qual & LR_SHIFTKEY) {
2560 f= (f-fstart)/10.0 + fstart;
2564 tempf= but->min+f*(but->max-but->min);
2565 temp= floor(tempf+.5);
2567 if(qual & LR_CTRLKEY) {
2568 if(tempf==but->min || tempf==but->max);
2569 else if( but->pointype==FLO ) {
2571 if(qual & LR_SHIFTKEY) {
2572 if(tempf==but->min || tempf==but->max);
2573 else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
2574 else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
2575 else tempf= floor(tempf);
2578 if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
2579 else if(but->max-but->min < 21.0) tempf= floor(tempf);
2580 else tempf= 10.0*floor(tempf/10.0);
2589 value= ui_get_but_val(but);
2590 lvalue= floor(value+0.5);
2592 if( but->pointype!=FLO )
2593 redraw= (temp != lvalue);
2595 redraw= (tempf != value);
2599 ui_set_but_val(but, tempf);
2602 ui_block_flush_back(but->block);
2604 if(but->a1) { /* color number */
2605 uiBut *bt= but->prev;
2607 if(bt->a2 == but->a1) ui_draw_but(bt);
2612 if(bt->a2 == but->a1) ui_draw_but(bt);
2616 /* save current window matrix (global UIwinmat)
2617 because button callback function MIGHT change it
2618 - which has until now occured through the Python API
2620 /* This is really not possible atm... nothing in Blender
2621 supports such functionality even now. Calling function
2622 callbacks while using a button screws up the UI (ton)
2624 /* Mat4CpyMat4(curmatrix, UIwinmat);
2626 Mat4CpyMat4(UIwinmat, curmatrix); */
2628 else BIF_wait_for_statechange();
2632 if(temp!=32767 && pos==0) { /* plus 1 or minus 1 */
2634 if( but->type==SLI) f= (float)(mval[0]-but->x1)/(but->x2-but->x1-h);
2635 else f= (float)(mval[0]- (but->x1+but->x2)/2)/( (but->x2-but->x1)/2 - h);
2637 f= but->min+f*(but->max-but->min);
2639 if( but->pointype!=FLO ) {
2643 if( temp>=but->min && temp<=but->max)
2644 ui_set_but_val(but, (float)temp);
2649 if(f<tempf) tempf-=.01;
2651 if( tempf>=but->min && tempf<=but->max)
2652 ui_set_but_val(but, tempf);
2659 ui_block_flush_back(but->block);
2664 static int ui_do_but_NUMSLI(uiBut *but)
2668 /* first define if it's a slider or textbut */
2669 uiGetMouse(mywinget(), mval);
2671 if(mval[0]>= -6+(but->x1+but->x2)/2 ) { /* slider */
2672 but->flag |= UI_SELECT;
2675 but->flag &= ~UI_SELECT;
2678 ui_act_as_text_but(but);
2679 uibut_do_func(but); // this is done in ui_do_but_SLI() not in ui_act_as_text_but()
2682 while(get_mbut() & L_MOUSE) BIF_wait_for_statechange();
2687 if(but->type==HSVSLI) {
2689 if(but->str[0]=='H') {
2690 ui_draw_but(but->next);
2691 ui_draw_but(but->next->next);
2693 else if(but->str[0]=='S') {
2694 ui_draw_but(but->next);
2695 ui_draw_but(but->prev);
2697 else if(but->str[0]=='V') {
2698 ui_draw_but(but->prev);
2699 ui_draw_but(but->prev->prev);
2706 /* event denotes if we make first item active or not */
2707 static uiBlock *ui_do_but_BLOCK(uiBut *but, int event)
2712 but->flag |= UI_SELECT;
2715 block= but->block_func(but->poin);
2716 block->parent= but->block; /* allows checking for nested pulldowns */
2718 block->xofs = -2; /* for proper alignment */
2720 /* only used for automatic toolbox, so can set the shift flag */
2721 if(but->flag & UI_MAKE_TOP) {
2722 block->direction= UI_TOP|UI_SHIFT_FLIPPED;
2723 uiBlockFlipOrder(block);
2725 if(but->flag & UI_MAKE_DOWN) block->direction= UI_DOWN|UI_SHIFT_FLIPPED;
2726 if(but->flag & UI_MAKE_LEFT) block->direction |= UI_LEFT;
2727 if(but->flag & UI_MAKE_RIGHT) block->direction |= UI_RIGHT;
2729 ui_positionblock(block, but);
2730 block->flag |= UI_BLOCK_LOOP;
2732 /* blocks can come (and get scaled) from a normal window, now we go to screenspace */
2733 block->win= G.curscreen->mainwin;
2734 for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
2735 bwin_getsinglematrix(block->win, block->winmat);
2737 /* postpone draw, this will cause a new window matrix, first finish all other buttons */
2738 block->flag |= UI_BLOCK_REDRAW;
2740 if(event!=MOUSEX && event!=MOUSEY && event!=LEFTMOUSE && but->type==BLOCK) {
2741 bt= ui_but_first(block);
2742 if(bt) bt->flag |= UI_ACTIVE;
2745 but->flag &= ~UI_SELECT;
2749 addqueue(curarea->win, UI_BUT_EVENT, (short)but->retval);
2754 static int ui_do_but_BUTM(uiBut *but)
2756 /* draw 'pushing-in' when clicked on for use as a normal button in a panel */
2758 int oflag= but->flag;
2761 uiGetMouse(mywinget(), mval);
2763 if (uibut_contains_pt(but, mval))
2764 but->flag |= UI_SELECT;
2766 but->flag &= ~UI_SELECT;
2768 if (but->flag != oflag) {
2770 ui_block_flush_back(but->block);
2774 } while (get_mbut() & L_MOUSE);
2776 ui_set_but_val(but, but->min);
2777 UIafterfunc_butm= but->butm_func;
2778 UIafterfunc_arg1= but->butm_func_arg;
2779 UIafterval= but->a2;
2783 but->flag &= ~UI_SELECT;
2789 static int ui_do_but_LABEL(uiBut *but)
2795 static uiBut *ui_get_valid_link_button(uiBlock *block, uiBut *but, short *mval)
2799 /* find button to link to */
2800 for (bt= block->buttons.first; bt; bt= bt->next)
2801 if(bt!=but && uibut_contains_pt(bt, mval))
2805 if (but->type==LINK && bt->type==INLINK) {
2806 if( but->link->tocode == (int)bt->min ) {
2810 else if(but->type==INLINK && bt->type==LINK) {
2811 if( bt->link->tocode == (int)but->min ) {
2820 static int ui_is_a_link(uiBut *from, uiBut *to)
2827 line= link->lines.first;
2829 if(line->from==from && line->to==to) return 1;
2836 static uiBut *ui_find_inlink(uiBlock *block, void *poin)
2840 but= block->buttons.first;
2842 if(but->type==INLINK) {
2843 if(but->poin == poin) return but;
2850 static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt)
2854 line= MEM_callocN(sizeof(uiLinkLine), "linkline");
2855 BLI_addtail(listb, line);
2860 uiBut *uiFindInlink(uiBlock *block, void *poin)
2862 return ui_find_inlink(block, poin);
2865 void uiComposeLinks(uiBlock *block)
2872 but= block->buttons.first;
2874 if(but->type==LINK) {
2877 /* for all pointers in the array */
2881 for(a=0; a < *(link->totlink); a++) {
2882 bt= ui_find_inlink(block, (*ppoin)[a] );
2884 ui_add_link_line(&link->lines, but, bt);
2888 else if(link->poin) {
2889 bt= ui_find_inlink(block, *(link->poin) );
2891 ui_add_link_line(&link->lines, but, bt);
2900 static void ui_add_link(uiBut *from, uiBut *to)
2902 /* in 'from' we have to add a link to 'to' */
2907 if(ui_is_a_link(from, to)) {
2908 printf("already exists\n");
2914 /* are there more pointers allowed? */
2916 oldppoin= *(link->ppoin);
2918 (*(link->totlink))++;
2919 *(link->ppoin)= MEM_callocN( *(link->totlink)*sizeof(void *), "new link");
2921 for(a=0; a< (*(link->totlink))-1; a++) {
2922 (*(link->ppoin))[a]= oldppoin[a];
2924 (*(link->ppoin))[a]= to->poin;
2926 if(oldppoin) MEM_freeN(oldppoin);
2929 *(link->poin)= to->poin;
2934 static int ui_do_but_LINK(uiBlock *block, uiBut *but)
2937 * This button only visualizes, the dobutton mode
2938 * can add a new link, but then the whole system
2939 * should be redrawn/initialized.
2942 uiBut *bt=0, *bto=NULL;
2943 short sval[2], mval[2], mvalo[2], first= 1;
2945 uiGetMouse(curarea->win, sval);
2949 while (get_mbut() & L_MOUSE) {
2950 uiGetMouse(curarea->win, mval);
2952 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || first) {
2953 /* clear completely, because of drawbuttons */
2954 bt= ui_get_valid_link_button(block, but, mval);
2956 bt->flag |= UI_ACTIVE;
2959 if(bto && bto!=bt) {
2960 bto->flag &= ~UI_ACTIVE;
2966 glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
2968 glutil_draw_front_xor_line(sval[0], sval[1], mval[0], mval[1]);
2975 else BIF_wait_for_statechange();
2979 glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
2983 if(but->type==LINK) ui_add_link(but, bt);
2984 else ui_add_link(bt, but);
2986 scrarea_queue_winredraw(curarea);
2992 /* picker sizes S hsize, F full size, D spacer, B button/pallette height */
2998 #define UI_PALETTE_TOT 16
2999 /* note; in tot+1 the old color is stored */
3000 static float palette[UI_PALETTE_TOT+1][3]= {
3001 {0.93, 0.83, 0.81}, {0.88, 0.89, 0.73}, {0.69, 0.81, 0.57}, {0.51, 0.76, 0.64},
3002 {0.37, 0.56, 0.61}, {0.33, 0.29, 0.55}, {0.46, 0.21, 0.51}, {0.40, 0.12, 0.18},
3003 {1.0, 1.0, 1.0}, {0.85, 0.85, 0.85}, {0.7, 0.7, 0.7}, {0.56, 0.56, 0.56},
3004 {0.42, 0.42, 0.42}, {0.28, 0.28, 0.28}, {0.14, 0.14, 0.14}, {0.0, 0.0, 0.0}
3007 /* for picker, while editing hsv */
3008 static void ui_set_but_hsv(uiBut *but)
3012 hsv_to_rgb(but->hsv[0], but->hsv[1], but->hsv[2], col, col+1, col+2);
3013 ui_set_but_vectorf(but, col);
3016 static void update_picker_hex(uiBlock *block, float *rgb)
3021 sprintf(col, "%02X%02X%02X", (unsigned int)(rgb[0]*255.0), (unsigned int)(rgb[1]*255.0), (unsigned int)(rgb[2]*255.0));
3023 // this updates button strings, is hackish... but button pointers are on stack of caller function
3025 for(bt= block->buttons.first; bt; bt= bt->next) {
3026 if(strcmp(bt->str, "Hex: ")==0) {
3027 strcpy(bt->poin, col);
3034 static void update_picker_buts_hsv(uiBlock *block, float *hsv, char *poin)
3040 // this updates button strings, is hackish... but button pointers are on stack of caller function
3041 hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r, &g, &b);
3043 rgb[0] = r; rgb[1] = g; rgb[2] = b;
3044 update_picker_hex(block, rgb);
3046 for(bt= block->buttons.first; bt; bt= bt->next) {
3047 if(bt->type==HSVCUBE) {
3048 VECCOPY(bt->hsv, hsv);
3051 else if(bt->str[1]==' ') {
3052 if(bt->str[0]=='R') {
3053 ui_set_but_val(bt, r);
3055 else if(bt->str[0]=='G') {
3056 ui_set_but_val(bt, g);
3058 else if(bt->str[0]=='B') {
3059 ui_set_but_val(bt, b);
3061 else if(bt->str[0]=='H') {
3062 ui_set_but_val(bt, hsv[0]);
3064 else if(bt->str[0]=='S') {
3065 ui_set_but_val(bt, hsv[1]);
3067 else if(bt->str[0]=='V') {
3068 ui_set_but_val(bt, hsv[2]);
3074 static void update_picker_buts_hex(uiBlock *block, char *hexcol)
3077 float r=0, g=0, b=0;
3081 // this updates button strings, is hackish... but button pointers are on stack of caller function
3082 hex_to_rgb(hexcol, &r, &g, &b);
3083 rgb_to_hsv(r, g, b, &h, &s, &v);
3085 for(bt= block->buttons.first; bt; bt= bt->next) {
3086 if(bt->type==HSVCUBE) {
3092 else if(bt->str[1]==' ') {
3093 if(bt->str[0]=='R') {
3094 ui_set_but_val(bt, r);
3096 else if(bt->str[0]=='G') {
3097 ui_set_but_val(bt, g);
3099 else if(bt->str[0]=='B') {
3100 ui_set_but_val(bt, b);
3102 else if(bt->str[0]=='H') {
3103 ui_set_but_val(bt, h);
3105 else if(bt->str[0]=='S') {
3106 ui_set_but_val(bt, s);
3108 else if(bt->str[0]=='V') {
3109 ui_set_but_val(bt, v);