A couple of smaller fixes;
[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         /* no draw of button now, for floating panels the matrix now is invalid...
1214            the button still is active, and will be redrawn in main loop to de-activate it */
1215         
1216         uibut_do_func(but);
1217
1218         return event;   
1219 }
1220
1221
1222
1223 /* ************* EVENTS ************* */
1224
1225 void uiGetMouse(int win, short *adr)
1226 {
1227         int x, y;
1228         float xwin, ywin;
1229         
1230         getmouseco_sc(adr);
1231         if (win == G.curscreen->mainwin) return;
1232         
1233         bwin_getsuborigin(win, &x, &y);
1234
1235         adr[0]-= x;
1236         adr[1]-= y;
1237
1238         xwin= adr[0];
1239         ywin= adr[1];
1240
1241         ui_window_to_graphics(win, &xwin, &ywin);
1242
1243         adr[0]= (short)(xwin+0.5);
1244         adr[1]= (short)(ywin+0.5);
1245 }
1246
1247 static void ui_is_but_sel(uiBut *but)
1248 {
1249         double value;
1250         int lvalue;
1251         short push=0, true=1;
1252
1253         value= ui_get_but_val(but);
1254
1255         if( but->type==TOGN ) true= 0;
1256
1257         if( but->bit ) {
1258                 lvalue= (int)value;
1259                 if( BTST(lvalue, (but->bitnr)) ) push= true;
1260                 else push= !true;
1261         }
1262         else {
1263                 switch(but->type) {
1264                 case BUT:
1265                         push= 0;
1266                         break;
1267                 case KEYEVT:
1268                         if (value==-1) push= 1;
1269                         break;
1270                 case TOG:
1271                 case TOGR:
1272                 case TOG3:
1273                 case ICONTOG:
1274                         if(value!=but->min) push= 1;
1275                         break;
1276                 case TOGN:
1277                         if(value==0.0) push= 1;
1278                         break;
1279                 case ROW:
1280                         if(value == but->max) push= 1;
1281                         break;
1282                 case COL:
1283                         push= 1;
1284                         break;
1285                 default:
1286                         push= 2;
1287                         break;
1288                 }
1289         }
1290         
1291         if(push==2);
1292         else if(push==1) but->flag |= UI_SELECT;
1293         else but->flag &= ~UI_SELECT;
1294 }
1295
1296 static int ui_do_but_BUT(uiBut *but)
1297 {
1298         int activated;
1299         
1300         do {
1301                 int oflag= but->flag;
1302                 short mval[2];
1303                         
1304                 uiGetMouse(mywinget(), mval);
1305
1306                 if (uibut_contains_pt(but, mval))
1307                         but->flag |= UI_SELECT;
1308                 else
1309                         but->flag &= ~UI_SELECT;
1310
1311                 if (but->flag != oflag) {
1312                         ui_draw_but(but);
1313                         ui_block_flush_back(but->block);
1314                 }
1315                 
1316                 PIL_sleep_ms(10);
1317         } while (get_mbut() & L_MOUSE);
1318
1319         activated= (but->flag & UI_SELECT);
1320
1321         if(activated) {
1322                 uibut_do_func(but);
1323         }
1324         
1325         but->flag &= ~UI_SELECT;
1326         ui_draw_but(but);
1327
1328         return activated?but->retval:0;
1329 }
1330
1331 static int ui_do_but_KEYEVT(uiBut *but)
1332 {
1333         unsigned short event= 0;
1334         short val;
1335
1336                 /* flag for ui_check_but */
1337         ui_set_but_val(but, -1);
1338         ui_check_but(but);
1339         ui_draw_but(but);
1340         ui_block_flush_back(but->block);
1341
1342         do {
1343                 event= extern_qread(&val);
1344         } while (!event || !val || ELEM(event, MOUSEX, MOUSEY));
1345
1346         if (!key_event_to_string(event)[0]) event= 0;
1347
1348         ui_set_but_val(but, (double) event);
1349         ui_check_but(but);
1350         ui_draw_but(but);
1351         
1352         return (event!=0);
1353 }
1354
1355 static int ui_do_but_TOG(uiBlock *block, uiBut *but)
1356 {
1357         uiBut *bt;
1358         double value;
1359         int w, lvalue, push;
1360         
1361         value= ui_get_but_val(but);
1362         lvalue= (int)value;
1363         
1364         if(but->bit) {
1365                 w= BTST(lvalue, but->bitnr);
1366                 if(w) lvalue = BCLR(lvalue, but->bitnr);
1367                 else lvalue = BSET(lvalue, but->bitnr);
1368                 
1369                 if(but->type==TOGR) {
1370                         if( (get_qual() & LR_SHIFTKEY)==0 ) {
1371                                 lvalue= 1<<(but->bitnr);
1372         
1373                                 ui_set_but_val(but, (double)lvalue);
1374
1375                                 bt= block->buttons.first;
1376                                 while(bt) {
1377                                         if( bt!=but && bt->poin==but->poin ) {
1378                                                 ui_is_but_sel(bt);
1379                                                 ui_draw_but(bt);
1380                                         }
1381                                         bt= bt->next;
1382                                 }
1383                         }
1384                         else {
1385                                 if(lvalue==0) lvalue= 1<<(but->bitnr);
1386                         }
1387                 }
1388                 ui_set_but_val(but, (double)lvalue);
1389                 if(but->type==ICONTOG) ui_check_but(but);
1390                 // no frontbuffer draw for this one
1391                 if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
1392         }
1393         else {
1394                 
1395                 if(value==0.0) push= 1; 
1396                 else push= 0;
1397                 
1398                 if(but->type==TOGN) push= !push;
1399                 ui_set_but_val(but, (double)push);
1400                 if(but->type==ICONTOG) ui_check_but(but);               
1401                 // no frontbuffer draw for this one
1402                 if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
1403         }
1404         
1405         /* no while loop...this button is used for viewmove */
1406
1407         uibut_do_func(but);
1408
1409         return but->retval;
1410 }
1411
1412 static int ui_do_but_ROW(uiBlock *block, uiBut *but)
1413 {
1414         uiBut *bt;
1415         
1416         ui_set_but_val(but, but->max);
1417         ui_draw_but(but);
1418
1419         bt= block->buttons.first;
1420         while(bt) {
1421                 if( bt!=but && bt->type==ROW ) {
1422                         if(bt->min==but->min) {
1423                                 ui_is_but_sel(bt);
1424                                 ui_draw_but(bt);
1425                         }
1426                 }
1427                 bt= bt->next;
1428         }
1429         return but->retval;
1430 }
1431
1432 static int ui_do_but_TEX(uiBut *but)
1433 {
1434         unsigned short dev;
1435         short x, mval[2], len=0, dodraw;
1436         char *str, backstr[UI_MAX_DRAW_STR];
1437         short capturing;
1438         
1439         str= (char *)but->poin;
1440         
1441         but->flag |= UI_SELECT;
1442
1443         uiGetMouse(mywinget(), mval);
1444
1445         /* calculate cursor pos with current mousecoords */
1446         BLI_strncpy(backstr, but->drawstr, UI_MAX_DRAW_STR);
1447         but->pos= strlen(backstr)-but->ofs;
1448
1449         while((but->aspect*BIF_GetStringWidth(but->font, backstr+but->ofs, 0) + but->x1) > mval[0]) {
1450                 if (but->pos <= 0) break;
1451                 but->pos--;
1452                 backstr[but->pos+but->ofs] = 0;
1453         }
1454         
1455         but->pos -= strlen(but->str);
1456         but->pos += but->ofs;
1457         if(but->pos<0) but->pos= 0;
1458
1459         /* backup */
1460         BLI_strncpy(backstr, but->poin, UI_MAX_DRAW_STR);
1461
1462         ui_draw_but(but);
1463         ui_block_flush_back(but->block);
1464         
1465         while (get_mbut() & L_MOUSE) BIF_wait_for_statechange();
1466         len= strlen(str);
1467         but->min= 0.0;
1468         
1469         capturing = TRUE;
1470         while(capturing) {
1471                 char ascii;
1472                 short val;
1473
1474                 dodraw= 0;
1475                 dev = extern_qread_ext(&val, &ascii);
1476
1477                 if(dev==INPUTCHANGE) break;
1478                 else if(get_mbut() & L_MOUSE) break;
1479                 else if(get_mbut() & R_MOUSE) break;
1480                 else if(dev==ESCKEY) break;
1481                 else if(dev==MOUSEX) val= 0;
1482                 else if(dev==MOUSEY) val= 0;
1483
1484                 if(ascii) {
1485                         if(len < but->max) {
1486                                 for(x= but->max; x>but->pos; x--)
1487                                         str[x]= str[x-1];
1488                                 str[but->pos]= ascii;
1489                                 but->pos++; 
1490                                 len++;
1491                                 str[len]= '\0';
1492                                 dodraw= 1;
1493                         }
1494                 }
1495                 else if(val) {
1496                 
1497                         switch (dev) {
1498                                 
1499                         case RIGHTARROWKEY:
1500                                 if(G.qual & LR_SHIFTKEY) but->pos= strlen(str);
1501                                 else but->pos++;
1502                                 if(but->pos>strlen(str)) but->pos= strlen(str);
1503                                 dodraw= 1;
1504                                 break;
1505                                 
1506                         case LEFTARROWKEY:
1507                                 if(G.qual & LR_SHIFTKEY) but->pos= 0;
1508                                 else if(but->pos>0) but->pos--;
1509                                 dodraw= 1;
1510                                 break;
1511
1512                         case ENDKEY:
1513                                 but->pos= strlen(str);
1514                                 dodraw= 1;
1515                                 break;
1516
1517                         case HOMEKEY:
1518                                 but->pos= 0;
1519                                 dodraw= 1;
1520                                 break;
1521                                 
1522                         case PADENTER:
1523                         case RETKEY:
1524                                 capturing = FALSE;
1525                                 break;
1526                                 
1527                         case DELKEY:
1528                                 if(but->pos>=0 && but->pos<strlen(str)) {
1529                                         for(x=but->pos; x<=strlen(str); x++)
1530                                                 str[x]= str[x+1];
1531                                         str[--len]='\0';
1532                                         dodraw= 1;
1533                                 }
1534                                 break;
1535
1536                         case BACKSPACEKEY:
1537                                 if(len!=0) {
1538                                         if(get_qual() & LR_SHIFTKEY) {
1539                                                 str[0]= 0;
1540                                                 but->pos= 0;
1541                                                 len= 0;
1542                                                 dodraw= 1;
1543                                         }
1544                                         else if(but->pos>0) {
1545                                                 for(x=but->pos; x<=strlen(str); x++)
1546                                                         str[x-1]= str[x];
1547                                                 but->pos--;
1548                                                 str[--len]='\0';
1549                                                 dodraw= 1;
1550                                         }
1551                                 } 
1552                                 break;
1553                         }
1554                 }
1555
1556                 
1557                 if(dodraw) {
1558                         ui_check_but(but);
1559                         ui_draw_but(but);
1560                         ui_block_flush_back(but->block);
1561                 }
1562         }
1563         
1564         if(dev==ESCKEY) strcpy(but->poin, backstr);
1565         but->pos= -1;
1566         but->flag &= ~UI_SELECT;
1567
1568         if(dev!=ESCKEY) {
1569                 /* give butfunc the original text too */
1570                 /* feature used for bone renaming, channels, etc */
1571                 if(but->func_arg2==NULL) but->func_arg2= backstr;
1572                 uibut_do_func(but);
1573         }
1574         
1575         ui_check_but(but);
1576         ui_draw_but(but);
1577         
1578         if(dev!=ESCKEY) return but->retval;
1579         else return 0;
1580 }
1581
1582
1583 static int uiActAsTextBut(uiBut *but)
1584 {
1585         void *but_func;
1586         double value;
1587         float min, max;
1588         int temp, retval, textleft;
1589         char str[UI_MAX_DRAW_STR], *point;
1590         
1591         
1592         value= ui_get_but_val(but);
1593         if( but->pointype==FLO ) {
1594                 if(but->a2) { /* amount of digits defined */
1595                         if(but->a2==1) sprintf(str, "%.1f", value);
1596                         else if(but->a2==2) sprintf(str, "%.2f", value);
1597                         else if(but->a2==3) sprintf(str, "%.3f", value);
1598                         else sprintf(str, "%.4f", value);
1599                 }
1600                 else sprintf(str, "%.3f", value);
1601         }
1602         else {
1603                 sprintf(str, "%d", (int)value);
1604         }
1605         /* store values before calling as text button */
1606         point= but->poin;
1607         but->poin= str;
1608         but_func= but->func;
1609         but->func= NULL;
1610         min= but->min;
1611         max= but->max;
1612         but->min= 0.0;
1613         but->max= 15.0;
1614         temp= but->type;
1615         but->type= TEX;
1616         textleft= but->flag & UI_TEXT_LEFT;
1617         but->flag |= UI_TEXT_LEFT;
1618         ui_check_but(but);
1619         
1620         retval= ui_do_but_TEX(but);
1621         
1622         /* restore values */
1623         but->type= temp;
1624         but->poin= point;
1625         but->func= but_func;
1626         but->min= min;
1627         but->max= max;
1628         if(textleft==0) but->flag &= ~UI_TEXT_LEFT;
1629
1630         if( but->pointype==FLO ) value= atof(str);
1631         else value= atoi(str);
1632
1633         if(value<min) value= min;
1634         if(value>max) value= max;
1635
1636         ui_set_but_val(but, value);
1637         ui_check_but(but);
1638         ui_draw_but(but);
1639         
1640         return retval;
1641 }
1642
1643 static int ui_do_but_NUM(uiBut *but)
1644 {
1645         double value;
1646         float deler, fstart, f, tempf;
1647         int lvalue, temp; /*  , firsttime=1; */
1648         short retval=0, qual, sx, mval[2], pos=0;
1649
1650         but->flag |= UI_SELECT;
1651         ui_draw_but(but);
1652         ui_block_flush_back(but->block);
1653         
1654         uiGetMouse(mywinget(), mval);
1655         value= ui_get_but_val(but);
1656         
1657         sx= mval[0];
1658         fstart= (value - but->min)/(but->max-but->min);
1659         f= fstart;
1660         
1661         temp= (int)value;
1662         tempf= value;
1663         
1664         if(get_qual() & LR_SHIFTKEY) {  /* make it textbut */
1665                 if( uiActAsTextBut(but) ) retval= but->retval;
1666         }
1667         else {
1668                 retval= but->retval;
1669                 /* firsttime: this button can be approached with enter as well */
1670                 while (get_mbut() & L_MOUSE) {
1671                         qual= get_qual();
1672                         
1673                         deler= 500;
1674                         if( but->pointype!=FLO ) {
1675         
1676                                 if( (but->max-but->min)<100 ) deler= 200.0;
1677                                 if( (but->max-but->min)<25 ) deler= 50.0;
1678         
1679                         }
1680                         if(qual & LR_SHIFTKEY) deler*= 10.0;
1681                         if(qual & LR_ALTKEY) deler*= 20.0;
1682         
1683                         uiGetMouse(mywinget(), mval);
1684                         
1685                         if(mval[0] != sx) {
1686                         
1687                                 f+= ((float)(mval[0]-sx))/deler;
1688                                 if(f>1.0) f= 1.0;
1689                                 if(f<0.0) f= 0.0;
1690                                 sx= mval[0];
1691                                 tempf= ( but->min + f*(but->max-but->min));
1692                                 
1693                                 if( but->pointype!=FLO ) {
1694                                         
1695                                         temp= floor(tempf+.5);
1696                                         
1697                                         if(tempf==but->min || tempf==but->max);
1698                                         else if(qual & LR_CTRLKEY) {
1699                                                 if(qual & LR_SHIFTKEY) temp= 100*(temp/100);
1700                                                 else temp= 10*(temp/10);
1701                                         }
1702                                         if( temp>=but->min && temp<=but->max) {
1703                                         
1704                                                 value= ui_get_but_val(but);
1705                                                 lvalue= (int)value;
1706                                                 
1707                                                 if(temp != lvalue ) {
1708                                                         pos= 1;
1709                                                         ui_set_but_val(but, (double)temp);
1710                                                         ui_check_but(but);
1711                                                         ui_draw_but(but);
1712                                                         ui_block_flush_back(but->block);
1713
1714                                                         uibut_do_func(but);
1715                                                 }
1716                                         }
1717         
1718                                 }
1719                                 else {
1720                                         temp= 0;
1721                                         if(qual & LR_CTRLKEY) {
1722                                                 if(qual & LR_SHIFTKEY) {
1723                                                         if(tempf==but->min || tempf==but->max);
1724                                                         else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
1725                                                         else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
1726                                                         else tempf= floor(tempf);
1727                                                 }
1728                                                 else {
1729                                                         if(tempf==but->min || tempf==but->max);
1730                                                         else if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
1731                                                         else if(but->max-but->min < 21.0) tempf= floor(tempf);
1732                                                         else tempf= 10.0*floor(tempf/10.0);
1733                                                 }
1734                                         }
1735         
1736                                         if( tempf>=but->min && tempf<=but->max) {
1737                                                 value= ui_get_but_val(but);
1738                                                 
1739                                                 if(tempf != value ) {
1740                                                         pos= 1;
1741                                                         ui_set_but_val(but, tempf);
1742                                                         ui_check_but(but);
1743                                                         ui_draw_but(but);
1744                                                         ui_block_flush_back(but->block);
1745                                                 }
1746                                         }
1747         
1748                                 }
1749                         }
1750                         BIF_wait_for_statechange();
1751                 }
1752                 
1753                 /* click on the side arrows to increment/decrement, click inside
1754                 * to edit the value directly */
1755                 if(pos==0) {  /* plus 1 or minus 1 */
1756                         if( but->pointype!=FLO ) {
1757         
1758                                 if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
1759                                         temp--;
1760                                         if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
1761                                 }
1762                                 else if(sx > (but->x1 + (2*(but->x2 - but->x1)/3) + 3)) {
1763                                         temp++;
1764                                         if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
1765                                 }
1766                                 else {
1767                                         if( uiActAsTextBut(but) ); else retval= 0;
1768                                 }
1769                         }
1770                         else {
1771                         
1772                                 if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
1773                                         tempf-= 0.01*but->a1;
1774                                         if (tempf < but->min) tempf = but->min;
1775                                         ui_set_but_val(but, tempf);
1776                                 }
1777                                 else if(sx > but->x1 + (2*((but->x2 - but->x1)/3) + 3)) {
1778                                         tempf+= 0.01*but->a1;
1779                                         if (tempf < but->min) tempf = but->min;
1780                                         ui_set_but_val(but, tempf);
1781                                 }
1782                                 else {
1783                                         if( uiActAsTextBut(but) ); else retval= 0;
1784                                 }
1785                         }
1786                 }
1787         }
1788
1789         but->flag &= ~UI_SELECT;
1790         ui_check_but(but);
1791         ui_draw_but(but);       
1792         ui_block_flush_back(but->block);
1793         
1794         uibut_do_func(but);
1795         
1796         return retval;
1797 }
1798
1799 static int ui_do_but_TOG3(uiBut *but)
1800
1801
1802         if( but->pointype==SHO ) {
1803                 short *sp= (short *)but->poin;
1804                 
1805                 if( BTST(sp[1], but->bitnr)) {
1806                         sp[1]= BCLR(sp[1], but->bitnr);
1807                         sp[0]= BCLR(sp[0], but->bitnr);
1808                 }
1809                 else if( BTST(sp[0], but->bitnr)) {
1810                         sp[1]= BSET(sp[1], but->bitnr);
1811                 } else {
1812                         sp[0]= BSET(sp[0], but->bitnr);
1813                 }
1814         }
1815         else {
1816                 if( BTST(*(but->poin+2), but->bitnr)) {
1817                         *(but->poin+2)= BCLR(*(but->poin+2), but->bitnr);
1818                         *(but->poin)= BCLR(*(but->poin), but->bitnr);
1819                 }
1820                 else if( BTST(*(but->poin), but->bitnr)) {
1821                         *(but->poin+2)= BSET(*(but->poin+2), but->bitnr);
1822                 } else {
1823                         *(but->poin)= BSET(*(but->poin), but->bitnr);
1824                 }
1825         }
1826         
1827         ui_is_but_sel(but);
1828         ui_draw_but(but);
1829         
1830         return but->retval;
1831 }
1832
1833 static int ui_do_but_ICONROW(uiBut *but)
1834 {
1835         ListBase listb= {NULL, NULL};
1836         uiBlock *block;
1837         int a;
1838         
1839         but->flag |= UI_SELECT;
1840         ui_draw_but(but);
1841         ui_block_flush_back(but->block);        // flush because this button creates own blocks loop
1842         
1843         /* here we go! */
1844         block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
1845         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
1846         block->themecol= TH_MENU_ITEM;
1847         
1848         for(a=(int)but->min; a<=(int)but->max; a++) {
1849                 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, "");
1850         }
1851         block->direction= UI_TOP;       
1852         ui_positionblock(block, but);
1853         
1854         /* the block is made with but-win, but is handled in mainwin space...
1855            this is needs better implementation */
1856         block->win= G.curscreen->mainwin;
1857         
1858         uiDoBlocks(&listb, 0);
1859
1860         but->flag &= ~UI_SELECT;
1861         ui_check_but(but);
1862         ui_draw_but(but);       
1863         
1864         return but->retval;
1865 }
1866
1867 static int ui_do_but_ICONTEXTROW(uiBut *but)
1868 {
1869         uiBlock *block;
1870         ListBase listb={NULL, NULL};
1871         int width, a, xmax, ypos;
1872         MenuData *md;
1873
1874         but->flag |= UI_SELECT;
1875         ui_draw_but(but);
1876         ui_block_flush_back(but->block);        // flush because this button creates own blocks loop
1877
1878         block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
1879         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
1880         block->themecol= TH_MENU_ITEM;
1881
1882         md= decompose_menu_string(but->str);
1883
1884         /* size and location */
1885         /* expand menu width to fit labels */
1886         if(md->title)
1887                 width= 2*strlen(md->title)+BIF_GetStringWidth(block->curfont, md->title, (U.transopts & USER_TR_MENUS));
1888         else
1889                 width= 0;
1890
1891         for(a=0; a<md->nitems; a++) {
1892                 xmax= BIF_GetStringWidth(block->curfont, md->items[a].str, (U.transopts & USER_TR_MENUS));
1893                 if(xmax>width) width= xmax;
1894         }
1895
1896         width+= 30;
1897         if (width<50) width=50;
1898
1899         ypos = 1;
1900
1901         /* loop through the menu options and draw them out with icons & text labels */
1902         for(a=0; a<md->nitems; a++) {
1903
1904                 /* add a space if there's a separator (%l) */
1905                 if (strcmp(md->items[a].str, "%l")==0) {
1906                         ypos +=3;
1907                 }
1908                 else {
1909                         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, "");
1910                         ypos += 20;
1911                 }
1912         }
1913         
1914         if(md->title) {
1915                 uiBut *bt;
1916                 uiSetCurFont(block, block->font+1);
1917                 bt= uiDefBut(block, LABEL, 0, md->title, 0, ypos, (short)width, 19, NULL, 0.0, 0.0, 0, 0, "");
1918                 uiSetCurFont(block, block->font);
1919                 bt->flag= UI_TEXT_LEFT;
1920         }
1921         
1922         block->direction= UI_TOP;
1923         ui_positionblock(block, but);
1924
1925         /* the block is made with but-win, but is handled in mainwin space...
1926            this is needs better implementation */
1927         block->win= G.curscreen->mainwin;
1928
1929         uiBoundsBlock(block, 3);
1930
1931         uiDoBlocks(&listb, 0);
1932         
1933         menudata_free(md);
1934
1935         but->flag &= ~UI_SELECT;
1936         ui_check_but(but);
1937         ui_draw_but(but);
1938
1939         uibut_do_func(but);
1940
1941         return but->retval;
1942
1943 }
1944
1945 static int ui_do_but_IDPOIN(uiBut *but)
1946 {
1947         char str[UI_MAX_DRAW_STR];
1948         ID *id;
1949         
1950         id= *but->idpoin_idpp;
1951         if(id) strcpy(str, id->name+2);
1952         else str[0]= 0;
1953         
1954         but->type= TEX;
1955         but->poin= str;
1956         but->min= 0.0;
1957         but->max= 22.0;
1958         ui_do_but_TEX(but);
1959         but->poin= NULL;
1960         but->type= IDPOIN;
1961         
1962         but->idpoin_func(str, but->idpoin_idpp);
1963         ui_check_but(but);
1964         ui_draw_but(but);
1965         
1966         return but->retval;
1967 }
1968
1969 static int ui_do_but_SLI(uiBut *but)
1970 {
1971         float f, fstart, tempf = 0.0, deler, value;
1972         int sx, h, temp, pos=0, lvalue, redraw;
1973         short mval[2], qual;
1974         float curmatrix[4][4];
1975
1976         value= ui_get_but_val(but);
1977         uiGetMouse(mywinget(), mval);
1978
1979         sx= mval[0];
1980         h= but->y2-but->y1;
1981         fstart= but->max-but->min;
1982         fstart= (value - but->min)/fstart;
1983         temp= 32767;
1984
1985         if( but->type==NUMSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
1986         else if( but->type==HSVSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
1987         else deler= (but->x2-but->x1- 5.0*but->aspect);
1988         
1989
1990         while (get_mbut() & L_MOUSE) {
1991         
1992                 qual= get_qual();
1993                 uiGetMouse(mywinget(), mval);
1994                 
1995                 f= (float)(mval[0]-sx)/deler +fstart;
1996                 
1997                 if (qual & LR_SHIFTKEY) {
1998                         f= (f-fstart)/10.0 + fstart;
1999                 }
2000
2001                 CLAMP(f, 0.0, 1.0);
2002                 tempf= but->min+f*(but->max-but->min);          
2003                 temp= floor(tempf+.5);
2004
2005                 if(qual & LR_CTRLKEY) {
2006                         if(tempf==but->min || tempf==but->max);
2007                         else if( but->pointype==FLO ) {
2008
2009                                 if(qual & LR_SHIFTKEY) {
2010                                         if(tempf==but->min || tempf==but->max);
2011                                         else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
2012                                         else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
2013                                         else tempf= floor(tempf);
2014                                 }
2015                                 else {
2016                                         if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
2017                                         else if(but->max-but->min < 21.0) tempf= floor(tempf);
2018                                         else tempf= 10.0*floor(tempf/10.0);
2019                                 }
2020                         }
2021                         else {
2022                                 temp= 10*(temp/10);
2023                                 tempf= temp;
2024                         }
2025                 } 
2026         
2027                 value= ui_get_but_val(but);
2028                 lvalue= floor(value+0.5);
2029                 
2030                 if( but->pointype!=FLO )
2031                         redraw= (temp != lvalue);
2032                 else
2033                         redraw= (tempf != value);
2034
2035                 if (redraw) {
2036                         pos= 1;
2037                         ui_set_but_val(but, tempf);
2038                         ui_check_but(but);
2039                         ui_draw_but(but);
2040                         ui_block_flush_back(but->block);
2041                         
2042                         if(but->a1) {   /* color number */
2043                                 uiBut *bt= but->prev;
2044                                 while(bt) {
2045                                         if(bt->a2 == but->a1) ui_draw_but(bt);
2046                                         bt= bt->prev;
2047                                 }
2048                                 bt= but->next;
2049                                 while(bt) {
2050                                         if(bt->a2 == but->a1) ui_draw_but(bt);
2051                                         bt= bt->next;
2052                                 }
2053                         }
2054                         /* save current window matrix (global UIwinmat)
2055                            because button callback function MIGHT change it
2056                            - which has until now occured through the Python API
2057                         */
2058                         Mat4CpyMat4(curmatrix, UIwinmat);
2059                         uibut_do_func(but);
2060                         Mat4CpyMat4(UIwinmat, curmatrix);
2061                 } 
2062                 else BIF_wait_for_statechange();
2063         }
2064
2065         
2066         if(temp!=32767 && pos==0) {  /* plus 1 or minus 1 */
2067                 
2068                 if( but->type==SLI) f= (float)(mval[0]-but->x1)/(but->x2-but->x1-h);
2069                 else f= (float)(mval[0]- (but->x1+but->x2)/2)/( (but->x2-but->x1)/2 - h);
2070                 
2071                 f= but->min+f*(but->max-but->min);
2072                 
2073                 if( but->pointype!=FLO ) {
2074
2075                         if(f<temp) temp--;
2076                         else temp++;
2077                         if( temp>=but->min && temp<=but->max)
2078                                 ui_set_but_val(but, (float)temp);
2079                 
2080                 } 
2081                 else {
2082
2083                         if(f<tempf) tempf-=.01;
2084                         else tempf+=.01;
2085                         if( tempf>=but->min && tempf<=but->max)
2086                                 ui_set_but_val(but, tempf);
2087
2088                 }
2089         }
2090         ui_check_but(but);
2091         ui_draw_but(but);
2092         ui_block_flush_back(but->block);
2093         
2094         return but->retval;
2095 }
2096
2097 static int ui_do_but_NUMSLI(uiBut *but)
2098 {
2099         short mval[2];
2100
2101         /* first define if it's a slider or textbut */
2102         uiGetMouse(mywinget(), mval);
2103         
2104         if(mval[0]>= -6+(but->x1+but->x2)/2 ) { /* slider */
2105                 but->flag |= UI_SELECT;
2106                 ui_draw_but(but);
2107                 ui_do_but_SLI(but);
2108                 but->flag &= ~UI_SELECT;
2109         }
2110         else {
2111                 uiActAsTextBut(but);
2112                 uibut_do_func(but);     // this is done in ui_do_but_SLI() not in uiActAsTextBut()
2113         }
2114
2115         while(get_mbut() & L_MOUSE) BIF_wait_for_statechange();
2116         
2117         ui_draw_but(but);
2118         
2119         /* hsv patch */
2120         if(but->type==HSVSLI) {
2121         
2122                 if(but->str[0]=='H') {
2123                         ui_draw_but(but->next);
2124                         ui_draw_but(but->next->next);
2125                 } 
2126                 else if(but->str[0]=='S') {
2127                         ui_draw_but(but->next);
2128                         ui_draw_but(but->prev);
2129                 } 
2130                 else if(but->str[0]=='V') {
2131                         ui_draw_but(but->prev);
2132                         ui_draw_but(but->prev->prev);
2133                 }
2134         }
2135         
2136         return but->retval;
2137 }
2138
2139 static int ui_do_but_BLOCK(uiBut *but)
2140 {
2141         uiBlock *block;
2142         uiBut *bt;
2143         
2144         but->flag |= UI_SELECT;
2145         ui_draw_but(but);       
2146
2147         block= but->block_func(but->poin);
2148
2149         block->xofs = -2;       /* for proper alignment */
2150         
2151         /* only used for automatic toolbox, so can set the shift flag */
2152         if(but->flag & UI_MAKE_TOP) {
2153                 block->direction= UI_TOP|UI_SHIFT_FLIPPED;
2154                 uiBlockFlipOrder(block);
2155         }
2156         if(but->flag & UI_MAKE_DOWN) block->direction= UI_DOWN|UI_SHIFT_FLIPPED;
2157         if(but->flag & UI_MAKE_LEFT) block->direction |= UI_LEFT;
2158         if(but->flag & UI_MAKE_RIGHT) block->direction |= UI_RIGHT;
2159         
2160         ui_positionblock(block, but);
2161         block->flag |= UI_BLOCK_LOOP;
2162         
2163         /* blocks can come (and get scaled) from a normal window, now we go to screenspace */
2164         block->win= G.curscreen->mainwin;
2165         for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
2166         bwin_getsinglematrix(block->win, block->winmat);
2167         
2168         /* postpone draw, this will cause a new window matrix, first finish all other buttons */
2169         block->flag |= UI_BLOCK_REDRAW;
2170         
2171         but->flag &= ~UI_SELECT;
2172         uibut_do_func(but);
2173         
2174         return 0;
2175 }
2176
2177 static int ui_do_but_BUTM(uiBut *but)
2178 {
2179
2180         ui_set_but_val(but, but->min);
2181         UIafterfunc= but->butm_func;
2182         UIafterfunc_arg= but->butm_func_arg;
2183         UIafterval= but->a2;
2184         
2185         return but->retval;
2186 }
2187
2188 static int ui_do_but_LABEL(uiBut *but)
2189 {
2190
2191         uibut_do_func(but);
2192         return but->retval;
2193 }
2194
2195 static uiBut *ui_get_valid_link_button(uiBlock *block, uiBut *but, short *mval)
2196 {
2197         uiBut *bt;
2198         
2199                 /* find button to link to */
2200         for (bt= block->buttons.first; bt; bt= bt->next)
2201                 if(bt!=but && uibut_contains_pt(bt, mval))
2202                         break;
2203
2204         if (bt) {
2205                 if (but->type==LINK && bt->type==INLINK) {
2206                         if( but->link->tocode == (int)bt->min ) {
2207                                 return bt;
2208                         }
2209                 }
2210                 else if(but->type==INLINK && bt->type==LINK) {
2211                         if( bt->link->tocode == (int)but->min ) {
2212                                 return bt;
2213                         }
2214                 }
2215         }
2216
2217         return NULL;
2218 }
2219
2220 static int ui_is_a_link(uiBut *from, uiBut *to)
2221 {
2222         uiLinkLine *line;
2223         uiLink *link;
2224         
2225         link= from->link;
2226         if(link) {
2227                 line= link->lines.first;
2228                 while(line) {
2229                         if(line->from==from && line->to==to) return 1;
2230                         line= line->next;
2231                 }
2232         }
2233         return 0;
2234 }
2235
2236 static uiBut *ui_find_inlink(uiBlock *block, void *poin)
2237 {
2238         uiBut *but;
2239         
2240         but= block->buttons.first;
2241         while(but) {
2242                 if(but->type==INLINK) {
2243                         if(but->poin == poin) return but;
2244                 }
2245                 but= but->next;
2246         }
2247         return NULL;
2248 }
2249
2250 static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt)
2251 {
2252         uiLinkLine *line;
2253         
2254         line= MEM_callocN(sizeof(uiLinkLine), "linkline");
2255         BLI_addtail(listb, line);
2256         line->from= but;
2257         line->to= bt;
2258 }
2259
2260
2261 void uiComposeLinks(uiBlock *block)
2262 {
2263         uiBut *but, *bt;
2264         uiLink *link;
2265         void ***ppoin;
2266         int a;
2267         
2268         but= block->buttons.first;
2269         while(but) {
2270                 if(but->type==LINK) {
2271                         link= but->link;
2272                         
2273                         /* for all pointers in the array */
2274                         if(link) {
2275                                 if(link->ppoin) {
2276                                         ppoin= link->ppoin;
2277                                         for(a=0; a < *(link->totlink); a++) {
2278                                                 bt= ui_find_inlink(block, (*ppoin)[a] );
2279                                                 if(bt) {
2280                                                         ui_add_link_line(&link->lines, but, bt);
2281                                                 }
2282                                         }
2283                                 }
2284                                 else if(link->poin) {
2285                                         bt= ui_find_inlink(block, *(link->poin) );
2286                                         if(bt) {
2287                                                 ui_add_link_line(&link->lines, but, bt);
2288                                         }
2289                                 }
2290                         }
2291                 }
2292                 but= but->next;
2293         }
2294 }
2295
2296 static void ui_add_link(uiBut *from, uiBut *to)
2297 {
2298         /* in 'from' we have to add a link to 'to' */
2299         uiLink *link;
2300         void **oldppoin;
2301         int a;
2302         
2303         if(ui_is_a_link(from, to)) {
2304                 printf("already exists\n");
2305                 return;
2306         }
2307         
2308         link= from->link;
2309
2310         /* are there more pointers allowed? */
2311         if(link->ppoin) {
2312                 oldppoin= *(link->ppoin);
2313                 
2314                 (*(link->totlink))++;
2315                 *(link->ppoin)= MEM_callocN( *(link->totlink)*sizeof(void *), "new link");
2316
2317                 for(a=0; a< (*(link->totlink))-1; a++) {
2318                         (*(link->ppoin))[a]= oldppoin[a];
2319                 }
2320                 (*(link->ppoin))[a]= to->poin;
2321                 
2322                 if(oldppoin) MEM_freeN(oldppoin);
2323         }
2324         else {
2325                 *(link->poin)= to->poin;
2326         }
2327         
2328 }
2329
2330 static int ui_do_but_LINK(uiBlock *block, uiBut *but)
2331 {
2332         /* 
2333          * This button only visualizes, the dobutton mode
2334          * can add a new link, but then the whole system
2335          * should be redrawn/initialized. 
2336          * 
2337          */
2338         uiBut *bt=0, *bto=NULL;
2339         short sval[2], mval[2], mvalo[2], first= 1;
2340
2341         uiGetMouse(curarea->win, sval);
2342         mvalo[0]= sval[0];
2343         mvalo[1]= sval[1];
2344         
2345         while (get_mbut() & L_MOUSE) {
2346                 uiGetMouse(curarea->win, mval);
2347
2348                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || first) {                   
2349                                 /* clear completely, because of drawbuttons */
2350                         bt= ui_get_valid_link_button(block, but, mval);
2351                         if(bt) {
2352                                 bt->flag |= UI_ACTIVE;
2353                                 ui_draw_but(bt);
2354                         }
2355                         if(bto && bto!=bt) {
2356                                 bto->flag &= ~UI_ACTIVE;
2357                                 ui_draw_but(bto);
2358                         }
2359                         bto= bt;
2360
2361                         if (!first) {
2362                                 glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
2363                         }
2364                         glutil_draw_front_xor_line(sval[0], sval[1], mval[0], mval[1]);
2365
2366                         mvalo[0]= mval[0];
2367                         mvalo[1]= mval[1];
2368
2369                         first= 0;
2370                 }
2371                 else BIF_wait_for_statechange();                
2372         }
2373         
2374         if (!first) {
2375                 glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
2376         }
2377
2378         if(bt) {
2379                 if(but->type==LINK) ui_add_link(but, bt);
2380                 else ui_add_link(bt, but);
2381
2382                 scrarea_queue_winredraw(curarea);
2383         }
2384
2385         return 0;
2386 }
2387
2388 /* picker sizes S hsize, F full size, D spacer, B button/pallette height  */
2389 #define SPICK   110.0
2390 #define FPICK   180.0
2391 #define DPICK   6.0
2392 #define BPICK   24.0
2393
2394 #define UI_PALETTE_TOT 16
2395 /* note; in tot+1 the old color is stored */
2396 static float palette[UI_PALETTE_TOT+1][3]= {
2397 {0.93, 0.83, 0.81}, {0.88, 0.89, 0.73}, {0.69, 0.81, 0.57}, {0.51, 0.76, 0.64}, 
2398 {0.37, 0.56, 0.61}, {0.33, 0.29, 0.55}, {0.46, 0.21, 0.51}, {0.40, 0.12, 0.18}, 
2399 {1.0, 1.0, 1.0}, {0.85, 0.85, 0.85}, {0.7, 0.7, 0.7}, {0.56, 0.56, 0.56}, 
2400 {0.42, 0.42, 0.42}, {0.28, 0.28, 0.28}, {0.14, 0.14, 0.14}, {0.0, 0.0, 0.0}
2401 };  
2402
2403 /* for picker, while editing hsv */
2404 static void ui_set_but_hsv(uiBut *but)
2405 {
2406         float col[3];
2407         
2408         hsv_to_rgb(but->hsv[0], but->hsv[1], but->hsv[2], col, col+1, col+2);
2409         ui_set_but_vectorf(but, col);
2410 }
2411
2412 static void update_picker_buts(uiBlock *block, float *hsv)
2413 {
2414         uiBut *bt;
2415         float r, g, b;
2416         
2417         // this updates button strings, is hackish... but button pointers are on stack of caller function
2418         hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r, &g, &b);
2419
2420         for(bt= block->buttons.first; bt; bt= bt->next) {
2421                 if(bt->type==HSVCUBE) {
2422                         VECCOPY(bt->hsv, hsv);
2423                         ui_set_but_hsv(bt);
2424                 }
2425                 else if(bt->str[1]==' ') {
2426                         if(bt->str[0]=='R') {
2427                                 ui_set_but_val(bt, r);
2428                                 ui_check_but(bt);
2429                         }
2430                         else if(bt->str[0]=='G') {
2431                                 ui_set_but_val(bt, g);
2432                                 ui_check_but(bt);
2433                         }
2434                         else if(bt->str[0]=='B') {
2435                                 ui_set_but_val(bt, b);
2436                                 ui_check_but(bt);
2437                         }
2438                         else if(bt->str[0]=='H') {
2439                                 ui_set_but_val(bt, hsv[0]);
2440                                 ui_check_but(bt);
2441                         }
2442                         else if(bt->str[0]=='S') {
2443                                 ui_set_but_val(bt, hsv[1]);
2444                                 ui_check_but(bt);
2445                         }
2446                         else if(bt->str[0]=='V') {
2447                                 ui_set_but_val(bt, hsv[2]);
2448                                 ui_check_but(bt);
2449                         }
2450                 }
2451         }
2452 }
2453
2454 /* bt1 is palette but, col1 is original color */
2455 /* callback to copy from/to palette */
2456 static void do_palette_cb(void *bt1, void *col1)
2457 {
2458         uiBut *but1= (uiBut *)bt1;
2459         uiBut *but;
2460         float *col= (float *)col1;
2461         float *fp, hsv[3];
2462         
2463         fp= (float *)but1->poin;
2464         
2465         if( (get_qual() & LR_CTRLKEY) ) {
2466                 VECCOPY(fp, col);
2467         }
2468         else {
2469                 VECCOPY(col, fp);
2470         }
2471         
2472         rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
2473         update_picker_buts(but1->block, hsv);
2474         
2475         for (but= but1->block->buttons.first; but; but= but->next) {
2476                 ui_draw_but(but);
2477         }
2478         but= but1->block->buttons.first;
2479         ui_block_flush_back(but->block);
2480 }
2481
2482 /* bt1 is num but, col1 is pointer to original color */
2483 /* callback to handle changes in num-buts in picker */
2484 static void do_palette1_cb(void *bt1, void *hsv1)
2485 {
2486         uiBut *but1= (uiBut *)bt1;
2487         uiBut *but;
2488         float *hsv= (float *)hsv1;
2489         float *fp= NULL;
2490         
2491         if(but1->str[0]=='R') fp= (float *)but1->poin;
2492         else if(but1->str[0]=='G') fp= ((float *)but1->poin)-1;
2493         else if(but1->str[0]=='B') fp= ((float *)but1->poin)-2;
2494         
2495         if(fp) {
2496                 rgb_to_hsv(fp[0], fp[1], fp[2], hsv, hsv+1, hsv+2);
2497         }
2498
2499         update_picker_buts(but1->block, hsv);   
2500         
2501         for (but= but1->block->buttons.first; but; but= but->next) {
2502                 ui_draw_but(but);
2503         }
2504         
2505         but= but1->block->buttons.first;
2506         ui_block_flush_back(but->block);
2507
2508 }
2509
2510 /* color picker, Gimp version. mode: 'f' = floating panel, 'p' =  popup */
2511 /* col = read/write to, hsv/old = memory for temporal use */
2512 void uiBlockPickerButtons(uiBlock *block, float *col, float *hsv, float *old, char mode, short retval)
2513 {
2514         uiBut *bt;
2515         float h, offs;
2516         int a;
2517
2518         VECCOPY(old, col);      // old color stored there, for palette_cb to work
2519         
2520         // the cube intersection
2521         bt= uiDefButF(block, HSVCUBE, retval, "",       0,DPICK+BPICK,FPICK,FPICK, col, 0.0, 0.0, 2, 0, "");
2522         uiButSetFlag(bt, UI_NO_HILITE);
2523
2524         bt= uiDefButF(block, HSVCUBE, retval, "",       0,0,FPICK,BPICK, col, 0.0, 0.0, 3, 0, "");
2525         uiButSetFlag(bt, UI_NO_HILITE);
2526
2527         // palette
2528         
2529         uiBlockSetEmboss(block, UI_EMBOSSP);
2530         
2531         bt=uiDefButF(block, COL, retval, "",            FPICK+DPICK, 0, BPICK,BPICK, old, 0.0, 0.0, -1, 0, "Old color, click to restore");
2532         uiButSetFunc(bt, do_palette_cb, bt, col);
2533         uiDefButF(block, COL, retval, "",               FPICK+DPICK, BPICK+DPICK, BPICK,60-BPICK-DPICK, col, 0.0, 0.0, -1, 0, "Active color");
2534
2535         h= (DPICK+BPICK+FPICK-64)/(UI_PALETTE_TOT/2.0);
2536         uiBlockBeginAlign(block);
2537         for(a= -1+UI_PALETTE_TOT/2; a>=0; a--) {
2538                 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");
2539                 uiButSetFunc(bt, do_palette_cb, bt, col);
2540                 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");               
2541                 uiButSetFunc(bt, do_palette_cb, bt, col);
2542         }
2543         uiBlockEndAlign(block);
2544         
2545         uiBlockSetEmboss(block, UI_EMBOSS);
2546
2547         // buttons
2548         rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
2549
2550         offs= FPICK+2*DPICK+BPICK;
2551
2552
2553         uiBlockBeginAlign(block);
2554         bt= uiDefButF(block, NUM, retval, "R ", offs, 110, 80,20, col, 0.0, 1.0, 10, 2, "");
2555         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2556         bt= uiDefButF(block, NUM, retval, "G ", offs, 90, 80,20, col+1, 0.0, 1.0, 10, 2, "");
2557         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2558         bt= uiDefButF(block, NUM, retval, "B ", offs, 70, 80,20, col+2, 0.0, 1.0, 10, 2, "");
2559         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2560         
2561         uiBlockBeginAlign(block);
2562         bt= uiDefButF(block, NUM, retval, "H ", offs, 40, 80,20, hsv, 0.0, 1.0, 10, 2, "");
2563         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2564         bt= uiDefButF(block, NUM, retval, "S ", offs, 20, 80,20, hsv+1, 0.0, 1.0, 10, 2, "");
2565         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2566         bt= uiDefButF(block, NUM, retval, "V ", offs, 0, 80,20, hsv+2, 0.0, 1.0, 10, 2, "");
2567         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2568         uiBlockEndAlign(block);
2569 }
2570
2571
2572 static int ui_do_but_COL(uiBut *but)
2573 {
2574         uiBlock *block;
2575         uiBut *bt;
2576         ListBase listb={NULL, NULL};
2577         float hsv[3], old[3], *poin= NULL, colstore[3];
2578         short event;
2579         
2580         // signal to prevent calling up color picker
2581         if(but->a1 == -1) {
2582                 uibut_do_func(but);
2583                 return but->retval;
2584         }
2585         
2586         // enable char button too, use temporal colstore for color
2587         if(but->pointype!=FLO) {
2588                 if(but->pointype==CHA) {
2589                         ui_get_but_vectorf(but, colstore);
2590                         poin= colstore;
2591                 }
2592                 else return but->retval;
2593         }
2594         else poin= (float *)but->poin;
2595         
2596         block= uiNewBlock(&listb, "colorpicker", UI_EMBOSS, UI_HELV, but->win);
2597         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW;
2598         block->themecol= TH_BUT_NUM;
2599         
2600         uiBlockPickerButtons(block, poin, hsv, old, 'p', 0);
2601
2602         /* and lets go */
2603         block->direction= UI_TOP;
2604         ui_positionblock(block, but);
2605         uiBoundsBlock(block, 3);
2606         
2607         /* blocks can come from a normal window, but we go to screenspace */
2608         block->win= G.curscreen->mainwin;
2609         for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
2610         bwin_getsinglematrix(block->win, block->winmat);
2611
2612         event= uiDoBlocks(&listb, 0);
2613         
2614         if(but->pointype==CHA) ui_set_but_vectorf(but, colstore);
2615         
2616         return but->retval;
2617
2618 }
2619
2620 static int ui_do_but_HSVCUBE(uiBut *but)
2621 {
2622         uiBut *bt;
2623         float x, y;
2624         short mval[2], mvalo[2];
2625         
2626         mvalo[0]= mvalo[1]= -32000;
2627         
2628         /* we work on persistant hsv, to prevent it being converted back and forth all the time */
2629                            
2630         while (get_mbut() & L_MOUSE) {
2631                 
2632                 uiGetMouse(mywinget(), mval);
2633
2634                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {                    
2635                         mvalo[0]= mval[0];
2636                         mvalo[1]= mval[1];
2637                         
2638                         /* relative position within box */
2639                         x= ((float)mval[0]-but->x1)/(but->x2-but->x1);
2640                         y= ((float)mval[1]-but->y1)/(but->y2-but->y1);
2641                         CLAMP(x, 0.0, 1.0);
2642                         CLAMP(y, 0.0, 1.0);
2643                         
2644                         if(but->a1==0) {
2645                                 but->hsv[0]= x; 
2646                                 but->hsv[2]= y; 
2647                                 // hsv_to_rgb(x, s, y, col, col+1, col+2);
2648                         }
2649                         else if(but->a1==1) {
2650                                 but->hsv[0]= x;                                 
2651                                 but->hsv[1]= y;                                 
2652                                 // hsv_to_rgb(x, y, v, col, col+1, col+2);
2653                         }
2654                         else if(but->a1==2) {
2655                                 but->hsv[2]= x; 
2656                                 but->hsv[1]= y; 
2657                                 // hsv_to_rgb(h, y, x, col, col+1, col+2);
2658                         }
2659                         else {
2660                                 but->hsv[0]= x; 
2661                                 // hsv_to_rgb(x, s, v, col, col+1, col+2);
2662                         }
2663         
2664                         ui_set_but_hsv(but);    // converts to rgb
2665                         
2666                         // update button values and strings
2667                         update_picker_buts(but->block, but->hsv);
2668
2669                         /* we redraw the entire block */
2670                         for (bt= but->block->buttons.first; bt; bt= bt->next) {
2671                                 if(but->poin == bt->poin) VECCOPY(bt->hsv, but->hsv);
2672                                 ui_draw_but(bt);
2673                         }
2674                         ui_block_flush_back(but->block);
2675                 }
2676                 else BIF_wait_for_statechange();
2677         }
2678
2679         return but->retval;
2680 }
2681
2682
2683 /* ************************************************ */
2684
2685 void uiSetButLock(int val, char *lockstr)
2686 {
2687         UIlock |= val;
2688         if (val) UIlockstr= lockstr;
2689 }
2690
2691 void uiClearButLock()
2692 {
2693         UIlock= 0;
2694         UIlockstr= NULL;
2695 }
2696
2697 /* ********************** NEXT/PREV for arrowkeys etc ************** */
2698
2699 static uiBut *ui_but_prev(uiBut *but)
2700 {
2701         while(but->prev) {
2702                 but= but->prev;
2703                 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
2704         }
2705         return NULL;
2706 }
2707
2708 static uiBut *ui_but_next(uiBut *but)
2709 {
2710         while(but->next) {
2711                 but= but->next;
2712                 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
2713         }
2714         return NULL;
2715 }
2716
2717 static uiBut *ui_but_first(uiBlock *block)
2718 {
2719         uiBut *but;
2720         
2721         but= block->buttons.first;
2722         while(but) {
2723                 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
2724                 but= but->next;
2725         }
2726         return NULL;
2727 }
2728
2729 static uiBut *ui_but_last(uiBlock *block)
2730 {
2731         uiBut *but;
2732         
2733         but= block->buttons.last;
2734         while(but) {
2735                 if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
2736                 but= but->prev;
2737         }
2738         return NULL;
2739 }
2740
2741 /* *************************************************************** */
2742
2743 static void setup_file(uiBlock *block)
2744 {
2745         uiBut *but;
2746         FILE *fp;
2747
2748         fp= fopen("butsetup","w");
2749         if(fp==NULL);
2750         else {
2751                 but= block->buttons.first;
2752                 while(but) {
2753                         ui_check_but(but);
2754                         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);
2755                         but= but->next;
2756                 }
2757                 fclose(fp);
2758         }
2759 }
2760
2761
2762 static void edit_but(uiBlock *block, uiBut *but, uiEvent *uevent)
2763 {
2764         short dx, dy, mval[2], mvalo[2], didit=0;
2765         
2766         getmouseco_sc(mvalo);
2767         while(TRUE) {
2768                 if( !(get_mbut() & L_MOUSE) ) break;    
2769         
2770                 getmouseco_sc(mval);
2771                 dx= (mval[0]-mvalo[0]);
2772                 dy= (mval[1]-mvalo[1]);
2773                 
2774                 if(dx!=0 || dy!=0) {
2775                         mvalo[0]= mval[0];
2776                         mvalo[1]= mval[1];
2777                         
2778                         cpack(0xc0c0c0);
2779                         glRectf(but->x1-2, but->y1-2, but->x2+2, but->y2+2); 
2780                         
2781                         if((uevent->qual & LR_SHIFTKEY)==0) {
2782                                 but->x1 += dx;
2783                                 but->y1 += dy;
2784                         }
2785                         but->x2 += dx;
2786                         but->y2 += dy;
2787                         
2788                         ui_draw_but(but);
2789                         ui_block_flush_back(but->block);
2790                         didit= 1;
2791
2792                 }
2793                 /* idle for this poor code */
2794                 else PIL_sleep_ms(30);
2795         }
2796         if(didit) setup_file(block);
2797 }
2798
2799
2800 /* is called when LEFTMOUSE is pressed or released
2801  * return: butval or zero
2802  */
2803 static int ui_do_button(uiBlock *block, uiBut *but, uiEvent *uevent)
2804 {
2805         int retval= 0;
2806
2807         if(but->lock) {
2808                 if (but->lockstr) {
2809                         error("%s", but->lockstr);
2810                         return 0;
2811                 }
2812         } 
2813         else {
2814                 if( but->pointype ) {           /* there's a pointer needed */
2815                         if(but->poin==0 ) {
2816                                 printf("DoButton pointer error: %s\n",but->str);
2817                                 return 0;
2818                         }
2819                 }
2820         }
2821
2822         if(G.rt==1 && (uevent->qual & LR_CTRLKEY)) {
2823                 edit_but(block, but, uevent);
2824                 return 0;
2825         }
2826         
2827         block->flag |= UI_BLOCK_BUSY;
2828
2829         switch(but->type) {
2830         case BUT:
2831                 if(uevent->val) retval= ui_do_but_BUT(but);             
2832                 break;
2833
2834         case KEYEVT:
2835                 if(uevent->val) retval= ui_do_but_KEYEVT(but);
2836                 break;
2837
2838         case TOG: 
2839         case TOGR: 
2840         case ICONTOG: 
2841         case TOGN:
2842                 if(uevent->val) {
2843                         retval= ui_do_but_TOG(block, but);
2844                 }
2845                 break;
2846                 
2847         case ROW:
2848                 if(uevent->val) retval= ui_do_but_ROW(block, but);
2849                 break;
2850
2851         case SCROLL:
2852                 /* DrawBut(b, 1); */
2853                 /* do_scrollbut(b); */
2854                 /* DrawBut(b,0); */
2855                 break;
2856
2857         case NUM:
2858                 if(uevent->val) retval= ui_do_but_NUM(but);
2859                 break;
2860                 
2861         case SLI:
2862         case NUMSLI:
2863         case HSVSLI:
2864                 if(uevent->val) retval= ui_do_but_NUMSLI(but);
2865                 break;
2866                 
2867         case LABEL:     
2868                 if(uevent->val) retval= ui_do_but_LABEL(but);
2869                 break;
2870                 
2871         case TOG3:      
2872                 if(uevent->val) retval= ui_do_but_TOG3(but);
2873                 break;
2874                 
2875         case TEX:
2876                 if(uevent->val) retval= ui_do_but_TEX(but);
2877                 break;
2878                 
2879         case MENU:
2880                 if(uevent->val) retval= ui_do_but_MENU(but);
2881                 break;
2882                 
2883         case ICONROW:
2884                 if(uevent->val) retval= ui_do_but_ICONROW(but);         
2885                 break;
2886                 
2887         case ICONTEXTROW:
2888                 if(uevent->val) retval= ui_do_but_ICONTEXTROW(but);
2889                 break;
2890
2891         case IDPOIN:
2892                 if(uevent->val) retval= ui_do_but_IDPOIN(but);  
2893                 break;
2894         
2895         case BLOCK:
2896         case PULLDOWN:
2897                 if(uevent->val) {
2898                         retval= ui_do_but_BLOCK(but);
2899                         if(block->auto_open==0) block->auto_open= 1;
2900                 }
2901                 break;
2902
2903         case BUTM:
2904                 retval= ui_do_but_BUTM(but);
2905                 break;
2906
2907         case LINK:
2908         case INLINK:
2909                 retval= ui_do_but_LINK(block, but);
2910                 break;
2911                 
2912         case COL:
2913                 if(uevent->val) retval= ui_do_but_COL(but);
2914                 break;
2915                 
2916         case HSVCUBE:
2917                 retval= ui_do_but_HSVCUBE(but);
2918                 break;
2919         }
2920         
2921         block->flag &= ~UI_BLOCK_BUSY;
2922
2923         return retval;
2924 }
2925
2926 static void ui_delete_active_linkline(uiBlock *block)
2927 {
2928         uiBut *but;
2929         uiLink *link;
2930         uiLinkLine *line, *nline;
2931         int a, b;
2932         
2933         but= block->buttons.first;
2934         while(but) {
2935                 if(but->type==LINK && but->link) {
2936                         line= but->link->lines.first;
2937                         while(line) {
2938                                 
2939                                 nline= line->next;
2940                                 
2941                                 if(line->flag & UI_SELECT) {
2942                                         BLI_remlink(&but->link->lines, line);
2943
2944                                         link= line->from->link;
2945
2946                                         /* are there more pointers allowed? */
2947                                         if(link->ppoin) {
2948                                                 
2949                                                 if(*(link->totlink)==1) {
2950                                                         *(link->totlink)= 0;
2951                                                         MEM_freeN(*(link->ppoin));
2952                                                         *(link->ppoin)= NULL;
2953                                                 }
2954                                                 else {
2955                                                         b= 0;
2956                                                         for(a=0; a< (*(link->totlink)); a++) {
2957                                                                 
2958                                                                 if( (*(link->ppoin))[a] != line->to->poin ) {
2959                                                                         (*(link->ppoin))[b]= (*(link->ppoin))[a];
2960                                                                         b++;
2961                                                                 }
2962                                                         }       
2963                                                         (*(link->totlink))--;
2964                                                 }
2965                                         }
2966                                         else {
2967                                                 *(link->poin)= NULL;
2968                                         }
2969
2970                                         MEM_freeN(line);
2971                                 }
2972                                 line= nline;
2973                         }
2974                 }
2975                 but= but->next;
2976         }
2977         
2978         /* temporal! these buttons can be everywhere... */
2979         allqueue(REDRAWBUTSLOGIC, 0);
2980 }
2981
2982 static void ui_do_active_linklines(uiBlock *block, short *mval)
2983 {
2984         uiBut *but;
2985         uiLinkLine *line, *act= NULL;
2986         float mindist= 12.0, fac, v1[2], v2[2], v3[3];
2987         int foundone= 0; 
2988         
2989         if(mval) {
2990                 v1[0]= mval[0];
2991                 v1[1]= mval[1];
2992                 
2993                 /* find a line close to the mouse */
2994                 but= block->buttons.first;
2995                 while(but) {
2996                         if(but->type==LINK && but->link) {
2997                                 foundone= 1;
2998                                 line= but->link->lines.first;
2999                                 while(line) {
3000                                         v2[0]= line->from->x2;
3001                                         v2[1]= (line->from->y1+line->from->y2)/2.0;
3002                                         v3[0]= line->to->x1;
3003                                         v3[1]= (line->to->y1+line->to->y2)/2.0;
3004                                         
3005                                         fac= PdistVL2Dfl(v1, v2, v3);
3006                                         if(fac < mindist) {
3007                                                 mindist= fac;
3008                                                 act= line;
3009                                         }
3010                                         line= line->next;
3011                                 }
3012                         }
3013                         but= but->next;
3014                 }
3015         }
3016
3017         /* check for a 'found one' to prevent going to 'frontbuffer' mode.
3018                 this slows done gfx quite some, and at OSX the 'finish' forces a swapbuffer */
3019         if(foundone) {
3020                 glDrawBuffer(GL_FRONT);
3021                 
3022                 /* draw */
3023                 but= block->buttons.first;
3024                 while(but) {
3025                         if(but->type==LINK && but->link) {
3026                                 line= but->link->lines.first;
3027                                 while(line) {
3028                                         if(line==act) {
3029                                                 if((line->flag & UI_SELECT)==0) {
3030                                                         line->flag |= UI_SELECT;
3031                                                         ui_draw_linkline(but, line);
3032                                                 }
3033                                         }
3034                                         else if(line->flag & UI_SELECT) {
3035                                                 line->flag &= ~UI_SELECT;
3036                                                 ui_draw_linkline(but, line);
3037                                         }
3038                                         line= line->next;
3039                                 }
3040                         }
3041                         but= but->next;
3042                 }
3043                 glFlush();
3044                 glDrawBuffer(GL_BACK);
3045         }
3046 }
3047
3048
3049 /* only to be used to prevent an 'outside' event when using nested pulldowns */
3050 /* only one checks:
3051   - while mouse moves in triangular area defined old mouse position and left/right side of new menu
3052   - only for 1 second
3053   
3054   return 0: check outside
3055 */
3056 static int ui_mouse_motion_towards_block(uiBlock *block, uiEvent *uevent)
3057 {
3058         short mvalo[2], dx, dy, domx, domy;
3059         int counter=0;
3060
3061         if((block->direction & UI_TOP) || (block->direction & UI_DOWN)) return 0;
3062         if(uevent->event!= MOUSEX && uevent->event!= MOUSEY) return 0;
3063         
3064         /* calculate dominant direction */
3065         domx= ( -uevent->mval[0] + (block->maxx+block->minx)/2 );
3066         domy= ( -uevent->mval[1] + (block->maxy+block->miny)/2 );
3067         /* we need some accuracy */
3068         if( abs(domx)<4 ) return 0;
3069         
3070         uiGetMouse(mywinget(), mvalo);
3071         
3072         while(TRUE) {
3073                 uiGetMouse(mywinget(), uevent->mval);
3074                 
3075                 /* check inside, if so return */
3076                 if( block->minx <= uevent->mval[0] && block->maxx >= uevent->mval[0] ) {                
3077                         if( block->miny <= uevent->mval[1] && block->maxy >= uevent->mval[1] ) {
3078                                 return 1;
3079                         }
3080                 }
3081                 
3082                 /* check direction */
3083                 dx= uevent->mval[0] - mvalo[0];
3084                 dy= uevent->mval[1] - mvalo[1];
3085                                 
3086                 if( abs(dx)+abs(dy)>4 ) {  // threshold
3087                         /* menu to right */
3088                         if(domx>0) {
3089                                 int fac= (uevent->mval[0] - mvalo[0])*(mvalo[1] - (short)(block->maxy +20)) + (uevent->mval[1] - mvalo[1])*(-mvalo[0] + (short)block->minx);
3090                                 if( (fac>0)) {
3091                                         // printf("Left outside 1, Fac %d\n", fac); 
3092                                         return 0;
3093                                 }
3094                                 
3095                                 fac= (uevent->mval[0] - mvalo[0])*(mvalo[1] - (short)(block->miny-20)) + (uevent->mval[1] - mvalo[1])*(-mvalo[0] + (short)block->minx);
3096                                 if( (fac<0))  {
3097                                         //printf("Left outside 2, Fac %d\n", fac); 
3098                                         return 0;
3099                                 }
3100                         }
3101                         else {
3102                                 int fac= (uevent->mval[0] - mvalo[0])*(mvalo[1] - (short)(block->maxy+20)) + (uevent->mval[1] - mvalo[1])*(-mvalo[0] + (short)block->maxx);
3103                                 if( (fac<0)) {
3104                                         // printf("Left outside 1, Fac %d\n", fac); 
3105                                         return 0;
3106                                 }
3107                                 
3108                                 fac= (uevent->mval[0] - mvalo[0])*(mvalo[1] - (short)(block->miny-20)) + (uevent->mval[1] - mvalo[1])*(-mvalo[0] + (short)block->maxx);
3109                                 if( (fac>0))  {
3110                                         // printf("Left outside 2, Fac %d\n", fac); 
3111                                         return 0;
3112                                 }
3113                         }
3114                 }
3115                 
3116                 /* idle for this poor code */
3117                 PIL_sleep_ms(10);
3118                 counter++;
3119                 if(counter > 100) {
3120                         //printf("left because of timer (1 sec)\n");
3121                         return 0;
3122                 }
3123         }
3124         
3125         return 0;
3126 }
3127
3128
3129 static void ui_set_ftf_font(uiBlock *block)
3130 {
3131
3132 #ifdef INTERNATIONAL
3133         if(block->aspect<1.15) {
3134                 FTF_SetFontSize('l');
3135         }
3136         else if(block->aspect<1.59) {
3137                 FTF_SetFontSize('m');
3138         }
3139         else {
3140                 FTF_SetFontSize('s');
3141         }
3142 #endif
3143 }
3144
3145
3146 /* return: 
3147  * UI_NOTHING   pass event to other ui's
3148  * UI_CONT              don't pass event to other ui's
3149  * UI_RETURN    something happened, return, swallow event
3150  */
3151 static int ui_do_block(uiBlock *block, uiEvent *uevent)
3152 {
3153         uiBut *but, *bt;
3154         int butevent, event, retval=UI_NOTHING, count, act=0;
3155         int inside= 0, active=0;
3156         
3157         if(block->win != mywinget()) return UI_NOTHING;
3158
3159         /* filter some unwanted events */
3160         /* btw: we allow event==0 for first time in menus, draws the hilited item */
3161         if(uevent==0 || uevent->event==LEFTSHIFTKEY || uevent->event==RIGHTSHIFTKEY) return UI_NOTHING;
3162         
3163         if(block->flag & UI_BLOCK_ENTER_OK) {
3164                 if((uevent->event==RETKEY || uevent->event==PADENTER) && uevent->val) {
3165                         // printf("qual: %d %d %d\n", uevent->qual, get_qual(), G.qual);
3166                         if ((G.qual & LR_SHIFTKEY) == 0) {
3167                                 return UI_RETURN_OK;
3168                         }
3169                 }
3170         }               
3171
3172         ui_set_ftf_font(block); // sets just a pointer in ftf lib... the button dont have ftf handles
3173         
3174         // added this for panels in windows with buttons... 
3175         // maybe speed optimize should require test
3176         if((block->flag & UI_BLOCK_LOOP)==0) {
3177                 glMatrixMode(GL_PROJECTION);
3178                 bwin_load_winmatrix(block->win, block->winmat);
3179                 glMatrixMode(GL_MODELVIEW);
3180                 glLoadIdentity();
3181         }
3182
3183         Mat4CpyMat4(UIwinmat, block->winmat);
3184         uiPanelPush(block); // push matrix; no return without pop!
3185
3186         uiGetMouse(mywinget(), uevent->mval);   /* transformed mouseco */
3187
3188         /* check boundbox and panel events */
3189         if( block->minx <= uevent->mval[0] && block->maxx >= uevent->mval[0] ) {
3190                 // inside block
3191                 if( block->miny <= uevent->mval[1] && block->maxy >= uevent->mval[1] ) inside= 1;
3192                 
3193                 if(block->panel && block->panel->paneltab==NULL) {
3194                         
3195                         /* clicked at panel header? */
3196                         if( block->panel->flag & PNL_CLOSEDX) {
3197                                 if(block->minx <= uevent->mval[0] && block->minx+PNL_HEADER >= uevent->mval[0]) 
3198                                         inside= 2;
3199                         }
3200                         else if( (block->maxy <= uevent->mval[1]) && (block->maxy+PNL_HEADER >= uevent->mval[1]) )
3201                                 inside= 2;
3202                                 
3203                         if(inside) {    // this stuff should move to do_panel
3204                                 
3205                                 if(uevent->event==LEFTMOUSE) {
3206                                         if(inside==2) {
3207                                                 uiPanelPop(block);      // pop matrix; no return without pop!
3208                                                 ui_do_panel(block, uevent);
3209                                                 return UI_EXIT_LOOP;    // exit loops because of moving panels
3210                                         }
3211                                 }
3212                                 else if(uevent->event==ESCKEY) {
3213                                         if(block->handler) {
3214                                                 rem_blockhandler(curarea, block->handler);
3215                                                 addqueue(curarea->win, REDRAW, 1);
3216                                         }
3217                                 }
3218                                 else if(uevent->event==PADPLUSKEY || uevent->event==PADMINUS) {
3219                                         SpaceLink *sl= curarea->spacedata.first;
3220                                         if(curarea->spacetype!=SPACE_BUTS) {
3221                                                 if(uevent->event==PADPLUSKEY) sl->blockscale+= 0.1;
3222                                                 else sl->blockscale-= 0.1;
3223                                                 CLAMP(sl->blockscale, 0.6, 1.0);
3224                                                 addqueue(block->winq, REDRAW, 1);
3225                                                 retval= UI_CONT;
3226                                         }
3227                                 }
3228                         }
3229                 }
3230         }
3231         
3232         switch(uevent->event) {
3233         case LEFTARROWKEY:      // later on implement opening/closing sublevels of pupmenus
3234         case RIGHTARROWKEY:
3235                 break;
3236         
3237         case PAD8: case PAD2:
3238         case UPARROWKEY:
3239         case DOWNARROWKEY:
3240                 if(inside || (block->flag & UI_BLOCK_LOOP)) {
3241                         /* arrowkeys: only handle for block_loop blocks */
3242                         event= 0;
3243                         if(block->flag & UI_BLOCK_LOOP) {
3244                                 event= uevent->event;
3245                                 if(event==PAD8) event= UPARROWKEY;
3246                                 if(event==PAD2) event= DOWNARROWKEY;
3247                         }
3248                         else {
3249                                 if(uevent->event==PAD8) event= UPARROWKEY;
3250                                 if(uevent->event==PAD2) event= DOWNARROWKEY;
3251                         }
3252                         if(event && uevent->val) {
3253         
3254                                 for(but= block->buttons.first; but; but= but->next) {
3255                                         but->flag &= ~UI_MOUSE_OVER;
3256                 
3257                                         if(but->flag & UI_ACTIVE) {
3258                                                 but->flag &= ~UI_ACTIVE;
3259                                                 ui_draw_but(but);
3260         
3261                                                 if(event==UPARROWKEY) {
3262                                                         if(block->direction & UI_TOP) bt= ui_but_next(but);
3263                                                         else bt= ui_but_prev(but);
3264                                                 }
3265                                                 else {
3266                                                         if(block->direction & UI_TOP) bt= ui_but_prev(but);
3267                                                         else bt= ui_but_next(but);
3268                                                 }
3269                                                 
3270                                                 if(bt) {
3271                                                         bt->flag |= UI_ACTIVE;
3272                                                         ui_draw_but(bt);
3273                                                         break;
3274                  &nbs