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