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