Tuesday merger of bf-blender into orange branch.
[blender-staging.git] / source / blender / src / interface.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
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
12  * about this.
13  *
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.
18  *
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.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 /* 
34      a full doc with API notes can be found in bf-blender/blender/doc/interface_API.txt
35
36  */
37  
38
39 #include <math.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <ctype.h>
43
44 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif
47
48 #ifndef WIN32
49 #include <unistd.h>
50 #else
51 #include <io.h>
52 #endif   
53
54 #include "MEM_guardedalloc.h"
55
56 #include "PIL_time.h"
57
58 #include "BMF_Api.h"
59 #include "BIF_language.h"
60 #ifdef INTERNATIONAL
61 #include "FTF_Api.h"
62 #endif // INTERNATIONAL
63
64 #include "BLI_blenlib.h"
65 #include "BLI_arithb.h"
66
67 #include "DNA_color_types.h"
68 #include "DNA_screen_types.h"
69 #include "DNA_space_types.h"
70 #include "DNA_userdef_types.h"
71 #include "DNA_vec_types.h"
72 #include "DNA_object_types.h"
73 #include "DNA_texture_types.h"
74 #include "DNA_vfont_types.h"
75
76 #include "BKE_blender.h"
77 #include "BKE_colortools.h"
78 #include "BKE_global.h"
79 #include "BKE_library.h"
80 #include "BKE_texture.h"
81 #include "BKE_utildefines.h"
82
83 #include "BIF_gl.h"
84 #include "BIF_graphics.h"
85 #include "BIF_keyval.h"
86 #include "BIF_mainqueue.h"
87 #include "BIF_resources.h"
88 #include "BIF_screen.h"
89 #include "BIF_toolbox.h"
90 #include "BIF_mywindow.h"
91 #include "BIF_space.h"
92 #include "BIF_glutil.h"
93 #include "BIF_editfont.h"
94 #include "BIF_interface.h"
95 #include "BIF_interface_icons.h"
96 #include "BIF_butspace.h"
97
98
99 #include "BSE_view.h"
100
101 #include "mydevice.h"
102 #include "interface.h"
103 #include "blendef.h"
104
105 /* naming conventions:
106  * 
107  * uiBlahBlah()         external function
108  * ui_blah_blah()       internal function
109  */
110
111 /***/
112 /* ************ GLOBALS ************* */
113
114 float UIwinmat[4][4];
115 static int UIlock= 0, UIafterval;
116 static char *UIlockstr=NULL;
117 static void (*UIafterfunc)(void *arg, int event);
118 static void *UIafterfunc_arg;
119
120 static uiFont UIfont[UI_ARRAY];  // no init needed
121 uiBut *UIbuttip;
122
123 /* ************* PROTOTYPES ***************** */
124
125 static void ui_set_but_val(uiBut *but, double value);
126 static void ui_do_but_tip(uiBut *buttip);
127
128 /* ****************************** */
129
130 static int uibut_contains_pt(uiBut *but, short *pt)
131 {
132         return ((but->x1<pt[0] && but->x2>=pt[0]) && 
133                         (but->y1<pt[1] && but->y2>=pt[1]));
134 }
135
136 static void uibut_do_func(uiBut *but)
137 {
138         if (but->func) {
139                 but->func(but->func_arg1, but->func_arg2);
140         }
141 }
142
143 /* ************* window matrix ************** */
144
145
146 void ui_graphics_to_window(int win, float *x, float *y) /* for rectwrite  */
147 {
148         float gx, gy;
149         int sx, sy;
150         int getsizex, getsizey;
151
152         bwin_getsize(win, &getsizex, &getsizey);
153         bwin_getsuborigin(win, &sx, &sy);
154
155         gx= *x;
156         gy= *y;
157         *x= ((float)sx) + ((float)getsizex)*(0.5+ 0.5*(gx*UIwinmat[0][0]+ gy*UIwinmat[1][0]+ UIwinmat[3][0]));
158         *y= ((float)sy) + ((float)getsizey)*(0.5+ 0.5*(gx*UIwinmat[0][1]+ gy*UIwinmat[1][1]+ UIwinmat[3][1]));
159 }
160
161
162
163 void ui_window_to_graphics(int win, float *x, float *y) /* for mouse cursor */
164 {
165         float a, b, c, d, e, f, px, py;
166         int getsizex, getsizey;
167                 
168         bwin_getsize(win, &getsizex, &getsizey);
169
170         a= .5*((float)getsizex)*UIwinmat[0][0];
171         b= .5*((float)getsizex)*UIwinmat[1][0];
172         c= .5*((float)getsizex)*(1.0+UIwinmat[3][0]);
173
174         d= .5*((float)getsizey)*UIwinmat[0][1];
175         e= .5*((float)getsizey)*UIwinmat[1][1];
176         f= .5*((float)getsizey)*(1.0+UIwinmat[3][1]);
177         
178         px= *x;
179         py= *y;
180         
181         *y=  (a*(py-f) + d*(c-px))/(a*e-d*b);
182         *x= (px- b*(*y)- c)/a;
183         
184 }
185
186
187 /* ************* SAVE UNDER ************ */
188
189 /* new method: 
190
191 OverDraw *ui_begin_overdraw(int minx, int miny, int maxx, int maxy);
192 - enforces mainwindow to become active
193 - grabs copy from frontbuffer, pastes in back
194
195 void ui_flush_overdraw(OverDraw *od);
196 - copies backbuffer to front
197
198 void ui_refresh_overdraw(Overdraw *od);
199 - pastes in back copy of frontbuffer again for fresh drawing
200
201 void ui_end_overdraw(OverDraw *od);
202 - puts back on frontbuffer saved image
203 - frees copy
204 - sets back active blender area
205 - signals backbuffer to be corrupt (sel buffer!)
206
207 */
208
209 /* frontbuffer updates now glCopyPixels too, with block->flush rect */
210
211 /* new idea for frontbuffer updates:
212
213 - hilites: with blended poly?
214
215 - full updates... thats harder, but:
216   - copy original
217   - before draw, always paste to backbuf
218   - flush
219   - always end with redraw event for full update
220
221 */
222
223 static void myglCopyPixels(int a, int b, int c, int d, int e)
224 {
225         if(G.rt==2) {
226                 unsigned int *buf= MEM_mallocN(4*c*d, "temp glcopypixels");
227                 glReadPixels(a, b, c, d, GL_RGBA, GL_UNSIGNED_BYTE, buf);
228                 glDrawPixels(c, d, GL_RGBA, GL_UNSIGNED_BYTE, buf);
229                 MEM_freeN(buf);
230         }
231         else glCopyPixels(a, b, c, d, e);
232 }
233
234 typedef struct {
235         short x, y, sx, sy, oldwin;
236         unsigned int *rect;
237 } uiOverDraw;
238
239
240 static uiOverDraw *ui_begin_overdraw(int minx, int miny, int maxx, int maxy)
241 {
242         uiOverDraw *od=NULL;
243         
244         // dirty patch removed for sun and sgi to mywindow.c commented out
245         
246         /* clip with actual window size */
247         if(minx < 0) minx= 0;
248         if(miny < 0) miny= 0;
249         if(maxx >= G.curscreen->sizex) maxx= G.curscreen->sizex-1;
250         if(maxy >= G.curscreen->sizey) maxy= G.curscreen->sizey-1;
251
252         if(minx<maxx && miny<maxy) {
253                 od= MEM_callocN(sizeof(uiOverDraw), "overdraw");        
254                 
255                 od->x= minx;
256                 od->y= miny;
257                 od->sx= maxx-minx;
258                 od->sy= maxy-miny;
259                 od->rect= MEM_mallocN(od->sx*od->sy*4, "temp_frontbuffer_image");
260
261                 od->oldwin= mywinget();
262                 mywinset(G.curscreen->mainwin);
263                 /* grab front */
264                 glReadBuffer(GL_FRONT);
265                 glReadPixels(od->x, od->y, od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
266                 glReadBuffer(GL_BACK);
267                 /* paste in back */
268                 glDisable(GL_DITHER);
269                 glRasterPos2f(od->x, od->y);
270                 glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
271                 glEnable(GL_DITHER);
272         }
273         
274         return od;
275 }
276
277 static void ui_flush_overdraw(uiOverDraw *od)
278 {
279
280         if(od==NULL) return;
281         glDisable(GL_DITHER);
282         glReadBuffer(GL_BACK);
283         glDrawBuffer(GL_FRONT);
284         glRasterPos2s(od->x, od->y);
285         myglCopyPixels(od->x, od->y, od->sx, od->sy, GL_COLOR);
286         glEnable(GL_DITHER);
287         glFlush();
288         glDrawBuffer(GL_BACK);
289 }
290
291 /* special flush version to enable transparent menus */
292 static void ui_block_flush_overdraw(uiBlock *block)
293 {
294         
295         if(block->flag & UI_BLOCK_LOOP) {
296                 char col[4];
297                 
298                 BIF_GetThemeColor4ubv(TH_MENU_BACK, col);
299                 if(col[3]!=255) {
300                         uiBut *bt;
301                         uiOverDraw *od= block->overdraw;
302
303                         /* completely draw all! */
304                         glRasterPos2s(od->x, od->y);
305                         glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
306                         
307                         uiDrawMenuBox(block->minx, block->miny, block->maxx, block->maxy, block->flag);
308                         for (bt= block->buttons.first; bt; bt= bt->next) {
309                                 ui_draw_but(bt);
310                         }
311                 }
312         }
313         
314         ui_flush_overdraw(block->overdraw);
315 }
316
317 static void ui_end_overdraw(uiOverDraw *od)
318 {
319         if(od==NULL) return;
320         
321         glDisable(GL_DITHER);
322
323         // clear in back
324         glRasterPos2s(od->x, od->y);
325         glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
326
327         // clear in front
328         glDrawBuffer(GL_FRONT);
329         glRasterPos2s(od->x, od->y);
330         glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
331
332         glFlush();
333         glDrawBuffer(GL_BACK);
334         glEnable(GL_DITHER);
335         
336         if(od->oldwin) mywinset(od->oldwin);
337         
338         MEM_freeN(od->rect);
339         MEM_freeN(od);
340
341         markdirty_all_back();   // sets flags only
342 }
343
344 /* ****************** live updates for hilites and button presses *********** */
345
346 void ui_block_flush_back(uiBlock *block)
347 {
348         int minx, miny, sizex, sizey;
349         
350         /* note; this routine also has to work for block loop */
351         if(block->needflush==0) return;
352
353         /* exception, when we cannot use backbuffer for draw... */
354         if(block->flag & UI_BLOCK_FRONTBUFFER) {
355                 glFlush();
356                 glDrawBuffer(GL_BACK);
357                 block->needflush= 0;
358                 return;
359         }
360         
361         /* copy pixels works on window coords, so we move to window space */
362
363         ui_graphics_to_window(block->win, &block->flush.xmin, &block->flush.ymin);
364         ui_graphics_to_window(block->win, &block->flush.xmax, &block->flush.ymax);
365         minx= floor(block->flush.xmin);
366         miny= floor(block->flush.ymin);
367         sizex= ceil(block->flush.xmax-block->flush.xmin);
368         sizey= ceil(block->flush.ymax-block->flush.ymin);
369
370         if(sizex>0 && sizey>0) {
371                 glPushMatrix();
372                 mywinset(G.curscreen->mainwin);
373                 
374                 glDisable(GL_DITHER);
375                 glReadBuffer(GL_BACK);
376                 glDrawBuffer(GL_FRONT);
377                 glRasterPos2i(minx, miny);
378 #ifdef __sun__          
379                 myglCopyPixels(minx, miny+1, sizex, sizey, GL_COLOR);
380 #else
381                 myglCopyPixels(minx, miny, sizex, sizey, GL_COLOR);
382 #endif
383                 glEnable(GL_DITHER);
384                 glFlush();
385                 glDrawBuffer(GL_BACK);
386
387                 mywinset(block->win);
388                 glPopMatrix();
389                 
390                 markdirty_win_back(block->win);
391         }
392
393         block->needflush= 0; 
394 }
395
396 /* merge info for live updates in frontbuf */
397 void ui_block_set_flush(uiBlock *block, uiBut *but)
398 {
399         /* clear signal */
400         if(but==NULL) {
401                 block->needflush= 0; 
402
403                 block->flush.xmin= 0.0;
404                 block->flush.xmax= 0.0;
405         }
406         else {
407                 /* exception, when we cannot use backbuffer for draw... */
408                 if(block->flag & UI_BLOCK_FRONTBUFFER) {
409                         glDrawBuffer(GL_FRONT);
410                 }
411                 else if(block->needflush==0) {
412                         /* first rect */
413                         block->flush.xmin= but->x1;
414                         block->flush.xmax= but->x2;
415                         block->flush.ymin= but->y1;
416                         block->flush.ymax= but->y2;
417                         
418                 }
419                 else {
420                         /* union of rects */
421                         if(block->flush.xmin > but->x1) block->flush.xmin= but->x1;
422                         if(block->flush.xmax < but->x2) block->flush.xmax= but->x2;
423                         if(block->flush.ymin > but->y1) block->flush.ymin= but->y1;
424                         if(block->flush.ymax < but->y2) block->flush.ymax= but->y2;
425                 }
426                 
427                 block->needflush= 1;
428                 
429         }
430 }
431
432 /* ******************* copy and paste ********************  */
433
434 /* c = copy, v = paste */
435 /* return 1 when something changed */
436 static int ui_but_copy_paste(uiBut *but, char mode)
437 {
438         static char str[256]="";
439         static double butval=0.0;
440         static float rgb[3];
441         void *poin;
442         
443         if(mode=='v' && but->lock) return 0;
444         
445         poin= but->poin;
446                 
447         if ELEM3(but->type, NUM, NUMSLI, HSVSLI) {
448         
449                 if(mode=='c') {
450                         butval= ui_get_but_val(but);
451                 }
452                 else {
453                         ui_set_but_val(but, butval);
454                         ui_check_but(but);
455                         return 1;
456                 }
457         }
458         else if(but->type==COL) {
459                 
460                 if(mode=='c') {
461                         if(but->pointype==FLO) {
462                                 float *fp= (float *) poin;
463                                 rgb[0]= fp[0];
464                                 rgb[1]= fp[1];
465                                 rgb[2]= fp[2];  
466                         }       
467                         else if (but->pointype==CHA) {
468                                 char *cp= (char *) poin;
469                                 rgb[0]= (float)(cp[0]/255.0);
470                                 rgb[1]= (float)(cp[1]/255.0);
471                                 rgb[2]= (float)(cp[2]/255.0);
472                         }
473                         
474                 }
475                 else {
476                         if(but->pointype==FLO) {
477                                 float *fp= (float *) poin;
478                                 fp[0] = rgb[0];
479                                 fp[1] = rgb[1];
480                                 fp[2] = rgb[2];
481                                 return 1;
482                         }
483                         else if (but->pointype==CHA) {
484                                 char *cp= (char *) poin;
485                                 cp[0] = (char)(rgb[0]*255.0);
486                                 cp[1] = (char)(rgb[1]*255.0);
487                                 cp[2] = (char)(rgb[2]*255.0);
488                                 
489                                 return 1;
490                         }
491                         
492                 }
493         }
494         else if(but->type==TEX) {
495                 
496                 if(mode=='c') {
497                         strncpy(str, but->poin, but->max);
498                 }
499                 else {
500                         char backstr[UI_MAX_DRAW_STR];
501                         /* give butfunc the original text too */
502                         /* feature used for bone renaming, channels, etc */
503                         if(but->func_arg2==NULL) {
504                                 strncpy(backstr, but->drawstr, UI_MAX_DRAW_STR);
505                                 but->func_arg2= backstr;
506                         }
507                         strncpy(but->poin, str, but->max);
508                         uibut_do_func(but);
509                         ui_check_but(but);
510                         return 1;
511                 }
512         }
513         else if(but->type==IDPOIN) {
514                 
515                 if(mode=='c') {
516                         ID *id= *but->idpoin_idpp;
517                         if(id) strncpy(str, id->name+2, 22);
518                 }
519                 else {
520                         but->idpoin_func(str, but->idpoin_idpp);
521                         ui_check_but(but);
522                         return 1;
523                 }
524         }
525                 
526                         
527         return 0;
528 }
529
530 /* ******************* block calc ************************* */
531
532 void uiTextBoundsBlock(uiBlock *block, int addval)
533 {
534         uiBut *bt;
535         int i = 0, j;
536         
537         bt= block->buttons.first;
538         while(bt) {
539                 if(bt->type!=SEPR) {
540                         int transopts= (U.transopts & USER_TR_BUTTONS);
541                         if(bt->type==TEX || bt->type==IDPOIN) transopts= 0;
542                         j= BIF_GetStringWidth(bt->font, bt->drawstr, transopts);
543
544                         if(j > i) i = j;
545                 }
546                 bt= bt->next;
547         }
548
549         
550         bt= block->buttons.first;
551         while(bt) {
552                 bt->x2 = i + addval;
553                 ui_check_but(bt);       // clips text again
554                 bt= bt->next;
555         }
556 }
557
558
559 void uiBoundsBlock(uiBlock *block, int addval)
560 {
561         uiBut *bt;
562         int xof;
563         
564         if(block->buttons.first==NULL) {
565                 if(block->panel) {
566                         block->minx= 0.0; block->maxx= block->panel->sizex;
567                         block->miny= 0.0; block->maxy= block->panel->sizey;
568                 }
569         }
570         else {
571         
572                 block->minx= block->miny= 10000;
573                 block->maxx= block->maxy= -10000;
574                 
575                 bt= block->buttons.first;
576                 while(bt) {
577                         if(bt->x1 < block->minx) block->minx= bt->x1;
578                         if(bt->y1 < block->miny) block->miny= bt->y1;
579         
580                         if(bt->x2 > block->maxx) block->maxx= bt->x2;
581                         if(bt->y2 > block->maxy) block->maxy= bt->y2;
582                         
583                         bt= bt->next;
584                 }
585                 
586                 block->minx -= addval;
587                 block->miny -= addval;
588                 block->maxx += addval;
589                 block->maxy += addval;
590         }
591
592         /* hardcoded exception... but that one is annoying with larger safety */ 
593         bt= block->buttons.first;
594         if(bt && strncmp(bt->str, "ERROR", 5)==0) xof= 10;
595         else xof= 40;
596         
597         block->safety.xmin= block->minx-xof;
598         block->safety.ymin= block->miny-xof;
599         block->safety.xmax= block->maxx+xof;
600         block->safety.ymax= block->maxy+xof;
601 }
602
603 static void ui_positionblock(uiBlock *block, uiBut *but)
604 {
605         /* position block relative to but */
606         uiBut *bt;
607         rctf butrct;
608         float aspect;
609         int xsize, ysize, xof=0, yof=0, centre;
610         short dir1= 0, dir2=0;
611         
612         /* first transform to screen coords, assuming matrix is stil OK */
613         /* the UIwinmat is in panelspace */
614
615         butrct.xmin= but->x1; butrct.xmax= but->x2;
616         butrct.ymin= but->y1; butrct.ymax= but->y2;
617
618         ui_graphics_to_window(block->win, &butrct.xmin, &butrct.ymin);
619         ui_graphics_to_window(block->win, &butrct.xmax, &butrct.ymax);
620         block->parentrct= butrct;       // will use that for pulldowns later
621
622         /* calc block rect */
623         if(block->buttons.first) {
624                 block->minx= block->miny= 10000;
625                 block->maxx= block->maxy= -10000;
626                 
627                 bt= block->buttons.first;
628                 while(bt) {
629                         if(bt->x1 < block->minx) block->minx= bt->x1;
630                         if(bt->y1 < block->miny) block->miny= bt->y1;
631
632                         if(bt->x2 > block->maxx) block->maxx= bt->x2;
633                         if(bt->y2 > block->maxy) block->maxy= bt->y2;
634                         
635                         bt= bt->next;
636                 }
637         }
638         else {
639                 /* we're nice and allow empty blocks too */
640                 block->minx= block->miny= 0;
641                 block->maxx= block->maxy= 20;
642         }
643         
644         aspect= (float)(block->maxx - block->minx + 4);
645         ui_graphics_to_window(block->win, &block->minx, &block->miny);
646         ui_graphics_to_window(block->win, &block->maxx, &block->maxy);
647
648         //block->minx-= 2.0; block->miny-= 2.0;
649         //block->maxx+= 2.0; block->maxy+= 2.0;
650         
651         xsize= block->maxx - block->minx+4; // 4 for shadow
652         ysize= block->maxy - block->miny+4;
653         aspect/= (float)xsize;
654
655         if(but) {
656                 short left=0, right=0, top=0, down=0;
657
658                 if(block->direction & UI_CENTRE) centre= ysize/2;
659                 else centre= 0;
660
661                 if( butrct.xmin-xsize > 0.0) left= 1;
662                 if( butrct.xmax+xsize < G.curscreen->sizex) right= 1;
663                 if( butrct.ymin-ysize+centre > 0.0) down= 1;
664                 if( butrct.ymax+ysize-centre < G.curscreen->sizey) top= 1;
665                 
666                 dir1= block->direction & UI_DIRECTION;
667
668                 /* secundary directions */
669                 if(dir1 & (UI_TOP|UI_DOWN)) {
670                         if(dir1 & UI_LEFT) dir2= UI_LEFT;
671                         else if(dir1 & UI_RIGHT) dir2= UI_RIGHT;
672                         dir1 &= (UI_TOP|UI_DOWN);
673                 }
674
675                 if(dir2==0) if(dir1==UI_LEFT || dir1==UI_RIGHT) dir2= UI_DOWN;
676                 if(dir2==0) if(dir1==UI_TOP || dir1==UI_DOWN) dir2= UI_LEFT;
677                 
678                 /* no space at all? dont change */
679                 if(left || right) {
680                         if(dir1==UI_LEFT && left==0) dir1= UI_RIGHT;
681                         if(dir1==UI_RIGHT && right==0) dir1= UI_LEFT;
682                         /* this is aligning, not append! */
683                         if(dir2==UI_LEFT && right==0) dir2= UI_RIGHT;
684                         if(dir2==UI_RIGHT && left==0) dir2= UI_LEFT;
685                 }
686                 if(down || top) {
687                         if(dir1==UI_TOP && top==0) dir1= UI_DOWN;
688                         if(dir1==UI_DOWN && down==0) dir1= UI_TOP;
689                         if(dir2==UI_TOP && top==0) dir2= UI_DOWN;
690                         if(dir2==UI_DOWN && down==0) dir2= UI_TOP;
691                 }
692                 
693                 if(dir1==UI_LEFT) {
694                         xof= butrct.xmin - block->maxx;
695                         if(dir2==UI_TOP) yof= butrct.ymin - block->miny-centre;
696                         else yof= butrct.ymax - block->maxy+centre;
697                 }
698                 else if(dir1==UI_RIGHT) {
699                         xof= butrct.xmax - block->minx;
700                         if(dir2==UI_TOP) yof= butrct.ymin - block->miny-centre;
701                         else yof= butrct.ymax - block->maxy+centre;
702                 }
703                 else if(dir1==UI_TOP) {
704                         yof= butrct.ymax - block->miny;
705                         if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
706                         else xof= butrct.xmin - block->minx;
707                         // changed direction? 
708                         if((dir1 & block->direction)==0) {
709                                 if(block->direction & UI_SHIFT_FLIPPED)
710                                         xof+= dir2==UI_LEFT?25:-25;
711                                 uiBlockFlipOrder(block);
712                         }
713                 }
714                 else if(dir1==UI_DOWN) {
715                         yof= butrct.ymin - block->maxy;
716                         if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
717                         else xof= butrct.xmin - block->minx;
718                         // changed direction?
719                         if((dir1 & block->direction)==0) {
720                                 if(block->direction & UI_SHIFT_FLIPPED)
721                                         xof+= dir2==UI_LEFT?25:-25;
722                                 uiBlockFlipOrder(block);
723                         }
724                 }
725
726                 /* and now we handle the exception; no space below or to top */
727                 if(top==0 && down==0) {
728                         if(dir1==UI_LEFT || dir1==UI_RIGHT) {
729                                 // align with bottom of screen 
730                                 yof= ysize;
731                         }
732                 }
733                 
734                 /* or no space left or right */
735                 if(left==0 && right==0) {
736                         if(dir1==UI_TOP || dir1==UI_DOWN) {
737                                 // align with left size of screen 
738                                 xof= -block->minx+5;
739                         }
740                 }
741                 
742                 // apply requested offset in the block
743                 xof += block->xofs/block->aspect;
744                 yof += block->yofs/block->aspect;
745                 
746         }
747         
748         /* apply */
749         
750         for(bt= block->buttons.first; bt; bt= bt->next) {
751                 
752                 ui_graphics_to_window(block->win, &bt->x1, &bt->y1);
753                 ui_graphics_to_window(block->win, &bt->x2, &bt->y2);
754
755                 bt->x1 += xof;
756                 bt->x2 += xof;
757                 bt->y1 += yof;
758                 bt->y2 += yof;
759
760                 bt->aspect= 1.0;
761                 // ui_check_but recalculates drawstring size in pixels
762                 ui_check_but(bt);
763         }
764         
765         block->minx += xof;
766         block->miny += yof;
767         block->maxx += xof;
768         block->maxy += yof;
769         
770         /* safety calculus */
771         if(but) {
772                 float midx= (block->parentrct.xmin+block->parentrct.xmax)/2.0;
773                 float midy= (block->parentrct.ymin+block->parentrct.ymax)/2.0;
774                 
775                 /* when you are outside parent button, safety there should be smaller */
776                 
777                 // parent button to left
778                 if( midx < block->minx ) block->safety.xmin= block->minx-3; 
779                 else block->safety.xmin= block->minx-40;
780                 // parent button to right
781                 if( midx > block->maxx ) block->safety.xmax= block->maxx+3; 
782                 else block->safety.xmax= block->maxx+40;
783                 
784                 // parent button on bottom
785                 if( midy < block->miny ) block->safety.ymin= block->miny-3; 
786                 else block->safety.ymin= block->miny-40;
787                 // parent button on top
788                 if( midy > block->maxy ) block->safety.ymax= block->maxy+3; 
789                 else block->safety.ymax= block->maxy+40;
790                 
791                 // exception for switched pulldowns...
792                 if(dir1 && (dir1 & block->direction)==0) {
793                         if(dir2==UI_RIGHT) block->safety.xmax= block->maxx+3; 
794                         if(dir2==UI_LEFT) block->safety.xmin= block->minx-3; 
795                 }
796                 block->direction= dir1;
797         }
798         else {
799                 block->safety.xmin= block->minx-40;
800                 block->safety.ymin= block->miny-40;
801                 block->safety.xmax= block->maxx+40;
802                 block->safety.ymax= block->maxy+40;
803         }
804
805 }
806
807
808 void ui_autofill(uiBlock *block)
809 {
810         uiBut *but;
811         float *maxw, *maxh, startx = 0, starty, height = 0;
812         float totmaxh;
813         int rows=0, /*  cols=0, */ i, lasti;
814         
815         /* first count rows */
816         but= block->buttons.last;
817         rows= but->x1+1;
818
819         /* calculate max width / height for each row */
820         maxw= MEM_callocN(sizeof(float)*rows, "maxw");
821         maxh= MEM_callocN(sizeof(float)*rows, "maxh");
822         but= block->buttons.first;
823         while(but) {
824                 i= but->x1;
825                 if( maxh[i] < but->y2) maxh[i]= but->y2;
826                 maxw[i] += but->x2;
827                 but= but->next;
828         }
829         
830         totmaxh= 0.0;
831         for(i=0; i<rows; i++) totmaxh+= maxh[i];
832         
833         /* apply widths/heights */
834         starty= block->maxy;
835         but= block->buttons.first;
836         lasti= -1;
837         while(but) {
838                 // signal for aligning code
839                 but->flag |= UI_BUT_ALIGN_DOWN;
840                 
841                 i= but->x1;
842
843                 if(i!=lasti) {
844                         startx= block->minx;
845                         height= (maxh[i]*(block->maxy-block->miny))/totmaxh;
846                         starty-= height;
847                         lasti= i;
848                 }
849                 
850                 but->y1= starty+but->aspect;
851                 but->y2= but->y1+height-but->aspect;
852                 
853                 but->x2= (but->x2*(block->maxx-block->minx))/maxw[i];
854                 but->x1= startx+but->aspect;
855                 
856                 startx+= but->x2;
857                 but->x2+= but->x1-but->aspect;
858                 
859                 ui_check_but(but);
860                 
861                 but= but->next;
862         }
863         
864         uiBlockEndAlign(block);
865         
866         MEM_freeN(maxw); MEM_freeN(maxh);       
867         block->autofill= 0;
868 }
869
870 /* ************** LINK LINE DRAWING  ************* */
871
872 /* link line drawing is not part of buttons or theme.. so we stick with it here */
873
874 static void ui_draw_linkline(uiBut *but, uiLinkLine *line)
875 {
876         float vec1[2], vec2[2];
877
878         if(line->from==NULL || line->to==NULL) return;
879         
880         vec1[0]= (line->from->x1+line->from->x2)/2.0;
881         vec1[1]= (line->from->y1+line->from->y2)/2.0;
882         vec2[0]= (line->to->x1+line->to->x2)/2.0;
883         vec2[1]= (line->to->y1+line->to->y2)/2.0;
884         
885         if(line->flag & UI_SELECT) BIF_ThemeColorShade(but->themecol, 80);
886         else glColor3ub(0,0,0);
887         fdrawline(vec1[0], vec1[1], vec2[0], vec2[1]);
888 }
889
890 static void ui_draw_links(uiBlock *block)
891 {
892         uiBut *but;
893         uiLinkLine *line;
894         
895         but= block->buttons.first;
896         while(but) {
897                 if(but->type==LINK && but->link) {
898                         line= but->link->lines.first;
899                         while(line) {
900                                 ui_draw_linkline(but, line);
901                                 line= line->next;
902                         }
903                 }
904                 but= but->next;
905         }       
906 }
907
908 /* ************** BLOCK DRAWING FUNCTION ************* */
909
910
911 void uiDrawBlock(uiBlock *block)
912 {
913         uiBut *but;
914         short testmouse=0, mouse[2];
915         
916         /* we set this only once */
917         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
918         
919         /* handle pending stuff */
920         if(block->autofill) ui_autofill(block);
921         if(block->minx==0.0 && block->maxx==0.0) uiBoundsBlock(block, 0);
922         if(block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block);
923         
924         /* we set active flag on a redraw again */
925         if((block->flag & UI_BLOCK_LOOP)==0) {
926                 testmouse= 1;  
927                 Mat4CpyMat4(UIwinmat, block->winmat);
928                 uiGetMouse(block->win, mouse);
929         }
930         
931         uiPanelPush(block); // panel matrix
932         
933         if(block->flag & UI_BLOCK_LOOP) {
934                 uiDrawMenuBox(block->minx, block->miny, block->maxx, block->maxy, block->flag);
935         }
936         else {
937                 if(block->panel) ui_draw_panel(block);
938         }               
939
940         if(block->drawextra) block->drawextra();
941
942         for (but= block->buttons.first; but; but= but->next) {
943                 
944                 if(testmouse && uibut_contains_pt(but, mouse))
945                         but->flag |= UI_ACTIVE;
946                 
947                 ui_draw_but(but);
948         }
949
950         ui_draw_links(block);
951
952         uiPanelPop(block); // matrix restored
953 }
954
955 /* ************* MENUBUTS *********** */
956
957 typedef struct {
958         char *str;
959         int retval;
960         int icon;
961 } MenuEntry;
962
963 typedef struct {
964         char *instr;
965         char *title;
966         int titleicon;
967         
968         MenuEntry *items;
969         int nitems, itemssize;
970 } MenuData;
971
972 static MenuData *menudata_new(char *instr) {
973         MenuData *md= MEM_mallocN(sizeof(*md), "MenuData");
974
975         md->instr= instr;
976         md->title= NULL;
977         md->titleicon= 0;
978         md->items= NULL;
979         md->nitems= md->itemssize= 0;
980         
981         return md;
982 }
983
984 static void menudata_set_title(MenuData *md, char *title, int titleicon) {
985         if (!md->title)
986                 md->title= title;
987         if (!md->titleicon)
988                 md->titleicon= titleicon;
989 }
990
991 static void menudata_add_item(MenuData *md, char *str, int retval, int icon) {
992         if (md->nitems==md->itemssize) {
993                 int nsize= md->itemssize?(md->itemssize<<1):1;
994                 MenuEntry *oitems= md->items;
995                 
996                 md->items= MEM_mallocN(nsize*sizeof(*md->items), "md->items");
997                 if (oitems) {
998                         memcpy(md->items, oitems, md->nitems*sizeof(*md->items));
999                         MEM_freeN(oitems);
1000                 }
1001                 
1002                 md->itemssize= nsize;
1003         }
1004         
1005         md->items[md->nitems].str= str;
1006         md->items[md->nitems].retval= retval;
1007         md->items[md->nitems].icon= icon;
1008         md->nitems++;
1009 }
1010
1011 static void menudata_free(MenuData *md) {
1012         MEM_freeN(md->instr);
1013         if (md->items)
1014                 MEM_freeN(md->items);
1015         MEM_freeN(md);
1016 }
1017
1018         /**
1019          * Parse menu description strings, string is of the
1020          * form "[sss%t|]{(sss[%xNN]|), (%l|)}", ssss%t indicates the
1021          * menu title, sss or sss%xNN indicates an option, 
1022          * if %xNN is given then NN is the return value if
1023          * that option is selected otherwise the return value
1024          * is the index of the option (starting with 1). %l
1025          * indicates a seperator.
1026          * 
1027          * @param str String to be parsed.
1028          * @retval new menudata structure, free with menudata_free()
1029          */
1030 static MenuData *decompose_menu_string(char *str) 
1031 {
1032         char *instr= BLI_strdup(str);
1033         MenuData *md= menudata_new(instr);
1034         char *nitem= NULL, *s= instr;
1035         int nicon=0, nretval= 1, nitem_is_title= 0;
1036         
1037         while (1) {
1038                 char c= *s;
1039
1040                 if (c=='%') {
1041                         if (s[1]=='x') {
1042                                 nretval= atoi(s+2);
1043
1044                                 *s= '\0';
1045                                 s++;
1046                         } else if (s[1]=='t') {
1047                                 nitem_is_title= 1;
1048
1049                                 *s= '\0';
1050                                 s++;
1051                         } else if (s[1]=='l') {
1052                                 nitem= "%l";
1053                                 s++;
1054                         } else if (s[1]=='i') {
1055                                 nicon= atoi(s+2);
1056                                 
1057                                 *s= '\0';
1058                                 s++;
1059                         }
1060                 } else if (c=='|' || c=='\0') {
1061                         if (nitem) {
1062                                 *s= '\0';
1063
1064                                 if (nitem_is_title) {
1065                                         menudata_set_title(md, nitem, nicon);
1066                                         nitem_is_title= 0;
1067                                 } else {
1068                                         menudata_add_item(md, nitem, nretval, nicon);
1069                                         nretval= md->nitems+1;
1070                                 } 
1071                                 
1072                                 nitem= NULL;
1073                                 nicon= 0;
1074                         }
1075                         
1076                         if (c=='\0')
1077                                 break;
1078                 } else if (!nitem)
1079                         nitem= s;
1080                 
1081                 s++;
1082         }
1083         
1084         return md;
1085 }
1086
1087 static void ui_set_name_menu(uiBut *but, int value)
1088 {
1089         MenuData *md;
1090         int i;
1091         
1092         md= decompose_menu_string(but->str);
1093         for (i=0; i<md->nitems; i++)
1094                 if (md->items[i].retval==value)
1095                         strcpy(but->drawstr, md->items[i].str);
1096         menudata_free(md);
1097 }
1098
1099 static void ui_warp_pointer(short x, short y)
1100 {
1101         /* OSX has very poor mousewarp support, it sends events;
1102            this causes a menu being pressed immediately ... */
1103         #ifndef __APPLE__
1104         warp_pointer(x, y);
1105         #endif
1106 }
1107
1108
1109 static int ui_do_but_MENU(uiBut *but)
1110 {
1111         uiBlock *block;
1112         uiBut *bt;
1113         ListBase listb={NULL, NULL}, lb;
1114         double fvalue;
1115         int width, height=0, a, xmax, starty;
1116         short startx;
1117         int columns=1, rows=0, boxh, event;
1118         short  x1, y1, active= -1;
1119         short mval[2];
1120         MenuData *md;
1121
1122         but->flag |= UI_SELECT;
1123         ui_draw_but(but);
1124         ui_block_flush_back(but->block);        // flush because this button creates own blocks loop
1125
1126         block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
1127         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
1128         block->themecol= TH_MENU_ITEM;
1129         
1130         md= decompose_menu_string(but->str);
1131
1132         /* columns and row calculation */
1133         columns= (md->nitems+20)/20;
1134         if (columns<1) columns= 1;
1135         
1136         if(columns>8) columns= (md->nitems+25)/25;
1137         
1138         rows= (int) md->nitems/columns;
1139         if (rows<1) rows= 1;
1140         
1141         while (rows*columns<md->nitems) rows++;
1142                 
1143         /* prevent scaling up of pupmenu */
1144         if (but->aspect < 1.0f) but->aspect = 1.0f;
1145
1146         /* size and location */
1147         if(md->title)
1148                 width= 1.5*but->aspect*strlen(md->title)+BIF_GetStringWidth(block->curfont, md->title, (U.transopts & USER_TR_MENUS));
1149         else
1150                 width= 0;
1151
1152         for(a=0; a<md->nitems; a++) {
1153                 xmax= but->aspect*BIF_GetStringWidth(block->curfont, md->items[a].str, (U.transopts & USER_TR_MENUS));
1154                 if ( md->items[a].icon) xmax += 20*but->aspect;
1155                 if(xmax>width) width= xmax;
1156         }
1157
1158         width+= 10;
1159         if (width < (but->x2 - but->x1)) width = (but->x2 - but->x1);
1160         if (width<50) width=50;
1161
1162         boxh= TBOXH;
1163         
1164         height= rows*boxh;
1165         if (md->title) height+= boxh;
1166         
1167         getmouseco_sc(mval);
1168         
1169         /* find active item */
1170         fvalue= ui_get_but_val(but);
1171         for(active=0; active<md->nitems; active++) {
1172                 if( md->items[active].retval== (int)fvalue ) break;
1173         }
1174         /* no active item? */
1175         if(active==md->nitems) {
1176                 if(md->title) active= -1;
1177                 else active= 0;
1178         }
1179
1180         /* for now disabled... works confusing because you think it's a title or so.... */
1181         active= -1;
1182
1183         /* here we go! */
1184         startx= but->x1;
1185         starty= but->y1;
1186         
1187         if(md->title) {
1188                 uiBut *bt;
1189                 uiSetCurFont(block, block->font+1);
1190                 if (md->titleicon) {
1191                         uiDefIconTextBut(block, LABEL, 0, md->titleicon, md->title, startx, (short)(starty+rows*boxh), (short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
1192                 } else {
1193                         bt= uiDefBut(block, LABEL, 0, md->title, startx, (short)(starty+rows*boxh), (short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
1194                         bt->flag= UI_TEXT_LEFT;
1195                 }
1196                 uiSetCurFont(block, block->font);
1197                 
1198         }
1199
1200         for(a=0; a<md->nitems; a++) {
1201                 
1202                 x1= but->x1 + width*((int)(md->nitems-a-1)/rows);
1203                 y1= but->y1 - boxh*(rows - ((md->nitems - a - 1)%rows)) + (rows*boxh);
1204
1205                 if (strcmp(md->items[md->nitems-a-1].str, "%l")==0) {
1206                         uiDefBut(block, SEPR, B_NOP, "", x1, y1,(short)(width-(rows>1)), (short)(boxh-1), NULL, 0.0, 0.0, 0, 0, "");
1207                 }
1208                 else if(md->items[md->nitems-a-1].icon) {
1209                         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, "");
1210                         if(active==a) bt->flag |= UI_ACTIVE;                    
1211                 }
1212                 else {
1213                         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, "");
1214                         if(active==a) bt->flag |= UI_ACTIVE;
1215                 }
1216         }
1217         
1218         /* the code up here has flipped locations, because of change of preferred order */
1219         /* thats why we have to switch list order too, to make arrowkeys work */
1220         
1221         lb.first= lb.last= NULL;
1222         bt= block->buttons.first;
1223         while(bt) {
1224                 uiBut *next= bt->next;
1225                 BLI_remlink(&block->buttons, bt);
1226                 BLI_addhead(&lb, bt);
1227                 bt= next;
1228         }
1229         block->buttons= lb;
1230
1231         /* and lets go */
1232         block->direction= UI_TOP;
1233         ui_positionblock(block, but);
1234         
1235         /* blocks can come (and get scaled) from a normal window, now we go to screenspace */
1236         block->win= G.curscreen->mainwin;
1237         for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
1238         bwin_getsinglematrix(block->win, block->winmat);
1239
1240         event= uiDoBlocks(&listb, 0);
1241         
1242         menudata_free(md);
1243         
1244         but->flag &= ~UI_SELECT;
1245         ui_check_but(but);
1246         /* no draw of button now, for floating panels the matrix now is invalid...
1247            the button still is active, and will be redrawn in main loop to de-activate it */
1248         
1249         uibut_do_func(but);
1250
1251         /* return no existing event, because the menu sends events instead */
1252         return -1;
1253 }
1254
1255 /* ********************** NEXT/PREV for arrowkeys etc ************** */
1256
1257 static uiBut *ui_but_prev(uiBut *but)
1258 {
1259         while(but->prev) {
1260                 but= but->prev;
1261                 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
1262         }
1263         return NULL;
1264 }
1265
1266 static uiBut *ui_but_next(uiBut *but)
1267 {
1268         while(but->next) {
1269                 but= but->next;
1270                 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
1271         }
1272         return NULL;
1273 }
1274
1275 static uiBut *ui_but_first(uiBlock *block)
1276 {
1277         uiBut *but;
1278         
1279         but= block->buttons.first;
1280         while(but) {
1281                 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
1282                 but= but->next;
1283         }
1284         return NULL;
1285 }
1286
1287 static uiBut *ui_but_last(uiBlock *block)
1288 {
1289         uiBut *but;
1290         
1291         but= block->buttons.last;
1292         while(but) {
1293                 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
1294                 but= but->prev;
1295         }
1296         return NULL;
1297 }
1298
1299
1300 /* ************* IN-BUTTON TEXT SELECTION/EDITING ************* */
1301
1302 static short ui_delete_selection_edittext(uiBut *but)
1303 {
1304         int x;
1305         short deletedwidth=0;
1306         char *str;
1307         
1308         str= (char *)but->poin;
1309         
1310         deletedwidth = SELWIDTH;
1311         
1312         for(x=0; x< strlen(str); x++) {
1313                 if (but->selend + x <= strlen(str) ) {
1314                         str[but->selsta + x]= str[but->selend + x];
1315                 } else {
1316                         str[but->selsta + x]= '\0';
1317                         break;
1318                 }
1319         }
1320         but->pos = but->selend = but->selsta;
1321         
1322         return deletedwidth;
1323 }
1324
1325 static void ui_set_cursor_pos_edittext(uiBut *but, short sx)
1326 {
1327         char backstr[UI_MAX_DRAW_STR];
1328         
1329         BLI_strncpy(backstr, but->drawstr, UI_MAX_DRAW_STR);
1330         but->pos= strlen(backstr)-but->ofs;
1331         
1332         while((but->aspect*BIF_GetStringWidth(but->font, backstr+but->ofs, 0) + but->x1) > sx) {
1333                 if (but->pos <= 0) break;
1334                 but->pos--;
1335                 backstr[but->pos+but->ofs] = 0;
1336         }
1337         
1338         but->pos -= strlen(but->str);
1339         but->pos += but->ofs;
1340         if(but->pos<0) but->pos= 0;
1341 }
1342
1343
1344 /* ************* EVENTS ************* */
1345
1346 void uiGetMouse(int win, short *adr)
1347 {
1348         int x, y;
1349         float xwin, ywin;
1350         
1351         getmouseco_sc(adr);
1352         if (win == G.curscreen->mainwin) return;
1353         
1354         bwin_getsuborigin(win, &x, &y);
1355
1356         adr[0]-= x;
1357         adr[1]-= y;
1358
1359         xwin= adr[0];
1360         ywin= adr[1];
1361
1362         ui_window_to_graphics(win, &xwin, &ywin);
1363
1364         adr[0]= (short)(xwin+0.5);
1365         adr[1]= (short)(ywin+0.5);
1366 }
1367
1368 static void ui_is_but_sel(uiBut *but)
1369 {
1370         double value;
1371         int lvalue;
1372         short push=0, true=1;
1373
1374         value= ui_get_but_val(but);
1375
1376         if( but->type==TOGN ) true= 0;
1377
1378         if( but->bit ) {
1379                 lvalue= (int)value;
1380                 if( BTST(lvalue, (but->bitnr)) ) push= true;
1381                 else push= !true;
1382         }
1383         else {
1384                 switch(but->type) {
1385                 case BUT:
1386                         push= 0;
1387                         break;
1388                 case KEYEVT:
1389                         if (value==-1) push= 1;
1390                         break;
1391                 case TOG:
1392                 case TOGR:
1393                 case TOG3:
1394                 case ICONTOG:
1395                         if(value!=but->min) push= 1;
1396                         break;
1397                 case TOGN:
1398                         if(value==0.0) push= 1;
1399                         break;
1400                 case ROW:
1401                         if(value == but->max) push= 1;
1402                         break;
1403                 case COL:
1404                         push= 1;
1405                         break;
1406                 default:
1407                         push= 2;
1408                         break;
1409                 }
1410         }
1411         
1412         if(push==2);
1413         else if(push==1) but->flag |= UI_SELECT;
1414         else but->flag &= ~UI_SELECT;
1415 }
1416
1417 static int ui_do_but_BUT(uiBut *but)
1418 {
1419         int activated;
1420         
1421         do {
1422                 int oflag= but->flag;
1423                 short mval[2];
1424                         
1425                 uiGetMouse(mywinget(), mval);
1426
1427                 if (uibut_contains_pt(but, mval))
1428                         but->flag |= UI_SELECT;
1429                 else
1430                         but->flag &= ~UI_SELECT;
1431
1432                 if (but->flag != oflag) {
1433                         ui_draw_but(but);
1434                         ui_block_flush_back(but->block);
1435                 }
1436                 
1437                 PIL_sleep_ms(10);
1438         } while (get_mbut() & L_MOUSE);
1439
1440         activated= (but->flag & UI_SELECT);
1441
1442         if(activated) {
1443                 uibut_do_func(but);
1444         }
1445         
1446         but->flag &= ~UI_SELECT;
1447         ui_draw_but(but);
1448
1449         return activated?but->retval:0;
1450 }
1451
1452 static int ui_do_but_KEYEVT(uiBut *but)
1453 {
1454         unsigned short event= 0;
1455         short val;
1456
1457                 /* flag for ui_check_but */
1458         ui_set_but_val(but, -1);
1459         ui_check_but(but);
1460         ui_draw_but(but);
1461         ui_block_flush_back(but->block);
1462
1463         do {
1464                 event= extern_qread(&val);
1465         } while (!event || !val || ELEM(event, MOUSEX, MOUSEY));
1466
1467         if (!key_event_to_string(event)[0]) event= 0;
1468
1469         ui_set_but_val(but, (double) event);
1470         ui_check_but(but);
1471         ui_draw_but(but);
1472         
1473         return (event!=0);
1474 }
1475
1476 static int ui_do_but_TOG(uiBlock *block, uiBut *but)
1477 {
1478         uiBut *bt;
1479         double value;
1480         int w, lvalue, push;
1481         
1482         value= ui_get_but_val(but);
1483         lvalue= (int)value;
1484         
1485         if(but->bit) {
1486                 w= BTST(lvalue, but->bitnr);
1487                 if(w) lvalue = BCLR(lvalue, but->bitnr);
1488                 else lvalue = BSET(lvalue, but->bitnr);
1489                 
1490                 if(but->type==TOGR) {
1491                         if( (get_qual() & LR_SHIFTKEY)==0 ) {
1492                                 lvalue= 1<<(but->bitnr);
1493         
1494                                 ui_set_but_val(but, (double)lvalue);
1495
1496                                 bt= block->buttons.first;
1497                                 while(bt) {
1498                                         if( bt!=but && bt->poin==but->poin ) {
1499                                                 ui_is_but_sel(bt);
1500                                                 ui_draw_but(bt);
1501                                         }
1502                                         bt= bt->next;
1503                                 }
1504                         }
1505                         else {
1506                                 if(lvalue==0) lvalue= 1<<(but->bitnr);
1507                         }
1508                 }
1509                 ui_set_but_val(but, (double)lvalue);
1510                 if(but->type==ICONTOG) ui_check_but(but);
1511                 // no frontbuffer draw for this one
1512                 if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
1513         }
1514         else {
1515                 
1516                 if(value==0.0) push= 1; 
1517                 else push= 0;
1518                 
1519                 if(but->type==TOGN) push= !push;
1520                 ui_set_but_val(but, (double)push);
1521                 if(but->type==ICONTOG) ui_check_but(but);               
1522                 // no frontbuffer draw for this one
1523                 if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
1524         }
1525         
1526         /* no while loop...this button is used for viewmove */
1527
1528         uibut_do_func(but);
1529
1530         return but->retval;
1531 }
1532
1533 static int ui_do_but_ROW(uiBlock *block, uiBut *but)
1534 {
1535         uiBut *bt;
1536         
1537         ui_set_but_val(but, but->max);
1538         ui_draw_but(but);
1539
1540         bt= block->buttons.first;
1541         while(bt) {
1542                 if( bt!=but && bt->type==ROW ) {
1543                         if(bt->min==but->min) {
1544                                 ui_is_but_sel(bt);
1545                                 ui_draw_but(bt);
1546                         }
1547                 }
1548                 bt= bt->next;
1549         }
1550         return but->retval;
1551 }
1552
1553 /* return 1 if char ch is special character otherwise
1554  * it returns 0 */
1555 static short test_special_char(char ch)
1556 {
1557         switch(ch) {
1558                 case '\\':
1559                 case '/':
1560                 case '~':
1561                 case '!':
1562                 case '@':
1563                 case '#':
1564                 case '$':
1565                 case '%':
1566                 case '^':
1567                 case '&':
1568                 case '*':
1569                 case '(':
1570                 case ')':
1571                 case '+':
1572                 case '=':
1573                 case '{':
1574                 case '}':
1575                 case '[':
1576                 case ']':
1577                 case ':':
1578                 case ';':
1579                 case '\'':
1580                 case '\"':
1581                 case '<':
1582                 case '>':
1583                 case ',':
1584                 case '.':
1585                 case '?':
1586                 case '_':
1587                 case '-':
1588                 case ' ':
1589                         return 1;
1590                         break;
1591                 default:
1592                         break;
1593         }
1594         return 0;
1595 }
1596
1597 static int ui_do_but_TEX(uiBut *but)
1598 {
1599         unsigned short dev;
1600         short x, mval[2], len=0, dodraw, selextend=0;
1601         char *str, backstr[UI_MAX_DRAW_STR];
1602         short capturing, sx, sy, prevx;
1603         
1604         str= (char *)but->poin;
1605         
1606         but->flag |= UI_SELECT;
1607
1608         uiGetMouse(mywinget(), mval);
1609
1610         /* set cursor pos to the end of the text */
1611         but->pos = strlen(str);
1612         but->selsta = 0;
1613         but->selend = strlen(but->drawstr) - strlen(but->str);
1614
1615         /* backup */
1616         BLI_strncpy(backstr, but->poin, UI_MAX_DRAW_STR);
1617
1618         ui_draw_but(but);
1619         ui_block_flush_back(but->block);
1620         
1621         while (get_mbut() & L_MOUSE) BIF_wait_for_statechange();
1622         len= strlen(str);
1623
1624         but->min= 0.0;
1625         
1626         capturing = TRUE;
1627         while(capturing) {
1628                 char ascii;
1629                 short val;
1630
1631                 dodraw= 0;
1632                 dev = extern_qread_ext(&val, &ascii);
1633
1634                 if(dev==INPUTCHANGE) break;
1635                 else if(get_mbut() & R_MOUSE) break;
1636                 else if(get_mbut() & L_MOUSE) {
1637                         uiGetMouse(mywinget(), mval);
1638                         sx = mval[0]; sy = mval[1];
1639                         
1640                         if ((but->y1 <= sy) && (sy <= but->y2) && (but->x1 <= sx) && (sx <= but->x2)) {
1641                                 ui_set_cursor_pos_edittext(but, mval[0]);
1642                                 
1643                                 but->selsta = but->selend = but->pos;
1644                                 
1645                                 /* drag text select */
1646                                 prevx= mval[0];
1647                                 while (get_mbut() & L_MOUSE) {
1648                                         uiGetMouse(mywinget(), mval);
1649                                         
1650                                         if(prevx!=mval[0]) {
1651                                                 
1652                                                 if (mval[0] > sx) selextend = EXTEND_RIGHT;
1653                                                 else if (mval[0] < sx) selextend = EXTEND_LEFT;
1654                                                 
1655                                                 ui_set_cursor_pos_edittext(but, mval[0]);
1656                                                 
1657                                                 if (selextend == EXTEND_RIGHT) but->selend = but->pos;
1658                                                 if (selextend == EXTEND_LEFT) but->selsta = but->pos;
1659                                                 
1660                                                 ui_check_but(but);
1661                                                 ui_draw_but(but);
1662                                                 ui_block_flush_back(but->block);
1663                                         }                                       
1664                                         PIL_sleep_ms(10);
1665                                 }
1666                                 dodraw= 1;
1667                         } else break;
1668                 }
1669                 else if(dev==ESCKEY) break;
1670                 else if(dev==MOUSEX) val= 0;
1671                 else if(dev==MOUSEY) val= 0;
1672
1673                 if(ascii) {
1674                         
1675                         if(len-SELWIDTH+1 <= but->max) {
1676
1677                                 /* type over the current selection */
1678                                 if (SELWIDTH > 0) {     
1679                                         len -= ui_delete_selection_edittext(but);
1680                                 }
1681                         
1682                                 /* add ascii characters */
1683                                 if(len < but->max) {
1684                                         for(x= but->max; x>but->pos; x--)
1685                                                 str[x]= str[x-1];
1686                                         str[but->pos]= ascii;
1687                                         but->pos++; 
1688                                         len++;
1689                                         str[len]= '\0';
1690                                         dodraw= 1;
1691                                 }
1692                         }
1693                 }
1694                 else if(val) {
1695                 
1696                         switch (dev) {
1697                                 
1698                         case RIGHTARROWKEY:
1699                                 /* if there's a selection */
1700                                 if (SELWIDTH > 0) {
1701                                         /* extend the selection based on the first direction taken */
1702                                         if(G.qual & LR_SHIFTKEY) {
1703                                                 if (!selextend) {
1704                                                         selextend = EXTEND_RIGHT;
1705                                                 }
1706                                                 if (selextend == EXTEND_RIGHT) {
1707                                                         but->selend++;
1708                                                         if (but->selend > len) but->selend = len;
1709                                                 } else if (selextend == EXTEND_LEFT) {
1710                                                         but->selsta++;
1711                                                         /* if the selection start has gone past the end,
1712                                                         * flip them so they're in sync again */
1713                                                         if (but->selsta == but->selend) {
1714                                                                 but->pos = but->selsta;
1715                                                                 selextend = EXTEND_RIGHT;
1716                                                         }
1717                                                 }
1718                                         } else {
1719                                                 but->selsta = but->pos = but->selend;
1720                                                 selextend = 0;
1721                                         }
1722                                 } else {
1723                                         if(G.qual & LR_SHIFTKEY) {
1724                                                 /* make a selection, starting from the cursor position */
1725                                                 but->selsta = but->pos;
1726                                                 
1727                                                 but->pos++;
1728                                                 if(but->pos>strlen(str)) but->pos= strlen(str);
1729                                                 
1730                                                 but->selend = but->pos;
1731                                         } else if(G.qual & LR_CTRLKEY) {
1732                                                 /* jump betweenn special characters (/,\,_,-, etc.),
1733                                                  * look at function test_special_char() for complete
1734                                                  * list of special character, ctr -> */
1735                                                 while(but->pos < len) {
1736                                                         but->pos++;
1737                                                         if(test_special_char(str[but->pos])) break;
1738                                                 }
1739                                         } else {
1740                                                 but->pos++;
1741                                                 if(but->pos>strlen(str)) but->pos= strlen(str);
1742                                         }
1743                                 }
1744                                 dodraw= 1;
1745                                 break;
1746                                 
1747                         case LEFTARROWKEY:
1748                                 /* if there's a selection */
1749                                 if (SELWIDTH > 0) {
1750                                         /* extend the selection based on the first direction taken */
1751                                         if(G.qual & LR_SHIFTKEY) {
1752                                                 if (!selextend) {
1753                                                         selextend = EXTEND_LEFT;
1754                                                 }
1755                                                 if (selextend == EXTEND_LEFT) {
1756                                                         but->selsta--;
1757                                                         if (but->selsta < 0) but->selsta = 0;
1758                                                 } else if (selextend == EXTEND_RIGHT) {
1759                                                         but->selend--;
1760                                                         /* if the selection start has gone past the end,
1761                                                         * flip them so they're in sync again */
1762                                                         if (but->selsta == but->selend) {
1763                                                                 but->pos = but->selsta;
1764                                                                 selextend = EXTEND_LEFT;
1765                                                         }
1766                                                 }
1767                                         } else {
1768                                                 but->pos = but->selend = but->selsta;
1769                                                 selextend = 0;
1770                                         }
1771                                 } else {
1772                                         if(G.qual & LR_SHIFTKEY) {
1773                                                 /* make a selection, starting from the cursor position */
1774                                                 but->selend = but->pos;
1775                                                 
1776                                                 but->pos--;
1777                                                 if(but->pos<0) but->pos= 0;
1778                                                 
1779                                                 but->selsta = but->pos;
1780                                         } else if(G.qual & LR_CTRLKEY) {
1781                                                 /* jump betweenn special characters (/,\,_,-, etc.),
1782                                                  * look at function test_special_char() for complete
1783                                                  * list of special character, ctr -> */
1784                                                 while(but->pos > 0){
1785                                                         but->pos--;
1786                                                         if(test_special_char(str[but->pos])) break;
1787                                                 }
1788                                         } else {
1789                                                 if(but->pos>0) but->pos--;
1790                                         }
1791                                 }
1792                                 dodraw= 1;
1793                                 break;
1794
1795                         case DOWNARROWKEY:
1796                         case ENDKEY:
1797                                 if(G.qual & LR_SHIFTKEY) {
1798                                         but->selsta = but->pos;
1799                                         but->selend = strlen(str);
1800                                         selextend = EXTEND_RIGHT;
1801                                 } else {
1802                                         but->selsta = but->selend = but->pos= strlen(str);
1803                                 }
1804                                 dodraw= 1;
1805                                 break;
1806                                 
1807                         case UPARROWKEY:
1808                         case HOMEKEY:
1809                                 if(G.qual & LR_SHIFTKEY) {
1810                                         but->selend = but->pos;
1811                                         but->selsta = 0;
1812                                         selextend = EXTEND_LEFT;
1813                                 } else {
1814                                         but->selsta = but->selend = but->pos= 0;
1815                                 }
1816                                 dodraw= 1;
1817                                 break;
1818                                 
1819                         case PADENTER:
1820                         case RETKEY:
1821                                 capturing = FALSE;
1822                                 break;
1823                                 
1824                         case DELKEY:
1825                                 if (SELWIDTH > 0) {
1826                                         len -= ui_delete_selection_edittext(but);
1827                                         
1828                                         if (len < 0) len = 0;
1829                                         dodraw=1;
1830                                 }
1831                                 else if(but->pos>=0 && but->pos<strlen(str)) {
1832                                         for(x=but->pos; x<=strlen(str); x++)
1833                                                 str[x]= str[x+1];
1834                                         str[--len]='\0';
1835                                         dodraw= 1;
1836                                 }
1837                                 break;
1838
1839                         case BACKSPACEKEY:
1840                                 if(len!=0) {
1841                                         if (SELWIDTH > 0) {
1842                                                 len -= ui_delete_selection_edittext(but);
1843                                                 
1844                                                 if (len < 0) len = 0;
1845                                                 dodraw=1;
1846                                         }
1847                                         else if(get_qual() & LR_SHIFTKEY) {
1848                                                 str[0]= 0;
1849                                                 but->pos= 0;
1850                                                 len= 0;
1851                                                 dodraw= 1;
1852                                         }
1853                                         else if(but->pos>0) {
1854                                                 for(x=but->pos; x<=strlen(str); x++)
1855                                                         str[x-1]= str[x];
1856                                                 but->pos--;
1857                                                 str[--len]='\0';
1858                                                 dodraw= 1;
1859                                         }
1860                                 } 
1861                                 break;
1862                                 
1863                         case TABKEY:
1864                                 if(but->autocomplete_func) {
1865                                         but->autocomplete_func(str, but->autofunc_arg);
1866                                         but->pos= strlen(str);
1867                                         len= but->pos;
1868                                         dodraw= 1;
1869                                 }
1870                                 else capturing= FALSE;
1871                                 
1872                                 break;
1873                         }
1874                 }
1875
1876                 
1877                 if(dodraw) {
1878                         ui_check_but(but);
1879                         ui_draw_but(but);
1880                         ui_block_flush_back(but->block);
1881                 }
1882         }
1883         
1884         if(dev==ESCKEY) strcpy(but->poin, backstr);
1885         but->pos= -1;
1886         but->flag &= ~UI_SELECT;
1887
1888         if(dev!=ESCKEY) {
1889                 /* give butfunc the original text too */
1890                 /* feature used for bone renaming, channels, etc */
1891                 if(but->func_arg2==NULL) but->func_arg2= backstr;
1892                 uibut_do_func(but);
1893         }
1894         
1895         ui_check_but(but);
1896         ui_draw_but(but);
1897         
1898         if(dev==TABKEY) addqueue(but->win, G.qual?BUT_PREV:BUT_NEXT, 1);
1899         
1900         if(dev!=ESCKEY) return but->retval;
1901         else return B_NOP;      // prevent event to be passed on
1902 }
1903
1904
1905 static int ui_act_as_text_but(uiBut *but)
1906 {
1907         void *but_func;
1908         double value;
1909         float min, max;
1910         int temp, retval, textleft;
1911         char str[UI_MAX_DRAW_STR], *point;
1912         
1913         /* this function is abused for tab-cycling */
1914         if(but->type==TEX)
1915                 return ui_do_but_TEX(but);
1916         
1917         value= ui_get_but_val(but);
1918         if( but->pointype==FLO ) {
1919                 if(but->a2) { /* amount of digits defined */
1920                         if(but->a2==1) sprintf(str, "%.1f", value);
1921                         else if(but->a2==2) sprintf(str, "%.2f", value);
1922                         else if(but->a2==3) sprintf(str, "%.3f", value);
1923                         else sprintf(str, "%.4f", value);
1924                 }
1925                 else sprintf(str, "%.3f", value);
1926         }
1927         else {
1928                 sprintf(str, "%d", (int)value);
1929         }
1930         /* store values before calling as text button */
1931         point= but->poin;
1932         but->poin= str;
1933         but_func= but->func;
1934         but->func= NULL;
1935         min= but->min;
1936         max= but->max;
1937         but->min= 0.0;
1938         but->max= 15.0;
1939         temp= but->type;
1940         but->type= TEX;
1941         textleft= but->flag & UI_TEXT_LEFT;
1942         but->flag |= UI_TEXT_LEFT;
1943         ui_check_but(but);
1944         
1945         retval= ui_do_but_TEX(but);
1946         
1947         /* restore values */
1948         but->type= temp;
1949         but->poin= point;
1950         but->func= but_func;
1951         but->min= min;
1952         but->max= max;
1953         if(textleft==0) but->flag &= ~UI_TEXT_LEFT;
1954
1955         if( but->pointype==FLO ) value= atof(str);
1956         else value= atoi(str);
1957
1958         if(value<min) value= min;
1959         if(value>max) value= max;
1960
1961         ui_set_but_val(but, value);
1962         ui_check_but(but);
1963         ui_draw_but(but);
1964         
1965         return retval;
1966 }
1967
1968 static int ui_do_but_NUM(uiBut *but)
1969 {
1970         double value;
1971         float deler, fstart, f, tempf;
1972         int lvalue, temp; /*  , firsttime=1; */
1973         short retval=0, qual, sx, mval[2], pos=0;
1974
1975         but->flag |= UI_SELECT;
1976         ui_draw_but(but);
1977         ui_block_flush_back(but->block);
1978         
1979         uiGetMouse(mywinget(), mval);
1980         value= ui_get_but_val(but);
1981         
1982         sx= mval[0];
1983         fstart= (value - but->min)/(but->max-but->min);
1984         f= fstart;
1985         
1986         temp= (int)value;
1987         tempf= value;
1988         
1989         if(get_qual() & LR_SHIFTKEY) {  /* make it textbut */
1990                 if( ui_act_as_text_but(but) ) retval= but->retval;
1991         }
1992         else {
1993                 retval= but->retval;
1994                 /* firsttime: this button can be approached with enter as well */
1995                 while (get_mbut() & L_MOUSE) {
1996                         qual= get_qual();
1997                         
1998                         deler= 500;
1999                         if( but->pointype!=FLO ) {
2000         
2001                                 if( (but->max-but->min)<100 ) deler= 200.0;
2002                                 if( (but->max-but->min)<25 ) deler= 50.0;
2003         
2004                         }
2005                         if(qual & LR_SHIFTKEY) deler*= 10.0;
2006                         if(qual & LR_ALTKEY) deler*= 20.0;
2007         
2008                         uiGetMouse(mywinget(), mval);
2009                         
2010                         if(mval[0] != sx) {
2011                         
2012                                 f+= ((float)(mval[0]-sx))/deler;
2013                                 if(f>1.0) f= 1.0;
2014                                 if(f<0.0) f= 0.0;
2015                                 sx= mval[0];
2016                                 tempf= ( but->min + f*(but->max-but->min));
2017                                 
2018                                 if( but->pointype!=FLO ) {
2019                                         
2020                                         temp= floor(tempf+.5);
2021                                         
2022                                         if(tempf==but->min || tempf==but->max);
2023                                         else if(qual & LR_CTRLKEY) {
2024                                                 if(qual & LR_SHIFTKEY) temp= 100*(temp/100);
2025                                                 else temp= 10*(temp/10);
2026                                         }
2027                                         if( temp>=but->min && temp<=but->max) {
2028                                         
2029                                                 value= ui_get_but_val(but);
2030                                                 lvalue= (int)value;
2031                                                 
2032                                                 if(temp != lvalue ) {
2033                                                         pos= 1;
2034                                                         ui_set_but_val(but, (double)temp);
2035                                                         ui_check_but(but);
2036                                                         ui_draw_but(but);
2037                                                         ui_block_flush_back(but->block);
2038
2039                                                         uibut_do_func(but);
2040                                                 }
2041                                         }
2042         
2043                                 }
2044                                 else {
2045                                         temp= 0;
2046                                         if(qual & LR_CTRLKEY) {
2047                                                 if(qual & LR_SHIFTKEY) {
2048                                                         if(tempf==but->min || tempf==but->max);
2049                                                         else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
2050                                                         else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
2051                                                         else tempf= floor(tempf);
2052                                                 }
2053                                                 else {
2054                                                         if(tempf==but->min || tempf==but->max);
2055                                                         else if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
2056                                                         else if(but->max-but->min < 21.0) tempf= floor(tempf);
2057                                                         else tempf= 10.0*floor(tempf/10.0);
2058                                                 }
2059                                         }
2060         
2061                                         if( tempf>=but->min && tempf<=but->max) {
2062                                                 value= ui_get_but_val(but);
2063                                                 
2064                                                 if(tempf != value ) {
2065                                                         pos= 1;
2066                                                         ui_set_but_val(but, tempf);
2067                                                         ui_check_but(but);
2068                                                         ui_draw_but(but);
2069                                                         ui_block_flush_back(but->block);
2070                                                 }
2071                                         }
2072         
2073                                 }
2074                         }
2075                         BIF_wait_for_statechange();
2076                 }
2077                 
2078                 /* click on the side arrows to increment/decrement, click inside
2079                 * to edit the value directly */
2080                 if(pos==0) {  /* plus 1 or minus 1 */
2081                         if( but->pointype!=FLO ) {
2082         
2083                                 if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
2084                                         temp--;
2085                                         if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
2086                                 }
2087                                 else if(sx > (but->x1 + (2*(but->x2 - but->x1)/3) + 3)) {
2088                                         temp++;
2089                                         if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
2090                                 }
2091                                 else {
2092                                         if( ui_act_as_text_but(but) ); else retval= 0;
2093                                 }
2094                         }
2095                         else {
2096                         
2097                                 if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
2098                                         tempf-= 0.01*but->a1;
2099                                         if (tempf < but->min) tempf = but->min;
2100                                         ui_set_but_val(but, tempf);
2101                                 }
2102                                 else if(sx > but->x1 + (2*((but->x2 - but->x1)/3) + 3)) {
2103                                         tempf+= 0.01*but->a1;
2104                                         if (tempf < but->min) tempf = but->min;
2105                                         ui_set_but_val(but, tempf);
2106                                 }
2107                                 else {
2108                                         if( ui_act_as_text_but(but) ); else retval= 0;
2109                                 }
2110                         }
2111                 }
2112         }
2113
2114         but->flag &= ~UI_SELECT;
2115         ui_check_but(but);
2116         ui_draw_but(but);       
2117         ui_block_flush_back(but->block);
2118         
2119         uibut_do_func(but);
2120         
2121         return retval;
2122 }
2123
2124 static int ui_do_but_TOG3(uiBut *but)
2125
2126
2127         if( but->pointype==SHO ) {
2128                 short *sp= (short *)but->poin;
2129                 
2130                 if( BTST(sp[1], but->bitnr)) {
2131                         sp[1]= BCLR(sp[1], but->bitnr);
2132                         sp[0]= BCLR(sp[0], but->bitnr);
2133                 }
2134                 else if( BTST(sp[0], but->bitnr)) {
2135                         sp[1]= BSET(sp[1], but->bitnr);
2136                 } else {
2137                         sp[0]= BSET(sp[0], but->bitnr);
2138                 }
2139         }
2140         else {
2141                 if( BTST(*(but->poin+2), but->bitnr)) {
2142                         *(but->poin+2)= BCLR(*(but->poin+2), but->bitnr);
2143                         *(but->poin)= BCLR(*(but->poin), but->bitnr);
2144                 }
2145                 else if( BTST(*(but->poin), but->bitnr)) {
2146                         *(but->poin+2)= BSET(*(but->poin+2), but->bitnr);
2147                 } else {
2148                         *(but->poin)= BSET(*(but->poin), but->bitnr);
2149                 }
2150         }
2151         
2152         ui_is_but_sel(but);
2153         ui_draw_but(but);
2154         
2155         return but->retval;
2156 }
2157
2158 static int ui_do_but_ICONROW(uiBut *but)
2159 {
2160         ListBase listb= {NULL, NULL};
2161         uiBlock *block;
2162         int a;
2163         
2164         but->flag |= UI_SELECT;
2165         ui_draw_but(but);
2166         ui_block_flush_back(but->block);        // flush because this button creates own blocks loop
2167         
2168         /* here we go! */
2169         block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
2170         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
2171         block->themecol= TH_MENU_ITEM;
2172         
2173         for(a=(int)but->min; a<=(int)but->max; a++) {
2174                 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, "");
2175         }
2176         block->direction= UI_TOP;       
2177         ui_positionblock(block, but);
2178         
2179         /* the block is made with but-win, but is handled in mainwin space...
2180            this is needs better implementation */
2181         block->win= G.curscreen->mainwin;
2182         
2183         uiDoBlocks(&listb, 0);
2184
2185         but->flag &= ~UI_SELECT;
2186         ui_check_but(but);
2187         ui_draw_but(but);       
2188         
2189         return but->retval;
2190 }
2191
2192 static int ui_do_but_ICONTEXTROW(uiBut *but)
2193 {
2194         uiBlock *block;
2195         ListBase listb={NULL, NULL};
2196         int width, a, xmax, ypos;
2197         MenuData *md;
2198
2199         but->flag |= UI_SELECT;
2200         ui_draw_but(but);
2201         ui_block_flush_back(but->block);        // flush because this button creates own blocks loop
2202
2203         block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
2204         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
2205         block->themecol= TH_MENU_ITEM;
2206
2207         md= decompose_menu_string(but->str);
2208
2209         /* size and location */
2210         /* expand menu width to fit labels */
2211         if(md->title)
2212                 width= 2*strlen(md->title)+BIF_GetStringWidth(block->curfont, md->title, (U.transopts & USER_TR_MENUS));
2213         else
2214                 width= 0;
2215
2216         for(a=0; a<md->nitems; a++) {
2217                 xmax= BIF_GetStringWidth(block->curfont, md->items[a].str, (U.transopts & USER_TR_MENUS));
2218                 if(xmax>width) width= xmax;
2219         }
2220
2221         width+= 30;
2222         if (width<50) width=50;
2223
2224         ypos = 1;
2225
2226         /* loop through the menu options and draw them out with icons & text labels */
2227         for(a=0; a<md->nitems; a++) {
2228
2229                 /* add a space if there's a separator (%l) */
2230                 if (strcmp(md->items[a].str, "%l")==0) {
2231                         ypos +=3;
2232                 }
2233                 else {
2234                         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, "");
2235                         ypos += 20;
2236                 }
2237         }
2238         
2239         if(md->title) {
2240                 uiBut *bt;
2241                 uiSetCurFont(block, block->font+1);
2242                 bt= uiDefBut(block, LABEL, 0, md->title, 0, ypos, (short)width, 19, NULL, 0.0, 0.0, 0, 0, "");
2243                 uiSetCurFont(block, block->font);
2244                 bt->flag= UI_TEXT_LEFT;
2245         }
2246         
2247         block->direction= UI_TOP;
2248         ui_positionblock(block, but);
2249
2250         /* the block is made with but-win, but is handled in mainwin space...
2251            this is needs better implementation */
2252         block->win= G.curscreen->mainwin;
2253
2254         uiBoundsBlock(block, 3);
2255
2256         uiDoBlocks(&listb, 0);
2257         
2258         menudata_free(md);
2259
2260         but->flag &= ~UI_SELECT;
2261         ui_check_but(but);
2262         ui_draw_but(but);
2263
2264         uibut_do_func(but);
2265
2266         return but->retval;
2267
2268 }
2269
2270 static int ui_do_but_IDPOIN(uiBut *but)
2271 {
2272         char str[UI_MAX_DRAW_STR];
2273         ID *id;
2274         
2275         id= *but->idpoin_idpp;
2276         if(id) strcpy(str, id->name+2);
2277         else str[0]= 0;
2278         
2279         but->type= TEX;
2280         but->poin= str;
2281         but->min= 0.0;
2282         but->max= 22.0;
2283         ui_check_but(but);
2284         ui_do_but_TEX(but);
2285         but->poin= NULL;
2286         but->type= IDPOIN;
2287         
2288         but->idpoin_func(str, but->idpoin_idpp);
2289         ui_check_but(but);
2290         ui_draw_but(but);
2291         
2292         return but->retval;
2293 }
2294
2295 static int ui_do_but_SLI(uiBut *but)
2296 {
2297         float f, fstart, tempf = 0.0, deler, value;
2298         int sx, h, temp, pos=0, lvalue, redraw;
2299         short mval[2], qual;
2300         float curmatrix[4][4];
2301
2302         value= ui_get_but_val(but);
2303         uiGetMouse(mywinget(), mval);
2304
2305         sx= mval[0];
2306         h= but->y2-but->y1;
2307         fstart= but->max-but->min;
2308         fstart= (value - but->min)/fstart;
2309         temp= 32767;
2310
2311         if( but->type==NUMSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
2312         else if( but->type==HSVSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
2313         else deler= (but->x2-but->x1- 5.0*but->aspect);
2314         
2315
2316         while (get_mbut() & L_MOUSE) {
2317         
2318                 qual= get_qual();
2319                 uiGetMouse(mywinget(), mval);
2320                 
2321                 f= (float)(mval[0]-sx)/deler +fstart;
2322                 
2323                 if (qual & LR_SHIFTKEY) {
2324                         f= (f-fstart)/10.0 + fstart;
2325                 }
2326
2327                 CLAMP(f, 0.0, 1.0);
2328                 tempf= but->min+f*(but->max-but->min);          
2329                 temp= floor(tempf+.5);
2330
2331                 if(qual & LR_CTRLKEY) {
2332                         if(tempf==but->min || tempf==but->max);
2333                         else if( but->pointype==FLO ) {
2334
2335                                 if(qual & LR_SHIFTKEY) {
2336                                         if(tempf==but->min || tempf==but->max);
2337                                         else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
2338                                         else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
2339                                         else tempf= floor(tempf);
2340                                 }
2341                                 else {
2342                                         if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
2343                                         else if(but->max-but->min < 21.0) tempf= floor(tempf);
2344                                         else tempf= 10.0*floor(tempf/10.0);
2345                                 }
2346                         }
2347                         else {
2348                                 temp= 10*(temp/10);
2349                                 tempf= temp;
2350                         }
2351                 } 
2352         
2353                 value= ui_get_but_val(but);
2354                 lvalue= floor(value+0.5);
2355                 
2356                 if( but->pointype!=FLO )
2357                         redraw= (temp != lvalue);
2358                 else
2359                         redraw= (tempf != value);
2360
2361                 if (redraw) {
2362                         pos= 1;
2363                         ui_set_but_val(but, tempf);
2364                         ui_check_but(but);
2365                         ui_draw_but(but);
2366                         ui_block_flush_back(but->block);
2367                         
2368                         if(but->a1) {   /* color number */
2369                                 uiBut *bt= but->prev;
2370                                 while(bt) {
2371                                         if(bt->a2 == but->a1) ui_draw_but(bt);
2372                                         bt= bt->prev;
2373                                 }
2374                                 bt= but->next;
2375                                 while(bt) {
2376                                         if(bt->a2 == but->a1) ui_draw_but(bt);
2377                                         bt= bt->next;
2378                                 }
2379                         }
2380                         /* save current window matrix (global UIwinmat)
2381                            because button callback function MIGHT change it
2382                            - which has until now occured through the Python API
2383                         */
2384                         Mat4CpyMat4(curmatrix, UIwinmat);
2385                         uibut_do_func(but);
2386                         Mat4CpyMat4(UIwinmat, curmatrix);
2387                 } 
2388                 else BIF_wait_for_statechange();
2389         }
2390
2391         
2392         if(temp!=32767 && pos==0) {  /* plus 1 or minus 1 */
2393                 
2394                 if( but->type==SLI) f= (float)(mval[0]-but->x1)/(but->x2-but->x1-h);
2395                 else f= (float)(mval[0]- (but->x1+but->x2)/2)/( (but->x2-but->x1)/2 - h);
2396                 
2397                 f= but->min+f*(but->max-but->min);
2398                 
2399                 if( but->pointype!=FLO ) {
2400
2401                         if(f<temp) temp--;
2402                         else temp++;
2403                         if( temp>=but->min && temp<=but->max)
2404                                 ui_set_but_val(but, (float)temp);
2405                 
2406                 } 
2407                 else {
2408
2409                         if(f<tempf) tempf-=.01;
2410                         else tempf+=.01;
2411                         if( tempf>=but->min && tempf<=but->max)
2412                                 ui_set_but_val(but, tempf);
2413
2414                 }
2415                 uibut_do_func(but);
2416         }
2417         ui_check_but(but);
2418         ui_draw_but(but);
2419         ui_block_flush_back(but->block);
2420         
2421         return but->retval;
2422 }
2423
2424 static int ui_do_but_NUMSLI(uiBut *but)
2425 {
2426         short mval[2];
2427
2428         /* first define if it's a slider or textbut */
2429         uiGetMouse(mywinget(), mval);
2430         
2431         if(mval[0]>= -6+(but->x1+but->x2)/2 ) { /* slider */
2432                 but->flag |= UI_SELECT;
2433                 ui_draw_but(but);
2434                 ui_do_but_SLI(but);
2435                 but->flag &= ~UI_SELECT;
2436         }
2437         else {
2438                 ui_act_as_text_but(but);
2439                 uibut_do_func(but);     // this is done in ui_do_but_SLI() not in ui_act_as_text_but()
2440         }
2441
2442         while(get_mbut() & L_MOUSE) BIF_wait_for_statechange();
2443         
2444         ui_draw_but(but);
2445         
2446         /* hsv patch */
2447         if(but->type==HSVSLI) {
2448         
2449                 if(but->str[0]=='H') {
2450                         ui_draw_but(but->next);
2451                         ui_draw_but(but->next->next);
2452                 } 
2453                 else if(but->str[0]=='S') {
2454                         ui_draw_but(but->next);
2455                         ui_draw_but(but->prev);
2456                 } 
2457                 else if(but->str[0]=='V') {
2458                         ui_draw_but(but->prev);
2459                         ui_draw_but(but->prev->prev);
2460                 }
2461         }
2462         
2463         return but->retval;
2464 }
2465
2466 /* event denotes if we make first item active or not */
2467 static uiBlock *ui_do_but_BLOCK(uiBut *but, int event)
2468 {
2469         uiBlock *block;
2470         uiBut *bt;
2471         
2472         but->flag |= UI_SELECT;
2473         ui_draw_but(but);       
2474
2475         block= but->block_func(but->poin);
2476         block->parent= but->block;      /* allows checking for nested pulldowns */
2477
2478         block->xofs = -2;       /* for proper alignment */
2479         
2480         /* only used for automatic toolbox, so can set the shift flag */
2481         if(but->flag & UI_MAKE_TOP) {
2482                 block->direction= UI_TOP|UI_SHIFT_FLIPPED;
2483                 uiBlockFlipOrder(block);
2484         }
2485         if(but->flag & UI_MAKE_DOWN) block->direction= UI_DOWN|UI_SHIFT_FLIPPED;
2486         if(but->flag & UI_MAKE_LEFT) block->direction |= UI_LEFT;
2487         if(but->flag & UI_MAKE_RIGHT) block->direction |= UI_RIGHT;
2488         
2489         ui_positionblock(block, but);
2490         block->flag |= UI_BLOCK_LOOP;
2491         
2492         /* blocks can come (and get scaled) from a normal window, now we go to screenspace */
2493         block->win= G.curscreen->mainwin;
2494         for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
2495         bwin_getsinglematrix(block->win, block->winmat);
2496         
2497         /* postpone draw, this will cause a new window matrix, first finish all other buttons */
2498         block->flag |= UI_BLOCK_REDRAW;
2499         
2500         if(event!=MOUSEX && event!=MOUSEY && event!=LEFTMOUSE && but->type==BLOCK) {
2501                 bt= ui_but_first(block);
2502                 if(bt) bt->flag |= UI_ACTIVE;
2503         }
2504         
2505         but->flag &= ~UI_SELECT;
2506         uibut_do_func(but);
2507         
2508         if(but->retval)
2509                 addqueue(curarea->win, UI_BUT_EVENT, (short)but->retval);
2510         
2511         return block;
2512 }
2513
2514 static int ui_do_but_BUTM(uiBut *but)
2515 {
2516
2517         ui_set_but_val(but, but->min);
2518         UIafterfunc= but->butm_func;
2519         UIafterfunc_arg= but->butm_func_arg;
2520         UIafterval= but->a2;
2521         
2522         return but->retval;
2523 }
2524
2525 static int ui_do_but_LABEL(uiBut *but)
2526 {
2527         uibut_do_func(but);
2528         return but->retval;
2529 }
2530
2531 static uiBut *ui_get_valid_link_button(uiBlock *block, uiBut *but, short *mval)
2532 {
2533         uiBut *bt;
2534         
2535                 /* find button to link to */
2536         for (bt= block->buttons.first; bt; bt= bt->next)
2537                 if(bt!=but && uibut_contains_pt(bt, mval))
2538                         break;
2539
2540         if (bt) {
2541                 if (but->type==LINK && bt->type==INLINK) {
2542                         if( but->link->tocode == (int)bt->min ) {
2543                                 return bt;
2544                         }
2545                 }
2546                 else if(but->type==INLINK && bt->type==LINK) {
2547                         if( bt->link->tocode == (int)but->min ) {
2548                                 return bt;
2549                         }
2550                 }
2551         }
2552
2553         return NULL;
2554 }
2555
2556 static int ui_is_a_link(uiBut *from, uiBut *to)
2557 {
2558         uiLinkLine *line;
2559         uiLink *link;
2560         
2561         link= from->link;
2562         if(link) {
2563                 line= link->lines.first;
2564                 while(line) {
2565                         if(line->from==from && line->to==to) return 1;
2566                         line= line->next;
2567                 }
2568         }
2569         return 0;
2570 }
2571
2572 static uiBut *ui_find_inlink(uiBlock *block, void *poin)
2573 {
2574         uiBut *but;
2575         
2576         but= block->buttons.first;
2577         while(but) {
2578                 if(but->type==INLINK) {
2579                         if(but->poin == poin) return but;
2580                 }
2581                 but= but->next;
2582         }
2583         return NULL;
2584 }
2585
2586 static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt)
2587 {
2588         uiLinkLine *line;
2589         
2590         line= MEM_callocN(sizeof(uiLinkLine), "linkline");
2591         BLI_addtail(listb, line);
2592         line->from= but;
2593         line->to= bt;
2594 }
2595
2596
2597 void uiComposeLinks(uiBlock *block)
2598 {
2599         uiBut *but, *bt;
2600         uiLink *link;
2601         void ***ppoin;
2602         int a;
2603         
2604         but= block->buttons.first;
2605         while(but) {
2606                 if(but->type==LINK) {
2607                         link= but->link;
2608                         
2609                         /* for all pointers in the array */
2610                         if(link) {
2611                                 if(link->ppoin) {
2612                                         ppoin= link->ppoin;
2613                                         for(a=0; a < *(link->totlink); a++) {
2614                                                 bt= ui_find_inlink(block, (*ppoin)[a] );
2615                                                 if(bt) {
2616                                                         ui_add_link_line(&link->lines, but, bt);
2617                                                 }
2618                                         }
2619                                 }
2620                                 else if(link->poin) {
2621                                         bt= ui_find_inlink(block, *(link->poin) );
2622                                         if(bt) {
2623                                                 ui_add_link_line(&link->lines, but, bt);
2624                                         }
2625                                 }
2626                         }
2627                 }
2628                 but= but->next;
2629         }
2630 }
2631
2632 static void ui_add_link(uiBut *from, uiBut *to)
2633 {
2634         /* in 'from' we have to add a link to 'to' */
2635         uiLink *link;
2636         void **oldppoin;
2637         int a;
2638         
2639         if(ui_is_a_link(from, to)) {
2640                 printf("already exists\n");
2641                 return;
2642         }
2643         
2644         link= from->link;
2645
2646         /* are there more pointers allowed? */
2647         if(link->ppoin) {
2648                 oldppoin= *(link->ppoin);
2649                 
2650                 (*(link->totlink))++;
2651                 *(link->ppoin)= MEM_callocN( *(link->totlink)*sizeof(void *), "new link");
2652
2653                 for(a=0; a< (*(link->totlink))-1; a++) {
2654                         (*(link->ppoin))[a]= oldppoin[a];
2655                 }
2656                 (*(link->ppoin))[a]= to->poin;
2657                 
2658                 if(oldppoin) MEM_freeN(oldppoin);
2659         }
2660         else {
2661                 *(link->poin)= to->poin;
2662         }
2663         
2664 }
2665
2666 static int ui_do_but_LINK(uiBlock *block, uiBut *but)
2667 {
2668         /* 
2669          * This button only visualizes, the dobutton mode
2670          * can add a new link, but then the whole system
2671          * should be redrawn/initialized. 
2672          * 
2673          */
2674         uiBut *bt=0, *bto=NULL;
2675         short sval[2], mval[2], mvalo[2], first= 1;
2676
2677         uiGetMouse(curarea->win, sval);
2678         mvalo[0]= sval[0];
2679         mvalo[1]= sval[1];
2680         
2681         while (get_mbut() & L_MOUSE) {
2682                 uiGetMouse(curarea->win, mval);
2683
2684                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || first) {                   
2685                                 /* clear completely, because of drawbuttons */
2686                         bt= ui_get_valid_link_button(block, but, mval);
2687                         if(bt) {
2688                                 bt->flag |= UI_ACTIVE;
2689                                 ui_draw_but(bt);
2690                         }
2691                         if(bto && bto!=bt) {
2692                                 bto->flag &= ~UI_ACTIVE;
2693                                 ui_draw_but(bto);
2694                         }
2695                         bto= bt;
2696
2697                         if (!first) {
2698                                 glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
2699                         }
2700                         glutil_draw_front_xor_line(sval[0], sval[1], mval[0], mval[1]);
2701
2702                         mvalo[0]= mval[0];
2703                         mvalo[1]= mval[1];
2704
2705                         first= 0;
2706                 }
2707                 else BIF_wait_for_statechange();                
2708         }
2709         
2710         if (!first) {
2711                 glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
2712         }
2713
2714         if(bt) {
2715                 if(but->type==LINK) ui_add_link(but, bt);
2716                 else ui_add_link(bt, but);
2717
2718                 scrarea_queue_winredraw(curarea);
2719         }
2720
2721         return 0;
2722 }
2723
2724 /* picker sizes S hsize, F full size, D spacer, B button/pallette height  */
2725 #define SPICK   110.0
2726 #define FPICK   180.0
2727 #define DPICK   6.0
2728 #define BPICK   24.0
2729
2730 #define UI_PALETTE_TOT 16
2731 /* note; in tot+1 the old color is stored */
2732 static float palette[UI_PALETTE_TOT+1][3]= {
2733 {0.93, 0.83, 0.81}, {0.88, 0.89, 0.73}, {0.69, 0.81, 0.57}, {0.51, 0.76, 0.64}, 
2734 {0.37, 0.56, 0.61}, {0.33, 0.29, 0.55}, {0.46, 0.21, 0.51}, {0.40, 0.12, 0.18}, 
2735 {1.0, 1.0, 1.0}, {0.85, 0.85, 0.85}, {0.7, 0.7, 0.7}, {0.56, 0.56, 0.56}, 
2736 {0.42, 0.42, 0.42}, {0.28, 0.28, 0.28}, {0.14, 0.14, 0.14}, {0.0, 0.0, 0.0}
2737 };  
2738
2739 /* for picker, while editing hsv */
2740 static void ui_set_but_hsv(uiBut *but)
2741 {
2742         float col[3];
2743         
2744         hsv_to_rgb(but->hsv[0], but->hsv[1], but->hsv[2], col, col+1, col+2);
2745         ui_set_but_vectorf(but, col);
2746 }
2747
2748 static void update_picker_hex(uiBlock *block, float *rgb)
2749 {
2750         uiBut *bt;
2751         char col[16];
2752         
2753         sprintf(col, "%02X%02X%02X", (unsigned int)(rgb[0]*255.0), (unsigned int)(rgb[1]*255.0), (unsigned int)(rgb[2]*255.0));
2754         
2755         // this updates button strings, is hackish... but button pointers are on stack of caller function
2756
2757         for(bt= block->buttons.first; bt; bt= bt->next) {
2758                 if(strcmp(bt->str, "Hex: ")==0) {
2759                         strcpy(bt->poin, col);
2760                         ui_check_but(bt);
2761                         break;
2762                 }
2763         }
2764 }
2765
2766 static void update_picker_buts_hsv(uiBlock *block, float *hsv, char *poin)
2767 {
2768         uiBut *bt;
2769         float r, g, b;
2770         float rgb[3];
2771         
2772         // this updates button strings, is hackish... but button pointers are on stack of caller function
2773         hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r, &g, &b);
2774         
2775         rgb[0] = r; rgb[1] = g; rgb[2] = b;
2776         update_picker_hex(block, rgb);
2777
2778         for(bt= block->buttons.first; bt; bt= bt->next) {
2779                 if(bt->poin == poin) {
2780                         if(bt->type==HSVCUBE) {
2781                                 VECCOPY(bt->hsv, hsv);
2782                                 ui_set_but_hsv(bt);
2783                         }
2784                         else if(bt->str[1]==' ') {
2785                                 if(bt->str[0]=='R') {
2786                                         ui_set_but_val(bt, r);
2787                                         ui_check_but(bt);
2788                                 }
2789                                 else if(bt->str[0]=='G') {
2790                                         ui_set_but_val(bt, g);
2791                                         ui_check_but(bt);
2792                                 }
2793                                 else if(bt->str[0]=='B') {
2794                                         ui_set_but_val(bt, b);
2795                                         ui_check_but(bt);
2796                                 }
2797                                 else if(bt->str[0]=='H') {
2798                                         ui_set_but_val(bt, hsv[0]);
2799                                         ui_check_but(bt);
2800                                 }
2801                                 else if(bt->str[0]=='S') {
2802                                         ui_set_but_val(bt, hsv[1]);
2803                                         ui_check_but(bt);
2804                                 }
2805                                 else if(bt->str[0]=='V') {
2806                                         ui_set_but_val(bt, hsv[2]);
2807                                         ui_check_but(bt);
2808                                 }
2809                         }
2810                 }
2811         }
2812 }
2813
2814 static void update_picker_buts_hex(uiBlock *block, char *hexcol)
2815 {
2816         uiBut *bt;
2817         float r=0, g=0, b=0;
2818         float h, s, v;
2819         
2820         
2821         // this updates button strings, is hackish... but button pointers are on stack of caller function
2822         hex_to_rgb(hexcol, &r, &g, &b);
2823         rgb_to_hsv(r, g, b, &h, &s, &v);
2824
2825         for(bt= block->buttons.first; bt; bt= bt->next) {
2826                 if(bt->type==HSVCUBE) {
2827                         bt->hsv[0] = h;
2828                         bt->hsv[1] = s;                 
2829                         bt->hsv[2] = v;
2830                         ui_set_but_hsv(bt);
2831                 }
2832                 else if(bt->str[1]==' ') {
2833                         if(bt->str[0]=='R') {
2834                                 ui_set_but_val(bt, r);
2835                                 ui_check_but(bt);
2836                         }
2837                         else if(bt->str[0]=='G') {
2838                                 ui_set_but_val(bt, g);
2839                                 ui_check_but(bt);
2840                         }
2841                         else if(bt->str[0]=='B') {
2842                                 ui_set_but_val(bt, b);
2843                                 ui_check_but(bt);
2844                         }
2845                         else if(bt->str[0]=='H') {
2846                                 ui_set_but_val(bt, h);
2847                                 ui_check_but(bt);
2848                         }
2849                         else if(bt->str[0]=='S') {
2850                                 ui_set_but_val(bt, s);
2851                                 ui_check_but(bt);
2852                         }
2853                         else if(bt->str[0]=='V') {
2854                                 ui_set_but_val(bt, v);
2855                                 ui_check_but(bt);
2856                         }
2857                 }
2858         }
2859 }
2860
2861
2862
2863 /* bt1 is palette but, col1 is original color */
2864 /* callback to copy from/to palette */
2865 static void do_palette_cb(void *bt1, void *col1)
2866 {
2867         uiBut *but1= (uiBut *)bt1;
2868         uiBut *but;
2869         float *col= (float *)col1;
2870         float *fp, hsv[3];
2871         
2872         fp= (float *)but1->poin;
2873         
2874         if( (get_qual() & LR_CTRLKEY) ) {
2875                 VECCOPY(fp, col);
2876         }
2877         else {
2878                 VECCOPY(col, fp);
2879         }
2880         
2881         rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
2882         update_picker_buts_hsv(but1->block, hsv, but1->poin);
2883         update_picker_hex(but1->block, col);
2884         
2885         for (but= but1->block->buttons.first; but; but= but->next) {
2886                 ui_draw_but(but);
2887         }
2888         but= but1->block->buttons.first;
2889         ui_block_flush_back(but->block);
2890 }
2891
2892 /* bt1 is num but, col1 is pointer to original color */
2893 /* callback to handle changes in num-buts in picker */
2894 static void do_palette1_cb(void *bt1, void *hsv1)
2895 {
2896         uiBut *but1= (uiBut *)bt1;
2897         uiBut *but;
2898         float *hsv= (float *)hsv1;
2899         float *fp= NULL;
2900         
2901         if(but1->str[0]=='R') fp= (float *)but1->poin;
2902         else if(but1->str[0]=='G') fp= ((float *)but1->poin)-1;
2903         else if(but1->str[0]=='B') fp= ((float *)but1->poin)-2;
2904         
2905         if(fp) {
2906                 rgb_to_hsv(fp[0], fp[1], fp[2], hsv, hsv+1, hsv+2);
2907         }
2908
2909         update_picker_buts_hsv(but1->block, hsv, but1->poin);
2910         if (fp) update_picker_hex(but1->block, fp);
2911         
2912         for (but= but1->block->buttons.first; but; but= but->next) {
2913                 ui_draw_but(but);
2914         }
2915         
2916         but= but1->block->buttons.first;
2917         ui_block_flush_back(but->block);
2918
2919 }
2920
2921 static void do_palette_hex_cb(void *bt1, void *hexcl)
2922 {
2923         uiBut *but1= (uiBut *)bt1;
2924         uiBut *but;
2925         char *hexcol= (char *)hexcl;
2926         
2927         update_picker_buts_hex(but1->block, hexcol);    
2928         
2929         for (but= but1->block->buttons.first; but; but= but->next) {
2930                 ui_draw_but(but);
2931         }
2932         
2933         but= but1->block->buttons.first;
2934         ui_block_flush_back(but->block);
2935
2936 }
2937
2938 /* color picker, Gimp version. mode: 'f' = floating panel, 'p' =  popup */
2939 /* col = read/write to, hsv/old/hexcol = memory for temporal use */
2940 void uiBlockPickerButtons(uiBlock *block, float *col, float *hsv, float *old, char *hexcol, char mode, short retval)
2941 {
2942         uiBut *bt;
2943         float h, offs;
2944         int a;
2945
2946         VECCOPY(old, col);      // old color stored there, for palette_cb to work
2947         
2948         // the cube intersection
2949         bt= uiDefButF(block, HSVCUBE, retval, "",       0,DPICK+BPICK,FPICK,FPICK, col, 0.0, 0.0, 2, 0, "");
2950         uiButSetFlag(bt, UI_NO_HILITE);
2951
2952         bt= uiDefButF(block, HSVCUBE, retval, "",       0,0,FPICK,BPICK, col, 0.0, 0.0, 3, 0, "");
2953         uiButSetFlag(bt, UI_NO_HILITE);
2954
2955         // palette
2956         
2957         uiBlockSetEmboss(block, UI_EMBOSSP);
2958         
2959         bt=uiDefButF(block, COL, retval, "",            FPICK+DPICK, 0, BPICK,BPICK, old, 0.0, 0.0, -1, 0, "Old color, click to restore");
2960         uiButSetFunc(bt, do_palette_cb, bt, col);
2961         uiDefButF(block, COL, retval, "",               FPICK+DPICK, BPICK+DPICK, BPICK,60-BPICK-DPICK, col, 0.0, 0.0, -1, 0, "Active color");
2962
2963         h= (DPICK+BPICK+FPICK-64)/(UI_PALETTE_TOT/2.0);
2964         uiBlockBeginAlign(block);
2965         for(a= -1+UI_PALETTE_TOT/2; a>=0; a--) {
2966                 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");
2967                 uiButSetFunc(bt, do_palette_cb, bt, col);
2968                 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");               
2969                 uiButSetFunc(bt, do_palette_cb, bt, col);
2970         }
2971         uiBlockEndAlign(block);
2972         
2973         uiBlockSetEmboss(block, UI_EMBOSS);
2974
2975         // buttons
2976         rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
2977         sprintf(hexcol, "%02X%02X%02X", (unsigned int)(col[0]*255.0), (unsigned int)(col[1]*255.0), (unsigned int)(col[2]*255.0));      
2978
2979         offs= FPICK+2*DPICK+BPICK;
2980
2981         bt= uiDefBut(block, TEX, retval, "Hex: ", offs, 140, 140, 20, hexcol, 0, 8, 0, 0, "Hex triplet for colour (#RRGGBB)");
2982         uiButSetFunc(bt, do_palette_hex_cb, bt, hexcol);
2983
2984         uiBlockBeginAlign(block);
2985         bt= uiDefButF(block, NUMSLI, retval, "R ",      offs, 110, 140,20, col, 0.0, 1.0, 10, 2, "");
2986         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2987         bt= uiDefButF(block, NUMSLI, retval, "G ",      offs, 90, 140,20, col+1, 0.0, 1.0, 10, 2, "");
2988         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2989         bt= uiDefButF(block, NUMSLI, retval, "B ",      offs, 70, 140,20, col+2, 0.0, 1.0, 10, 2, "");
2990         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2991         
2992         uiBlockBeginAlign(block);
2993         bt= uiDefButF(block, NUMSLI, retval, "H ",      offs, 40, 140,20, hsv, 0.0, 1.0, 10, 2, "");
2994         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2995         bt= uiDefButF(block, NUMSLI, retval, "S ",      offs, 20, 140,20, hsv+1, 0.0, 1.0, 10, 2, "");
2996         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2997         bt= uiDefButF(block, NUMSLI, retval, "V ",      offs, 0, 140,20, hsv+2, 0.0, 1.0, 10, 2, "");
2998         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2999         uiBlockEndAlign(block);
3000 }
3001
3002
3003 static int ui_do_but_COL(uiBut *but)
3004 {
3005         uiBlock *block;
3006         uiBut *bt;
3007         ListBase listb={NULL, NULL};
3008         float hsv[3], old[3], *poin= NULL, colstore[3];
3009         static char hexcol[128];
3010         short event;
3011         
3012         // signal to prevent calling up color picker
3013         if(but->a1 == -1) {
3014                 uibut_do_func(but);
3015                 return but->retval;
3016         }
3017         
3018         // enable char button too, use temporal colstore for color
3019         if(but->pointype!=FLO) {
3020                 if(but->pointype==CHA) {
3021                         ui_get_but_vectorf(but, colstore);
3022                         poin= colstore;
3023                 }
3024                 else return but->retval;
3025         }
3026         else poin= (float *)but->poin;
3027         
3028         block= uiNewBlock(&listb, "colorpicker", UI_EMBOSS, UI_HELV, but->win);
3029         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW;
3030         block->themecol= TH_BUT_NUM;
3031         
3032         uiBlockPickerButtons(block, poin, hsv, old, hexcol, 'p', 0);
3033
3034         /* and lets go */
3035         block->direction= UI_TOP;
3036         ui_positionblock(block, but);
3037         uiBoundsBlock(block, 3);
3038         
3039         /* blocks can come from a normal window, but we go to screenspace */
3040         block->win= G.curscreen->mainwin;
3041         for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
3042         bwin_getsinglematrix(block->win, block->winmat);
3043
3044         event= uiDoBlocks(&listb, 0);
3045         
3046         if(but->pointype==CHA) ui_set_but_vectorf(but, colstore);
3047         
3048         uibut_do_func(but);
3049         return but->retval;
3050
3051 }
3052
3053 static int ui_do_but_HSVCUBE(uiBut *but)
3054 {
3055         uiBut *bt;
3056         float x, y;
3057         short mval[2], mvalo[2];
3058         
3059         mvalo[0]= mvalo[1]= -32000;
3060         
3061         /* we work on persistant hsv, to prevent it being converted back and forth all the time */
3062                            
3063         while (get_mbut() & L_MOUSE) {
3064                 
3065                 uiGetMouse(mywinget(), mval);
3066
3067                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {                    
3068                         mvalo[0]= mval[0];
3069                         mvalo[1]= mval[1];
3070                         
3071                         /* relative position within box */
3072                         x= ((float)mval[0]-but->x1)/(but->x2-but->x1);
3073                         y= ((float)mval[1]-but->y1)/(but->y2-but->y1);
3074                         CLAMP(x, 0.0, 1.0);
3075                         CLAMP(y, 0.0, 1.0);
3076                         
3077                         if(but->a1==0) {
3078                                 but->hsv[0]= x; 
3079                                 but->hsv[2]= y; 
3080                                 // hsv_to_rgb(x, s, y, col, col+1, col+2);
3081                         }
3082                         else if(but->a1==1) {
3083                                 but->hsv[0]= x;                                 
3084                                 but->hsv[1]= y;                                 
3085                                 // hsv_to_rgb(x, y, v, col, col+1, col+2);
3086                         }
3087                         else if(but->a1==2) {
3088                                 but->hsv[2]= x; 
3089                                 but->hsv[1]= y; 
3090                                 // hsv_to_rgb(h, y, x, col, col+1, col+2);
3091                         }
3092                         else {
3093                                 but->hsv[0]= x; 
3094                                 // hsv_to_rgb(x, s, v, col, col+1, col+2);
3095                         }
3096         
3097                         ui_set_but_hsv(but);    // converts to rgb
3098                         
3099                         // update button values and strings
3100                         update_picker_buts_hsv(but->block, but->hsv, but->poin);
3101 //                      update_picker_buts_hex(but->block, but->hsv);                   
3102
3103                         /* we redraw the entire block */
3104                         for (bt= but->block->buttons.first; bt; bt= bt->next) {
3105                                 if(but->poin == bt->poin) VECCOPY(bt->hsv, but->hsv);
3106                                 ui_draw_but(bt);
3107                         }
3108                         ui_block_flush_back(but->block);
3109                 }
3110                 else BIF_wait_for_statechange();
3111         }
3112
3113         return but->retval;
3114 }
3115
3116 #ifdef INTERNATIONAL
3117
3118 static int ui_do_but_CHARTAB(uiBut *but)
3119 {
3120         /* Variables */
3121         short mval[2];
3122         float sx, sy, ex, ey;
3123         float width, height;
3124         float butw, buth;
3125         int x, y, cs, che;
3126
3127         /* Check the position */
3128         uiGetMouse(mywinget(), mval);
3129
3130         /* Calculate the size of the button */
3131         width = abs(but->x2 - but->x1);
3132         height = abs(but->y2 - but->y1);
3133
3134         butw = floor(width / 12);
3135         buth = floor(height / 6);
3136
3137         /* Initialize variables */
3138         sx = but->x1;
3139         ex = but->x1 + butw;
3140         sy = but->y1 + height - buth;
3141         ey = but->y1 + height;
3142
3143         cs = G.charstart;
3144
3145         /* And the character is */
3146         x = (int) ((mval[0] / butw) - 0.5);
3147         y = (int) (6 - ((mval[1] / buth) - 0.5));
3148
3149         che = cs + (y*12) + x;
3150
3151         if(che > G.charmax)
3152                 che = 0;
3153
3154         if(G.obedit)
3155         {
3156                 do_textedit(0,0,che);
3157         }
3158
3159         return but->retval;
3160 }