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