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