4 * ***** BEGIN GPL/BL DUAL 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. The Blender
10 * Foundation also sells licenses for use in proprietary software under
11 * the Blender License. See http://www.blender.org/BL/ for information
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24 * All rights reserved.
26 * The Original Code is: all of this file.
28 * Contributor(s): none yet.
30 * ***** END GPL/BL DUAL LICENSE BLOCK *****
34 a full doc with API notes can be found in bf-blender/blender/doc/interface_API.txt
54 #include "MEM_guardedalloc.h"
59 #include "BIF_language.h"
62 #endif // INTERNATIONAL
64 #include "BLI_blenlib.h"
65 #include "BLI_arithb.h"
67 #include "DNA_screen_types.h"
68 #include "DNA_space_types.h"
69 #include "DNA_userdef_types.h"
70 #include "DNA_vec_types.h"
71 #include "DNA_object_types.h"
72 #include "DNA_vfont_types.h"
74 #include "BKE_blender.h"
75 #include "BKE_global.h"
76 #include "BKE_library.h"
77 #include "BKE_utildefines.h"
80 #include "BIF_graphics.h"
81 #include "BIF_keyval.h"
82 #include "BIF_mainqueue.h"
83 #include "BIF_resources.h"
84 #include "BIF_screen.h"
85 #include "BIF_toolbox.h"
86 #include "BIF_mywindow.h"
87 #include "BIF_space.h"
88 #include "BIF_glutil.h"
89 #include "BIF_editfont.h"
90 #include "BIF_interface.h"
91 #include "BIF_butspace.h"
96 #include "interface.h"
99 /* naming conventions:
101 * uiBlahBlah() external function
102 * ui_blah_blah() internal function
106 /* ************ GLOBALS ************* */
108 float UIwinmat[4][4];
109 static int UIlock= 0, UIafterval;
110 static char *UIlockstr=NULL;
111 static void (*UIafterfunc)(void *arg, int event);
112 static void *UIafterfunc_arg;
114 static uiFont UIfont[UI_ARRAY]; // no init needed
117 /* ************* PROTOTYPES ***************** */
119 static void ui_set_but_val(uiBut *but, double value);
120 static void ui_do_but_tip(uiBut *buttip);
122 /* ****************************** */
124 static int uibut_contains_pt(uiBut *but, short *pt)
126 return ((but->x1<pt[0] && but->x2>=pt[0]) &&
127 (but->y1<pt[1] && but->y2>=pt[1]));
130 static void uibut_do_func(uiBut *but)
133 but->func(but->func_arg1, but->func_arg2);
137 /* ************* window matrix ************** */
140 void ui_graphics_to_window(int win, float *x, float *y) /* for rectwrite */
144 int getsizex, getsizey;
146 bwin_getsize(win, &getsizex, &getsizey);
147 bwin_getsuborigin(win, &sx, &sy);
151 *x= ((float)sx) + ((float)getsizex)*(0.5+ 0.5*(gx*UIwinmat[0][0]+ gy*UIwinmat[1][0]+ UIwinmat[3][0]));
152 *y= ((float)sy) + ((float)getsizey)*(0.5+ 0.5*(gx*UIwinmat[0][1]+ gy*UIwinmat[1][1]+ UIwinmat[3][1]));
157 void ui_window_to_graphics(int win, float *x, float *y) /* for mouse cursor */
159 float a, b, c, d, e, f, px, py;
160 int getsizex, getsizey;
162 bwin_getsize(win, &getsizex, &getsizey);
164 a= .5*((float)getsizex)*UIwinmat[0][0];
165 b= .5*((float)getsizex)*UIwinmat[1][0];
166 c= .5*((float)getsizex)*(1.0+UIwinmat[3][0]);
168 d= .5*((float)getsizey)*UIwinmat[0][1];
169 e= .5*((float)getsizey)*UIwinmat[1][1];
170 f= .5*((float)getsizey)*(1.0+UIwinmat[3][1]);
175 *y= (a*(py-f) + d*(c-px))/(a*e-d*b);
176 *x= (px- b*(*y)- c)/a;
181 /* ************* SAVE UNDER ************ */
185 OverDraw *ui_begin_overdraw(int minx, int miny, int maxx, int maxy);
186 - enforces mainwindow to become active
187 - grabs copy from frontbuffer, pastes in back
189 void ui_flush_overdraw(OverDraw *od);
190 - copies backbuffer to front
192 void ui_refresh_overdraw(Overdraw *od);
193 - pastes in back copy of frontbuffer again for fresh drawing
195 void ui_end_overdraw(OverDraw *od);
196 - puts back on frontbuffer saved image
198 - sets back active blender area
199 - signals backbuffer to be corrupt (sel buffer!)
203 /* frontbuffer updates now glCopyPixels too, with block->flush rect */
205 /* new idea for frontbuffer updates:
207 - hilites: with blended poly?
209 - full updates... thats harder, but:
211 - before draw, always paste to backbuf
213 - always end with redraw event for full update
217 static void myglCopyPixels(int a, int b, int c, int d, int e)
220 unsigned int *buf= MEM_mallocN(4*c*d, "temp glcopypixels");
221 glReadPixels(a, b, c, d, GL_RGBA, GL_UNSIGNED_BYTE, buf);
222 glDrawPixels(c, d, GL_RGBA, GL_UNSIGNED_BYTE, buf);
225 else glCopyPixels(a, b, c, d, e);
229 short x, y, sx, sy, oldwin;
234 static uiOverDraw *ui_begin_overdraw(int minx, int miny, int maxx, int maxy)
238 // dirty patch removed for sun and sgi to mywindow.c commented out
240 /* clip with actual window size */
241 if(minx < 0) minx= 0;
242 if(miny < 0) miny= 0;
243 if(maxx >= G.curscreen->sizex) maxx= G.curscreen->sizex-1;
244 if(maxy >= G.curscreen->sizey) maxy= G.curscreen->sizey-1;
246 if(minx<maxx && miny<maxy) {
247 od= MEM_callocN(sizeof(uiOverDraw), "overdraw");
253 od->rect= MEM_mallocN(od->sx*od->sy*4, "temp_frontbuffer_image");
255 od->oldwin= mywinget();
256 mywinset(G.curscreen->mainwin);
258 glReadBuffer(GL_FRONT);
259 glReadPixels(od->x, od->y, od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
260 glReadBuffer(GL_BACK);
262 glDisable(GL_DITHER);
263 glRasterPos2f(od->x, od->y);
264 glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
271 static void ui_flush_overdraw(uiOverDraw *od)
275 glDisable(GL_DITHER);
276 glReadBuffer(GL_BACK);
277 glDrawBuffer(GL_FRONT);
278 glRasterPos2s(od->x, od->y);
279 myglCopyPixels(od->x, od->y, od->sx, od->sy, GL_COLOR);
282 glDrawBuffer(GL_BACK);
285 /* special flush version to enable transparent menus */
286 static void ui_block_flush_overdraw(uiBlock *block)
289 if(block->flag & UI_BLOCK_LOOP) {
292 BIF_GetThemeColor4ubv(TH_MENU_BACK, col);
295 uiOverDraw *od= block->overdraw;
297 /* completely draw all! */
298 glRasterPos2s(od->x, od->y);
299 glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
301 uiDrawMenuBox(block->minx, block->miny, block->maxx, block->maxy, block->flag);
302 for (bt= block->buttons.first; bt; bt= bt->next) {
308 ui_flush_overdraw(block->overdraw);
311 static void ui_end_overdraw(uiOverDraw *od)
315 glDisable(GL_DITHER);
318 glRasterPos2s(od->x, od->y);
319 glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
322 glDrawBuffer(GL_FRONT);
323 glRasterPos2s(od->x, od->y);
324 glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
327 glDrawBuffer(GL_BACK);
330 if(od->oldwin) mywinset(od->oldwin);
335 markdirty_all_back(); // sets flags only
338 /* ****************** live updates for hilites and button presses *********** */
340 void ui_block_flush_back(uiBlock *block)
342 int minx, miny, sizex, sizey;
344 /* note; this routine also has to work for block loop */
345 if(block->needflush==0) return;
347 /* exception, when we cannot use backbuffer for draw... */
348 if(block->flag & UI_BLOCK_FRONTBUFFER) {
350 glDrawBuffer(GL_BACK);
355 /* copy pixels works on window coords, so we move to window space */
357 ui_graphics_to_window(block->win, &block->flush.xmin, &block->flush.ymin);
358 ui_graphics_to_window(block->win, &block->flush.xmax, &block->flush.ymax);
359 minx= floor(block->flush.xmin);
360 miny= floor(block->flush.ymin);
361 sizex= ceil(block->flush.xmax-block->flush.xmin);
362 sizey= ceil(block->flush.ymax-block->flush.ymin);
364 if(sizex>0 && sizey>0) {
366 mywinset(G.curscreen->mainwin);
368 glDisable(GL_DITHER);
369 glReadBuffer(GL_BACK);
370 glDrawBuffer(GL_FRONT);
371 glRasterPos2i(minx, miny);
373 myglCopyPixels(minx, miny+1, sizex, sizey, GL_COLOR);
375 myglCopyPixels(minx, miny, sizex, sizey, GL_COLOR);
379 glDrawBuffer(GL_BACK);
381 mywinset(block->win);
384 markdirty_win_back(block->win);
390 /* merge info for live updates in frontbuf */
391 void ui_block_set_flush(uiBlock *block, uiBut *but)
397 block->flush.xmin= 0.0;
398 block->flush.xmax= 0.0;
401 /* exception, when we cannot use backbuffer for draw... */
402 if(block->flag & UI_BLOCK_FRONTBUFFER) {
403 glDrawBuffer(GL_FRONT);
405 else if(block->needflush==0) {
407 block->flush.xmin= but->x1;
408 block->flush.xmax= but->x2;
409 block->flush.ymin= but->y1;
410 block->flush.ymax= but->y2;
415 if(block->flush.xmin > but->x1) block->flush.xmin= but->x1;
416 if(block->flush.xmax < but->x2) block->flush.xmax= but->x2;
417 if(block->flush.ymin > but->y1) block->flush.ymin= but->y1;
418 if(block->flush.ymax < but->y2) block->flush.ymax= but->y2;
426 /* ******************* copy and paste ******************** */
428 /* c = copy, v = paste */
429 /* return 1 when something changed */
430 static int ui_but_copy_paste(uiBut *but, char mode)
432 static char str[256]="";
433 static double butval=0.0;
437 if(mode=='v' && but->lock) return 0;
441 if ELEM3(but->type, NUM, NUMSLI, HSVSLI) {
444 butval= ui_get_but_val(but);
447 ui_set_but_val(but, butval);
452 else if(but->type==COL) {
455 if(but->pointype==FLO) {
456 float *fp= (float *) poin;
461 else if (but->pointype==CHA) {
462 char *cp= (char *) poin;
463 rgb[0]= (float)(cp[0]/255.0);
464 rgb[1]= (float)(cp[1]/255.0);
465 rgb[2]= (float)(cp[2]/255.0);
470 if(but->pointype==FLO) {
471 float *fp= (float *) poin;
477 else if (but->pointype==CHA) {
478 char *cp= (char *) poin;
479 cp[0] = (char)(rgb[0]*255.0);
480 cp[1] = (char)(rgb[1]*255.0);
481 cp[2] = (char)(rgb[2]*255.0);
488 else if(but->type==TEX) {
491 strncpy(str, but->poin, but->max);
494 char backstr[UI_MAX_DRAW_STR];
495 /* give butfunc the original text too */
496 /* feature used for bone renaming, channels, etc */
497 if(but->func_arg2==NULL) {
498 strncpy(backstr, but->drawstr, UI_MAX_DRAW_STR);
499 but->func_arg2= backstr;
501 strncpy(but->poin, str, but->max);
507 else if(but->type==IDPOIN) {
510 ID *id= *but->idpoin_idpp;
511 if(id) strncpy(str, id->name+2, 22);
514 but->idpoin_func(str, but->idpoin_idpp);
524 /* ******************* block calc ************************* */
526 void uiTextBoundsBlock(uiBlock *block, int addval)
531 bt= block->buttons.first;
534 int transopts= (U.transopts & USER_TR_BUTTONS);
535 if(bt->type==TEX || bt->type==IDPOIN) transopts= 0;
536 j= BIF_GetStringWidth(bt->font, bt->drawstr, transopts);
544 bt= block->buttons.first;
547 ui_check_but(bt); // clips text again
553 void uiBoundsBlock(uiBlock *block, int addval)
558 if(block->buttons.first==NULL) {
560 block->minx= 0.0; block->maxx= block->panel->sizex;
561 block->miny= 0.0; block->maxy= block->panel->sizey;
566 block->minx= block->miny= 10000;
567 block->maxx= block->maxy= -10000;
569 bt= block->buttons.first;
571 if(bt->x1 < block->minx) block->minx= bt->x1;
572 if(bt->y1 < block->miny) block->miny= bt->y1;
574 if(bt->x2 > block->maxx) block->maxx= bt->x2;
575 if(bt->y2 > block->maxy) block->maxy= bt->y2;
580 block->minx -= addval;
581 block->miny -= addval;
582 block->maxx += addval;
583 block->maxy += addval;
586 /* hardcoded exception... but that one is annoying with larger safety */
587 bt= block->buttons.first;
588 if(bt && strncmp(bt->str, "ERROR", 5)==0) xof= 10;
591 block->safety.xmin= block->minx-xof;
592 block->safety.ymin= block->miny-xof;
593 block->safety.xmax= block->maxx+xof;
594 block->safety.ymax= block->maxy+xof;
597 static void ui_positionblock(uiBlock *block, uiBut *but)
599 /* position block relative to but */
602 int xsize, ysize, xof=0, yof=0, centre;
603 short dir1= 0, dir2=0;
605 /* first transform to screen coords, assuming matrix is stil OK */
606 /* the UIwinmat is in panelspace */
608 butrct.xmin= but->x1; butrct.xmax= but->x2;
609 butrct.ymin= but->y1; butrct.ymax= but->y2;
611 ui_graphics_to_window(block->win, &butrct.xmin, &butrct.ymin);
612 ui_graphics_to_window(block->win, &butrct.xmax, &butrct.ymax);
613 block->parentrct= butrct; // will use that for pulldowns later
615 /* calc block rect */
616 if(block->buttons.first) {
617 block->minx= block->miny= 10000;
618 block->maxx= block->maxy= -10000;
620 bt= block->buttons.first;
622 if(bt->x1 < block->minx) block->minx= bt->x1;
623 if(bt->y1 < block->miny) block->miny= bt->y1;
625 if(bt->x2 > block->maxx) block->maxx= bt->x2;
626 if(bt->y2 > block->maxy) block->maxy= bt->y2;
632 /* we're nice and allow empty blocks too */
633 block->minx= block->miny= 0;
634 block->maxx= block->maxy= 20;
637 ui_graphics_to_window(block->win, &block->minx, &block->miny);
638 ui_graphics_to_window(block->win, &block->maxx, &block->maxy);
640 //block->minx-= 2.0; block->miny-= 2.0;
641 //block->maxx+= 2.0; block->maxy+= 2.0;
643 xsize= block->maxx - block->minx+4; // 4 for shadow
644 ysize= block->maxy - block->miny+4;
647 short left=0, right=0, top=0, down=0;
649 if(block->direction & UI_CENTRE) centre= ysize/2;
652 if( butrct.xmin-xsize > 0.0) left= 1;
653 if( butrct.xmax+xsize < G.curscreen->sizex) right= 1;
654 if( butrct.ymin-ysize+centre > 0.0) down= 1;
655 if( butrct.ymax+ysize-centre < G.curscreen->sizey) top= 1;
657 dir1= block->direction & UI_DIRECTION;
659 /* secundary directions */
660 if(dir1 & (UI_TOP|UI_DOWN)) {
661 if(dir1 & UI_LEFT) dir2= UI_LEFT;
662 else if(dir1 & UI_RIGHT) dir2= UI_RIGHT;
663 dir1 &= (UI_TOP|UI_DOWN);
666 if(dir2==0) if(dir1==UI_LEFT || dir1==UI_RIGHT) dir2= UI_DOWN;
667 if(dir2==0) if(dir1==UI_TOP || dir1==UI_DOWN) dir2= UI_LEFT;
669 /* no space at all? dont change */
671 if(dir1==UI_LEFT && left==0) dir1= UI_RIGHT;
672 if(dir1==UI_RIGHT && right==0) dir1= UI_LEFT;
673 /* this is aligning, not append! */
674 if(dir2==UI_LEFT && right==0) dir2= UI_RIGHT;
675 if(dir2==UI_RIGHT && left==0) dir2= UI_LEFT;
678 if(dir1==UI_TOP && top==0) dir1= UI_DOWN;
679 if(dir1==UI_DOWN && down==0) dir1= UI_TOP;
680 if(dir2==UI_TOP && top==0) dir2= UI_DOWN;
681 if(dir2==UI_DOWN && down==0) dir2= UI_TOP;
685 xof= butrct.xmin - block->maxx;
686 if(dir2==UI_TOP) yof= butrct.ymin - block->miny-centre;
687 else yof= butrct.ymax - block->maxy+centre;
689 else if(dir1==UI_RIGHT) {
690 xof= butrct.xmax - block->minx;
691 if(dir2==UI_TOP) yof= butrct.ymin - block->miny-centre;
692 else yof= butrct.ymax - block->maxy+centre;
694 else if(dir1==UI_TOP) {
695 yof= butrct.ymax - block->miny;
696 if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
697 else xof= butrct.xmin - block->minx;
698 // changed direction?
699 if((dir1 & block->direction)==0) {
700 if(block->direction & UI_SHIFT_FLIPPED)
701 xof+= dir2==UI_LEFT?25:-25;
702 uiBlockFlipOrder(block);
705 else if(dir1==UI_DOWN) {
706 yof= butrct.ymin - block->maxy;
707 if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
708 else xof= butrct.xmin - block->minx;
709 // changed direction?
710 if((dir1 & block->direction)==0) {
711 if(block->direction & UI_SHIFT_FLIPPED)
712 xof+= dir2==UI_LEFT?25:-25;
713 uiBlockFlipOrder(block);
717 /* and now we handle the exception; no space below or to top */
718 if(top==0 && down==0) {
719 if(dir1==UI_LEFT || dir1==UI_RIGHT) {
720 // align with bottom of screen
725 /* or no space left or right */
726 if(left==0 && right==0) {
727 if(dir1==UI_TOP || dir1==UI_DOWN) {
728 // align with left size of screen
733 // apply requested offset in the block
734 xof += block->xofs/block->aspect;
735 yof += block->yofs/block->aspect;
740 bt= block->buttons.first;
743 ui_graphics_to_window(block->win, &bt->x1, &bt->y1);
744 ui_graphics_to_window(block->win, &bt->x2, &bt->y2);
752 // ui_check_but recalculates drawstring size in pixels
763 /* safety calculus */
765 float midx= (block->parentrct.xmin+block->parentrct.xmax)/2.0;
766 float midy= (block->parentrct.ymin+block->parentrct.ymax)/2.0;
768 /* when you are outside parent button, safety there should be smaller */
770 // parent button to left
771 if( midx < block->minx ) block->safety.xmin= block->minx-3;
772 else block->safety.xmin= block->minx-40;
773 // parent button to right
774 if( midx > block->maxx ) block->safety.xmax= block->maxx+3;
775 else block->safety.xmax= block->maxx+40;
777 // parent button on bottom
778 if( midy < block->miny ) block->safety.ymin= block->miny-3;
779 else block->safety.ymin= block->miny-40;
780 // parent button on top
781 if( midy > block->maxy ) block->safety.ymax= block->maxy+3;
782 else block->safety.ymax= block->maxy+40;
784 // exception for switched pulldowns...
785 if(dir1 && (dir1 & block->direction)==0) {
786 if(dir2==UI_RIGHT) block->safety.xmax= block->maxx+3;
787 if(dir2==UI_LEFT) block->safety.xmin= block->minx-3;
789 block->direction= dir1;
792 block->safety.xmin= block->minx-40;
793 block->safety.ymin= block->miny-40;
794 block->safety.xmax= block->maxx+40;
795 block->safety.ymax= block->maxy+40;
801 void ui_autofill(uiBlock *block)
804 float *maxw, *maxh, startx = 0, starty, height = 0;
806 int rows=0, /* cols=0, */ i, lasti;
808 /* first count rows */
809 but= block->buttons.last;
812 /* calculate max width / height for each row */
813 maxw= MEM_callocN(sizeof(float)*rows, "maxw");
814 maxh= MEM_callocN(sizeof(float)*rows, "maxh");
815 but= block->buttons.first;
818 if( maxh[i] < but->y2) maxh[i]= but->y2;
824 for(i=0; i<rows; i++) totmaxh+= maxh[i];
826 /* apply widths/heights */
828 but= block->buttons.first;
831 // signal for aligning code
832 but->flag |= UI_BUT_ALIGN_DOWN;
838 height= (maxh[i]*(block->maxy-block->miny))/totmaxh;
843 but->y1= starty+but->aspect;
844 but->y2= but->y1+height-but->aspect;
846 but->x2= (but->x2*(block->maxx-block->minx))/maxw[i];
847 but->x1= startx+but->aspect;
850 but->x2+= but->x1-but->aspect;
857 uiBlockEndAlign(block);
859 MEM_freeN(maxw); MEM_freeN(maxh);
863 /* ************** LINK LINE DRAWING ************* */
865 /* link line drawing is not part of buttons or theme.. so we stick with it here */
867 static void ui_draw_linkline(uiBut *but, uiLinkLine *line)
869 float vec1[2], vec2[2];
871 if(line->from==NULL || line->to==NULL) return;
873 vec1[0]= (line->from->x1+line->from->x2)/2.0;
874 vec1[1]= (line->from->y1+line->from->y2)/2.0;
875 vec2[0]= (line->to->x1+line->to->x2)/2.0;
876 vec2[1]= (line->to->y1+line->to->y2)/2.0;
878 if(line->flag & UI_SELECT) BIF_ThemeColorShade(but->themecol, 80);
879 else glColor3ub(0,0,0);
880 fdrawline(vec1[0], vec1[1], vec2[0], vec2[1]);
883 static void ui_draw_links(uiBlock *block)
888 but= block->buttons.first;
890 if(but->type==LINK && but->link) {
891 line= but->link->lines.first;
893 ui_draw_linkline(but, line);
901 /* ************** BLOCK DRAWING FUNCTION ************* */
904 void uiDrawBlock(uiBlock *block)
907 short testmouse=0, mouse[2];
909 /* handle pending stuff */
910 if(block->autofill) ui_autofill(block);
911 if(block->minx==0.0 && block->maxx==0.0) uiBoundsBlock(block, 0);
912 if(block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block);
914 /* we set active flag on a redraw again */
915 if((block->flag & UI_BLOCK_LOOP)==0) {
917 Mat4CpyMat4(UIwinmat, block->winmat);
918 uiGetMouse(block->win, mouse);
921 uiPanelPush(block); // panel matrix
923 if(block->flag & UI_BLOCK_LOOP) {
924 uiDrawMenuBox(block->minx, block->miny, block->maxx, block->maxy, block->flag);
927 if(block->panel) ui_draw_panel(block);
930 if(block->drawextra) block->drawextra();
932 for (but= block->buttons.first; but; but= but->next) {
934 if(testmouse && uibut_contains_pt(but, mouse))
935 but->flag |= UI_ACTIVE;
940 ui_draw_links(block);
942 uiPanelPop(block); // matrix restored
945 /* ************* MENUBUTS *********** */
959 int nitems, itemssize;
962 static MenuData *menudata_new(char *instr) {
963 MenuData *md= MEM_mallocN(sizeof(*md), "MenuData");
969 md->nitems= md->itemssize= 0;
974 static void menudata_set_title(MenuData *md, char *title, int titleicon) {
978 md->titleicon= titleicon;
981 static void menudata_add_item(MenuData *md, char *str, int retval, int icon) {
982 if (md->nitems==md->itemssize) {
983 int nsize= md->itemssize?(md->itemssize<<1):1;
984 MenuEntry *oitems= md->items;
986 md->items= MEM_mallocN(nsize*sizeof(*md->items), "md->items");
988 memcpy(md->items, oitems, md->nitems*sizeof(*md->items));
992 md->itemssize= nsize;
995 md->items[md->nitems].str= str;
996 md->items[md->nitems].retval= retval;
997 md->items[md->nitems].icon= icon;
1001 static void menudata_free(MenuData *md) {
1002 MEM_freeN(md->instr);
1004 MEM_freeN(md->items);
1009 * Parse menu description strings, string is of the
1010 * form "[sss%t|]{(sss[%xNN]|), (%l|)}", ssss%t indicates the
1011 * menu title, sss or sss%xNN indicates an option,
1012 * if %xNN is given then NN is the return value if
1013 * that option is selected otherwise the return value
1014 * is the index of the option (starting with 1). %l
1015 * indicates a seperator.
1017 * @param str String to be parsed.
1018 * @retval new menudata structure, free with menudata_free()
1020 static MenuData *decompose_menu_string(char *str)
1022 char *instr= BLI_strdup(str);
1023 MenuData *md= menudata_new(instr);
1024 char *nitem= NULL, *s= instr;
1025 int nicon=0, nretval= 1, nitem_is_title= 0;
1036 } else if (s[1]=='t') {
1041 } else if (s[1]=='l') {
1044 } else if (s[1]=='i') {
1050 } else if (c=='|' || c=='\0') {
1054 if (nitem_is_title) {
1055 menudata_set_title(md, nitem, nicon);
1058 menudata_add_item(md, nitem, nretval, nicon);
1059 nretval= md->nitems+1;
1077 static void ui_set_name_menu(uiBut *but, int value)
1082 md= decompose_menu_string(but->str);
1083 for (i=0; i<md->nitems; i++)
1084 if (md->items[i].retval==value)
1085 strcpy(but->drawstr, md->items[i].str);
1089 static void ui_warp_pointer(short x, short y)
1091 /* OSX has very poor mousewarp support, it sends events;
1092 this causes a menu being pressed immediately ... */
1099 static int ui_do_but_MENU(uiBut *but)
1103 ListBase listb={NULL, NULL}, lb;
1105 int width, height=0, a, xmax, starty;
1107 int columns=1, rows=0, boxh, event;
1108 short x1, y1, active= -1;
1112 but->flag |= UI_SELECT;
1114 ui_block_flush_back(but->block); // flush because this button creates own blocks loop
1116 block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
1117 block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
1118 block->themecol= TH_MENU_ITEM;
1120 md= decompose_menu_string(but->str);
1122 /* columns and row calculation */
1123 columns= (md->nitems+20)/20;
1124 if (columns<1) columns= 1;
1126 if(columns>8) columns= (md->nitems+25)/25;
1128 rows= (int) md->nitems/columns;
1129 if (rows<1) rows= 1;
1131 while (rows*columns<md->nitems) rows++;
1133 /* size and location */
1135 width= 1.5*but->aspect*strlen(md->title)+BIF_GetStringWidth(block->curfont, md->title, (U.transopts & USER_TR_MENUS));
1139 for(a=0; a<md->nitems; a++) {
1140 xmax= but->aspect*BIF_GetStringWidth(block->curfont, md->items[a].str, (U.transopts & USER_TR_MENUS));
1141 if(xmax>width) width= xmax;
1145 if (width < (but->x2 - but->x1)) width = (but->x2 - but->x1);
1146 if (width<50) width=50;
1151 if (md->title) height+= boxh;
1153 getmouseco_sc(mval);
1155 /* find active item */
1156 fvalue= ui_get_but_val(but);
1157 for(active=0; active<md->nitems; active++) {
1158 if( md->items[active].retval== (int)fvalue ) break;
1160 /* no active item? */
1161 if(active==md->nitems) {
1162 if(md->title) active= -1;
1166 /* for now disabled... works confusing because you think it's a title or so.... */
1175 uiSetCurFont(block, block->font+1);
1176 if (md->titleicon) {
1177 uiDefIconTextBut(block, LABEL, 0, md->titleicon, md->title, startx, (short)(starty+rows*boxh), (short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
1179 bt= uiDefBut(block, LABEL, 0, md->title, startx, (short)(starty+rows*boxh), (short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
1180 bt->flag= UI_TEXT_LEFT;
1182 uiSetCurFont(block, block->font);
1186 for(a=0; a<md->nitems; a++) {
1188 x1= but->x1 + width*((int)(md->nitems-a-1)/rows);
1189 y1= but->y1 - boxh*(rows - ((md->nitems - a - 1)%rows)) + (rows*boxh);
1191 if (strcmp(md->items[md->nitems-a-1].str, "%l")==0) {
1192 uiDefBut(block, SEPR, B_NOP, "", x1, y1,(short)(width-(rows>1)), (short)(boxh-1), NULL, 0.0, 0.0, 0, 0, "");
1194 else if(md->items[md->nitems-a-1].icon) {
1195 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, "");
1196 if(active==a) bt->flag |= UI_ACTIVE;
1199 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, "");
1200 if(active==a) bt->flag |= UI_ACTIVE;
1204 /* the code up here has flipped locations, because of change of preferred order */
1205 /* thats why we have to switch list order too, to make arrowkeys work */
1207 lb.first= lb.last= NULL;
1208 bt= block->buttons.first;
1210 uiBut *next= bt->next;
1211 BLI_remlink(&block->buttons, bt);
1212 BLI_addhead(&lb, bt);
1218 block->direction= UI_TOP;
1219 ui_positionblock(block, but);
1221 /* blocks can come (and get scaled) from a normal window, now we go to screenspace */
1222 block->win= G.curscreen->mainwin;
1223 for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
1224 bwin_getsinglematrix(block->win, block->winmat);
1226 event= uiDoBlocks(&listb, 0);
1230 but->flag &= ~UI_SELECT;
1232 /* no draw of button now, for floating panels the matrix now is invalid...
1233 the button still is active, and will be redrawn in main loop to de-activate it */
1237 /* return no existing event, because the menu sends events instead */
1241 /* ********************** NEXT/PREV for arrowkeys etc ************** */
1243 static uiBut *ui_but_prev(uiBut *but)
1247 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
1252 static uiBut *ui_but_next(uiBut *but)
1256 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
1261 static uiBut *ui_but_first(uiBlock *block)
1265 but= block->buttons.first;
1267 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
1273 static uiBut *ui_but_last(uiBlock *block)
1277 but= block->buttons.last;
1279 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
1286 /* ************* IN-BUTTON TEXT SELECTION/EDITING ************* */
1288 static short ui_delete_selection_edittext(uiBut *but)
1291 short deletedwidth=0;
1294 str= (char *)but->poin;
1296 deletedwidth = SELWIDTH;
1298 for(x=0; x< strlen(str); x++) {
1299 if (but->selend + x <= strlen(str) ) {
1300 str[but->selsta + x]= str[but->selend + x];
1302 str[but->selsta + x]= '\0';
1306 but->pos = but->selend = but->selsta;
1308 return deletedwidth;
1311 static void ui_set_cursor_pos_edittext(uiBut *but, short sx)
1313 char backstr[UI_MAX_DRAW_STR];
1315 BLI_strncpy(backstr, but->drawstr, UI_MAX_DRAW_STR);
1316 but->pos= strlen(backstr)-but->ofs;
1318 while((but->aspect*BIF_GetStringWidth(but->font, backstr+but->ofs, 0) + but->x1) > sx) {
1319 if (but->pos <= 0) break;
1321 backstr[but->pos+but->ofs] = 0;
1324 but->pos -= strlen(but->str);
1325 but->pos += but->ofs;
1326 if(but->pos<0) but->pos= 0;
1330 /* ************* EVENTS ************* */
1332 void uiGetMouse(int win, short *adr)
1338 if (win == G.curscreen->mainwin) return;
1340 bwin_getsuborigin(win, &x, &y);
1348 ui_window_to_graphics(win, &xwin, &ywin);
1350 adr[0]= (short)(xwin+0.5);
1351 adr[1]= (short)(ywin+0.5);
1354 static void ui_is_but_sel(uiBut *but)
1358 short push=0, true=1;
1360 value= ui_get_but_val(but);
1362 if( but->type==TOGN ) true= 0;
1366 if( BTST(lvalue, (but->bitnr)) ) push= true;
1375 if (value==-1) push= 1;
1381 if(value!=but->min) push= 1;
1384 if(value==0.0) push= 1;
1387 if(value == but->max) push= 1;
1399 else if(push==1) but->flag |= UI_SELECT;
1400 else but->flag &= ~UI_SELECT;
1403 static int ui_do_but_BUT(uiBut *but)
1408 int oflag= but->flag;
1411 uiGetMouse(mywinget(), mval);
1413 if (uibut_contains_pt(but, mval))
1414 but->flag |= UI_SELECT;
1416 but->flag &= ~UI_SELECT;
1418 if (but->flag != oflag) {
1420 ui_block_flush_back(but->block);
1424 } while (get_mbut() & L_MOUSE);
1426 activated= (but->flag & UI_SELECT);
1432 but->flag &= ~UI_SELECT;
1435 return activated?but->retval:0;
1438 static int ui_do_but_KEYEVT(uiBut *but)
1440 unsigned short event= 0;
1443 /* flag for ui_check_but */
1444 ui_set_but_val(but, -1);
1447 ui_block_flush_back(but->block);
1450 event= extern_qread(&val);
1451 } while (!event || !val || ELEM(event, MOUSEX, MOUSEY));
1453 if (!key_event_to_string(event)[0]) event= 0;
1455 ui_set_but_val(but, (double) event);
1462 static int ui_do_but_TOG(uiBlock *block, uiBut *but)
1466 int w, lvalue, push;
1468 value= ui_get_but_val(but);
1472 w= BTST(lvalue, but->bitnr);
1473 if(w) lvalue = BCLR(lvalue, but->bitnr);
1474 else lvalue = BSET(lvalue, but->bitnr);
1476 if(but->type==TOGR) {
1477 if( (get_qual() & LR_SHIFTKEY)==0 ) {
1478 lvalue= 1<<(but->bitnr);
1480 ui_set_but_val(but, (double)lvalue);
1482 bt= block->buttons.first;
1484 if( bt!=but && bt->poin==but->poin ) {
1492 if(lvalue==0) lvalue= 1<<(but->bitnr);
1495 ui_set_but_val(but, (double)lvalue);
1496 if(but->type==ICONTOG) ui_check_but(but);
1497 // no frontbuffer draw for this one
1498 if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
1502 if(value==0.0) push= 1;
1505 if(but->type==TOGN) push= !push;
1506 ui_set_but_val(but, (double)push);
1507 if(but->type==ICONTOG) ui_check_but(but);
1508 // no frontbuffer draw for this one
1509 if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
1512 /* no while loop...this button is used for viewmove */
1519 static int ui_do_but_ROW(uiBlock *block, uiBut *but)
1523 ui_set_but_val(but, but->max);
1526 bt= block->buttons.first;
1528 if( bt!=but && bt->type==ROW ) {
1529 if(bt->min==but->min) {
1539 /* return 1 if char ch is special character otherwise
1541 static short test_special_char(char ch)
1583 static int ui_do_but_TEX(uiBut *but)
1586 short x, mval[2], len=0, dodraw, selextend=0;
1587 char *str, backstr[UI_MAX_DRAW_STR];
1588 short capturing, sx, sy, prevx;
1590 str= (char *)but->poin;
1592 but->flag |= UI_SELECT;
1594 uiGetMouse(mywinget(), mval);
1596 /* set cursor pos to the end of the text */
1597 but->pos = strlen(str);
1599 but->selend = strlen(but->drawstr) - strlen(but->str);
1602 BLI_strncpy(backstr, but->poin, UI_MAX_DRAW_STR);
1605 ui_block_flush_back(but->block);
1607 while (get_mbut() & L_MOUSE) BIF_wait_for_statechange();
1618 dev = extern_qread_ext(&val, &ascii);
1620 if(dev==INPUTCHANGE) break;
1621 else if(get_mbut() & R_MOUSE) break;
1622 else if(get_mbut() & L_MOUSE) {
1623 uiGetMouse(mywinget(), mval);
1624 sx = mval[0]; sy = mval[1];
1626 if ((but->y1 <= sy) && (sy <= but->y2) && (but->x1 <= sx) && (sx <= but->x2)) {
1627 ui_set_cursor_pos_edittext(but, mval[0]);
1629 but->selsta = but->selend = but->pos;
1631 /* drag text select */
1633 while (get_mbut() & L_MOUSE) {
1634 uiGetMouse(mywinget(), mval);
1636 if(prevx!=mval[0]) {
1638 if (mval[0] > sx) selextend = EXTEND_RIGHT;
1639 else if (mval[0] < sx) selextend = EXTEND_LEFT;
1641 ui_set_cursor_pos_edittext(but, mval[0]);
1643 if (selextend == EXTEND_RIGHT) but->selend = but->pos;
1644 if (selextend == EXTEND_LEFT) but->selsta = but->pos;
1648 ui_block_flush_back(but->block);
1655 else if(dev==ESCKEY) break;
1656 else if(dev==MOUSEX) val= 0;
1657 else if(dev==MOUSEY) val= 0;
1660 if(len <= but->max) {
1662 /* type over the current selection */
1664 len -= ui_delete_selection_edittext(but);
1667 /* add ascii characters */
1668 if(len < but->max) {
1669 for(x= but->max; x>but->pos; x--)
1671 str[but->pos]= ascii;
1684 /* if there's a selection */
1686 /* extend the selection based on the first direction taken */
1687 if(G.qual & LR_SHIFTKEY) {
1689 selextend = EXTEND_RIGHT;
1691 if (selextend == EXTEND_RIGHT) {
1693 if (but->selend > len) but->selend = len;
1694 } else if (selextend == EXTEND_LEFT) {
1696 /* if the selection start has gone past the end,
1697 * flip them so they're in sync again */
1698 if (but->selsta == but->selend) {
1699 but->pos = but->selsta;
1700 selextend = EXTEND_RIGHT;
1704 but->selsta = but->pos = but->selend;
1708 if(G.qual & LR_SHIFTKEY) {
1709 /* make a selection, starting from the cursor position */
1710 but->selsta = but->pos;
1713 if(but->pos>strlen(str)) but->pos= strlen(str);
1715 but->selend = but->pos;
1716 } else if(G.qual & LR_CTRLKEY) {
1717 /* jump betweenn special characters (/,\,_,-, etc.),
1718 * look at function test_special_char() for complete
1719 * list of special character, ctr -> */
1720 while(but->pos < len) {
1722 if(test_special_char(str[but->pos])) break;
1726 if(but->pos>strlen(str)) but->pos= strlen(str);
1733 /* if there's a selection */
1735 /* extend the selection based on the first direction taken */
1736 if(G.qual & LR_SHIFTKEY) {
1738 selextend = EXTEND_LEFT;
1740 if (selextend == EXTEND_LEFT) {
1742 if (but->selsta < 0) but->selsta = 0;
1743 } else if (selextend == EXTEND_RIGHT) {
1745 /* if the selection start has gone past the end,
1746 * flip them so they're in sync again */
1747 if (but->selsta == but->selend) {
1748 but->pos = but->selsta;
1749 selextend = EXTEND_LEFT;
1753 but->pos = but->selend = but->selsta;
1757 if(G.qual & LR_SHIFTKEY) {
1758 /* make a selection, starting from the cursor position */
1759 but->selend = but->pos;
1762 if(but->pos<0) but->pos= 0;
1764 but->selsta = but->pos;
1765 } else if(G.qual & LR_CTRLKEY) {
1766 /* jump betweenn special characters (/,\,_,-, etc.),
1767 * look at function test_special_char() for complete
1768 * list of special character, ctr -> */
1769 while(but->pos > 0){
1771 if(test_special_char(str[but->pos])) break;
1774 if(but->pos>0) but->pos--;
1782 if(G.qual & LR_SHIFTKEY) {
1783 but->selsta = but->pos;
1784 but->selend = strlen(str);
1785 selextend = EXTEND_RIGHT;
1787 but->selsta = but->selend = but->pos= strlen(str);
1794 if(G.qual & LR_SHIFTKEY) {
1795 but->selend = but->pos;
1797 selextend = EXTEND_LEFT;
1799 but->selsta = but->selend = but->pos= 0;
1811 len -= ui_delete_selection_edittext(but);
1813 if (len < 0) len = 0;
1816 else if(but->pos>=0 && but->pos<strlen(str)) {
1817 for(x=but->pos; x<=strlen(str); x++)
1827 len -= ui_delete_selection_edittext(but);
1829 if (len < 0) len = 0;
1832 else if(get_qual() & LR_SHIFTKEY) {
1838 else if(but->pos>0) {
1839 for(x=but->pos; x<=strlen(str); x++)
1849 if(but->autocomplete_func) {
1850 but->autocomplete_func(str, but->autofunc_arg);
1851 but->pos= strlen(str);
1855 else capturing= FALSE;
1865 ui_block_flush_back(but->block);
1869 if(dev==ESCKEY) strcpy(but->poin, backstr);
1871 but->flag &= ~UI_SELECT;
1874 /* give butfunc the original text too */
1875 /* feature used for bone renaming, channels, etc */
1876 if(but->func_arg2==NULL) but->func_arg2= backstr;
1883 if(dev==TABKEY) addqueue(but->win, G.qual?BUT_PREV:BUT_NEXT, 1);
1885 if(dev!=ESCKEY) return but->retval;
1886 else return B_NOP; // prevent event to be passed on
1890 static int ui_act_as_text_but(uiBut *but)
1895 int temp, retval, textleft;
1896 char str[UI_MAX_DRAW_STR], *point;
1898 /* this function is abused for tab-cycling */
1900 return ui_do_but_TEX(but);
1902 value= ui_get_but_val(but);
1903 if( but->pointype==FLO ) {
1904 if(but->a2) { /* amount of digits defined */
1905 if(but->a2==1) sprintf(str, "%.1f", value);
1906 else if(but->a2==2) sprintf(str, "%.2f", value);
1907 else if(but->a2==3) sprintf(str, "%.3f", value);
1908 else sprintf(str, "%.4f", value);
1910 else sprintf(str, "%.3f", value);
1913 sprintf(str, "%d", (int)value);
1915 /* store values before calling as text button */
1918 but_func= but->func;
1926 textleft= but->flag & UI_TEXT_LEFT;
1927 but->flag |= UI_TEXT_LEFT;
1930 retval= ui_do_but_TEX(but);
1932 /* restore values */
1935 but->func= but_func;
1938 if(textleft==0) but->flag &= ~UI_TEXT_LEFT;
1940 if( but->pointype==FLO ) value= atof(str);
1941 else value= atoi(str);
1943 if(value<min) value= min;
1944 if(value>max) value= max;
1946 ui_set_but_val(but, value);
1953 static int ui_do_but_NUM(uiBut *but)
1956 float deler, fstart, f, tempf;
1957 int lvalue, temp; /* , firsttime=1; */
1958 short retval=0, qual, sx, mval[2], pos=0;
1960 but->flag |= UI_SELECT;
1962 ui_block_flush_back(but->block);
1964 uiGetMouse(mywinget(), mval);
1965 value= ui_get_but_val(but);
1968 fstart= (value - but->min)/(but->max-but->min);
1974 if(get_qual() & LR_SHIFTKEY) { /* make it textbut */
1975 if( ui_act_as_text_but(but) ) retval= but->retval;
1978 retval= but->retval;
1979 /* firsttime: this button can be approached with enter as well */
1980 while (get_mbut() & L_MOUSE) {
1984 if( but->pointype!=FLO ) {
1986 if( (but->max-but->min)<100 ) deler= 200.0;
1987 if( (but->max-but->min)<25 ) deler= 50.0;
1990 if(qual & LR_SHIFTKEY) deler*= 10.0;
1991 if(qual & LR_ALTKEY) deler*= 20.0;
1993 uiGetMouse(mywinget(), mval);
1997 f+= ((float)(mval[0]-sx))/deler;
2001 tempf= ( but->min + f*(but->max-but->min));
2003 if( but->pointype!=FLO ) {
2005 temp= floor(tempf+.5);
2007 if(tempf==but->min || tempf==but->max);
2008 else if(qual & LR_CTRLKEY) {
2009 if(qual & LR_SHIFTKEY) temp= 100*(temp/100);
2010 else temp= 10*(temp/10);
2012 if( temp>=but->min && temp<=but->max) {
2014 value= ui_get_but_val(but);
2017 if(temp != lvalue ) {
2019 ui_set_but_val(but, (double)temp);
2022 ui_block_flush_back(but->block);
2031 if(qual & LR_CTRLKEY) {
2032 if(qual & LR_SHIFTKEY) {
2033 if(tempf==but->min || tempf==but->max);
2034 else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
2035 else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
2036 else tempf= floor(tempf);
2039 if(tempf==but->min || tempf==but->max);
2040 else if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
2041 else if(but->max-but->min < 21.0) tempf= floor(tempf);
2042 else tempf= 10.0*floor(tempf/10.0);
2046 if( tempf>=but->min && tempf<=but->max) {
2047 value= ui_get_but_val(but);
2049 if(tempf != value ) {
2051 ui_set_but_val(but, tempf);
2054 ui_block_flush_back(but->block);
2060 BIF_wait_for_statechange();
2063 /* click on the side arrows to increment/decrement, click inside
2064 * to edit the value directly */
2065 if(pos==0) { /* plus 1 or minus 1 */
2066 if( but->pointype!=FLO ) {
2068 if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
2070 if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
2072 else if(sx > (but->x1 + (2*(but->x2 - but->x1)/3) + 3)) {
2074 if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
2077 if( ui_act_as_text_but(but) ); else retval= 0;
2082 if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
2083 tempf-= 0.01*but->a1;
2084 if (tempf < but->min) tempf = but->min;
2085 ui_set_but_val(but, tempf);
2087 else if(sx > but->x1 + (2*((but->x2 - but->x1)/3) + 3)) {
2088 tempf+= 0.01*but->a1;
2089 if (tempf < but->min) tempf = but->min;
2090 ui_set_but_val(but, tempf);
2093 if( ui_act_as_text_but(but) ); else retval= 0;
2099 but->flag &= ~UI_SELECT;
2102 ui_block_flush_back(but->block);
2109 static int ui_do_but_TOG3(uiBut *but)
2112 if( but->pointype==SHO ) {
2113 short *sp= (short *)but->poin;
2115 if( BTST(sp[1], but->bitnr)) {
2116 sp[1]= BCLR(sp[1], but->bitnr);
2117 sp[0]= BCLR(sp[0], but->bitnr);
2119 else if( BTST(sp[0], but->bitnr)) {
2120 sp[1]= BSET(sp[1], but->bitnr);
2122 sp[0]= BSET(sp[0], but->bitnr);
2126 if( BTST(*(but->poin+2), but->bitnr)) {
2127 *(but->poin+2)= BCLR(*(but->poin+2), but->bitnr);
2128 *(but->poin)= BCLR(*(but->poin), but->bitnr);
2130 else if( BTST(*(but->poin), but->bitnr)) {
2131 *(but->poin+2)= BSET(*(but->poin+2), but->bitnr);
2133 *(but->poin)= BSET(*(but->poin), but->bitnr);
2143 static int ui_do_but_ICONROW(uiBut *but)
2145 ListBase listb= {NULL, NULL};
2149 but->flag |= UI_SELECT;
2151 ui_block_flush_back(but->block); // flush because this button creates own blocks loop
2154 block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
2155 block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
2156 block->themecol= TH_MENU_ITEM;
2158 for(a=(int)but->min; a<=(int)but->max; a++) {
2159 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, "");
2161 block->direction= UI_TOP;
2162 ui_positionblock(block, but);
2164 /* the block is made with but-win, but is handled in mainwin space...
2165 this is needs better implementation */
2166 block->win= G.curscreen->mainwin;
2168 uiDoBlocks(&listb, 0);
2170 but->flag &= ~UI_SELECT;
2177 static int ui_do_but_ICONTEXTROW(uiBut *but)
2180 ListBase listb={NULL, NULL};
2181 int width, a, xmax, ypos;
2184 but->flag |= UI_SELECT;
2186 ui_block_flush_back(but->block); // flush because this button creates own blocks loop
2188 block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
2189 block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
2190 block->themecol= TH_MENU_ITEM;
2192 md= decompose_menu_string(but->str);
2194 /* size and location */
2195 /* expand menu width to fit labels */
2197 width= 2*strlen(md->title)+BIF_GetStringWidth(block->curfont, md->title, (U.transopts & USER_TR_MENUS));
2201 for(a=0; a<md->nitems; a++) {
2202 xmax= BIF_GetStringWidth(block->curfont, md->items[a].str, (U.transopts & USER_TR_MENUS));
2203 if(xmax>width) width= xmax;
2207 if (width<50) width=50;
2211 /* loop through the menu options and draw them out with icons & text labels */
2212 for(a=0; a<md->nitems; a++) {
2214 /* add a space if there's a separator (%l) */
2215 if (strcmp(md->items[a].str, "%l")==0) {
2219 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, "");
2226 uiSetCurFont(block, block->font+1);
2227 bt= uiDefBut(block, LABEL, 0, md->title, 0, ypos, (short)width, 19, NULL, 0.0, 0.0, 0, 0, "");
2228 uiSetCurFont(block, block->font);
2229 bt->flag= UI_TEXT_LEFT;
2232 block->direction= UI_TOP;
2233 ui_positionblock(block, but);
2235 /* the block is made with but-win, but is handled in mainwin space...
2236 this is needs better implementation */
2237 block->win= G.curscreen->mainwin;
2239 uiBoundsBlock(block, 3);
2241 uiDoBlocks(&listb, 0);
2245 but->flag &= ~UI_SELECT;
2255 static int ui_do_but_IDPOIN(uiBut *but)
2257 char str[UI_MAX_DRAW_STR];
2260 id= *but->idpoin_idpp;
2261 if(id) strcpy(str, id->name+2);
2273 but->idpoin_func(str, but->idpoin_idpp);
2280 static int ui_do_but_SLI(uiBut *but)
2282 float f, fstart, tempf = 0.0, deler, value;
2283 int sx, h, temp, pos=0, lvalue, redraw;
2284 short mval[2], qual;
2285 float curmatrix[4][4];
2287 value= ui_get_but_val(but);
2288 uiGetMouse(mywinget(), mval);
2292 fstart= but->max-but->min;
2293 fstart= (value - but->min)/fstart;
2296 if( but->type==NUMSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
2297 else if( but->type==HSVSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
2298 else deler= (but->x2-but->x1- 5.0*but->aspect);
2301 while (get_mbut() & L_MOUSE) {
2304 uiGetMouse(mywinget(), mval);
2306 f= (float)(mval[0]-sx)/deler +fstart;
2308 if (qual & LR_SHIFTKEY) {
2309 f= (f-fstart)/10.0 + fstart;
2313 tempf= but->min+f*(but->max-but->min);
2314 temp= floor(tempf+.5);
2316 if(qual & LR_CTRLKEY) {
2317 if(tempf==but->min || tempf==but->max);
2318 else if( but->pointype==FLO ) {
2320 if(qual & LR_SHIFTKEY) {
2321 if(tempf==but->min || tempf==but->max);
2322 else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
2323 else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
2324 else tempf= floor(tempf);
2327 if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
2328 else if(but->max-but->min < 21.0) tempf= floor(tempf);
2329 else tempf= 10.0*floor(tempf/10.0);
2338 value= ui_get_but_val(but);
2339 lvalue= floor(value+0.5);
2341 if( but->pointype!=FLO )
2342 redraw= (temp != lvalue);
2344 redraw= (tempf != value);
2348 ui_set_but_val(but, tempf);
2351 ui_block_flush_back(but->block);
2353 if(but->a1) { /* color number */
2354 uiBut *bt= but->prev;
2356 if(bt->a2 == but->a1) ui_draw_but(bt);
2361 if(bt->a2 == but->a1) ui_draw_but(bt);
2365 /* save current window matrix (global UIwinmat)
2366 because button callback function MIGHT change it
2367 - which has until now occured through the Python API
2369 Mat4CpyMat4(curmatrix, UIwinmat);
2371 Mat4CpyMat4(UIwinmat, curmatrix);
2373 else BIF_wait_for_statechange();
2377 if(temp!=32767 && pos==0) { /* plus 1 or minus 1 */
2379 if( but->type==SLI) f= (float)(mval[0]-but->x1)/(but->x2-but->x1-h);
2380 else f= (float)(mval[0]- (but->x1+but->x2)/2)/( (but->x2-but->x1)/2 - h);
2382 f= but->min+f*(but->max-but->min);
2384 if( but->pointype!=FLO ) {
2388 if( temp>=but->min && temp<=but->max)
2389 ui_set_but_val(but, (float)temp);
2394 if(f<tempf) tempf-=.01;
2396 if( tempf>=but->min && tempf<=but->max)
2397 ui_set_but_val(but, tempf);
2404 ui_block_flush_back(but->block);
2409 static int ui_do_but_NUMSLI(uiBut *but)
2413 /* first define if it's a slider or textbut */
2414 uiGetMouse(mywinget(), mval);
2416 if(mval[0]>= -6+(but->x1+but->x2)/2 ) { /* slider */
2417 but->flag |= UI_SELECT;
2420 but->flag &= ~UI_SELECT;
2423 ui_act_as_text_but(but);
2424 uibut_do_func(but); // this is done in ui_do_but_SLI() not in ui_act_as_text_but()
2427 while(get_mbut() & L_MOUSE) BIF_wait_for_statechange();
2432 if(but->type==HSVSLI) {
2434 if(but->str[0]=='H') {
2435 ui_draw_but(but->next);
2436 ui_draw_but(but->next->next);
2438 else if(but->str[0]=='S') {
2439 ui_draw_but(but->next);
2440 ui_draw_but(but->prev);
2442 else if(but->str[0]=='V') {
2443 ui_draw_but(but->prev);
2444 ui_draw_but(but->prev->prev);
2451 /* event denotes if we make first item active or not */
2452 static int ui_do_but_BLOCK(uiBut *but, int event)
2457 but->flag |= UI_SELECT;
2460 block= but->block_func(but->poin);
2461 block->parent= but->block; /* allows checking for nested pulldowns */
2463 block->xofs = -2; /* for proper alignment */
2465 /* only used for automatic toolbox, so can set the shift flag */
2466 if(but->flag & UI_MAKE_TOP) {
2467 block->direction= UI_TOP|UI_SHIFT_FLIPPED;
2468 uiBlockFlipOrder(block);
2470 if(but->flag & UI_MAKE_DOWN) block->direction= UI_DOWN|UI_SHIFT_FLIPPED;
2471 if(but->flag & UI_MAKE_LEFT) block->direction |= UI_LEFT;
2472 if(but->flag & UI_MAKE_RIGHT) block->direction |= UI_RIGHT;
2474 ui_positionblock(block, but);
2475 block->flag |= UI_BLOCK_LOOP;
2477 /* blocks can come (and get scaled) from a normal window, now we go to screenspace */
2478 block->win= G.curscreen->mainwin;
2479 for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
2480 bwin_getsinglematrix(block->win, block->winmat);
2482 /* postpone draw, this will cause a new window matrix, first finish all other buttons */
2483 block->flag |= UI_BLOCK_REDRAW;
2485 if(event!=MOUSEX && event!=MOUSEY && event!=LEFTMOUSE && but->type==BLOCK) {
2486 bt= ui_but_first(block);
2487 if(bt) bt->flag |= UI_ACTIVE;
2490 but->flag &= ~UI_SELECT;
2496 static int ui_do_but_BUTM(uiBut *but)
2499 ui_set_but_val(but, but->min);
2500 UIafterfunc= but->butm_func;
2501 UIafterfunc_arg= but->butm_func_arg;
2502 UIafterval= but->a2;
2507 static int ui_do_but_LABEL(uiBut *but)
2514 static uiBut *ui_get_valid_link_button(uiBlock *block, uiBut *but, short *mval)
2518 /* find button to link to */
2519 for (bt= block->buttons.first; bt; bt= bt->next)
2520 if(bt!=but && uibut_contains_pt(bt, mval))
2524 if (but->type==LINK && bt->type==INLINK) {
2525 if( but->link->tocode == (int)bt->min ) {
2529 else if(but->type==INLINK && bt->type==LINK) {
2530 if( bt->link->tocode == (int)but->min ) {
2539 static int ui_is_a_link(uiBut *from, uiBut *to)
2546 line= link->lines.first;
2548 if(line->from==from && line->to==to) return 1;
2555 static uiBut *ui_find_inlink(uiBlock *block, void *poin)
2559 but= block->buttons.first;
2561 if(but->type==INLINK) {
2562 if(but->poin == poin) return but;
2569 static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt)
2573 line= MEM_callocN(sizeof(uiLinkLine), "linkline");
2574 BLI_addtail(listb, line);
2580 void uiComposeLinks(uiBlock *block)
2587 but= block->buttons.first;
2589 if(but->type==LINK) {
2592 /* for all pointers in the array */
2596 for(a=0; a < *(link->totlink); a++) {
2597 bt= ui_find_inlink(block, (*ppoin)[a] );
2599 ui_add_link_line(&link->lines, but, bt);
2603 else if(link->poin) {
2604 bt= ui_find_inlink(block, *(link->poin) );
2606 ui_add_link_line(&link->lines, but, bt);
2615 static void ui_add_link(uiBut *from, uiBut *to)
2617 /* in 'from' we have to add a link to 'to' */
2622 if(ui_is_a_link(from, to)) {
2623 printf("already exists\n");
2629 /* are there more pointers allowed? */
2631 oldppoin= *(link->ppoin);
2633 (*(link->totlink))++;
2634 *(link->ppoin)= MEM_callocN( *(link->totlink)*sizeof(void *), "new link");
2636 for(a=0; a< (*(link->totlink))-1; a++) {
2637 (*(link->ppoin))[a]= oldppoin[a];
2639 (*(link->ppoin))[a]= to->poin;
2641 if(oldppoin) MEM_freeN(oldppoin);
2644 *(link->poin)= to->poin;
2649 static int ui_do_but_LINK(uiBlock *block, uiBut *but)
2652 * This button only visualizes, the dobutton mode
2653 * can add a new link, but then the whole system
2654 * should be redrawn/initialized.
2657 uiBut *bt=0, *bto=NULL;
2658 short sval[2], mval[2], mvalo[2], first= 1;
2660 uiGetMouse(curarea->win, sval);
2664 while (get_mbut() & L_MOUSE) {
2665 uiGetMouse(curarea->win, mval);
2667 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || first) {
2668 /* clear completely, because of drawbuttons */
2669 bt= ui_get_valid_link_button(block, but, mval);
2671 bt->flag |= UI_ACTIVE;
2674 if(bto && bto!=bt) {
2675 bto->flag &= ~UI_ACTIVE;
2681 glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
2683 glutil_draw_front_xor_line(sval[0], sval[1], mval[0], mval[1]);
2690 else BIF_wait_for_statechange();
2694 glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
2698 if(but->type==LINK) ui_add_link(but, bt);
2699 else ui_add_link(bt, but);
2701 scrarea_queue_winredraw(curarea);
2707 /* picker sizes S hsize, F full size, D spacer, B button/pallette height */
2713 #define UI_PALETTE_TOT 16
2714 /* note; in tot+1 the old color is stored */
2715 static float palette[UI_PALETTE_TOT+1][3]= {
2716 {0.93, 0.83, 0.81}, {0.88, 0.89, 0.73}, {0.69, 0.81, 0.57}, {0.51, 0.76, 0.64},
2717 {0.37, 0.56, 0.61}, {0.33, 0.29, 0.55}, {0.46, 0.21, 0.51}, {0.40, 0.12, 0.18},
2718 {1.0, 1.0, 1.0}, {0.85, 0.85, 0.85}, {0.7, 0.7, 0.7}, {0.56, 0.56, 0.56},
2719 {0.42, 0.42, 0.42}, {0.28, 0.28, 0.28}, {0.14, 0.14, 0.14}, {0.0, 0.0, 0.0}
2722 /* for picker, while editing hsv */
2723 static void ui_set_but_hsv(uiBut *but)
2727 hsv_to_rgb(but->hsv[0], but->hsv[1], but->hsv[2], col, col+1, col+2);
2728 ui_set_but_vectorf(but, col);
2731 static void update_picker_hex(uiBlock *block, float *rgb)
2736 sprintf(col, "%02X%02X%02X", (unsigned int)(rgb[0]*255.0), (unsigned int)(rgb[1]*255.0), (unsigned int)(rgb[2]*255.0));
2738 // this updates button strings, is hackish... but button pointers are on stack of caller function
2740 for(bt= block->buttons.first; bt; bt= bt->next) {
2741 if(strcmp(bt->str, "Hex: ")==0) {
2742 strcpy(bt->poin, col);
2749 static void update_picker_buts_hsv(uiBlock *block, float *hsv)
2755 // this updates button strings, is hackish... but button pointers are on stack of caller function
2756 hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r, &g, &b);
2758 rgb[0] = r; rgb[1] = g; rgb[2] = b;
2759 update_picker_hex(block, rgb);
2761 for(bt= block->buttons.first; bt; bt= bt->next) {
2762 if(bt->type==HSVCUBE) {
2763 VECCOPY(bt->hsv, hsv);
2766 else if(bt->str[1]==' ') {
2767 if(bt->str[0]=='R') {
2768 ui_set_but_val(bt, r);
2771 else if(bt->str[0]=='G') {
2772 ui_set_but_val(bt, g);
2775 else if(bt->str[0]=='B') {
2776 ui_set_but_val(bt, b);
2779 else if(bt->str[0]=='H') {
2780 ui_set_but_val(bt, hsv[0]);
2783 else if(bt->str[0]=='S') {
2784 ui_set_but_val(bt, hsv[1]);
2787 else if(bt->str[0]=='V') {
2788 ui_set_but_val(bt, hsv[2]);
2795 static void update_picker_buts_hex(uiBlock *block, char *hexcol)
2798 float r=0, g=0, b=0;
2802 // this updates button strings, is hackish... but button pointers are on stack of caller function
2803 hex_to_rgb(hexcol, &r, &g, &b);
2804 rgb_to_hsv(r, g, b, &h, &s, &v);
2806 for(bt= block->buttons.first; bt; bt= bt->next) {
2807 if(bt->type==HSVCUBE) {
2813 else if(bt->str[1]==' ') {
2814 if(bt->str[0]=='R') {
2815 ui_set_but_val(bt, r);
2818 else if(bt->str[0]=='G') {
2819 ui_set_but_val(bt, g);
2822 else if(bt->str[0]=='B') {
2823 ui_set_but_val(bt, b);
2826 else if(bt->str[0]=='H') {
2827 ui_set_but_val(bt, h);
2830 else if(bt->str[0]=='S') {
2831 ui_set_but_val(bt, s);
2834 else if(bt->str[0]=='V') {
2835 ui_set_but_val(bt, v);
2844 /* bt1 is palette but, col1 is original color */
2845 /* callback to copy from/to palette */
2846 static void do_palette_cb(void *bt1, void *col1)
2848 uiBut *but1= (uiBut *)bt1;
2850 float *col= (float *)col1;
2853 fp= (float *)but1->poin;
2855 if( (get_qual() & LR_CTRLKEY) ) {
2862 rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
2863 update_picker_buts_hsv(but1->block, hsv);
2864 update_picker_hex(but1->block, col);
2866 for (but= but1->block->buttons.first; but; but= but->next) {
2869 but= but1->block->buttons.first;
2870 ui_block_flush_back(but->block);
2873 /* bt1 is num but, col1 is pointer to original color */
2874 /* callback to handle changes in num-buts in picker */
2875 static void do_palette1_cb(void *bt1, void *hsv1)
2877 uiBut *but1= (uiBut *)bt1;
2879 float *hsv= (float *)hsv1;
2882 if(but1->str[0]=='R') fp= (float *)but1->poin;
2883 else if(but1->str[0]=='G') fp= ((float *)but1->poin)-1;
2884 else if(but1->str[0]=='B') fp= ((float *)but1->poin)-2;
2887 rgb_to_hsv(fp[0], fp[1], fp[2], hsv, hsv+1, hsv+2);
2890 update_picker_buts_hsv(but1->block, hsv);
2891 if (fp) update_picker_hex(but1->block, fp);
2893 for (but= but1->block->buttons.first; but; but= but->next) {
2897 but= but1->block->buttons.first;
2898 ui_block_flush_back(but->block);
2902 static void do_palette_hex_cb(void *bt1, void *hexcl)
2904 uiBut *but1= (uiBut *)bt1;
2906 char *hexcol= (char *)hexcl;
2908 update_picker_buts_hex(but1->block, hexcol);
2910 for (but= but1->block->buttons.first; but; but= but->next) {
2914 but= but1->block->buttons.first;
2915 ui_block_flush_back(but->block);
2919 /* color picker, Gimp version. mode: 'f' = floating panel, 'p' = popup */
2920 /* col = read/write to, hsv/old/hexcol = memory for temporal use */
2921 void uiBlockPickerButtons(uiBlock *block, float *col, float *hsv, float *old, char *hexcol, char mode, short retval)
2927 VECCOPY(old, col); // old color stored there, for palette_cb to work
2929 // the cube intersection
2930 bt= uiDefButF(block, HSVCUBE, retval, "", 0,DPICK+BPICK,FPICK,FPICK, col, 0.0, 0.0, 2, 0, "");
2931 uiButSetFlag(bt, UI_NO_HILITE);
2933 bt= uiDefButF(block, HSVCUBE, retval, "", 0,0,FPICK,BPICK, col, 0.0, 0.0, 3, 0, "");
2934 uiButSetFlag(bt, UI_NO_HILITE);
2938 uiBlockSetEmboss(block, UI_EMBOSSP);
2940 bt=uiDefButF(block, COL, retval, "", FPICK+DPICK, 0, BPICK,BPICK, old, 0.0, 0.0, -1, 0, "Old color, click to restore");
2941 uiButSetFunc(bt, do_palette_cb, bt, col);
2942 uiDefButF(block, COL, retval, "", FPICK+DPICK, BPICK+DPICK, BPICK,60-BPICK-DPICK, col, 0.0, 0.0, -1, 0, "Active color");
2944 h= (DPICK+BPICK+FPICK-64)/(UI_PALETTE_TOT/2.0);
2945 uiBlockBeginAlign(block);
2946 for(a= -1+UI_PALETTE_TOT/2; a>=0; a--) {
2947 bt= uiDefButF(block, COL, retval, "", FPICK+DPICK, 65.0+(float)a*h, BPICK/2, h, palette[a+UI_PALETTE_TOT/2], 0.0, 0.0, -1, 0, "Click to choose, hold CTRL to store in palette");
2948 uiButSetFunc(bt, do_palette_cb, bt, col);
2949 bt= uiDefButF(block, COL, retval, "", FPICK+DPICK+BPICK/2, 65.0+(float)a*h, BPICK/2, h, palette[a], 0.0, 0.0, -1, 0, "Click to choose, hold CTRL to store in palette");
2950 uiButSetFunc(bt, do_palette_cb, bt, col);
2952 uiBlockEndAlign(block);
2954 uiBlockSetEmboss(block, UI_EMBOSS);
2957 rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
2958 sprintf(hexcol, "%02X%02X%02X", (unsigned int)(col[0]*255.0), (unsigned int)(col[1]*255.0), (unsigned int)(col[2]*255.0));
2960 offs= FPICK+2*DPICK+BPICK;
2962 bt= uiDefBut(block, TEX, retval, "Hex: ", offs, 140, 140, 20, hexcol, 0, 8, 0, 0, "Hex triplet for colour (#RRGGBB)");
2963 uiButSetFunc(bt, do_palette_hex_cb, bt, hexcol);
2965 uiBlockBeginAlign(block);
2966 bt= uiDefButF(block, NUMSLI, retval, "R ", offs, 110, 140,20, col, 0.0, 1.0, 10, 2, "");
2967 uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2968 bt= uiDefButF(block, NUMSLI, retval, "G ", offs, 90, 140,20, col+1, 0.0, 1.0, 10, 2, "");
2969 uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2970 bt= uiDefButF(block, NUMSLI, retval, "B ", offs, 70, 140,20, col+2, 0.0, 1.0, 10, 2, "");
2971 uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2973 uiBlockBeginAlign(block);
2974 bt= uiDefButF(block, NUMSLI, retval, "H ", offs, 40, 140,20, hsv, 0.0, 1.0, 10, 2, "");
2975 uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2976 bt= uiDefButF(block, NUMSLI, retval, "S ", offs, 20, 140,20, hsv+1, 0.0, 1.0, 10, 2, "");
2977 uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2978 bt= uiDefButF(block, NUMSLI, retval, "V ", offs, 0, 140,20, hsv+2, 0.0, 1.0, 10, 2, "");
2979 uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2980 uiBlockEndAlign(block);
2984 static int ui_do_but_COL(uiBut *but)
2988 ListBase listb={NULL, NULL};
2989 float hsv[3], old[3], *poin= NULL, colstore[3];
2990 static char hexcol[128];
2993 // signal to prevent calling up color picker
2999 // enable char button too, use temporal colstore for color
3000 if(but->pointype!=FLO) {
3001 if(but->pointype==CHA) {
3002 ui_get_but_vectorf(but, colstore);
3005 else return but->retval;
3007 else poin= (float *)but->poin;
3009 block= uiNewBlock(&listb, "colorpicker", UI_EMBOSS, UI_HELV, but->win);
3010 block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW;
3011 block->themecol= TH_BUT_NUM;
3013 uiBlockPickerButtons(block, poin, hsv, old, hexcol, 'p', 0);
3016 block->direction= UI_TOP;
3017 ui_positionblock(block, but);
3018 uiBoundsBlock(block, 3);
3020 /* blocks can come from a normal window, but we go to screenspace */
3021 block->win= G.curscreen->mainwin;
3022 for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
3023 bwin_getsinglematrix(block->win, block->winmat);
3025 event= uiDoBlocks(&listb, 0);
3027 if(but->pointype==CHA) ui_set_but_vectorf(but, colstore);
3033 static int ui_do_but_HSVCUBE(uiBut *but)
3037 short mval[2], mvalo[2];
3039 mvalo[0]= mvalo[1]= -32000;
3041 /* we work on persistant hsv, to prevent it being converted back and forth all the time */
3043 while (get_mbut() & L_MOUSE) {
3045 uiGetMouse(mywinget(), mval);
3047 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
3051 /* relative position within box */
3052 x= ((float)mval[0]-but->x1)/(but->x2-but->x1);
3053 y= ((float)mval[1]-but->y1)/(but->y2-but->y1);
3060 // hsv_to_rgb(x, s, y, col, col+1, col+2);
3062 else if(but->a1==1) {
3065 // hsv_to_rgb(x, y, v, col, col+1, col+2);
3067 else if(but->a1==2) {
3070 // hsv_to_rgb(h, y, x, col, col+1, col+2);
3074 // hsv_to_rgb(x, s, v, col, col+1, col+2);
3077 ui_set_but_hsv(but); // converts to rgb
3079 // update button values and strings
3080 update_picker_buts_hsv(but->block, but->hsv);
3081 // update_picker_buts_hex(but->block, but->hsv);
3083 /* we redraw the entire block */
3084 for (bt= but->block->buttons.first; bt; bt= bt->next) {
3085 if(but->poin == bt->poin) VECCOPY(bt->hsv, but->hsv);
3088 ui_block_flush_back(but->block);
3090 else BIF_wait_for_statechange();
3096 #ifdef INTERNATIONAL
3098 static int ui_do_but_CHARTAB(uiBut *but)
3102 float sx, sy, ex, ey;
3103 float width, height;
3107 /* Check the position */
3108 uiGetMouse(mywinget(), mval);
3110 /* Calculate the size of the button */
3111 width = abs(but->x2 - but->x1);
3112 height = abs(but->y2 - but->y1);
3114 butw = floor(width / 12);
3115 buth = floor(height / 6);
3117 /* Initialize variables */
3119 ex = but->x1 + butw;
3120 sy = but->y1 + height - buth;
3121 ey = but->y1 + height;
3125 /* And the character is */
3126 x = (int) ((mval[0] / butw) - 0.5);
3127 y = (int) (6 - ((mval[1] / buth) - 0.5));
3129 che = cs + (y*12) + x;
3136 do_textedit(0,0,che);
3145 /* ************************************************ */
3147 void uiSetButLock(int val, char *lockstr)
3150 if (val) UIlockstr= lockstr;
3153 void uiClearButLock()
3159 /* *************************************************************** */
3161 static void setup_file(uiBlock *block)
3166 fp= fopen("butsetup","w");
3169 but= block->buttons.first;
3172 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);
3180 static void edit_but(uiBlock *block, uiBut *but, uiEvent *uevent)
3182 short dx, dy, mval[2], mvalo[2], didit=0;
3184 getmouseco_sc(mvalo);
3186 if( !(get_mbut() & L_MOUSE) ) break;
3188 getmouseco_sc(mval);
3189 dx= (mval[0]-mvalo[0]);
3190 dy= (mval[1]-mvalo[1]);
3192 if(dx!=0 || dy!=0) {
3197 glRectf(but->x1-2, but->y1-2, but->x2+2, but->y2+2);
3199 if((uevent->qual & LR_SHIFTKEY)==0) {
3207 ui_block_flush_back(but->block);
3211 /* idle for this poor code */
3212 else PIL_sleep_ms(30);
3214 if(didit) setup_file(block);
3218 /* is called when LEFTMOUSE is pressed or released
3219 * return: butval or zero
3221 static int ui_do_button(uiBlock *block, uiBut *but, uiEvent *uevent)
3227 error("%s", but->lockstr);
3232 if( but->pointype ) { /* there's a pointer needed */
3234 printf("DoButton pointer error: %s\n",but->str);
3240 if(G.rt==1 && (uevent->qual & LR_CTRLKEY)) {
3241 edit_but(block, but, uevent);
3245 block->flag |= UI_BLOCK_BUSY;
3249 if(uevent->val) retval= ui_do_but_BUT(but);