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