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