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