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