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