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