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