New textbutton didn't accept buttons with Object names (or Mesh, etc), the
[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 /* return 1 if char ch is special character otherwise
1541  * it returns 0 */
1542 static short test_special_char(char ch)
1543 {
1544         switch(ch) {
1545                 case '\\':
1546                 case '/':
1547                 case '~':
1548                 case '!':
1549                 case '@':
1550                 case '#':
1551                 case '$':
1552                 case '%':
1553                 case '^':
1554                 case '&':
1555                 case '*':
1556                 case '(':
1557                 case ')':
1558                 case '+':
1559                 case '=':
1560                 case '{':
1561                 case '}':
1562                 case '[':
1563                 case ']':
1564                 case ':':
1565                 case ';':
1566                 case '\'':
1567                 case '\"':
1568                 case '<':
1569                 case '>':
1570                 case ',':
1571                 case '.':
1572                 case '?':
1573                 case '_':
1574                 case '-':
1575                 case ' ':
1576                         return 1;
1577                         break;
1578                 default:
1579                         break;
1580         }
1581         return 0;
1582 }
1583
1584 static int ui_do_but_TEX(uiBut *but)
1585 {
1586         unsigned short dev;
1587         short x, mval[2], len=0, dodraw, selextend=0;
1588         char *str, backstr[UI_MAX_DRAW_STR];
1589         short capturing, sx, sy, prevx;
1590         
1591         str= (char *)but->poin;
1592         
1593         but->flag |= UI_SELECT;
1594
1595         uiGetMouse(mywinget(), mval);
1596
1597         /* set cursor pos to the end of the text */
1598         but->pos = strlen(str);
1599         but->selsta = 0;
1600         but->selend = strlen(but->drawstr) - strlen(but->str);
1601
1602         /* backup */
1603         BLI_strncpy(backstr, but->poin, UI_MAX_DRAW_STR);
1604
1605         ui_draw_but(but);
1606         ui_block_flush_back(but->block);
1607         
1608         while (get_mbut() & L_MOUSE) BIF_wait_for_statechange();
1609         len= strlen(str);
1610
1611         but->min= 0.0;
1612         
1613         capturing = TRUE;
1614         while(capturing) {
1615                 char ascii;
1616                 short val;
1617
1618                 dodraw= 0;
1619                 dev = extern_qread_ext(&val, &ascii);
1620
1621                 if(dev==INPUTCHANGE) break;
1622                 else if(get_mbut() & R_MOUSE) break;
1623                 else if(get_mbut() & L_MOUSE) {
1624                         uiGetMouse(mywinget(), mval);
1625                         sx = mval[0]; sy = mval[1];
1626                         
1627                         if ((but->y1 <= sy) && (sy <= but->y2) && (but->x1 <= sx) && (sx <= but->x2)) {
1628                                 ui_set_cursor_pos_edittext(but, mval[0]);
1629                                 
1630                                 but->selsta = but->selend = but->pos;
1631                                 
1632                                 /* drag text select */
1633                                 prevx= mval[0];
1634                                 while (get_mbut() & L_MOUSE) {
1635                                         uiGetMouse(mywinget(), mval);
1636                                         
1637                                         if(prevx!=mval[0]) {
1638                                                 
1639                                                 if (mval[0] > sx) selextend = EXTEND_RIGHT;
1640                                                 else if (mval[0] < sx) selextend = EXTEND_LEFT;
1641                                                 
1642                                                 ui_set_cursor_pos_edittext(but, mval[0]);
1643                                                 
1644                                                 if (selextend == EXTEND_RIGHT) but->selend = but->pos;
1645                                                 if (selextend == EXTEND_LEFT) but->selsta = but->pos;
1646                                                 
1647                                                 ui_check_but(but);
1648                                                 ui_draw_but(but);
1649                                                 ui_block_flush_back(but->block);
1650                                         }                                       
1651                                         PIL_sleep_ms(10);
1652                                 }
1653                                 dodraw= 1;
1654                         } else break;
1655                 }
1656                 else if(dev==ESCKEY) break;
1657                 else if(dev==MOUSEX) val= 0;
1658                 else if(dev==MOUSEY) val= 0;
1659
1660                 if(ascii) {
1661                         if(len <= but->max) {
1662
1663                                 /* type over the current selection */
1664                                 if (SELWIDTH > 0) {     
1665                                         len -= ui_delete_selection_edittext(but);
1666                                 }
1667                         
1668                                 /* add ascii characters */
1669                                 if(len < but->max) {
1670                                         for(x= but->max; x>but->pos; x--)
1671                                                 str[x]= str[x-1];
1672                                         str[but->pos]= ascii;
1673                                         but->pos++; 
1674                                         len++;
1675                                         str[len]= '\0';
1676                                         dodraw= 1;
1677                                 }
1678                         }
1679                 }
1680                 else if(val) {
1681                 
1682                         switch (dev) {
1683                                 
1684                         case RIGHTARROWKEY:
1685                                 /* if there's a selection */
1686                                 if (SELWIDTH > 0) {
1687                                         /* extend the selection based on the first direction taken */
1688                                         if(G.qual & LR_SHIFTKEY) {
1689                                                 if (!selextend) {
1690                                                         selextend = EXTEND_RIGHT;
1691                                                 }
1692                                                 if (selextend == EXTEND_RIGHT) {
1693                                                         but->selend++;
1694                                                         if (but->selend > len) but->selend = len;
1695                                                 } else if (selextend == EXTEND_LEFT) {
1696                                                         but->selsta++;
1697                                                         /* if the selection start has gone past the end,
1698                                                         * flip them so they're in sync again */
1699                                                         if (but->selsta == but->selend) {
1700                                                                 but->pos = but->selsta;
1701                                                                 selextend = EXTEND_RIGHT;
1702                                                         }
1703                                                 }
1704                                         } else {
1705                                                 but->selsta = but->pos = but->selend;
1706                                                 selextend = 0;
1707                                         }
1708                                 } else {
1709                                         if(G.qual & LR_SHIFTKEY) {
1710                                                 /* make a selection, starting from the cursor position */
1711                                                 but->selsta = but->pos;
1712                                                 
1713                                                 but->pos++;
1714                                                 if(but->pos>strlen(str)) but->pos= strlen(str);
1715                                                 
1716                                                 but->selend = but->pos;
1717                                         } else if(G.qual & LR_CTRLKEY) {
1718                                                 /* jump betweenn special characters (/,\,_,-, etc.),
1719                                                  * look at function test_special_char() for complete
1720                                                  * list of special character, ctr -> */
1721                                                 while(but->pos < len) {
1722                                                         but->pos++;
1723                                                         if(test_special_char(str[but->pos])) break;
1724                                                 }
1725                                         } else {
1726                                                 but->pos++;
1727                                                 if(but->pos>strlen(str)) but->pos= strlen(str);
1728                                         }
1729                                 }
1730                                 dodraw= 1;
1731                                 break;
1732                                 
1733                         case LEFTARROWKEY:
1734                                 /* if there's a selection */
1735                                 if (SELWIDTH > 0) {
1736                                         /* extend the selection based on the first direction taken */
1737                                         if(G.qual & LR_SHIFTKEY) {
1738                                                 if (!selextend) {
1739                                                         selextend = EXTEND_LEFT;
1740                                                 }
1741                                                 if (selextend == EXTEND_LEFT) {
1742                                                         but->selsta--;
1743                                                         if (but->selsta < 0) but->selsta = 0;
1744                                                 } else if (selextend == EXTEND_RIGHT) {
1745                                                         but->selend--;
1746                                                         /* if the selection start has gone past the end,
1747                                                         * flip them so they're in sync again */
1748                                                         if (but->selsta == but->selend) {
1749                                                                 but->pos = but->selsta;
1750                                                                 selextend = EXTEND_LEFT;
1751                                                         }
1752                                                 }
1753                                         } else {
1754                                                 but->pos = but->selend = but->selsta;
1755                                                 selextend = 0;
1756                                         }
1757                                 } else {
1758                                         if(G.qual & LR_SHIFTKEY) {
1759                                                 /* make a selection, starting from the cursor position */
1760                                                 but->selend = but->pos;
1761                                                 
1762                                                 but->pos--;
1763                                                 if(but->pos<0) but->pos= 0;
1764                                                 
1765                                                 but->selsta = but->pos;
1766                                         } else if(G.qual & LR_CTRLKEY) {
1767                                                 /* jump betweenn special characters (/,\,_,-, etc.),
1768                                                  * look at function test_special_char() for complete
1769                                                  * list of special character, ctr -> */
1770                                                 while(but->pos > 0){
1771                                                         but->pos--;
1772                                                         if(test_special_char(str[but->pos])) break;
1773                                                 }
1774                                         } else {
1775                                                 if(but->pos>0) but->pos--;
1776                                         }
1777                                 }
1778                                 dodraw= 1;
1779                                 break;
1780
1781                         case DOWNARROWKEY:
1782                         case ENDKEY:
1783                                 if(G.qual & LR_SHIFTKEY) {
1784                                         but->selsta = but->pos;
1785                                         but->selend = strlen(str);
1786                                         selextend = EXTEND_RIGHT;
1787                                 } else {
1788                                         but->selsta = but->selend = but->pos= strlen(str);
1789                                 }
1790                                 dodraw= 1;
1791                                 break;
1792                                 
1793                         case UPARROWKEY:
1794                         case HOMEKEY:
1795                                 if(G.qual & LR_SHIFTKEY) {
1796                                         but->selend = but->pos;
1797                                         but->selsta = 0;
1798                                         selextend = EXTEND_LEFT;
1799                                 } else {
1800                                         but->selsta = but->selend = but->pos= 0;
1801                                 }
1802                                 dodraw= 1;
1803                                 break;
1804                                 
1805                         case PADENTER:
1806                         case RETKEY:
1807                                 capturing = FALSE;
1808                                 break;
1809                                 
1810                         case DELKEY:
1811                                 if (SELWIDTH > 0) {
1812                                         len -= ui_delete_selection_edittext(but);
1813                                         
1814                                         if (len < 0) len = 0;
1815                                         dodraw=1;
1816                                 }
1817                                 else if(but->pos>=0 && but->pos<strlen(str)) {
1818                                         for(x=but->pos; x<=strlen(str); x++)
1819                                                 str[x]= str[x+1];
1820                                         str[--len]='\0';
1821                                         dodraw= 1;
1822                                 }
1823                                 break;
1824
1825                         case BACKSPACEKEY:
1826                                 if(len!=0) {
1827                                         if (SELWIDTH > 0) {
1828                                                 len -= ui_delete_selection_edittext(but);
1829                                                 
1830                                                 if (len < 0) len = 0;
1831                                                 dodraw=1;
1832                                         }
1833                                         else if(get_qual() & LR_SHIFTKEY) {
1834                                                 str[0]= 0;
1835                                                 but->pos= 0;
1836                                                 len= 0;
1837                                                 dodraw= 1;
1838                                         }
1839                                         else if(but->pos>0) {
1840                                                 for(x=but->pos; x<=strlen(str); x++)
1841                                                         str[x-1]= str[x];
1842                                                 but->pos--;
1843                                                 str[--len]='\0';
1844                                                 dodraw= 1;
1845                                         }
1846                                 } 
1847                                 break;
1848                                 
1849                         case TABKEY:
1850                                 if(but->autocomplete_func) {
1851                                         but->autocomplete_func(str, but->autofunc_arg);
1852                                         but->pos= strlen(str);
1853                                         len= but->pos;
1854                                         dodraw= 1;
1855                                 }
1856                                 else capturing= FALSE;
1857                                 
1858                                 break;
1859                         }
1860                 }
1861
1862                 
1863                 if(dodraw) {
1864                         ui_check_but(but);
1865                         ui_draw_but(but);
1866                         ui_block_flush_back(but->block);
1867                 }
1868         }
1869         
1870         if(dev==ESCKEY) strcpy(but->poin, backstr);
1871         but->pos= -1;
1872         but->flag &= ~UI_SELECT;
1873
1874         if(dev!=ESCKEY) {
1875                 /* give butfunc the original text too */
1876                 /* feature used for bone renaming, channels, etc */
1877                 if(but->func_arg2==NULL) but->func_arg2= backstr;
1878                 uibut_do_func(but);
1879         }
1880         
1881         ui_check_but(but);
1882         ui_draw_but(but);
1883         
1884         if(dev==TABKEY) addqueue(but->win, G.qual?BUT_PREV:BUT_NEXT, 1);
1885         
1886         if(dev!=ESCKEY) return but->retval;
1887         else return B_NOP;      // prevent event to be passed on
1888 }
1889
1890
1891 static int ui_act_as_text_but(uiBut *but)
1892 {
1893         void *but_func;
1894         double value;
1895         float min, max;
1896         int temp, retval, textleft;
1897         char str[UI_MAX_DRAW_STR], *point;
1898         
1899         /* this function is abused for tab-cycling */
1900         if(but->type==TEX)
1901                 return ui_do_but_TEX(but);
1902         
1903         value= ui_get_but_val(but);
1904         if( but->pointype==FLO ) {
1905                 if(but->a2) { /* amount of digits defined */
1906                         if(but->a2==1) sprintf(str, "%.1f", value);
1907                         else if(but->a2==2) sprintf(str, "%.2f", value);
1908                         else if(but->a2==3) sprintf(str, "%.3f", value);
1909                         else sprintf(str, "%.4f", value);
1910                 }
1911                 else sprintf(str, "%.3f", value);
1912         }
1913         else {
1914                 sprintf(str, "%d", (int)value);
1915         }
1916         /* store values before calling as text button */
1917         point= but->poin;
1918         but->poin= str;
1919         but_func= but->func;
1920         but->func= NULL;
1921         min= but->min;
1922         max= but->max;
1923         but->min= 0.0;
1924         but->max= 15.0;
1925         temp= but->type;
1926         but->type= TEX;
1927         textleft= but->flag & UI_TEXT_LEFT;
1928         but->flag |= UI_TEXT_LEFT;
1929         ui_check_but(but);
1930         
1931         retval= ui_do_but_TEX(but);
1932         
1933         /* restore values */
1934         but->type= temp;
1935         but->poin= point;
1936         but->func= but_func;
1937         but->min= min;
1938         but->max= max;
1939         if(textleft==0) but->flag &= ~UI_TEXT_LEFT;
1940
1941         if( but->pointype==FLO ) value= atof(str);
1942         else value= atoi(str);
1943
1944         if(value<min) value= min;
1945         if(value>max) value= max;
1946
1947         ui_set_but_val(but, value);
1948         ui_check_but(but);
1949         ui_draw_but(but);
1950         
1951         return retval;
1952 }
1953
1954 static int ui_do_but_NUM(uiBut *but)
1955 {
1956         double value;
1957         float deler, fstart, f, tempf;
1958         int lvalue, temp; /*  , firsttime=1; */
1959         short retval=0, qual, sx, mval[2], pos=0;
1960
1961         but->flag |= UI_SELECT;
1962         ui_draw_but(but);
1963         ui_block_flush_back(but->block);
1964         
1965         uiGetMouse(mywinget(), mval);
1966         value= ui_get_but_val(but);
1967         
1968         sx= mval[0];
1969         fstart= (value - but->min)/(but->max-but->min);
1970         f= fstart;
1971         
1972         temp= (int)value;
1973         tempf= value;
1974         
1975         if(get_qual() & LR_SHIFTKEY) {  /* make it textbut */
1976                 if( ui_act_as_text_but(but) ) retval= but->retval;
1977         }
1978         else {
1979                 retval= but->retval;
1980                 /* firsttime: this button can be approached with enter as well */
1981                 while (get_mbut() & L_MOUSE) {
1982                         qual= get_qual();
1983                         
1984                         deler= 500;
1985                         if( but->pointype!=FLO ) {
1986         
1987                                 if( (but->max-but->min)<100 ) deler= 200.0;
1988                                 if( (but->max-but->min)<25 ) deler= 50.0;
1989         
1990                         }
1991                         if(qual & LR_SHIFTKEY) deler*= 10.0;
1992                         if(qual & LR_ALTKEY) deler*= 20.0;
1993         
1994                         uiGetMouse(mywinget(), mval);
1995                         
1996                         if(mval[0] != sx) {
1997                         
1998                                 f+= ((float)(mval[0]-sx))/deler;
1999                                 if(f>1.0) f= 1.0;
2000                                 if(f<0.0) f= 0.0;
2001                                 sx= mval[0];
2002                                 tempf= ( but->min + f*(but->max-but->min));
2003                                 
2004                                 if( but->pointype!=FLO ) {
2005                                         
2006                                         temp= floor(tempf+.5);
2007                                         
2008                                         if(tempf==but->min || tempf==but->max);
2009                                         else if(qual & LR_CTRLKEY) {
2010                                                 if(qual & LR_SHIFTKEY) temp= 100*(temp/100);
2011                                                 else temp= 10*(temp/10);
2012                                         }
2013                                         if( temp>=but->min && temp<=but->max) {
2014                                         
2015                                                 value= ui_get_but_val(but);
2016                                                 lvalue= (int)value;
2017                                                 
2018                                                 if(temp != lvalue ) {
2019                                                         pos= 1;
2020                                                         ui_set_but_val(but, (double)temp);
2021                                                         ui_check_but(but);
2022                                                         ui_draw_but(but);
2023                                                         ui_block_flush_back(but->block);
2024
2025                                                         uibut_do_func(but);
2026                                                 }
2027                                         }
2028         
2029                                 }
2030                                 else {
2031                                         temp= 0;
2032                                         if(qual & LR_CTRLKEY) {
2033                                                 if(qual & LR_SHIFTKEY) {
2034                                                         if(tempf==but->min || tempf==but->max);
2035                                                         else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
2036                                                         else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
2037                                                         else tempf= floor(tempf);
2038                                                 }
2039                                                 else {
2040                                                         if(tempf==but->min || tempf==but->max);
2041                                                         else if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
2042                                                         else if(but->max-but->min < 21.0) tempf= floor(tempf);
2043                                                         else tempf= 10.0*floor(tempf/10.0);
2044                                                 }
2045                                         }
2046         
2047                                         if( tempf>=but->min && tempf<=but->max) {
2048                                                 value= ui_get_but_val(but);
2049                                                 
2050                                                 if(tempf != value ) {
2051                                                         pos= 1;
2052                                                         ui_set_but_val(but, tempf);
2053                                                         ui_check_but(but);
2054                                                         ui_draw_but(but);
2055                                                         ui_block_flush_back(but->block);
2056                                                 }
2057                                         }
2058         
2059                                 }
2060                         }
2061                         BIF_wait_for_statechange();
2062                 }
2063                 
2064                 /* click on the side arrows to increment/decrement, click inside
2065                 * to edit the value directly */
2066                 if(pos==0) {  /* plus 1 or minus 1 */
2067                         if( but->pointype!=FLO ) {
2068         
2069                                 if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
2070                                         temp--;
2071                                         if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
2072                                 }
2073                                 else if(sx > (but->x1 + (2*(but->x2 - but->x1)/3) + 3)) {
2074                                         temp++;
2075                                         if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
2076                                 }
2077                                 else {
2078                                         if( ui_act_as_text_but(but) ); else retval= 0;
2079                                 }
2080                         }
2081                         else {
2082                         
2083                                 if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
2084                                         tempf-= 0.01*but->a1;
2085                                         if (tempf < but->min) tempf = but->min;
2086                                         ui_set_but_val(but, tempf);
2087                                 }
2088                                 else if(sx > but->x1 + (2*((but->x2 - but->x1)/3) + 3)) {
2089                                         tempf+= 0.01*but->a1;
2090                                         if (tempf < but->min) tempf = but->min;
2091                                         ui_set_but_val(but, tempf);
2092                                 }
2093                                 else {
2094                                         if( ui_act_as_text_but(but) ); else retval= 0;
2095                                 }
2096                         }
2097                 }
2098         }
2099
2100         but->flag &= ~UI_SELECT;
2101         ui_check_but(but);
2102         ui_draw_but(but);       
2103         ui_block_flush_back(but->block);
2104         
2105         uibut_do_func(but);
2106         
2107         return retval;
2108 }
2109
2110 static int ui_do_but_TOG3(uiBut *but)
2111
2112
2113         if( but->pointype==SHO ) {
2114                 short *sp= (short *)but->poin;
2115                 
2116                 if( BTST(sp[1], but->bitnr)) {
2117                         sp[1]= BCLR(sp[1], but->bitnr);
2118                         sp[0]= BCLR(sp[0], but->bitnr);
2119                 }
2120                 else if( BTST(sp[0], but->bitnr)) {
2121                         sp[1]= BSET(sp[1], but->bitnr);
2122                 } else {
2123                         sp[0]= BSET(sp[0], but->bitnr);
2124                 }
2125         }
2126         else {
2127                 if( BTST(*(but->poin+2), but->bitnr)) {
2128                         *(but->poin+2)= BCLR(*(but->poin+2), but->bitnr);
2129                         *(but->poin)= BCLR(*(but->poin), but->bitnr);
2130                 }
2131                 else if( BTST(*(but->poin), but->bitnr)) {
2132                         *(but->poin+2)= BSET(*(but->poin+2), but->bitnr);
2133                 } else {
2134                         *(but->poin)= BSET(*(but->poin), but->bitnr);
2135                 }
2136         }
2137         
2138         ui_is_but_sel(but);
2139         ui_draw_but(but);
2140         
2141         return but->retval;
2142 }
2143
2144 static int ui_do_but_ICONROW(uiBut *but)
2145 {
2146         ListBase listb= {NULL, NULL};
2147         uiBlock *block;
2148         int a;
2149         
2150         but->flag |= UI_SELECT;
2151         ui_draw_but(but);
2152         ui_block_flush_back(but->block);        // flush because this button creates own blocks loop
2153         
2154         /* here we go! */
2155         block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
2156         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
2157         block->themecol= TH_MENU_ITEM;
2158         
2159         for(a=(int)but->min; a<=(int)but->max; a++) {
2160                 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, "");
2161         }
2162         block->direction= UI_TOP;       
2163         ui_positionblock(block, but);
2164         
2165         /* the block is made with but-win, but is handled in mainwin space...
2166            this is needs better implementation */
2167         block->win= G.curscreen->mainwin;
2168         
2169         uiDoBlocks(&listb, 0);
2170
2171         but->flag &= ~UI_SELECT;
2172         ui_check_but(but);
2173         ui_draw_but(but);       
2174         
2175         return but->retval;
2176 }
2177
2178 static int ui_do_but_ICONTEXTROW(uiBut *but)
2179 {
2180         uiBlock *block;
2181         ListBase listb={NULL, NULL};
2182         int width, a, xmax, ypos;
2183         MenuData *md;
2184
2185         but->flag |= UI_SELECT;
2186         ui_draw_but(but);
2187         ui_block_flush_back(but->block);        // flush because this button creates own blocks loop
2188
2189         block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
2190         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
2191         block->themecol= TH_MENU_ITEM;
2192
2193         md= decompose_menu_string(but->str);
2194
2195         /* size and location */
2196         /* expand menu width to fit labels */
2197         if(md->title)
2198                 width= 2*strlen(md->title)+BIF_GetStringWidth(block->curfont, md->title, (U.transopts & USER_TR_MENUS));
2199         else
2200                 width= 0;
2201
2202         for(a=0; a<md->nitems; a++) {
2203                 xmax= BIF_GetStringWidth(block->curfont, md->items[a].str, (U.transopts & USER_TR_MENUS));
2204                 if(xmax>width) width= xmax;
2205         }
2206
2207         width+= 30;
2208         if (width<50) width=50;
2209
2210         ypos = 1;
2211
2212         /* loop through the menu options and draw them out with icons & text labels */
2213         for(a=0; a<md->nitems; a++) {
2214
2215                 /* add a space if there's a separator (%l) */
2216                 if (strcmp(md->items[a].str, "%l")==0) {
2217                         ypos +=3;
2218                 }
2219                 else {
2220                         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, "");
2221                         ypos += 20;
2222                 }
2223         }
2224         
2225         if(md->title) {
2226                 uiBut *bt;
2227                 uiSetCurFont(block, block->font+1);
2228                 bt= uiDefBut(block, LABEL, 0, md->title, 0, ypos, (short)width, 19, NULL, 0.0, 0.0, 0, 0, "");
2229                 uiSetCurFont(block, block->font);
2230                 bt->flag= UI_TEXT_LEFT;
2231         }
2232         
2233         block->direction= UI_TOP;
2234         ui_positionblock(block, but);
2235
2236         /* the block is made with but-win, but is handled in mainwin space...
2237            this is needs better implementation */
2238         block->win= G.curscreen->mainwin;
2239
2240         uiBoundsBlock(block, 3);
2241
2242         uiDoBlocks(&listb, 0);
2243         
2244         menudata_free(md);
2245
2246         but->flag &= ~UI_SELECT;
2247         ui_check_but(but);
2248         ui_draw_but(but);
2249
2250         uibut_do_func(but);
2251
2252         return but->retval;
2253
2254 }
2255
2256 static int ui_do_but_IDPOIN(uiBut *but)
2257 {
2258         char str[UI_MAX_DRAW_STR];
2259         ID *id;
2260         
2261         id= *but->idpoin_idpp;
2262         if(id) strcpy(str, id->name+2);
2263         else str[0]= 0;
2264         
2265         but->type= TEX;
2266         but->poin= str;
2267         but->min= 0.0;
2268         but->max= 22.0;
2269         ui_check_but(but);
2270         ui_do_but_TEX(but);
2271         but->poin= NULL;
2272         but->type= IDPOIN;
2273         
2274         but->idpoin_func(str, but->idpoin_idpp);
2275         ui_check_but(but);
2276         ui_draw_but(but);
2277         
2278         return but->retval;
2279 }
2280
2281 static int ui_do_but_SLI(uiBut *but)
2282 {
2283         float f, fstart, tempf = 0.0, deler, value;
2284         int sx, h, temp, pos=0, lvalue, redraw;
2285         short mval[2], qual;
2286         float curmatrix[4][4];
2287
2288         value= ui_get_but_val(but);
2289         uiGetMouse(mywinget(), mval);
2290
2291         sx= mval[0];
2292         h= but->y2-but->y1;
2293         fstart= but->max-but->min;
2294         fstart= (value - but->min)/fstart;
2295         temp= 32767;
2296
2297         if( but->type==NUMSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
2298         else if( but->type==HSVSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
2299         else deler= (but->x2-but->x1- 5.0*but->aspect);
2300         
2301
2302         while (get_mbut() & L_MOUSE) {
2303         
2304                 qual= get_qual();
2305                 uiGetMouse(mywinget(), mval);
2306                 
2307                 f= (float)(mval[0]-sx)/deler +fstart;
2308                 
2309                 if (qual & LR_SHIFTKEY) {
2310                         f= (f-fstart)/10.0 + fstart;
2311                 }
2312
2313                 CLAMP(f, 0.0, 1.0);
2314                 tempf= but->min+f*(but->max-but->min);          
2315                 temp= floor(tempf+.5);
2316
2317                 if(qual & LR_CTRLKEY) {
2318                         if(tempf==but->min || tempf==but->max);
2319                         else if( but->pointype==FLO ) {
2320
2321                                 if(qual & LR_SHIFTKEY) {
2322                                         if(tempf==but->min || tempf==but->max);
2323                                         else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
2324                                         else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
2325                                         else tempf= floor(tempf);
2326                                 }
2327                                 else {
2328                                         if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
2329                                         else if(but->max-but->min < 21.0) tempf= floor(tempf);
2330                                         else tempf= 10.0*floor(tempf/10.0);
2331                                 }
2332                         }
2333                         else {
2334                                 temp= 10*(temp/10);
2335                                 tempf= temp;
2336                         }
2337                 } 
2338         
2339                 value= ui_get_but_val(but);
2340                 lvalue= floor(value+0.5);
2341                 
2342                 if( but->pointype!=FLO )
2343                         redraw= (temp != lvalue);
2344                 else
2345                         redraw= (tempf != value);
2346
2347                 if (redraw) {
2348                         pos= 1;
2349                         ui_set_but_val(but, tempf);
2350                         ui_check_but(but);
2351                         ui_draw_but(but);
2352                         ui_block_flush_back(but->block);
2353                         
2354                         if(but->a1) {   /* color number */
2355                                 uiBut *bt= but->prev;
2356                                 while(bt) {
2357                                         if(bt->a2 == but->a1) ui_draw_but(bt);
2358                                         bt= bt->prev;
2359                                 }
2360                                 bt= but->next;
2361                                 while(bt) {
2362                                         if(bt->a2 == but->a1) ui_draw_but(bt);
2363                                         bt= bt->next;
2364                                 }
2365                         }
2366                         /* save current window matrix (global UIwinmat)
2367                            because button callback function MIGHT change it
2368                            - which has until now occured through the Python API
2369                         */
2370                         Mat4CpyMat4(curmatrix, UIwinmat);
2371                         uibut_do_func(but);
2372                         Mat4CpyMat4(UIwinmat, curmatrix);
2373                 } 
2374                 else BIF_wait_for_statechange();
2375         }
2376
2377         
2378         if(temp!=32767 && pos==0) {  /* plus 1 or minus 1 */
2379                 
2380                 if( but->type==SLI) f= (float)(mval[0]-but->x1)/(but->x2-but->x1-h);
2381                 else f= (float)(mval[0]- (but->x1+but->x2)/2)/( (but->x2-but->x1)/2 - h);
2382                 
2383                 f= but->min+f*(but->max-but->min);
2384                 
2385                 if( but->pointype!=FLO ) {
2386
2387                         if(f<temp) temp--;
2388                         else temp++;
2389                         if( temp>=but->min && temp<=but->max)
2390                                 ui_set_but_val(but, (float)temp);
2391                 
2392                 } 
2393                 else {
2394
2395                         if(f<tempf) tempf-=.01;
2396                         else tempf+=.01;
2397                         if( tempf>=but->min && tempf<=but->max)
2398                                 ui_set_but_val(but, tempf);
2399
2400                 }
2401                 uibut_do_func(but);
2402         }
2403         ui_check_but(but);
2404         ui_draw_but(but);
2405         ui_block_flush_back(but->block);
2406         
2407         return but->retval;
2408 }
2409
2410 static int ui_do_but_NUMSLI(uiBut *but)
2411 {
2412         short mval[2];
2413
2414         /* first define if it's a slider or textbut */
2415         uiGetMouse(mywinget(), mval);
2416         
2417         if(mval[0]>= -6+(but->x1+but->x2)/2 ) { /* slider */
2418                 but->flag |= UI_SELECT;
2419                 ui_draw_but(but);
2420                 ui_do_but_SLI(but);
2421                 but->flag &= ~UI_SELECT;
2422         }
2423         else {
2424                 ui_act_as_text_but(but);
2425                 uibut_do_func(but);     // this is done in ui_do_but_SLI() not in ui_act_as_text_but()
2426         }
2427
2428         while(get_mbut() & L_MOUSE) BIF_wait_for_statechange();
2429         
2430         ui_draw_but(but);
2431         
2432         /* hsv patch */
2433         if(but->type==HSVSLI) {
2434         
2435                 if(but->str[0]=='H') {
2436                         ui_draw_but(but->next);
2437                         ui_draw_but(but->next->next);
2438                 } 
2439                 else if(but->str[0]=='S') {
2440                         ui_draw_but(but->next);
2441                         ui_draw_but(but->prev);
2442                 } 
2443                 else if(but->str[0]=='V') {
2444                         ui_draw_but(but->prev);
2445                         ui_draw_but(but->prev->prev);
2446                 }
2447         }
2448         
2449         return but->retval;
2450 }
2451
2452 /* event denotes if we make first item active or not */
2453 static int ui_do_but_BLOCK(uiBut *but, int event)
2454 {
2455         uiBlock *block;
2456         uiBut *bt;
2457         
2458         but->flag |= UI_SELECT;
2459         ui_draw_but(but);       
2460
2461         block= but->block_func(but->poin);
2462         block->parent= but->block;      /* allows checking for nested pulldowns */
2463
2464         block->xofs = -2;       /* for proper alignment */
2465         
2466         /* only used for automatic toolbox, so can set the shift flag */
2467         if(but->flag & UI_MAKE_TOP) {
2468                 block->direction= UI_TOP|UI_SHIFT_FLIPPED;
2469                 uiBlockFlipOrder(block);
2470         }
2471         if(but->flag & UI_MAKE_DOWN) block->direction= UI_DOWN|UI_SHIFT_FLIPPED;
2472         if(but->flag & UI_MAKE_LEFT) block->direction |= UI_LEFT;
2473         if(but->flag & UI_MAKE_RIGHT) block->direction |= UI_RIGHT;
2474         
2475         ui_positionblock(block, but);
2476         block->flag |= UI_BLOCK_LOOP;
2477         
2478         /* blocks can come (and get scaled) from a normal window, now we go to screenspace */
2479         block->win= G.curscreen->mainwin;
2480         for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
2481         bwin_getsinglematrix(block->win, block->winmat);
2482         
2483         /* postpone draw, this will cause a new window matrix, first finish all other buttons */
2484         block->flag |= UI_BLOCK_REDRAW;
2485         
2486         if(event!=MOUSEX && event!=MOUSEY && event!=LEFTMOUSE && but->type==BLOCK) {
2487                 bt= ui_but_first(block);
2488                 if(bt) bt->flag |= UI_ACTIVE;
2489         }
2490         
2491         but->flag &= ~UI_SELECT;
2492         uibut_do_func(but);
2493         
2494         return 0;
2495 }
2496
2497 static int ui_do_but_BUTM(uiBut *but)
2498 {
2499
2500         ui_set_but_val(but, but->min);
2501         UIafterfunc= but->butm_func;
2502         UIafterfunc_arg= but->butm_func_arg;
2503         UIafterval= but->a2;
2504         
2505         return but->retval;
2506 }
2507
2508 static int ui_do_but_LABEL(uiBut *but)
2509 {
2510
2511         uibut_do_func(but);
2512         return but->retval;
2513 }
2514
2515 static uiBut *ui_get_valid_link_button(uiBlock *block, uiBut *but, short *mval)
2516 {
2517         uiBut *bt;
2518         
2519                 /* find button to link to */
2520         for (bt= block->buttons.first; bt; bt= bt->next)
2521                 if(bt!=but && uibut_contains_pt(bt, mval))
2522                         break;
2523
2524         if (bt) {
2525                 if (but->type==LINK && bt->type==INLINK) {
2526                         if( but->link->tocode == (int)bt->min ) {
2527                                 return bt;
2528                         }
2529                 }
2530                 else if(but->type==INLINK && bt->type==LINK) {
2531                         if( bt->link->tocode == (int)but->min ) {
2532                                 return bt;
2533                         }
2534                 }
2535         }
2536
2537         return NULL;
2538 }
2539
2540 static int ui_is_a_link(uiBut *from, uiBut *to)
2541 {
2542         uiLinkLine *line;
2543         uiLink *link;
2544         
2545         link= from->link;
2546         if(link) {
2547                 line= link->lines.first;
2548                 while(line) {
2549                         if(line->from==from && line->to==to) return 1;
2550                         line= line->next;
2551                 }
2552         }
2553         return 0;
2554 }
2555
2556 static uiBut *ui_find_inlink(uiBlock *block, void *poin)
2557 {
2558         uiBut *but;
2559         
2560         but= block->buttons.first;
2561         while(but) {
2562                 if(but->type==INLINK) {
2563                         if(but->poin == poin) return but;
2564                 }
2565                 but= but->next;
2566         }
2567         return NULL;
2568 }
2569
2570 static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt)
2571 {
2572         uiLinkLine *line;
2573         
2574         line= MEM_callocN(sizeof(uiLinkLine), "linkline");
2575         BLI_addtail(listb, line);
2576         line->from= but;
2577         line->to= bt;
2578 }
2579
2580
2581 void uiComposeLinks(uiBlock *block)
2582 {
2583         uiBut *but, *bt;
2584         uiLink *link;
2585         void ***ppoin;
2586         int a;
2587         
2588         but= block->buttons.first;
2589         while(but) {
2590                 if(but->type==LINK) {
2591                         link= but->link;
2592                         
2593                         /* for all pointers in the array */
2594                         if(link) {
2595                                 if(link->ppoin) {
2596                                         ppoin= link->ppoin;
2597                                         for(a=0; a < *(link->totlink); a++) {
2598                                                 bt= ui_find_inlink(block, (*ppoin)[a] );
2599                                                 if(bt) {
2600                                                         ui_add_link_line(&link->lines, but, bt);
2601                                                 }
2602                                         }
2603                                 }
2604                                 else if(link->poin) {
2605                                         bt= ui_find_inlink(block, *(link->poin) );
2606                                         if(bt) {
2607                                                 ui_add_link_line(&link->lines, but, bt);
2608                                         }
2609                                 }
2610                         }
2611                 }
2612                 but= but->next;
2613         }
2614 }
2615
2616 static void ui_add_link(uiBut *from, uiBut *to)
2617 {
2618         /* in 'from' we have to add a link to 'to' */
2619         uiLink *link;
2620         void **oldppoin;
2621         int a;
2622         
2623         if(ui_is_a_link(from, to)) {
2624                 printf("already exists\n");
2625                 return;
2626         }
2627         
2628         link= from->link;
2629
2630         /* are there more pointers allowed? */
2631         if(link->ppoin) {
2632                 oldppoin= *(link->ppoin);
2633                 
2634                 (*(link->totlink))++;
2635                 *(link->ppoin)= MEM_callocN( *(link->totlink)*sizeof(void *), "new link");
2636
2637                 for(a=0; a< (*(link->totlink))-1; a++) {
2638                         (*(link->ppoin))[a]= oldppoin[a];
2639                 }
2640                 (*(link->ppoin))[a]= to->poin;
2641                 
2642                 if(oldppoin) MEM_freeN(oldppoin);
2643         }
2644         else {
2645                 *(link->poin)= to->poin;
2646         }
2647         
2648 }
2649
2650 static int ui_do_but_LINK(uiBlock *block, uiBut *but)
2651 {
2652         /* 
2653          * This button only visualizes, the dobutton mode
2654          * can add a new link, but then the whole system
2655          * should be redrawn/initialized. 
2656          * 
2657          */
2658         uiBut *bt=0, *bto=NULL;
2659         short sval[2], mval[2], mvalo[2], first= 1;
2660
2661         uiGetMouse(curarea->win, sval);
2662         mvalo[0]= sval[0];
2663         mvalo[1]= sval[1];
2664         
2665         while (get_mbut() & L_MOUSE) {
2666                 uiGetMouse(curarea->win, mval);
2667
2668                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || first) {                   
2669                                 /* clear completely, because of drawbuttons */
2670                         bt= ui_get_valid_link_button(block, but, mval);
2671                         if(bt) {
2672                                 bt->flag |= UI_ACTIVE;
2673                                 ui_draw_but(bt);
2674                         }
2675                         if(bto && bto!=bt) {
2676                                 bto->flag &= ~UI_ACTIVE;
2677                                 ui_draw_but(bto);
2678                         }
2679                         bto= bt;
2680
2681                         if (!first) {
2682                                 glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
2683                         }
2684                         glutil_draw_front_xor_line(sval[0], sval[1], mval[0], mval[1]);
2685
2686                         mvalo[0]= mval[0];
2687                         mvalo[1]= mval[1];
2688
2689                         first= 0;
2690                 }
2691                 else BIF_wait_for_statechange();                
2692         }
2693         
2694         if (!first) {
2695                 glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
2696         }
2697
2698         if(bt) {
2699                 if(but->type==LINK) ui_add_link(but, bt);
2700                 else ui_add_link(bt, but);
2701
2702                 scrarea_queue_winredraw(curarea);
2703         }
2704
2705         return 0;
2706 }
2707
2708 /* picker sizes S hsize, F full size, D spacer, B button/pallette height  */
2709 #define SPICK   110.0
2710 #define FPICK   180.0
2711 #define DPICK   6.0
2712 #define BPICK   24.0
2713
2714 #define UI_PALETTE_TOT 16
2715 /* note; in tot+1 the old color is stored */
2716 static float palette[UI_PALETTE_TOT+1][3]= {
2717 {0.93, 0.83, 0.81}, {0.88, 0.89, 0.73}, {0.69, 0.81, 0.57}, {0.51, 0.76, 0.64}, 
2718 {0.37, 0.56, 0.61}, {0.33, 0.29, 0.55}, {0.46, 0.21, 0.51}, {0.40, 0.12, 0.18}, 
2719 {1.0, 1.0, 1.0}, {0.85, 0.85, 0.85}, {0.7, 0.7, 0.7}, {0.56, 0.56, 0.56}, 
2720 {0.42, 0.42, 0.42}, {0.28, 0.28, 0.28}, {0.14, 0.14, 0.14}, {0.0, 0.0, 0.0}
2721 };  
2722
2723 /* for picker, while editing hsv */
2724 static void ui_set_but_hsv(uiBut *but)
2725 {
2726         float col[3];
2727         
2728         hsv_to_rgb(but->hsv[0], but->hsv[1], but->hsv[2], col, col+1, col+2);
2729         ui_set_but_vectorf(but, col);
2730 }
2731
2732 static void update_picker_hex(uiBlock *block, float *rgb)
2733 {
2734         uiBut *bt;
2735         char col[16];
2736         
2737         sprintf(col, "%02X%02X%02X", (unsigned int)(rgb[0]*255.0), (unsigned int)(rgb[1]*255.0), (unsigned int)(rgb[2]*255.0));
2738         
2739         // this updates button strings, is hackish... but button pointers are on stack of caller function
2740
2741         for(bt= block->buttons.first; bt; bt= bt->next) {
2742                 if(strcmp(bt->str, "Hex: ")==0) {
2743                         strcpy(bt->poin, col);
2744                         ui_check_but(bt);
2745                         break;
2746                 }
2747         }
2748 }
2749
2750 static void update_picker_buts_hsv(uiBlock *block, float *hsv)
2751 {
2752         uiBut *bt;
2753         float r, g, b;
2754         float rgb[3];
2755         
2756         // this updates button strings, is hackish... but button pointers are on stack of caller function
2757         hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r, &g, &b);
2758         
2759         rgb[0] = r; rgb[1] = g; rgb[2] = b;
2760         update_picker_hex(block, rgb);
2761
2762         for(bt= block->buttons.first; bt; bt= bt->next) {
2763                 if(bt->type==HSVCUBE) {
2764                         VECCOPY(bt->hsv, hsv);
2765                         ui_set_but_hsv(bt);
2766                 }
2767                 else if(bt->str[1]==' ') {
2768                         if(bt->str[0]=='R') {
2769                                 ui_set_but_val(bt, r);
2770                                 ui_check_but(bt);
2771                         }
2772                         else if(bt->str[0]=='G') {
2773                                 ui_set_but_val(bt, g);
2774                                 ui_check_but(bt);
2775                         }
2776                         else if(bt->str[0]=='B') {
2777                                 ui_set_but_val(bt, b);
2778                                 ui_check_but(bt);
2779                         }
2780                         else if(bt->str[0]=='H') {
2781                                 ui_set_but_val(bt, hsv[0]);
2782                                 ui_check_but(bt);
2783                         }
2784                         else if(bt->str[0]=='S') {
2785                                 ui_set_but_val(bt, hsv[1]);
2786                                 ui_check_but(bt);
2787                         }
2788                         else if(bt->str[0]=='V') {
2789                                 ui_set_but_val(bt, hsv[2]);
2790                                 ui_check_but(bt);
2791                         }
2792                 }
2793         }
2794 }
2795
2796 static void update_picker_buts_hex(uiBlock *block, char *hexcol)
2797 {
2798         uiBut *bt;
2799         float r=0, g=0, b=0;
2800         float h, s, v;
2801         
2802         
2803         // this updates button strings, is hackish... but button pointers are on stack of caller function
2804         hex_to_rgb(hexcol, &r, &g, &b);
2805         rgb_to_hsv(r, g, b, &h, &s, &v);
2806
2807         for(bt= block->buttons.first; bt; bt= bt->next) {
2808                 if(bt->type==HSVCUBE) {
2809                         bt->hsv[0] = h;
2810                         bt->hsv[1] = s;                 
2811                         bt->hsv[2] = v;
2812                         ui_set_but_hsv(bt);
2813                 }
2814                 else if(bt->str[1]==' ') {
2815                         if(bt->str[0]=='R') {
2816                                 ui_set_but_val(bt, r);
2817                                 ui_check_but(bt);
2818                         }
2819                         else if(bt->str[0]=='G') {
2820                                 ui_set_but_val(bt, g);
2821                                 ui_check_but(bt);
2822                         }
2823                         else if(bt->str[0]=='B') {
2824                                 ui_set_but_val(bt, b);
2825                                 ui_check_but(bt);
2826                         }
2827                         else if(bt->str[0]=='H') {
2828                                 ui_set_but_val(bt, h);
2829                                 ui_check_but(bt);
2830                         }
2831                         else if(bt->str[0]=='S') {
2832                                 ui_set_but_val(bt, s);
2833                                 ui_check_but(bt);
2834                         }
2835                         else if(bt->str[0]=='V') {
2836                                 ui_set_but_val(bt, v);
2837                                 ui_check_but(bt);
2838                         }
2839                 }
2840         }
2841 }
2842
2843
2844
2845 /* bt1 is palette but, col1 is original color */
2846 /* callback to copy from/to palette */
2847 static void do_palette_cb(void *bt1, void *col1)
2848 {
2849         uiBut *but1= (uiBut *)bt1;
2850         uiBut *but;
2851         float *col= (float *)col1;
2852         float *fp, hsv[3];
2853         
2854         fp= (float *)but1->poin;
2855         
2856         if( (get_qual() & LR_CTRLKEY) ) {
2857                 VECCOPY(fp, col);
2858         }
2859         else {
2860                 VECCOPY(col, fp);
2861         }
2862         
2863         rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
2864         update_picker_buts_hsv(but1->block, hsv);
2865         update_picker_hex(but1->block, col);
2866         
2867         for (but= but1->block->buttons.first; but; but= but->next) {
2868                 ui_draw_but(but);
2869         }
2870         but= but1->block->buttons.first;
2871         ui_block_flush_back(but->block);
2872 }
2873
2874 /* bt1 is num but, col1 is pointer to original color */
2875 /* callback to handle changes in num-buts in picker */
2876 static void do_palette1_cb(void *bt1, void *hsv1)
2877 {
2878         uiBut *but1= (uiBut *)bt1;
2879         uiBut *but;
2880         float *hsv= (float *)hsv1;
2881         float *fp= NULL;
2882         
2883         if(but1->str[0]=='R') fp= (float *)but1->poin;
2884         else if(but1->str[0]=='G') fp= ((float *)but1->poin)-1;
2885         else if(but1->str[0]=='B') fp= ((float *)but1->poin)-2;
2886         
2887         if(fp) {
2888                 rgb_to_hsv(fp[0], fp[1], fp[2], hsv, hsv+1, hsv+2);
2889         }
2890
2891         update_picker_buts_hsv(but1->block, hsv);       
2892         if (fp) update_picker_hex(but1->block, fp);
2893         
2894         for (but= but1->block->buttons.first; but; but= but->next) {
2895                 ui_draw_but(but);
2896         }
2897         
2898         but= but1->block->buttons.first;
2899         ui_block_flush_back(but->block);
2900
2901 }
2902
2903 static void do_palette_hex_cb(void *bt1, void *hexcl)
2904 {
2905         uiBut *but1= (uiBut *)bt1;
2906         uiBut *but;
2907         char *hexcol= (char *)hexcl;
2908         
2909         update_picker_buts_hex(but1->block, hexcol);    
2910         
2911         for (but= but1->block->buttons.first; but; but= but->next) {
2912                 ui_draw_but(but);
2913         }
2914         
2915         but= but1->block->buttons.first;
2916         ui_block_flush_back(but->block);
2917
2918 }
2919
2920 /* color picker, Gimp version. mode: 'f' = floating panel, 'p' =  popup */
2921 /* col = read/write to, hsv/old/hexcol = memory for temporal use */
2922 void uiBlockPickerButtons(uiBlock *block, float *col, float *hsv, float *old, char *hexcol, char mode, short retval)
2923 {
2924         uiBut *bt;
2925         float h, offs;
2926         int a;
2927
2928         VECCOPY(old, col);      // old color stored there, for palette_cb to work
2929         
2930         // the cube intersection
2931         bt= uiDefButF(block, HSVCUBE, retval, "",       0,DPICK+BPICK,FPICK,FPICK, col, 0.0, 0.0, 2, 0, "");
2932         uiButSetFlag(bt, UI_NO_HILITE);
2933
2934         bt= uiDefButF(block, HSVCUBE, retval, "",       0,0,FPICK,BPICK, col, 0.0, 0.0, 3, 0, "");
2935         uiButSetFlag(bt, UI_NO_HILITE);
2936
2937         // palette
2938         
2939         uiBlockSetEmboss(block, UI_EMBOSSP);
2940         
2941         bt=uiDefButF(block, COL, retval, "",            FPICK+DPICK, 0, BPICK,BPICK, old, 0.0, 0.0, -1, 0, "Old color, click to restore");
2942         uiButSetFunc(bt, do_palette_cb, bt, col);
2943         uiDefButF(block, COL, retval, "",               FPICK+DPICK, BPICK+DPICK, BPICK,60-BPICK-DPICK, col, 0.0, 0.0, -1, 0, "Active color");
2944
2945         h= (DPICK+BPICK+FPICK-64)/(UI_PALETTE_TOT/2.0);
2946         uiBlockBeginAlign(block);
2947         for(a= -1+UI_PALETTE_TOT/2; a>=0; a--) {
2948                 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");
2949                 uiButSetFunc(bt, do_palette_cb, bt, col);
2950                 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");               
2951                 uiButSetFunc(bt, do_palette_cb, bt, col);
2952         }
2953         uiBlockEndAlign(block);
2954         
2955         uiBlockSetEmboss(block, UI_EMBOSS);
2956
2957         // buttons
2958         rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
2959         sprintf(hexcol, "%02X%02X%02X", (unsigned int)(col[0]*255.0), (unsigned int)(col[1]*255.0), (unsigned int)(col[2]*255.0));      
2960
2961         offs= FPICK+2*DPICK+BPICK;
2962
2963         bt= uiDefBut(block, TEX, retval, "Hex: ", offs, 140, 140, 20, hexcol, 0, 8, 0, 0, "Hex triplet for colour (#RRGGBB)");
2964         uiButSetFunc(bt, do_palette_hex_cb, bt, hexcol);
2965
2966         uiBlockBeginAlign(block);
2967         bt= uiDefButF(block, NUMSLI, retval, "R ",      offs, 110, 140,20, col, 0.0, 1.0, 10, 2, "");
2968         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2969         bt= uiDefButF(block, NUMSLI, retval, "G ",      offs, 90, 140,20, col+1, 0.0, 1.0, 10, 2, "");
2970         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2971         bt= uiDefButF(block, NUMSLI, retval, "B ",      offs, 70, 140,20, col+2, 0.0, 1.0, 10, 2, "");
2972         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2973         
2974         uiBlockBeginAlign(block);
2975         bt= uiDefButF(block, NUMSLI, retval, "H ",      offs, 40, 140,20, hsv, 0.0, 1.0, 10, 2, "");
2976         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2977         bt= uiDefButF(block, NUMSLI, retval, "S ",      offs, 20, 140,20, hsv+1, 0.0, 1.0, 10, 2, "");
2978         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2979         bt= uiDefButF(block, NUMSLI, retval, "V ",      offs, 0, 140,20, hsv+2, 0.0, 1.0, 10, 2, "");
2980         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
2981         uiBlockEndAlign(block);
2982 }
2983
2984
2985 static int ui_do_but_COL(uiBut *but)
2986 {
2987         uiBlock *block;
2988         uiBut *bt;
2989         ListBase listb={NULL, NULL};
2990         float hsv[3], old[3], *poin= NULL, colstore[3];
2991         static char hexcol[128];
2992         short event;
2993         
2994         // signal to prevent calling up color picker
2995         if(but->a1 == -1) {
2996                 uibut_do_func(but);
2997                 return but->retval;
2998         }
2999         
3000         // enable char button too, use temporal colstore for color
3001         if(but->pointype!=FLO) {
3002                 if(but->pointype==CHA) {
3003                         ui_get_but_vectorf(but, colstore);
3004                         poin= colstore;
3005                 }
3006                 else return but->retval;
3007         }
3008         else poin= (float *)but->poin;
3009         
3010         block= uiNewBlock(&listb, "colorpicker", UI_EMBOSS, UI_HELV, but->win);
3011         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW;
3012         block->themecol= TH_BUT_NUM;
3013         
3014         uiBlockPickerButtons(block, poin, hsv, old, hexcol, 'p', 0);
3015
3016         /* and lets go */
3017         block->direction= UI_TOP;
3018         ui_positionblock(block, but);
3019         uiBoundsBlock(block, 3);
3020         
3021         /* blocks can come from a normal window, but we go to screenspace */
3022         block->win= G.curscreen->mainwin;
3023         for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
3024         bwin_getsinglematrix(block->win, block->winmat);
3025
3026         event= uiDoBlocks(&listb, 0);
3027         
3028         if(but->pointype==CHA) ui_set_but_vectorf(but, colstore);
3029         
3030         return but->retval;
3031
3032 }
3033
3034 static int ui_do_but_HSVCUBE(uiBut *but)
3035 {
3036         uiBut *bt;
3037         float x, y;
3038         short mval[2], mvalo[2];
3039         
3040         mvalo[0]= mvalo[1]= -32000;
3041         
3042         /* we work on persistant hsv, to prevent it being converted back and forth all the time */
3043                            
3044         while (get_mbut() & L_MOUSE) {
3045                 
3046                 uiGetMouse(mywinget(), mval);
3047
3048                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {                    
3049                         mvalo[0]= mval[0];
3050                         mvalo[1]= mval[1];
3051                         
3052                         /* relative position within box */
3053                         x= ((float)mval[0]-but->x1)/(but->x2-but->x1);
3054                         y= ((float)mval[1]-but->y1)/(but->y2-but->y1);
3055                         CLAMP(x, 0.0, 1.0);
3056                         CLAMP(y, 0.0, 1.0);
3057                         
3058                         if(but->a1==0) {
3059                                 but->hsv[0]= x; 
3060                                 but->hsv[2]= y; 
3061                                 // hsv_to_rgb(x, s, y, col, col+1, col+2);
3062                         }
3063                         else if(but->a1==1) {
3064                                 but->hsv[0]= x;                                 
3065                                 but->hsv[1]= y;                                 
3066                                 // hsv_to_rgb(x, y, v, col, col+1, col+2);
3067                         }
3068                         else if(but->a1==2) {
3069                                 but->hsv[2]= x; 
3070                                 but->hsv[1]= y; 
3071                                 // hsv_to_rgb(h, y, x, col, col+1, col+2);
3072                         }
3073                         else {
3074                                 but->hsv[0]= x; 
3075                                 // hsv_to_rgb(x, s, v, col, col+1, col+2);
3076                         }
3077         
3078                         ui_set_but_hsv(but);    // converts to rgb
3079                         
3080                         // update button values and strings
3081                         update_picker_buts_hsv(but->block, but->hsv);
3082 //                      update_picker_buts_hex(but->block, but->hsv);                   
3083
3084                         /* we redraw the entire block */
3085                         for (bt= but->block->buttons.first; bt; bt= bt->next) {
3086                                 if(but->poin == bt->poin) VECCOPY(bt->hsv, but->hsv);
3087                                 ui_draw_but(bt);
3088                         }
3089                         ui_block_flush_back(but->block);
3090                 }
3091                 else BIF_wait_for_statechange();
3092         }
3093
3094         return but->retval;
3095 }
3096
3097 #ifdef INTERNATIONAL
3098
3099 static int ui_do_but_CHARTAB(uiBut *but)
3100 {
3101         /* Variables */
3102         short mval[2];
3103         float sx, sy, ex, ey;
3104         float width, height;
3105         float butw, buth;
3106         int x, y, cs, che;
3107
3108         /* Check the position */
3109         uiGetMouse(mywinget(), mval);
3110
3111         /* Calculate the size of the button */
3112         width = abs(but->x2 - but->x1);
3113         height = abs(but->y2 - but->y1);
3114
3115         butw = floor(width / 12);
3116         buth = floor(height / 6);
3117
3118         /* Initialize variables */
3119         sx = but->x1;
3120         ex = but->x1 + butw;
3121         sy = but->y1 + height - buth;
3122         ey = but->y1 + height;
3123
3124         cs = G.charstart;
3125
3126         /* And the character is */
3127         x = (int) ((mval[0] / butw) - 0.5);
3128         y = (int) (6 - ((mval[1] / buth) - 0.5));
3129
3130         che = cs + (y*12) + x;
3131
3132         if(che > G.charmax)
3133                 che = 0;
3134
3135         if(G.obedit)
3136         {
3137                 do_textedit(0,0,che);
3138         }
3139
3140         return but->retval;
3141 }
3142
3143 #endif
3144
3145
3146 /* ************************************************ */
3147
3148 void uiSetButLock(int val, char *lockstr)
3149 {
3150         UIlock |= val;
3151         if (val) UIlockstr= lockstr;
3152 }
3153
3154 void uiClearButLock()
3155 {
3156         UIlock= 0;
3157         UIlockstr= NULL;
3158 }
3159
3160 /* *************************************************************** */
3161
3162 static void setup_file(uiBlock *block)
3163 {
3164         uiBut *but;
3165         FILE *fp;
3166
3167         fp= fopen("butsetup","w");
3168         if(fp==NULL);
3169         else {
3170                 but= block->buttons.first;
3171                 while(but) {
3172                         ui_check_but(but);
3173                         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);
3174                         but= but->next;
3175                 }
3176                 fclose(fp);
3177         }
3178 }
3179
3180
3181 static void edit_but(uiBlock *block, uiBut *but, uiEvent *uevent)
3182 {
3183         short dx, dy, mval[2], mvalo[2], didit=0;
3184         
3185         getmouseco_sc(mvalo);
3186         while(TRUE) {
3187                 if( !(get_mbut() & L_MOUSE) ) break;    
3188         
3189                 getmouseco_sc(mval);
3190                 dx= (mval[0]-mvalo[0]);
3191                 dy= (mval[1]-mvalo[1]);
3192                 
3193                 if(dx!=0 || dy!=0) {
3194                         mvalo[0]= mval[0];
3195                         mvalo[1]= mval[1];
3196                         
3197                         cpack(0xc0c0c0);
3198                         glRectf(but->x1-2, but->y1-2, but->x2+2, but->y2+2); 
3199                         
3200                         if((uevent->qual & LR_SHIFTKEY)==0) {
3201                                 but->x1 += dx;
3202                                 but->y1 += dy;
3203                         }
3204                         but->x2 += dx;
3205                         but->y2 += dy;
3206                         
3207                         ui_draw_but(but);
3208                         ui_block_flush_back(but->block);
3209                         didit= 1;
3210
3211                 }
3212                 /* idle for this poor code */
3213                 else PIL_sleep_ms(30);
3214         }
3215         if(didit) setup_file(block);
3216 }
3217
3218
3219 /* is called when LEFTMOUSE is pressed or released
3220  * return: butval or zero
3221  */
3222 static int ui_do_button(uiBlock *block, uiBut *but, uiEvent *uevent)
3223 {
3224         int retval= 0;
3225
3226         if(but->lock) {
3227                 if (but->lockstr) {
3228                         error("%s", but->lockstr);
3229                         return 0;
3230                 }
3231         } 
3232         else {
3233                 if( but->pointype ) {           /* there's a pointer needed */
3234                         if(but->poin==0 ) {
3235                                 printf("DoButton pointer error: %s\n",but->str);
3236                                 return 0;
3237                         }
3238                 }
3239         }
3240
3241         if(G.rt==1 && (uevent->qual & LR_CTRLKEY)) {
3242                 edit_but(block, but, uevent);
3243                 return 0;
3244         }
3245         
3246         block->flag |= UI_BLOCK_BUSY;
3247
3248         switch(but->type) {
3249         case BUT:
3250                 if(uevent->val) retval= ui_do_but_BUT(but);             
3251                 break;