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