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