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