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