2.5: Render
[blender-staging.git] / source / blender / editors / interface / interface_regions.c
1 /**
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  * 
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_screen_types.h"
34 #include "DNA_view2d_types.h"
35 #include "DNA_userdef_types.h"
36 #include "DNA_windowmanager_types.h"
37
38 #include "BLI_arithb.h"
39 #include "BLI_blenlib.h"
40 #include "BLI_dynstr.h"
41
42 #include "BKE_context.h"
43 #include "BKE_icons.h"
44 #include "BKE_report.h"
45 #include "BKE_screen.h"
46 #include "BKE_texture.h"
47 #include "BKE_utildefines.h"
48
49 #include "WM_api.h"
50 #include "WM_types.h"
51 #include "wm_draw.h"
52 #include "wm_subwindow.h"
53 #include "wm_window.h"
54
55 #include "RNA_access.h"
56
57 #include "BIF_gl.h"
58
59 #include "UI_interface.h"
60 #include "UI_interface_icons.h"
61 #include "UI_view2d.h"
62
63 #include "BLF_api.h"
64
65 #include "ED_screen.h"
66
67 #include "interface_intern.h"
68
69 #define MENU_BUTTON_HEIGHT      20
70 #define MENU_SEPR_HEIGHT        6
71 #define B_NOP                   -1
72 #define MENU_SHADOW_SIDE        8
73 #define MENU_SHADOW_BOTTOM      10
74 #define MENU_TOP                        8
75
76 /*********************** Menu Data Parsing ********************* */
77
78 typedef struct {
79         char *str;
80         int retval;
81         int icon;
82 } MenuEntry;
83
84 typedef struct {
85         char *instr;
86         char *title;
87         int titleicon;
88         
89         MenuEntry *items;
90         int nitems, itemssize;
91 } MenuData;
92
93 static MenuData *menudata_new(char *instr)
94 {
95         MenuData *md= MEM_mallocN(sizeof(*md), "MenuData");
96
97         md->instr= instr;
98         md->title= NULL;
99         md->titleicon= 0;
100         md->items= NULL;
101         md->nitems= md->itemssize= 0;
102         
103         return md;
104 }
105
106 static void menudata_set_title(MenuData *md, char *title, int titleicon)
107 {
108         if (!md->title)
109                 md->title= title;
110         if (!md->titleicon)
111                 md->titleicon= titleicon;
112 }
113
114 static void menudata_add_item(MenuData *md, char *str, int retval, int icon)
115 {
116         if (md->nitems==md->itemssize) {
117                 int nsize= md->itemssize?(md->itemssize<<1):1;
118                 MenuEntry *oitems= md->items;
119                 
120                 md->items= MEM_mallocN(nsize*sizeof(*md->items), "md->items");
121                 if (oitems) {
122                         memcpy(md->items, oitems, md->nitems*sizeof(*md->items));
123                         MEM_freeN(oitems);
124                 }
125                 
126                 md->itemssize= nsize;
127         }
128         
129         md->items[md->nitems].str= str;
130         md->items[md->nitems].retval= retval;
131         md->items[md->nitems].icon= icon;
132         md->nitems++;
133 }
134
135 void menudata_free(MenuData *md)
136 {
137         MEM_freeN(md->instr);
138         if (md->items)
139                 MEM_freeN(md->items);
140         MEM_freeN(md);
141 }
142
143         /**
144          * Parse menu description strings, string is of the
145          * form "[sss%t|]{(sss[%xNN]|), (%l|)}", ssss%t indicates the
146          * menu title, sss or sss%xNN indicates an option, 
147          * if %xNN is given then NN is the return value if
148          * that option is selected otherwise the return value
149          * is the index of the option (starting with 1). %l
150          * indicates a seperator.
151          * 
152          * @param str String to be parsed.
153          * @retval new menudata structure, free with menudata_free()
154          */
155 MenuData *decompose_menu_string(char *str) 
156 {
157         char *instr= BLI_strdup(str);
158         MenuData *md= menudata_new(instr);
159         char *nitem= NULL, *s= instr;
160         int nicon=0, nretval= 1, nitem_is_title= 0;
161         
162         while (1) {
163                 char c= *s;
164
165                 if (c=='%') {
166                         if (s[1]=='x') {
167                                 nretval= atoi(s+2);
168
169                                 *s= '\0';
170                                 s++;
171                         } else if (s[1]=='t') {
172                                 nitem_is_title= 1;
173
174                                 *s= '\0';
175                                 s++;
176                         } else if (s[1]=='l') {
177                                 nitem= "%l";
178                                 s++;
179                         } else if (s[1]=='i') {
180                                 nicon= atoi(s+2);
181                                 
182                                 *s= '\0';
183                                 s++;
184                         }
185                 } else if (c=='|' || c == '\n' || c=='\0') {
186                         if (nitem) {
187                                 *s= '\0';
188
189                                 if (nitem_is_title) {
190                                         menudata_set_title(md, nitem, nicon);
191                                         nitem_is_title= 0;
192                                 } else {
193                                         /* prevent separator to get a value */
194                                         if(nitem[0]=='%' && nitem[1]=='l')
195                                                 menudata_add_item(md, nitem, -1, nicon);
196                                         else
197                                                 menudata_add_item(md, nitem, nretval, nicon);
198                                         nretval= md->nitems+1;
199                                 } 
200                                 
201                                 nitem= NULL;
202                                 nicon= 0;
203                         }
204                         
205                         if (c=='\0')
206                                 break;
207                 } else if (!nitem)
208                         nitem= s;
209                 
210                 s++;
211         }
212         
213         return md;
214 }
215
216 void ui_set_name_menu(uiBut *but, int value)
217 {
218         MenuData *md;
219         int i;
220         
221         md= decompose_menu_string(but->str);
222         for (i=0; i<md->nitems; i++)
223                 if (md->items[i].retval==value)
224                         strcpy(but->drawstr, md->items[i].str);
225         
226         menudata_free(md);
227 }
228
229 int ui_step_name_menu(uiBut *but, int step)
230 {
231         MenuData *md;
232         int value= ui_get_but_val(but);
233         int i;
234         
235         md= decompose_menu_string(but->str);
236         for (i=0; i<md->nitems; i++)
237                 if (md->items[i].retval==value)
238                         break;
239         
240         if(step==1) {
241                 /* skip separators */
242                 for(; i<md->nitems-1; i++) {
243                         if(md->items[i+1].retval != -1) {
244                                 value= md->items[i+1].retval;
245                                 break;
246                         }
247                 }
248         }
249         else {
250                 if(i>0) {
251                         /* skip separators */
252                         for(; i>0; i--) {
253                                 if(md->items[i-1].retval != -1) {
254                                         value= md->items[i-1].retval;
255                                         break;
256                                 }
257                         }
258                 }
259         }
260         
261         menudata_free(md);
262                 
263         return value;
264 }
265
266
267 /******************** Creating Temporary regions ******************/
268
269 ARegion *ui_add_temporary_region(bScreen *sc)
270 {
271         ARegion *ar;
272
273         ar= MEM_callocN(sizeof(ARegion), "area region");
274         BLI_addtail(&sc->regionbase, ar);
275
276         ar->regiontype= RGN_TYPE_TEMPORARY;
277         ar->alignment= RGN_ALIGN_FLOAT;
278
279         return ar;
280 }
281
282 void ui_remove_temporary_region(bContext *C, bScreen *sc, ARegion *ar)
283 {
284         if(CTX_wm_window(C))
285                 wm_draw_region_clear(CTX_wm_window(C), ar);
286
287         ED_region_exit(C, ar);
288         BKE_area_region_free(NULL, ar);         /* NULL: no spacetype */
289         BLI_freelinkN(&sc->regionbase, ar);
290 }
291
292 /************************* Creating Tooltips **********************/
293
294 typedef struct uiTooltipData {
295         rcti bbox;
296         uiFontStyle fstyle;
297         char lines[5][512];
298         int totline;
299         int toth, spaceh, lineh;
300 } uiTooltipData;
301
302 static void ui_tooltip_region_draw(const bContext *C, ARegion *ar)
303 {
304         uiTooltipData *data= ar->regiondata;
305         rcti bbox= data->bbox;
306         int a;
307         
308         ui_draw_menu_back(U.uistyles.first, NULL, &data->bbox);
309         
310         /* draw text */
311         uiStyleFontSet(&data->fstyle);
312
313         bbox.ymax= bbox.ymax - 0.5f*((bbox.ymax - bbox.ymin) - data->toth);
314         bbox.ymin= bbox.ymax - data->lineh;
315
316         for(a=0; a<data->totline; a++) {
317                 if(a == 0) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
318                 else glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
319
320                 uiStyleFontDraw(&data->fstyle, &bbox, data->lines[a]);
321                 bbox.ymin -= data->lineh + data->spaceh;
322                 bbox.ymax -= data->lineh + data->spaceh;
323         }
324 }
325
326 static void ui_tooltip_region_free(ARegion *ar)
327 {
328         uiTooltipData *data;
329
330         data= ar->regiondata;
331         MEM_freeN(data);
332         ar->regiondata= NULL;
333 }
334
335 ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
336 {
337         uiStyle *style= U.uistyles.first;       // XXX pass on as arg
338         static ARegionType type;
339         ARegion *ar;
340         uiTooltipData *data;
341         IDProperty *prop;
342         char buf[512];
343         float fonth, fontw, aspect= but->block->aspect;
344         float x1f, x2f, y1f, y2f;
345         int x1, x2, y1, y2, winx, winy, ofsx, ofsy, w, h, a;
346
347         if(!but->tip || strlen(but->tip)==0)
348                 return NULL;
349
350         /* create area region */
351         ar= ui_add_temporary_region(CTX_wm_screen(C));
352
353         memset(&type, 0, sizeof(ARegionType));
354         type.draw= ui_tooltip_region_draw;
355         type.free= ui_tooltip_region_free;
356         ar->type= &type;
357
358         /* create tooltip data */
359         data= MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
360
361         BLI_strncpy(data->lines[0], but->tip, sizeof(data->lines[0]));
362         data->totline= 1;
363
364         if(but->optype && !(but->block->flag & UI_BLOCK_LOOP)) {
365                 /* operator keymap (not menus, they already have it) */
366                 prop= (but->opptr)? but->opptr->data: NULL;
367
368                 if(WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, buf, sizeof(buf))) {
369                         BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Shortcut: %s", buf);
370                         data->totline++;
371                 }
372         }
373
374         if(ELEM3(but->type, TEX, IDPOIN, SEARCH_MENU)) {
375                 /* full string */
376                 ui_get_but_string(but, buf, sizeof(buf));
377                 if(buf[0]) {
378                         BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Value: %s", buf);
379                         data->totline++;
380                 }
381         }
382
383         if(but->rnaprop) {
384                 if(but->flag & UI_BUT_DRIVEN) {
385                         if(ui_but_anim_expression_get(but, buf, sizeof(buf))) {
386                                 /* expression */
387                                 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Expression: %s", buf);
388                                 data->totline++;
389                         }
390                 }
391
392                 /* rna info */
393                 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Python: %s.%s", RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop));
394                 data->totline++;
395         }
396         
397         /* set font, get bb */
398         data->fstyle= style->widget; /* copy struct */
399         data->fstyle.align= UI_STYLE_TEXT_CENTER;
400         ui_fontscale(&data->fstyle.points, aspect);
401         uiStyleFontSet(&data->fstyle);
402
403         h= BLF_height(data->lines[0]);
404
405         for(a=0, fontw=0, fonth=0; a<data->totline; a++) {
406                 w= BLF_width(data->lines[a]);
407                 fontw= MAX2(fontw, w);
408                 fonth += (a == 0)? h: h+5;
409         }
410
411         fontw *= aspect;
412         fonth *= aspect;
413
414         ar->regiondata= data;
415
416         data->toth= fonth;
417         data->lineh= h*aspect;
418         data->spaceh= 5*aspect;
419
420         /* compute position */
421         ofsx= (but->block->panel)? but->block->panel->ofsx: 0;
422         ofsy= (but->block->panel)? but->block->panel->ofsy: 0;
423
424         x1f= (but->x1+but->x2)/2.0f + ofsx - 16.0f*aspect;
425         x2f= x1f + fontw + 16.0f*aspect;
426         y2f= but->y1 + ofsy - 15.0f*aspect;
427         y1f= y2f - fonth - 10.0f*aspect;
428         
429         /* copy to int, gets projected if possible too */
430         x1= x1f; y1= y1f; x2= x2f; y2= y2f; 
431         
432         if(butregion) {
433                 /* XXX temp, region v2ds can be empty still */
434                 if(butregion->v2d.cur.xmin != butregion->v2d.cur.xmax) {
435                         UI_view2d_to_region_no_clip(&butregion->v2d, x1f, y1f, &x1, &y1);
436                         UI_view2d_to_region_no_clip(&butregion->v2d, x2f, y2f, &x2, &y2);
437                 }
438
439                 x1 += butregion->winrct.xmin;
440                 x2 += butregion->winrct.xmin;
441                 y1 += butregion->winrct.ymin;
442                 y2 += butregion->winrct.ymin;
443         }
444
445         wm_window_get_size(CTX_wm_window(C), &winx, &winy);
446
447         if(x2 > winx) {
448                 /* super size */
449                 if(x2 > winx + x1) {
450                         x2= winx;
451                         x1= 0;
452                 }
453                 else {
454                         x1 -= x2-winx;
455                         x2= winx;
456                 }
457         }
458         if(y1 < 0) {
459                 y1 += 56*aspect;
460                 y2 += 56*aspect;
461         }
462
463         /* widget rect, in region coords */
464         data->bbox.xmin= MENU_SHADOW_SIDE;
465         data->bbox.xmax= x2-x1 + MENU_SHADOW_SIDE;
466         data->bbox.ymin= MENU_SHADOW_BOTTOM;
467         data->bbox.ymax= y2-y1 + MENU_SHADOW_BOTTOM;
468         
469         /* region bigger for shadow */
470         ar->winrct.xmin= x1 - MENU_SHADOW_SIDE;
471         ar->winrct.xmax= x2 + MENU_SHADOW_SIDE;
472         ar->winrct.ymin= y1 - MENU_SHADOW_BOTTOM;
473         ar->winrct.ymax= y2 + MENU_TOP;
474
475         /* adds subwindow */
476         ED_region_init(C, ar);
477         
478         /* notify change and redraw */
479         ED_region_tag_redraw(ar);
480
481         return ar;
482 }
483
484 void ui_tooltip_free(bContext *C, ARegion *ar)
485 {
486         ui_remove_temporary_region(C, CTX_wm_screen(C), ar);
487 }
488
489
490 /************************* Creating Search Box **********************/
491
492 struct uiSearchItems {
493         int maxitem, totitem, maxstrlen;
494         
495         int offset, offset_i; /* offset for inserting in array */
496         int more;  /* flag indicating there are more items */
497         
498         char **names;
499         void **pointers;
500         int *icons;
501
502         AutoComplete *autocpl;
503         void *active;
504 };
505
506 typedef struct uiSearchboxData {
507         rcti bbox;
508         uiFontStyle fstyle;
509         uiSearchItems items;
510         int active;             /* index in items array */
511         int noback;             /* when menu opened with enough space for this */
512 } uiSearchboxData;
513
514 #define SEARCH_ITEMS    10
515
516 /* exported for use by search callbacks */
517 /* returns zero if nothing to add */
518 int uiSearchItemAdd(uiSearchItems *items, const char *name, void *poin, int iconid)
519 {
520         /* hijack for autocomplete */
521         if(items->autocpl) {
522                 autocomplete_do_name(items->autocpl, name);
523                 return 1;
524         }
525         
526         /* hijack for finding active item */
527         if(items->active) {
528                 if(poin==items->active)
529                         items->offset_i= items->totitem;
530                 items->totitem++;
531                 return 1;
532         }
533         
534         if(items->totitem>=items->maxitem) {
535                 items->more= 1;
536                 return 0;
537         }
538         
539         /* skip first items in list */
540         if(items->offset_i > 0) {
541                 items->offset_i--;
542                 return 1;
543         }
544         
545         BLI_strncpy(items->names[items->totitem], name, items->maxstrlen);
546         items->pointers[items->totitem]= poin;
547         items->icons[items->totitem]= iconid;
548         
549         items->totitem++;
550         
551         return 1;
552 }
553
554 int uiSearchBoxhHeight(void)
555 {
556         return SEARCH_ITEMS*MENU_BUTTON_HEIGHT + 2*MENU_TOP;
557 }
558
559 /* ar is the search box itself */
560 static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step)
561 {
562         uiSearchboxData *data= ar->regiondata;
563         
564         /* apply step */
565         data->active+= step;
566         
567         if(data->items.totitem==0)
568                 data->active= 0;
569         else if(data->active > data->items.totitem) {
570                 if(data->items.more) {
571                         data->items.offset++;
572                         data->active= data->items.totitem;
573                         ui_searchbox_update(C, ar, but, 0);
574                 }
575                 else
576                         data->active= data->items.totitem;
577         }
578         else if(data->active < 1) {
579                 if(data->items.offset) {
580                         data->items.offset--;
581                         data->active= 1;
582                         ui_searchbox_update(C, ar, but, 0);
583                 }
584                 else if(data->active < 0)
585                         data->active= 0;
586         }
587         
588         ED_region_tag_redraw(ar);
589 }
590
591 static void ui_searchbox_butrect(rcti *rect, uiSearchboxData *data, int itemnr)
592 {
593         int buth= (data->bbox.ymax-data->bbox.ymin - 2*MENU_TOP)/SEARCH_ITEMS;
594         
595         *rect= data->bbox;
596         rect->xmin= data->bbox.xmin + 3.0f;
597         rect->xmax= data->bbox.xmax - 3.0f;
598         
599         rect->ymax= data->bbox.ymax - MENU_TOP - itemnr*buth;
600         rect->ymin= rect->ymax - buth;
601         
602 }
603
604 /* x and y in screencoords */
605 int ui_searchbox_inside(ARegion *ar, int x, int y)
606 {
607         uiSearchboxData *data= ar->regiondata;
608         
609         return(BLI_in_rcti(&data->bbox, x-ar->winrct.xmin, y-ar->winrct.ymin));
610 }
611
612 /* string validated to be of correct length (but->hardmax) */
613 void ui_searchbox_apply(uiBut *but, ARegion *ar)
614 {
615         uiSearchboxData *data= ar->regiondata;
616
617         but->func_arg2= NULL;
618         
619         if(data->active) {
620                 char *name= data->items.names[data->active-1];
621                 char *cpoin= strchr(name, '|');
622                 
623                 if(cpoin) cpoin[0]= 0;
624                 BLI_strncpy(but->editstr, name, data->items.maxstrlen);
625                 if(cpoin) cpoin[0]= '|';
626                 
627                 but->func_arg2= data->items.pointers[data->active-1];
628         }
629 }
630
631 void ui_searchbox_event(bContext *C, ARegion *ar, uiBut *but, wmEvent *event)
632 {
633         uiSearchboxData *data= ar->regiondata;
634         
635         switch(event->type) {
636                 case WHEELUPMOUSE:
637                 case UPARROWKEY:
638                         ui_searchbox_select(C, ar, but, -1);
639                         break;
640                 case WHEELDOWNMOUSE:
641                 case DOWNARROWKEY:
642                         ui_searchbox_select(C, ar, but, 1);
643                         break;
644                 case MOUSEMOVE:
645                         if(BLI_in_rcti(&ar->winrct, event->x, event->y)) {
646                                 rcti rect;
647                                 int a;
648                                 
649                                 for(a=0; a<data->items.totitem; a++) {
650                                         ui_searchbox_butrect(&rect, data, a);
651                                         if(BLI_in_rcti(&rect, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin)) {
652                                                 if( data->active!= a+1) {
653                                                         data->active= a+1;
654                                                         ui_searchbox_select(C, ar, but, 0);
655                                                         break;
656                                                 }
657                                         }
658                                 }
659                         }
660                         break;
661         }
662 }
663
664 /* ar is the search box itself */
665 void ui_searchbox_update(bContext *C, ARegion *ar, uiBut *but, int reset)
666 {
667         uiSearchboxData *data= ar->regiondata;
668         
669         /* reset vars */
670         data->items.totitem= 0;
671         data->items.more= 0;
672         if(reset==0) {
673                 data->items.offset_i= data->items.offset;
674         }
675         else {
676                 data->items.offset_i= data->items.offset= 0;
677                 data->active= 0;
678                 
679                 /* handle active */
680                 if(but->search_func && but->func_arg2) {
681                         data->items.active= but->func_arg2;
682                         but->search_func(C, but->search_arg, but->editstr, &data->items);
683                         data->items.active= NULL;
684                         
685                         /* found active item, calculate real offset by centering it */
686                         if(data->items.totitem) {
687                                 /* first case, begin of list */
688                                 if(data->items.offset_i < data->items.maxitem) {
689                                         data->active= data->items.offset_i+1;
690                                         data->items.offset_i= 0;
691                                 }
692                                 else {
693                                         /* second case, end of list */
694                                         if(data->items.totitem - data->items.offset_i <= data->items.maxitem) {
695                                                 data->active= 1 + data->items.offset_i - data->items.totitem + data->items.maxitem;
696                                                 data->items.offset_i= data->items.totitem - data->items.maxitem;
697                                         }
698                                         else {
699                                                 /* center active item */
700                                                 data->items.offset_i -= data->items.maxitem/2;
701                                                 data->active= 1 + data->items.maxitem/2;
702                                         }
703                                 }
704                         }
705                         data->items.offset= data->items.offset_i;
706                         data->items.totitem= 0;
707                 }
708         }
709         
710         /* callback */
711         if(but->search_func)
712                 but->search_func(C, but->search_arg, but->editstr, &data->items);
713         
714         /* handle case where editstr is equal to one of items */
715         if(reset && data->active==0) {
716                 int a;
717                 
718                 for(a=0; a<data->items.totitem; a++) {
719                         char *cpoin= strchr(data->items.names[a], '|');
720                         
721                         if(cpoin) cpoin[0]= 0;
722                         if(0==strcmp(but->editstr, data->items.names[a]))
723                                 data->active= a+1;
724                         if(cpoin) cpoin[0]= '|';
725                 }
726                 if(data->items.totitem==1)
727                         data->active= 1;
728         }
729
730         /* validate selected item */
731         ui_searchbox_select(C, ar, but, 0);
732         
733         ED_region_tag_redraw(ar);
734 }
735
736 void ui_searchbox_autocomplete(bContext *C, ARegion *ar, uiBut *but, char *str)
737 {
738         uiSearchboxData *data= ar->regiondata;
739
740         data->items.autocpl= autocomplete_begin(str, ui_get_but_string_max_length(but));
741
742         but->search_func(C, but->search_arg, but->editstr, &data->items);
743
744         autocomplete_end(data->items.autocpl, str);
745         data->items.autocpl= NULL;
746 }
747
748 static void ui_searchbox_region_draw(const bContext *C, ARegion *ar)
749 {
750         uiSearchboxData *data= ar->regiondata;
751         
752         /* pixel space */
753         wmOrtho2(-0.01f, ar->winx-0.01f, -0.01f, ar->winy-0.01f);
754
755         if(!data->noback)
756                 ui_draw_search_back(U.uistyles.first, NULL, &data->bbox);
757         
758         /* draw text */
759         if(data->items.totitem) {
760                 rcti rect;
761                 int a;
762                                 
763                 /* draw items */
764                 for(a=0; a<data->items.totitem; a++) {
765                         ui_searchbox_butrect(&rect, data, a);
766                         
767                         /* widget itself */
768                         ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0);
769                         
770                 }
771                 /* indicate more */
772                 if(data->items.more) {
773                         ui_searchbox_butrect(&rect, data, data->items.maxitem-1);
774                         glEnable(GL_BLEND);
775                         UI_icon_draw((rect.xmax-rect.xmin)/2, rect.ymin-9, ICON_TRIA_DOWN);
776                         glDisable(GL_BLEND);
777                 }
778                 if(data->items.offset) {
779                         ui_searchbox_butrect(&rect, data, 0);
780                         glEnable(GL_BLEND);
781                         UI_icon_draw((rect.xmax-rect.xmin)/2, rect.ymax-7, ICON_TRIA_UP);
782                         glDisable(GL_BLEND);
783                 }
784         }
785 }
786
787 static void ui_searchbox_region_free(ARegion *ar)
788 {
789         uiSearchboxData *data= ar->regiondata;
790         int a;
791
792         /* free search data */
793         for(a=0; a<SEARCH_ITEMS; a++)
794                 MEM_freeN(data->items.names[a]);
795         MEM_freeN(data->items.names);
796         MEM_freeN(data->items.pointers);
797         MEM_freeN(data->items.icons);
798         
799         MEM_freeN(data);
800         ar->regiondata= NULL;
801 }
802
803 ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
804 {
805         uiStyle *style= U.uistyles.first;       // XXX pass on as arg
806         static ARegionType type;
807         ARegion *ar;
808         uiSearchboxData *data;
809         float aspect= but->block->aspect;
810         float x1f, x2f, y1f, y2f;
811         int x1, x2, y1, y2, winx, winy, ofsx, ofsy;
812         
813         /* create area region */
814         ar= ui_add_temporary_region(CTX_wm_screen(C));
815         
816         memset(&type, 0, sizeof(ARegionType));
817         type.draw= ui_searchbox_region_draw;
818         type.free= ui_searchbox_region_free;
819         ar->type= &type;
820         
821         /* create searchbox data */
822         data= MEM_callocN(sizeof(uiSearchboxData), "uiSearchboxData");
823         
824         /* set font, get bb */
825         data->fstyle= style->widget; /* copy struct */
826         data->fstyle.align= UI_STYLE_TEXT_CENTER;
827         ui_fontscale(&data->fstyle.points, aspect);
828         uiStyleFontSet(&data->fstyle);
829         
830         ar->regiondata= data;
831         
832         /* special case, hardcoded feature, not draw backdrop when called from menus,
833            assume for design that popup already added it */
834         if(but->block->flag & UI_BLOCK_LOOP)
835                 data->noback= 1;
836         
837         /* compute position */
838         
839         if(but->block->flag & UI_BLOCK_LOOP) {
840                 /* this case is search menu inside other menu */
841                 /* we copy region size */
842
843                 ar->winrct= butregion->winrct;
844                 
845                 /* widget rect, in region coords */
846                 data->bbox.xmin= MENU_SHADOW_SIDE;
847                 data->bbox.xmax= (ar->winrct.xmax-ar->winrct.xmin) - MENU_SHADOW_SIDE;
848                 data->bbox.ymin= MENU_SHADOW_BOTTOM;
849                 data->bbox.ymax= (ar->winrct.ymax-ar->winrct.ymin) - MENU_SHADOW_BOTTOM;
850                 
851                 /* check if button is lower half */
852                 if( but->y2 < (but->block->minx+but->block->maxx)/2 ) {
853                         data->bbox.ymin += (but->y2-but->y1);
854                 }
855                 else {
856                         data->bbox.ymax -= (but->y2-but->y1);
857                 }
858         }
859         else {
860                 x1f= but->x1 - 5;       /* align text with button */
861                 x2f= but->x2 + 5;       /* symmetrical */
862                 y2f= but->y1;
863                 y1f= y2f - uiSearchBoxhHeight();
864
865                 ofsx= (but->block->panel)? but->block->panel->ofsx: 0;
866                 ofsy= (but->block->panel)? but->block->panel->ofsy: 0;
867
868                 x1f += ofsx;
869                 x2f += ofsx;
870                 y1f += ofsy;
871                 y2f += ofsy;
872         
873                 /* minimal width */
874                 if(x2f - x1f < 150) x2f= x1f+150; // XXX arbitrary
875                 
876                 /* copy to int, gets projected if possible too */
877                 x1= x1f; y1= y1f; x2= x2f; y2= y2f; 
878                 
879                 if(butregion) {
880                         if(butregion->v2d.cur.xmin != butregion->v2d.cur.xmax) {
881                                 UI_view2d_to_region_no_clip(&butregion->v2d, x1f, y1f, &x1, &y1);
882                                 UI_view2d_to_region_no_clip(&butregion->v2d, x2f, y2f, &x2, &y2);
883                         }
884                         
885                         x1 += butregion->winrct.xmin;
886                         x2 += butregion->winrct.xmin;
887                         y1 += butregion->winrct.ymin;
888                         y2 += butregion->winrct.ymin;
889                 }
890                 
891                 wm_window_get_size(CTX_wm_window(C), &winx, &winy);
892                 
893                 if(x2 > winx) {
894                         /* super size */
895                         if(x2 > winx + x1) {
896                                 x2= winx;
897                                 x1= 0;
898                         }
899                         else {
900                                 x1 -= x2-winx;
901                                 x2= winx;
902                         }
903                 }
904                 if(y1 < 0) {
905                         y1 += 36;
906                         y2 += 36;
907                 }
908                 
909                 /* widget rect, in region coords */
910                 data->bbox.xmin= MENU_SHADOW_SIDE;
911                 data->bbox.xmax= x2-x1 + MENU_SHADOW_SIDE;
912                 data->bbox.ymin= MENU_SHADOW_BOTTOM;
913                 data->bbox.ymax= y2-y1 + MENU_SHADOW_BOTTOM;
914                 
915                 /* region bigger for shadow */
916                 ar->winrct.xmin= x1 - MENU_SHADOW_SIDE;
917                 ar->winrct.xmax= x2 + MENU_SHADOW_SIDE;
918                 ar->winrct.ymin= y1 - MENU_SHADOW_BOTTOM;
919                 ar->winrct.ymax= y2;
920         }
921         
922         /* adds subwindow */
923         ED_region_init(C, ar);
924         
925         /* notify change and redraw */
926         ED_region_tag_redraw(ar);
927         
928         /* prepare search data */
929         data->items.maxitem= SEARCH_ITEMS;
930         data->items.maxstrlen= but->hardmax;
931         data->items.totitem= 0;
932         data->items.names= MEM_callocN(SEARCH_ITEMS*sizeof(void *), "search names");
933         data->items.pointers= MEM_callocN(SEARCH_ITEMS*sizeof(void *), "search pointers");
934         data->items.icons= MEM_callocN(SEARCH_ITEMS*sizeof(int), "search icons");
935         for(x1=0; x1<SEARCH_ITEMS; x1++)
936                 data->items.names[x1]= MEM_callocN(but->hardmax+1, "search pointers");
937         
938         return ar;
939 }
940
941 void ui_searchbox_free(bContext *C, ARegion *ar)
942 {
943         ui_remove_temporary_region(C, CTX_wm_screen(C), ar);
944 }
945
946
947 /************************* Creating Menu Blocks **********************/
948
949 /* position block relative to but, result is in window space */
950 static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, uiBlock *block)
951 {
952         uiBut *bt;
953         uiSafetyRct *saferct;
954         rctf butrct;
955         float aspect;
956         int xsize, ysize, xof=0, yof=0, center;
957         short dir1= 0, dir2=0;
958         
959         /* transform to window coordinates, using the source button region/block */
960         butrct.xmin= but->x1; butrct.xmax= but->x2;
961         butrct.ymin= but->y1; butrct.ymax= but->y2;
962
963         ui_block_to_window_fl(butregion, but->block, &butrct.xmin, &butrct.ymin);
964         ui_block_to_window_fl(butregion, but->block, &butrct.xmax, &butrct.ymax);
965
966         /* calc block rect */
967         if(block->minx == 0.0f && block->maxx == 0.0f) {
968                 if(block->buttons.first) {
969                         block->minx= block->miny= 10000;
970                         block->maxx= block->maxy= -10000;
971                         
972                         bt= block->buttons.first;
973                         while(bt) {
974                                 if(bt->x1 < block->minx) block->minx= bt->x1;
975                                 if(bt->y1 < block->miny) block->miny= bt->y1;
976
977                                 if(bt->x2 > block->maxx) block->maxx= bt->x2;
978                                 if(bt->y2 > block->maxy) block->maxy= bt->y2;
979                                 
980                                 bt= bt->next;
981                         }
982                 }
983                 else {
984                         /* we're nice and allow empty blocks too */
985                         block->minx= block->miny= 0;
986                         block->maxx= block->maxy= 20;
987                 }
988         }
989         
990         aspect= (float)(block->maxx - block->minx + 4);
991         ui_block_to_window_fl(butregion, but->block, &block->minx, &block->miny);
992         ui_block_to_window_fl(butregion, but->block, &block->maxx, &block->maxy);
993
994         //block->minx-= 2.0; block->miny-= 2.0;
995         //block->maxx+= 2.0; block->maxy+= 2.0;
996         
997         xsize= block->maxx - block->minx+4; // 4 for shadow
998         ysize= block->maxy - block->miny+4;
999         aspect/= (float)xsize;
1000
1001         if(but) {
1002                 int left=0, right=0, top=0, down=0;
1003                 int winx, winy;
1004
1005                 wm_window_get_size(window, &winx, &winy);
1006
1007                 if(block->direction & UI_CENTER) center= ysize/2;
1008                 else center= 0;
1009
1010                 if( butrct.xmin-xsize > 0.0) left= 1;
1011                 if( butrct.xmax+xsize < winx) right= 1;
1012                 if( butrct.ymin-ysize+center > 0.0) down= 1;
1013                 if( butrct.ymax+ysize-center < winy) top= 1;
1014                 
1015                 dir1= block->direction & UI_DIRECTION;
1016
1017                 /* secundary directions */
1018                 if(dir1 & (UI_TOP|UI_DOWN)) {
1019                         if(dir1 & UI_LEFT) dir2= UI_LEFT;
1020                         else if(dir1 & UI_RIGHT) dir2= UI_RIGHT;
1021                         dir1 &= (UI_TOP|UI_DOWN);
1022                 }
1023
1024                 if(dir2==0) if(dir1==UI_LEFT || dir1==UI_RIGHT) dir2= UI_DOWN;
1025                 if(dir2==0) if(dir1==UI_TOP || dir1==UI_DOWN) dir2= UI_LEFT;
1026                 
1027                 /* no space at all? dont change */
1028                 if(left || right) {
1029                         if(dir1==UI_LEFT && left==0) dir1= UI_RIGHT;
1030                         if(dir1==UI_RIGHT && right==0) dir1= UI_LEFT;
1031                         /* this is aligning, not append! */
1032                         if(dir2==UI_LEFT && right==0) dir2= UI_RIGHT;
1033                         if(dir2==UI_RIGHT && left==0) dir2= UI_LEFT;
1034                 }
1035                 if(down || top) {
1036                         if(dir1==UI_TOP && top==0) dir1= UI_DOWN;
1037                         if(dir1==UI_DOWN && down==0) dir1= UI_TOP;
1038                         if(dir2==UI_TOP && top==0) dir2= UI_DOWN;
1039                         if(dir2==UI_DOWN && down==0) dir2= UI_TOP;
1040                 }
1041                 
1042                 if(dir1==UI_LEFT) {
1043                         xof= butrct.xmin - block->maxx;
1044                         if(dir2==UI_TOP) yof= butrct.ymin - block->miny-center;
1045                         else yof= butrct.ymax - block->maxy+center;
1046                 }
1047                 else if(dir1==UI_RIGHT) {
1048                         xof= butrct.xmax - block->minx;
1049                         if(dir2==UI_TOP) yof= butrct.ymin - block->miny-center;
1050                         else yof= butrct.ymax - block->maxy+center;
1051                 }
1052                 else if(dir1==UI_TOP) {
1053                         yof= butrct.ymax - block->miny;
1054                         if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
1055                         else xof= butrct.xmin - block->minx;
1056                         // changed direction? 
1057                         if((dir1 & block->direction)==0) {
1058                                 if(block->direction & UI_SHIFT_FLIPPED)
1059                                         xof+= dir2==UI_LEFT?25:-25;
1060                                 uiBlockFlipOrder(block);
1061                         }
1062                 }
1063                 else if(dir1==UI_DOWN) {
1064                         yof= butrct.ymin - block->maxy;
1065                         if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
1066                         else xof= butrct.xmin - block->minx;
1067                         // changed direction?
1068                         if((dir1 & block->direction)==0) {
1069                                 if(block->direction & UI_SHIFT_FLIPPED)
1070                                         xof+= dir2==UI_LEFT?25:-25;
1071                                 uiBlockFlipOrder(block);
1072                         }
1073                 }
1074
1075                 /* and now we handle the exception; no space below or to top */
1076                 if(top==0 && down==0) {
1077                         if(dir1==UI_LEFT || dir1==UI_RIGHT) {
1078                                 // align with bottom of screen 
1079                                 yof= ysize;
1080                         }
1081                 }
1082                 
1083                 /* or no space left or right */
1084                 if(left==0 && right==0) {
1085                         if(dir1==UI_TOP || dir1==UI_DOWN) {
1086                                 // align with left size of screen 
1087                                 xof= -block->minx+5;
1088                         }
1089                 }
1090                 
1091                 // apply requested offset in the block
1092                 xof += block->xofs/block->aspect;
1093                 yof += block->yofs/block->aspect;
1094         }
1095         
1096         /* apply */
1097         
1098         for(bt= block->buttons.first; bt; bt= bt->next) {
1099                 ui_block_to_window_fl(butregion, but->block, &bt->x1, &bt->y1);
1100                 ui_block_to_window_fl(butregion, but->block, &bt->x2, &bt->y2);
1101
1102                 bt->x1 += xof;
1103                 bt->x2 += xof;
1104                 bt->y1 += yof;
1105                 bt->y2 += yof;
1106
1107                 bt->aspect= 1.0;
1108                 // ui_check_but recalculates drawstring size in pixels
1109                 ui_check_but(bt);
1110         }
1111         
1112         block->minx += xof;
1113         block->miny += yof;
1114         block->maxx += xof;
1115         block->maxy += yof;
1116
1117         /* safety calculus */
1118         if(but) {
1119                 float midx= (butrct.xmin+butrct.xmax)/2.0;
1120                 float midy= (butrct.ymin+butrct.ymax)/2.0;
1121                 
1122                 /* when you are outside parent button, safety there should be smaller */
1123                 
1124                 // parent button to left
1125                 if( midx < block->minx ) block->safety.xmin= block->minx-3; 
1126                 else block->safety.xmin= block->minx-40;
1127                 // parent button to right
1128                 if( midx > block->maxx ) block->safety.xmax= block->maxx+3; 
1129                 else block->safety.xmax= block->maxx+40;
1130                 
1131                 // parent button on bottom
1132                 if( midy < block->miny ) block->safety.ymin= block->miny-3; 
1133                 else block->safety.ymin= block->miny-40;
1134                 // parent button on top
1135                 if( midy > block->maxy ) block->safety.ymax= block->maxy+3; 
1136                 else block->safety.ymax= block->maxy+40;
1137                 
1138                 // exception for switched pulldowns...
1139                 if(dir1 && (dir1 & block->direction)==0) {
1140                         if(dir2==UI_RIGHT) block->safety.xmax= block->maxx+3; 
1141                         if(dir2==UI_LEFT) block->safety.xmin= block->minx-3; 
1142                 }
1143                 block->direction= dir1;
1144         }
1145         else {
1146                 block->safety.xmin= block->minx-40;
1147                 block->safety.ymin= block->miny-40;
1148                 block->safety.xmax= block->maxx+40;
1149                 block->safety.ymax= block->maxy+40;
1150         }
1151
1152         /* keep a list of these, needed for pulldown menus */
1153         saferct= MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct");
1154         saferct->parent= butrct;
1155         saferct->safety= block->safety;
1156         BLI_freelistN(&block->saferct);
1157         if(but)
1158                 BLI_duplicatelist(&block->saferct, &but->block->saferct);
1159         BLI_addhead(&block->saferct, saferct);
1160 }
1161
1162 static void ui_block_region_draw(const bContext *C, ARegion *ar)
1163 {
1164         uiBlock *block;
1165
1166         for(block=ar->uiblocks.first; block; block=block->next)
1167                 uiDrawBlock(C, block);
1168 }
1169
1170 uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut *but, uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func, void *arg)
1171 {
1172         wmWindow *window= CTX_wm_window(C);
1173         static ARegionType type;
1174         ARegion *ar;
1175         uiBlock *block;
1176         uiBut *bt;
1177         uiPopupBlockHandle *handle;
1178         uiSafetyRct *saferct;
1179
1180         /* create handle */
1181         handle= MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
1182
1183         /* store context for operator */
1184         handle->ctx_area= CTX_wm_area(C);
1185         handle->ctx_region= CTX_wm_region(C);
1186         
1187         /* create area region */
1188         ar= ui_add_temporary_region(CTX_wm_screen(C));
1189         handle->region= ar;
1190
1191         memset(&type, 0, sizeof(ARegionType));
1192         type.draw= ui_block_region_draw;
1193         ar->type= &type;
1194
1195         UI_add_region_handlers(&ar->handlers);
1196
1197         /* create ui block */
1198         if(create_func)
1199                 block= create_func(C, handle->region, arg);
1200         else
1201                 block= handle_create_func(C, handle, arg);
1202         
1203         if(block->handle) {
1204                 memcpy(block->handle, handle, sizeof(uiPopupBlockHandle));
1205                 MEM_freeN(handle);
1206                 handle= block->handle;
1207         }
1208         else
1209                 block->handle= handle;
1210
1211         ar->regiondata= handle;
1212
1213         if(!block->endblock)
1214                 uiEndBlock(C, block);
1215
1216         /* if this is being created from a button */
1217         if(but) {
1218                 if(ELEM(but->type, BLOCK, PULLDOWN))
1219                         block->xofs = -2;       /* for proper alignment */
1220
1221                 /* only used for automatic toolbox, so can set the shift flag */
1222                 if(but->flag & UI_MAKE_TOP) {
1223                         block->direction= UI_TOP|UI_SHIFT_FLIPPED;
1224                         uiBlockFlipOrder(block);
1225                 }
1226                 if(but->flag & UI_MAKE_DOWN) block->direction= UI_DOWN|UI_SHIFT_FLIPPED;
1227                 if(but->flag & UI_MAKE_LEFT) block->direction |= UI_LEFT;
1228                 if(but->flag & UI_MAKE_RIGHT) block->direction |= UI_RIGHT;
1229
1230                 ui_block_position(window, butregion, but, block);
1231         }
1232         else {
1233                 /* keep a list of these, needed for pulldown menus */
1234                 saferct= MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct");
1235                 saferct->safety= block->safety;
1236                 BLI_addhead(&block->saferct, saferct);
1237                 block->flag |= UI_BLOCK_POPUP;
1238         }
1239
1240         /* the block and buttons were positioned in window space as in 2.4x, now
1241          * these menu blocks are regions so we bring it back to region space.
1242          * additionally we add some padding for the menu shadow or rounded menus */
1243         ar->winrct.xmin= block->minx - MENU_SHADOW_SIDE;
1244         ar->winrct.xmax= block->maxx + MENU_SHADOW_SIDE;
1245         ar->winrct.ymin= block->miny - MENU_SHADOW_BOTTOM;
1246         ar->winrct.ymax= block->maxy + MENU_TOP;
1247
1248         block->minx -= ar->winrct.xmin;
1249         block->maxx -= ar->winrct.xmin;
1250         block->miny -= ar->winrct.ymin;
1251         block->maxy -= ar->winrct.ymin;
1252
1253         for(bt= block->buttons.first; bt; bt= bt->next) {
1254                 bt->x1 -= ar->winrct.xmin;
1255                 bt->x2 -= ar->winrct.xmin;
1256                 bt->y1 -= ar->winrct.ymin;
1257                 bt->y2 -= ar->winrct.ymin;
1258         }
1259
1260         block->flag |= UI_BLOCK_LOOP|UI_BLOCK_MOVEMOUSE_QUIT;
1261
1262         /* adds subwindow */
1263         ED_region_init(C, ar);
1264
1265         /* get winmat now that we actually have the subwindow */
1266         wmSubWindowSet(window, ar->swinid);
1267         
1268         wm_subwindow_getmatrix(window, ar->swinid, block->winmat);
1269         
1270         /* notify change and redraw */
1271         ED_region_tag_redraw(ar);
1272
1273         return handle;
1274 }
1275
1276 void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle)
1277 {
1278         /* XXX ton added, chrash on load file with popup open... need investigate */
1279         if(CTX_wm_screen(C))
1280                 ui_remove_temporary_region(C, CTX_wm_screen(C), handle->region);
1281         MEM_freeN(handle);
1282 }
1283
1284 /***************************** Menu Button ***************************/
1285
1286 uiBlock *ui_block_func_MENU(bContext *C, uiPopupBlockHandle *handle, void *arg_but)
1287 {
1288         uiBut *but= arg_but;
1289         uiBlock *block;
1290         uiBut *bt;
1291         MenuData *md;
1292         ListBase lb;
1293         float aspect;
1294         int width, height, boxh, columns, rows, startx, starty, x1, y1, xmax, a;
1295
1296         /* create the block */
1297         block= uiBeginBlock(C, handle->region, "menu", UI_EMBOSSP);
1298         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
1299
1300         /* compute menu data */
1301         md= decompose_menu_string(but->str);
1302
1303         /* columns and row calculation */
1304         columns= (md->nitems+20)/20;
1305         if(columns<1)
1306                 columns= 1;
1307         if(columns>8)
1308                 columns= (md->nitems+25)/25;
1309         
1310         rows= md->nitems/columns;
1311         if(rows<1)
1312                 rows= 1;
1313         while(rows*columns<md->nitems)
1314                 rows++;
1315                 
1316         /* prevent scaling up of pupmenu */
1317         aspect= but->block->aspect;
1318         if(aspect < 1.0f)
1319                 aspect = 1.0f;
1320
1321         /* size and location */
1322         if(md->title)
1323                 width= 1.5*aspect*strlen(md->title)+UI_GetStringWidth(md->title);
1324         else
1325                 width= 0;
1326
1327         for(a=0; a<md->nitems; a++) {
1328                 xmax= aspect*UI_GetStringWidth(md->items[a].str);
1329                 if(md->items[a].icon)
1330                         xmax += 20*aspect;
1331                 if(xmax>width)
1332                         width= xmax;
1333         }
1334
1335         width+= 10;
1336         if(width < (but->x2 - but->x1))
1337                 width = (but->x2 - but->x1);
1338         if(width<50)
1339                 width=50;
1340         
1341         boxh= MENU_BUTTON_HEIGHT;
1342         
1343         height= rows*boxh;
1344         if(md->title)
1345                 height+= boxh;
1346
1347         /* here we go! */
1348         startx= but->x1;
1349         starty= but->y1;
1350         
1351         if(md->title) {
1352                 uiBut *bt;
1353
1354                 if (md->titleicon) {
1355                         bt= uiDefIconTextBut(block, LABEL, 0, md->titleicon, md->title, startx, (short)(starty+rows*boxh), (short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
1356                 } else {
1357                         bt= uiDefBut(block, LABEL, 0, md->title, startx, (short)(starty+rows*boxh), (short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
1358                         bt->flag= UI_TEXT_LEFT;
1359                 }
1360         }
1361
1362         for(a=0; a<md->nitems; a++) {
1363                 
1364                 x1= startx + width*((int)(md->nitems-a-1)/rows);
1365                 y1= starty - boxh*(rows - ((md->nitems - a - 1)%rows)) + (rows*boxh);
1366
1367                 if (strcmp(md->items[md->nitems-a-1].str, "%l")==0) {
1368                         bt= uiDefBut(block, SEPR, B_NOP, "", x1, y1,(short)(width-(rows>1)), (short)(boxh-1), NULL, 0.0, 0.0, 0, 0, "");
1369                 }
1370                 else if(md->items[md->nitems-a-1].icon) {
1371                         bt= uiDefIconTextButF(block, BUTM|FLO, B_NOP, md->items[md->nitems-a-1].icon ,md->items[md->nitems-a-1].str, x1, y1,(short)(width-(rows>1)), (short)(boxh-1), &handle->retvalue, (float) md->items[md->nitems-a-1].retval, 0.0, 0, 0, "");
1372                 }
1373                 else {
1374                         bt= uiDefButF(block, BUTM|FLO, B_NOP, md->items[md->nitems-a-1].str, x1, y1,(short)(width-(rows>1)), (short)(boxh-1), &handle->retvalue, (float) md->items[md->nitems-a-1].retval, 0.0, 0, 0, "");
1375                 }
1376         }
1377         
1378         menudata_free(md);
1379
1380         /* the code up here has flipped locations, because of change of preferred order */
1381         /* thats why we have to switch list order too, to make arrowkeys work */
1382         
1383         lb.first= lb.last= NULL;
1384         bt= block->buttons.first;
1385         while(bt) {
1386                 uiBut *next= bt->next;
1387                 BLI_remlink(&block->buttons, bt);
1388                 BLI_addhead(&lb, bt);
1389                 bt= next;
1390         }
1391         block->buttons= lb;
1392
1393         block->direction= UI_TOP;
1394         uiEndBlock(C, block);
1395
1396         return block;
1397 }
1398
1399 uiBlock *ui_block_func_ICONROW(bContext *C, uiPopupBlockHandle *handle, void *arg_but)
1400 {
1401         uiBut *but= arg_but;
1402         uiBlock *block;
1403         int a;
1404         
1405         block= uiBeginBlock(C, handle->region, "menu", UI_EMBOSSP);
1406         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
1407         
1408         for(a=(int)but->hardmin; a<=(int)but->hardmax; a++) {
1409                 uiDefIconButF(block, BUTM|FLO, B_NOP, but->icon+(a-but->hardmin), 0, (short)(18*a), (short)(but->x2-but->x1-4), 18, &handle->retvalue, (float)a, 0.0, 0, 0, "");
1410         }
1411
1412         block->direction= UI_TOP;       
1413
1414         uiEndBlock(C, block);
1415
1416         return block;
1417 }
1418
1419 uiBlock *ui_block_func_ICONTEXTROW(bContext *C, uiPopupBlockHandle *handle, void *arg_but)
1420 {
1421         uiBut *but= arg_but;
1422         uiBlock *block;
1423         MenuData *md;
1424         int width, xmax, ypos, a;
1425
1426         block= uiBeginBlock(C, handle->region, "menu", UI_EMBOSSP);
1427         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
1428
1429         md= decompose_menu_string(but->str);
1430
1431         /* size and location */
1432         /* expand menu width to fit labels */
1433         if(md->title)
1434                 width= 2*strlen(md->title)+UI_GetStringWidth(md->title);
1435         else
1436                 width= 0;
1437
1438         for(a=0; a<md->nitems; a++) {
1439                 xmax= UI_GetStringWidth(md->items[a].str);
1440                 if(xmax>width) width= xmax;
1441         }
1442
1443         width+= 30;
1444         if (width<50) width=50;
1445
1446         ypos = 1;
1447
1448         /* loop through the menu options and draw them out with icons & text labels */
1449         for(a=0; a<md->nitems; a++) {
1450
1451                 /* add a space if there's a separator (%l) */
1452                 if (strcmp(md->items[a].str, "%l")==0) {
1453                         ypos +=3;
1454                 }
1455                 else {
1456                         uiDefIconTextButF(block, BUTM|FLO, B_NOP, (short)((but->icon)+(md->items[a].retval-but->hardmin)), md->items[a].str, 0, ypos,(short)width, 19, &handle->retvalue, (float) md->items[a].retval, 0.0, 0, 0, "");
1457                         ypos += 20;
1458                 }
1459         }
1460         
1461         if(md->title) {
1462                 uiBut *bt;
1463
1464                 bt= uiDefBut(block, LABEL, 0, md->title, 0, ypos, (short)width, 19, NULL, 0.0, 0.0, 0, 0, "");
1465                 bt->flag= UI_TEXT_LEFT;
1466         }
1467         
1468         menudata_free(md);
1469
1470         block->direction= UI_TOP;
1471
1472         uiBoundsBlock(block, 3);
1473         uiEndBlock(C, block);
1474
1475         return block;
1476 }
1477
1478 static void ui_warp_pointer(short x, short y)
1479 {
1480         /* XXX 2.50 which function to use for this? */
1481 #if 0
1482         /* OSX has very poor mousewarp support, it sends events;
1483            this causes a menu being pressed immediately ... */
1484         #ifndef __APPLE__
1485         warp_pointer(x, y);
1486         #endif
1487 #endif
1488 }
1489
1490 /********************* Color Button ****************/
1491
1492 /* picker sizes S hsize, F full size, D spacer, B button/pallette height  */
1493 #define SPICK   110.0
1494 #define FPICK   180.0
1495 #define DPICK   6.0
1496 #define BPICK   24.0
1497
1498 #define UI_PALETTE_TOT 16
1499 /* note; in tot+1 the old color is stored */
1500 static float palette[UI_PALETTE_TOT+1][3]= {
1501 {0.93, 0.83, 0.81}, {0.88, 0.89, 0.73}, {0.69, 0.81, 0.57}, {0.51, 0.76, 0.64}, 
1502 {0.37, 0.56, 0.61}, {0.33, 0.29, 0.55}, {0.46, 0.21, 0.51}, {0.40, 0.12, 0.18}, 
1503 {1.0, 1.0, 1.0}, {0.85, 0.85, 0.85}, {0.7, 0.7, 0.7}, {0.56, 0.56, 0.56}, 
1504 {0.42, 0.42, 0.42}, {0.28, 0.28, 0.28}, {0.14, 0.14, 0.14}, {0.0, 0.0, 0.0}
1505 };  
1506
1507 /* for picker, while editing hsv */
1508 void ui_set_but_hsv(uiBut *but)
1509 {
1510         float col[3];
1511         
1512         hsv_to_rgb(but->hsv[0], but->hsv[1], but->hsv[2], col, col+1, col+2);
1513         ui_set_but_vectorf(but, col);
1514 }
1515
1516 static void update_picker_hex(uiBlock *block, float *rgb)
1517 {
1518         uiBut *bt;
1519         char col[16];
1520         
1521         sprintf(col, "%02X%02X%02X", (unsigned int)(rgb[0]*255.0), (unsigned int)(rgb[1]*255.0), (unsigned int)(rgb[2]*255.0));
1522         
1523         // this updates button strings, is hackish... but button pointers are on stack of caller function
1524
1525         for(bt= block->buttons.first; bt; bt= bt->next) {
1526                 if(strcmp(bt->str, "Hex: ")==0)
1527                         strcpy(bt->poin, col);
1528
1529                 ui_check_but(bt);
1530         }
1531 }
1532
1533 /* also used by small picker, be careful with name checks below... */
1534 void ui_update_block_buts_hsv(uiBlock *block, float *hsv)
1535 {
1536         uiBut *bt;
1537         float r, g, b;
1538         float rgb[3];
1539         
1540         // this updates button strings, is hackish... but button pointers are on stack of caller function
1541         hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r, &g, &b);
1542         
1543         rgb[0] = r; rgb[1] = g; rgb[2] = b;
1544         update_picker_hex(block, rgb);
1545
1546         for(bt= block->buttons.first; bt; bt= bt->next) {
1547                 if(ELEM(bt->type, HSVCUBE, HSVCIRCLE)) {
1548                         VECCOPY(bt->hsv, hsv);
1549                         ui_set_but_hsv(bt);
1550                 }
1551                 else if(bt->str[1]==' ') {
1552                         if(bt->str[0]=='R') {
1553                                 ui_set_but_val(bt, r);
1554                         }
1555                         else if(bt->str[0]=='G') {
1556                                 ui_set_but_val(bt, g);
1557                         }
1558                         else if(bt->str[0]=='B') {
1559                                 ui_set_but_val(bt, b);
1560                         }
1561                         else if(bt->str[0]=='H') {
1562                                 ui_set_but_val(bt, hsv[0]);
1563                         }
1564                         else if(bt->str[0]=='S') {
1565                                 ui_set_but_val(bt, hsv[1]);
1566                         }
1567                         else if(bt->str[0]=='V') {
1568                                 ui_set_but_val(bt, hsv[2]);
1569                         }
1570                 }               
1571
1572                 ui_check_but(bt);
1573         }
1574 }
1575
1576 static void ui_update_block_buts_hex(uiBlock *block, char *hexcol)
1577 {
1578         uiBut *bt;
1579         float r=0, g=0, b=0;
1580         float h, s, v;
1581         
1582         
1583         // this updates button strings, is hackish... but button pointers are on stack of caller function
1584         hex_to_rgb(hexcol, &r, &g, &b);
1585         rgb_to_hsv(r, g, b, &h, &s, &v);
1586
1587         for(bt= block->buttons.first; bt; bt= bt->next) {
1588                 if(bt->type==HSVCUBE) {
1589                         bt->hsv[0] = h;
1590                         bt->hsv[1] = s;                 
1591                         bt->hsv[2] = v;
1592                         ui_set_but_hsv(bt);
1593                 }
1594                 else if(bt->str[1]==' ') {
1595                         if(bt->str[0]=='R') {
1596                                 ui_set_but_val(bt, r);
1597                         }
1598                         else if(bt->str[0]=='G') {
1599                                 ui_set_but_val(bt, g);
1600                         }
1601                         else if(bt->str[0]=='B') {
1602                                 ui_set_but_val(bt, b);
1603                         }
1604                         else if(bt->str[0]=='H') {
1605                                 ui_set_but_val(bt, h);
1606                         }
1607                         else if(bt->str[0]=='S') {
1608                                 ui_set_but_val(bt, s);
1609                         }
1610                         else if(bt->str[0]=='V') {
1611                                 ui_set_but_val(bt, v);
1612                         }
1613                 }
1614
1615                 ui_check_but(bt);
1616         }
1617 }
1618
1619 /* bt1 is palette but, col1 is original color */
1620 /* callback to copy from/to palette */
1621 static void do_palette_cb(bContext *C, void *bt1, void *col1)
1622 {
1623         wmWindow *win= CTX_wm_window(C);
1624         uiBut *but1= (uiBut *)bt1;
1625         uiPopupBlockHandle *popup= but1->block->handle;
1626         float *col= (float *)col1;
1627         float *fp, hsv[3];
1628         
1629         fp= (float *)but1->poin;
1630         
1631         if(win->eventstate->ctrl) {
1632                 VECCOPY(fp, col);
1633         }
1634         else {
1635                 VECCOPY(col, fp);
1636         }
1637         
1638         rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
1639         ui_update_block_buts_hsv(but1->block, hsv);
1640         update_picker_hex(but1->block, col);
1641
1642         if(popup)
1643                 popup->menuretval= UI_RETURN_UPDATE;
1644 }
1645
1646 static void do_hsv_cb(bContext *C, void *bt1, void *unused)
1647 {
1648         uiBut *but1= (uiBut *)bt1;
1649         uiPopupBlockHandle *popup= but1->block->handle;
1650
1651         if(popup)
1652                 popup->menuretval= UI_RETURN_UPDATE;
1653 }
1654
1655 /* bt1 is num but, hsv1 is pointer to original color in hsv space*/
1656 /* callback to handle changes in num-buts in picker */
1657 static void do_palette1_cb(bContext *C, void *bt1, void *hsv1)
1658 {
1659         uiBut *but1= (uiBut *)bt1;
1660         uiPopupBlockHandle *popup= but1->block->handle;
1661         float *hsv= (float *)hsv1;
1662         float *fp= NULL;
1663         
1664         if(but1->str[1]==' ') {
1665                 if(but1->str[0]=='R') fp= (float *)but1->poin;
1666                 else if(but1->str[0]=='G') fp= ((float *)but1->poin)-1;
1667                 else if(but1->str[0]=='B') fp= ((float *)but1->poin)-2;
1668         }
1669         if(fp) {
1670                 rgb_to_hsv(fp[0], fp[1], fp[2], hsv, hsv+1, hsv+2);
1671         } 
1672         ui_update_block_buts_hsv(but1->block, hsv);
1673
1674         if(popup)
1675                 popup->menuretval= UI_RETURN_UPDATE;
1676 }
1677
1678 /* bt1 is num but, col1 is pointer to original color */
1679 /* callback to handle changes in num-buts in picker */
1680 static void do_palette2_cb(bContext *C, void *bt1, void *col1)
1681 {
1682         uiBut *but1= (uiBut *)bt1;
1683         uiPopupBlockHandle *popup= but1->block->handle;
1684         float *rgb= (float *)col1;
1685         float *fp= NULL;
1686         
1687         if(but1->str[1]==' ') {
1688                 if(but1->str[0]=='H') fp= (float *)but1->poin;
1689                 else if(but1->str[0]=='S') fp= ((float *)but1->poin)-1;
1690                 else if(but1->str[0]=='V') fp= ((float *)but1->poin)-2;
1691         }
1692         if(fp) {
1693                 hsv_to_rgb(fp[0], fp[1], fp[2], rgb, rgb+1, rgb+2);
1694         } 
1695         ui_update_block_buts_hsv(but1->block, fp);
1696
1697         if(popup)
1698                 popup->menuretval= UI_RETURN_UPDATE;
1699 }
1700
1701 static void do_palette_hex_cb(bContext *C, void *bt1, void *hexcl)
1702 {
1703         uiBut *but1= (uiBut *)bt1;
1704         uiPopupBlockHandle *popup= but1->block->handle;
1705         char *hexcol= (char *)hexcl;
1706         
1707         ui_update_block_buts_hex(but1->block, hexcol);  
1708
1709         if(popup)
1710                 popup->menuretval= UI_RETURN_UPDATE;
1711 }
1712
1713 /* used for both 3d view and image window */
1714 static void do_palette_sample_cb(bContext *C, void *bt1, void *col1)    /* frontbuf */
1715 {
1716         /* XXX 2.50 this should become an operator? */
1717 #if 0
1718         uiBut *but1= (uiBut *)bt1;
1719         uiBut *but;
1720         float tempcol[4];
1721         int x=0, y=0;
1722         short mval[2];
1723         float hsv[3];
1724         short capturing;
1725         int oldcursor;
1726         Window *win;
1727         unsigned short dev;
1728         
1729         oldcursor=get_cursor();
1730         win=winlay_get_active_window();
1731         
1732         while (get_mbut() & L_MOUSE) UI_wait_for_statechange();
1733         
1734         SetBlenderCursor(BC_EYEDROPPER_CURSOR);
1735         
1736         /* loop and wait for a mouse click */
1737         capturing = TRUE;
1738         while(capturing) {
1739                 char ascii;
1740                 short val;
1741                 
1742                 dev = extern_qread_ext(&val, &ascii);
1743                 
1744                 if(dev==INPUTCHANGE) break;
1745                 if(get_mbut() & R_MOUSE) break;
1746                 else if(get_mbut() & L_MOUSE) {
1747                         uiGetMouse(mywinget(), mval);
1748                         x= mval[0]; y= mval[1];
1749                         
1750                         capturing = FALSE;
1751                         break;
1752                 }
1753                 else if(dev==ESCKEY) break;
1754         }
1755         window_set_cursor(win, oldcursor);
1756         
1757         if(capturing) return;
1758         
1759         if(x<0 || y<0) return;
1760         
1761         /* if we've got a glick, use OpenGL to sample the color under the mouse pointer */
1762         glReadBuffer(GL_FRONT);
1763         glReadPixels(x, y, 1, 1, GL_RGBA, GL_FLOAT, tempcol);
1764         glReadBuffer(GL_BACK);
1765         
1766         /* and send that color back to the picker */
1767         rgb_to_hsv(tempcol[0], tempcol[1], tempcol[2], hsv, hsv+1, hsv+2);
1768         ui_update_block_buts_hsv(but1->block, hsv);
1769         update_picker_hex(but1->block, tempcol);
1770         
1771         for (but= but1->block->buttons.first; but; but= but->next) {
1772                 ui_check_but(but);
1773                 ui_draw_but(but);
1774         }
1775         
1776         but= but1->block->buttons.first;
1777         ui_block_flush_back(but->block);
1778 #endif
1779 }
1780
1781 /* color picker, Gimp version. mode: 'f' = floating panel, 'p' =  popup */
1782 /* col = read/write to, hsv/old/hexcol = memory for temporal use */
1783 void uiBlockPickerButtons(uiBlock *block, float *col, float *hsv, float *old, char *hexcol, char mode, short retval)
1784 {
1785         uiBut *bt;
1786         float h, offs;
1787         int a;
1788
1789         VECCOPY(old, col);      // old color stored there, for palette_cb to work
1790         
1791         // the cube intersection
1792         bt= uiDefButF(block, HSVCUBE, retval, "",       0,DPICK+BPICK,FPICK,FPICK, col, 0.0, 0.0, 2, 0, "");
1793         uiButSetFunc(bt, do_hsv_cb, bt, NULL);
1794
1795         bt= uiDefButF(block, HSVCUBE, retval, "",       0,0,FPICK,BPICK, col, 0.0, 0.0, 3, 0, "");
1796         uiButSetFunc(bt, do_hsv_cb, bt, NULL);
1797
1798         // palette
1799         
1800         bt=uiDefButF(block, COL, retval, "",            FPICK+DPICK, 0, BPICK,BPICK, old, 0.0, 0.0, -1, 0, "Old color, click to restore");
1801         uiButSetFunc(bt, do_palette_cb, bt, col);
1802         uiDefButF(block, COL, retval, "",               FPICK+DPICK, BPICK+DPICK, BPICK,60-BPICK-DPICK, col, 0.0, 0.0, -1, 0, "Active color");
1803
1804         h= (DPICK+BPICK+FPICK-64)/(UI_PALETTE_TOT/2.0);
1805         uiBlockBeginAlign(block);
1806         for(a= -1+UI_PALETTE_TOT/2; a>=0; a--) {
1807                 bt= uiDefButF(block, COL, retval, "",   FPICK+DPICK, 65.0+(float)a*h, BPICK/2, h, palette[a+UI_PALETTE_TOT/2], 0.0, 0.0, -1, 0, "Click to choose, hold CTRL to store in palette");
1808                 uiButSetFunc(bt, do_palette_cb, bt, col);
1809                 bt= uiDefButF(block, COL, retval, "",   FPICK+DPICK+BPICK/2, 65.0+(float)a*h, BPICK/2, h, palette[a], 0.0, 0.0, -1, 0, "Click to choose, hold CTRL to store in palette");               
1810                 uiButSetFunc(bt, do_palette_cb, bt, col);
1811         }
1812         uiBlockEndAlign(block);
1813         
1814         // buttons
1815         rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
1816         sprintf(hexcol, "%02X%02X%02X", (unsigned int)(col[0]*255.0), (unsigned int)(col[1]*255.0), (unsigned int)(col[2]*255.0));      
1817
1818         offs= FPICK+2*DPICK+BPICK;
1819
1820         /* note; made this a TOG now, with NULL pointer. Is because BUT now gets handled with a afterfunc */
1821         bt= uiDefIconTextBut(block, TOG, UI_RETURN_OK, ICON_EYEDROPPER, "Sample", offs+55, 170, 85, 20, NULL, 0, 0, 0, 0, "Sample the color underneath the following mouse click (ESC or RMB to cancel)");
1822         uiButSetFunc(bt, do_palette_sample_cb, bt, col);
1823         uiButSetFlag(bt, UI_TEXT_LEFT);
1824         
1825         bt= uiDefBut(block, TEX, retval, "Hex: ", offs, 140, 140, 20, hexcol, 0, 8, 0, 0, "Hex triplet for color (#RRGGBB)");
1826         uiButSetFunc(bt, do_palette_hex_cb, bt, hexcol);
1827
1828         uiBlockBeginAlign(block);
1829         bt= uiDefButF(block, NUMSLI, retval, "R ",      offs, 110, 140,20, col, 0.0, 1.0, 10, 3, "");
1830         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
1831         bt= uiDefButF(block, NUMSLI, retval, "G ",      offs, 90, 140,20, col+1, 0.0, 1.0, 10, 3, "");
1832         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
1833         bt= uiDefButF(block, NUMSLI, retval, "B ",      offs, 70, 140,20, col+2, 0.0, 1.0, 10, 3, "");
1834         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
1835         
1836         uiBlockBeginAlign(block);
1837         bt= uiDefButF(block, NUMSLI, retval, "H ",      offs, 40, 140,20, hsv, 0.0, 1.0, 10, 3, "");
1838         uiButSetFunc(bt, do_palette2_cb, bt, col);
1839         bt= uiDefButF(block, NUMSLI, retval, "S ",      offs, 20, 140,20, hsv+1, 0.0, 1.0, 10, 3, "");
1840         uiButSetFunc(bt, do_palette2_cb, bt, col);
1841         bt= uiDefButF(block, NUMSLI, retval, "V ",      offs, 0, 140,20, hsv+2, 0.0, 1.0, 10, 3, "");
1842         uiButSetFunc(bt, do_palette2_cb, bt, col);
1843         uiBlockEndAlign(block);
1844 }
1845
1846 /* bt1 is num but, hsv1 is pointer to original color in hsv space*/
1847 /* callback to handle changes */
1848 static void do_picker_small_cb(bContext *C, void *bt1, void *hsv1)
1849 {
1850         uiBut *but1= (uiBut *)bt1;
1851         uiPopupBlockHandle *popup= but1->block->handle;
1852         float *hsv= (float *)hsv1;
1853         float *fp= NULL;
1854         
1855         fp= (float *)but1->poin;
1856         rgb_to_hsv(fp[0], fp[1], fp[2], hsv, hsv+1, hsv+2);
1857
1858         ui_update_block_buts_hsv(but1->block, hsv);
1859         
1860         if(popup)
1861                 popup->menuretval= UI_RETURN_UPDATE;
1862 }
1863
1864 /* picker sizes S hsize, F full size, D spacer, B button/pallette height  */
1865 #define SPICK1  150.0
1866 #define DPICK1  6.0
1867
1868 /* only the color, a HS circle and V slider */
1869 static void uiBlockPickerSmall(uiBlock *block, float *col, float *hsv, float *old, char *hexcol, char mode, short retval)
1870 {
1871         uiBut *bt;
1872         
1873         VECCOPY(old, col);      // old color stored there, for palette_cb to work
1874         
1875         /* HS circle */
1876         bt= uiDefButF(block, HSVCIRCLE, retval, "",     0, 0,SPICK1,SPICK1, col, 0.0, 0.0, 0, 0, "");
1877         uiButSetFunc(bt, do_picker_small_cb, bt, hsv);
1878
1879         /* value */
1880         bt= uiDefButF(block, HSVCUBE, retval, "",       SPICK1+DPICK1,0,14,SPICK1, col, 0.0, 0.0, 4, 0, "");
1881         uiButSetFunc(bt, do_picker_small_cb, bt, hsv);
1882 }
1883
1884
1885 static void picker_new_hide_reveal(uiBlock *block, short colormode)
1886 {
1887         uiBut *bt;
1888         
1889         /* tag buttons */
1890         for(bt= block->buttons.first; bt; bt= bt->next) {
1891                 
1892                 if(bt->type==NUMSLI || bt->type==TEX) {
1893                         if( bt->str[1]=='e') {
1894                                 if(colormode==2) bt->flag &= ~UI_HIDDEN;
1895                                 else bt->flag |= UI_HIDDEN;
1896                         }
1897                         else if( ELEM3(bt->str[0], 'R', 'G', 'B')) {
1898                                 if(colormode==0) bt->flag &= ~UI_HIDDEN;
1899                                 else bt->flag |= UI_HIDDEN;
1900                         }
1901                         else if( ELEM3(bt->str[0], 'H', 'S', 'V')) {
1902                                 if(colormode==1) bt->flag &= ~UI_HIDDEN;
1903                                 else bt->flag |= UI_HIDDEN;
1904                         }
1905                 }
1906         }
1907 }
1908
1909 static void do_picker_new_mode_cb(bContext *C, void *bt1, void *colv)
1910 {
1911         uiBut *bt= bt1;
1912         short colormode= ui_get_but_val(bt);
1913
1914         picker_new_hide_reveal(bt->block, colormode);
1915 }
1916
1917
1918 /* a HS circle, V slider, rgb/hsv/hex sliders */
1919 static void uiBlockPickerNew(uiBlock *block, float *col, float *hsv, float *old, char *hexcol, char mode, short retval)
1920 {
1921         static short colormode= 0;      /* temp? 0=rgb, 1=hsv, 2=hex */
1922         uiBut *bt;
1923         int width;
1924         
1925         VECCOPY(old, col);      // old color stored there, for palette_cb to work
1926         
1927         /* HS circle */
1928         bt= uiDefButF(block, HSVCIRCLE, retval, "",     0, 0,SPICK1,SPICK1, col, 0.0, 0.0, 0, 0, "");
1929         uiButSetFunc(bt, do_picker_small_cb, bt, hsv);
1930         
1931         /* value */
1932         bt= uiDefButF(block, HSVCUBE, retval, "",       SPICK1+DPICK1,0,14,SPICK1, col, 0.0, 0.0, 4, 0, "");
1933         uiButSetFunc(bt, do_picker_small_cb, bt, hsv);
1934         
1935         /* mode */
1936         width= (SPICK1+DPICK1+14)/3;
1937         uiBlockBeginAlign(block);
1938         bt= uiDefButS(block, ROW, retval, "RGB",        0, -30, width, 19, &colormode, 0.0, 0.0, 0, 0, "");
1939         uiButSetFunc(bt, do_picker_new_mode_cb, bt, col);
1940         bt= uiDefButS(block, ROW, retval, "HSV",        width, -30, width, 19, &colormode, 0.0, 1.0, 0, 0, "");
1941         uiButSetFunc(bt, do_picker_new_mode_cb, bt, hsv);
1942         bt= uiDefButS(block, ROW, retval, "Hex",        2*width, -30, width, 19, &colormode, 0.0, 2.0, 0, 0, "");
1943         uiButSetFunc(bt, do_picker_new_mode_cb, bt, hexcol);
1944         uiBlockEndAlign(block);
1945         
1946         /* sliders or hex */
1947         width= (SPICK1+DPICK1+14);
1948         rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
1949         sprintf(hexcol, "%02X%02X%02X", (unsigned int)(col[0]*255.0), (unsigned int)(col[1]*255.0), (unsigned int)(col[2]*255.0));      
1950
1951         uiBlockBeginAlign(block);
1952         bt= uiDefButF(block, NUMSLI, 0, "R ",   0, -60, width, 19, col, 0.0, 1.0, 10, 3, "");
1953         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
1954         bt= uiDefButF(block, NUMSLI, 0, "G ",   0, -80, width, 19, col+1, 0.0, 1.0, 10, 3, "");
1955         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
1956         bt= uiDefButF(block, NUMSLI, 0, "B ",   0, -100, width, 19, col+2, 0.0, 1.0, 10, 3, "");
1957         uiButSetFunc(bt, do_palette1_cb, bt, hsv);
1958         uiBlockEndAlign(block);
1959
1960         uiBlockBeginAlign(block);
1961         bt= uiDefButF(block, NUMSLI, 0, "H ",   0, -60, width, 19, hsv, 0.0, 1.0, 10, 3, "");
1962         uiButSetFunc(bt, do_palette2_cb, bt, col);
1963         bt= uiDefButF(block, NUMSLI, 0, "S ",   0, -80, width, 19, hsv+1, 0.0, 1.0, 10, 3, "");
1964         uiButSetFunc(bt, do_palette2_cb, bt, col);
1965         bt= uiDefButF(block, NUMSLI, 0, "V ",   0, -100, width, 19, hsv+2, 0.0, 1.0, 10, 3, "");
1966         uiButSetFunc(bt, do_palette2_cb, bt, col);
1967         uiBlockEndAlign(block);
1968
1969         bt= uiDefBut(block, TEX, 0, "Hex: ", 0, -80, width, 19, hexcol, 0, 8, 0, 0, "Hex triplet for color (#RRGGBB)");
1970         uiButSetFunc(bt, do_palette_hex_cb, bt, hexcol);
1971
1972         picker_new_hide_reveal(block, colormode);
1973 }
1974
1975
1976 static int ui_picker_small_wheel(const bContext *C, uiBlock *block, wmEvent *event)
1977 {
1978         float add= 0.0f;
1979         
1980         if(event->type==WHEELUPMOUSE)
1981                 add= 0.05f;
1982         else if(event->type==WHEELDOWNMOUSE)
1983                 add= -0.05f;
1984         
1985         if(add!=0.0f) {
1986                 uiBut *but;
1987                 
1988                 for(but= block->buttons.first; but; but= but->next) {
1989                         if(but->type==HSVCUBE && but->active==NULL) {
1990                                 uiPopupBlockHandle *popup= block->handle;
1991                                 float col[3];
1992                                 
1993                                 ui_get_but_vectorf(but, col);
1994                                 
1995                                 rgb_to_hsv(col[0], col[1], col[2], but->hsv, but->hsv+1, but->hsv+2);
1996                                 but->hsv[2]= CLAMPIS(but->hsv[2]+add, 0.0f, 1.0f);
1997                                 hsv_to_rgb(but->hsv[0], but->hsv[1], but->hsv[2], col, col+1, col+2);
1998
1999                                 ui_set_but_vectorf(but, col);
2000                                 
2001                                 ui_update_block_buts_hsv(block, but->hsv);
2002                                 if(popup)
2003                                         popup->menuretval= UI_RETURN_UPDATE;
2004                                 
2005                                 return 1;
2006                         }
2007                 }
2008         }
2009         return 0;
2010 }
2011
2012 uiBlock *ui_block_func_COL(bContext *C, uiPopupBlockHandle *handle, void *arg_but)
2013 {
2014         wmWindow *win= CTX_wm_window(C); // XXX temp, needs to become keymap to detect type?
2015         uiBut *but= arg_but;
2016         uiBlock *block;
2017         static float hsvcol[3], oldcol[3];
2018         static char hexcol[128];
2019         
2020         block= uiBeginBlock(C, handle->region, "colorpicker", UI_EMBOSS);
2021         
2022         VECCOPY(handle->retvec, but->editvec);
2023         if(win->eventstate->shift) {
2024                 uiBlockPickerButtons(block, handle->retvec, hsvcol, oldcol, hexcol, 'p', 0);
2025                 block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_KEEP_OPEN;
2026                 uiBoundsBlock(block, 3);
2027         }
2028         else if(win->eventstate->alt) {
2029                 uiBlockPickerSmall(block, handle->retvec, hsvcol, oldcol, hexcol, 'p', 0);
2030                 block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1|UI_BLOCK_OUT_1;
2031                 uiBoundsBlock(block, 10);
2032                 
2033                 block->block_event_func= ui_picker_small_wheel;
2034         }
2035         else {
2036                 uiBlockPickerNew(block, handle->retvec, hsvcol, oldcol, hexcol, 'p', 0);
2037                 block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_KEEP_OPEN;
2038                 uiBoundsBlock(block, 10);
2039                 
2040                 block->block_event_func= ui_picker_small_wheel;
2041         }
2042         
2043         
2044         /* and lets go */
2045         block->direction= UI_TOP;
2046         
2047         return block;
2048 }
2049
2050 /* ******************** Color band *************** */
2051
2052 static int vergcband(const void *a1, const void *a2)
2053 {
2054         const CBData *x1=a1, *x2=a2;
2055         
2056         if( x1->pos > x2->pos ) return 1;
2057         else if( x1->pos < x2->pos) return -1;
2058         return 0;
2059 }
2060
2061 static void colorband_pos_cb(bContext *C, void *coba_v, void *unused_v)
2062 {
2063         ColorBand *coba= coba_v;
2064         int a;
2065         
2066         if(coba->tot<2) return;
2067         
2068         for(a=0; a<coba->tot; a++) coba->data[a].cur= a;
2069         qsort(coba->data, coba->tot, sizeof(CBData), vergcband);
2070         for(a=0; a<coba->tot; a++) {
2071                 if(coba->data[a].cur==coba->cur) {
2072                         /* if(coba->cur!=a) addqueue(curarea->win, REDRAW, 0); */       /* button cur */
2073                         coba->cur= a;
2074                         break;
2075                 }
2076         }
2077 }
2078
2079 static void colorband_add_cb(bContext *C, void *coba_v, void *unused_v)
2080 {
2081         ColorBand *coba= coba_v;
2082         
2083         if(coba->tot < MAXCOLORBAND-1) coba->tot++;
2084         coba->cur= coba->tot-1;
2085         
2086         colorband_pos_cb(C, coba, NULL);
2087 //      BIF_undo_push("Add colorband");
2088         
2089 }
2090
2091 static void colorband_del_cb(bContext *C, void *coba_v, void *unused_v)
2092 {
2093         ColorBand *coba= coba_v;
2094         int a;
2095         
2096         if(coba->tot<2) return;
2097         
2098         for(a=coba->cur; a<coba->tot; a++) {
2099                 coba->data[a]= coba->data[a+1];
2100         }
2101         if(coba->cur) coba->cur--;
2102         coba->tot--;
2103         
2104 //      BIF_undo_push("Delete colorband");
2105 //      BIF_preview_changed(ID_TE);
2106 }
2107
2108 void uiBlockColorbandButtons(uiBlock *block, ColorBand *coba, rctf *butr, int event)
2109 {
2110         CBData *cbd;
2111         uiBut *bt;
2112         float unit= (butr->xmax-butr->xmin)/14.0f;
2113         float xs= butr->xmin;
2114         
2115         cbd= coba->data + coba->cur;
2116         
2117         uiBlockBeginAlign(block);
2118         uiDefButF(block, COL, event,            "",                     xs,butr->ymin+20.0f,2.0f*unit,20,                               &(cbd->r), 0, 0, 0, 0, "");
2119         uiDefButF(block, NUM, event,            "A:",           xs+2.0f*unit,butr->ymin+20.0f,4.0f*unit,20,     &(cbd->a), 0.0f, 1.0f, 10, 2, "");
2120         bt= uiDefBut(block, BUT, event, "Add",          xs+6.0f*unit,butr->ymin+20.0f,2.0f*unit,20,     NULL, 0, 0, 0, 0, "Adds a new color position to the colorband");
2121         uiButSetFunc(bt, colorband_add_cb, coba, NULL);
2122         bt= uiDefBut(block, BUT, event, "Del",          xs+8.0f*unit, butr->ymin+20.0f, 2.0f*unit, 20,  NULL, 0, 0, 0, 0, "Deletes the active position");
2123         uiButSetFunc(bt, colorband_del_cb, coba, NULL);
2124         
2125         uiDefButS(block, MENU, event,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
2126                           xs + 10.0f*unit, butr->ymin+20.0f, unit*4.0f, 20,             &coba->ipotype, 0.0, 0.0, 0, 0, "Sets interpolation type");
2127         
2128         uiDefBut(block, BUT_COLORBAND, event, "",               xs, butr->ymin, butr->xmax-butr->xmin, 20.0f, coba, 0, 0, 0, 0, "");
2129         uiBlockEndAlign(block);
2130         
2131 }
2132
2133
2134 /* ******************** PUPmenu ****************** */
2135
2136 static int pupmenu_set= 0;
2137
2138 void uiPupMenuSetActive(int val)
2139 {
2140         pupmenu_set= val;
2141 }
2142
2143 /* value== -1 read, otherwise set */
2144 static int pupmenu_memory(char *str, int value)
2145 {
2146         static char mem[256], first=1;
2147         int val=0, nr=0;
2148         
2149         if(first) {
2150                 memset(mem, 0, 256);
2151                 first= 0;
2152         }
2153         while(str[nr]) {
2154                 val+= str[nr];
2155                 nr++;
2156         }
2157
2158         if(value >= 0) mem[ val & 255 ]= value;
2159         else return mem[ val & 255 ];
2160         
2161         return 0;
2162 }
2163
2164 #define PUP_LABELH      6
2165
2166 typedef struct uiPupMenuInfo {
2167         char *instr;
2168         int mx, my;
2169         int startx, starty;
2170         int maxrow;
2171 } uiPupMenuInfo;
2172
2173 uiBlock *ui_block_func_PUPMENU(bContext *C, uiPopupBlockHandle *handle, void *arg_info)
2174 {
2175         uiBlock *block;
2176         uiPupMenuInfo *info;
2177         int columns, rows, mousemove[2]= {0, 0}, mousewarp= 0;
2178         int width, height, xmax, ymax, maxrow;
2179         int a, startx, starty, endx, endy, x1, y1;
2180         int lastselected;
2181         MenuData *md;
2182
2183         info= arg_info;
2184         maxrow= info->maxrow;
2185         height= 0;
2186
2187         /* block stuff first, need to know the font */
2188         block= uiBeginBlock(C, handle->region, "menu", UI_EMBOSSP);
2189         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1|UI_BLOCK_NUMSELECT);
2190         block->direction= UI_DOWN;
2191         
2192         md= decompose_menu_string(info->instr);
2193
2194         rows= md->nitems;
2195         if(rows<1)
2196                 rows= 1;
2197         
2198         columns= 1;
2199
2200         /* size and location, title slightly bigger for bold */
2201         if(md->title) {
2202                 width= 2*strlen(md->title)+UI_GetStringWidth(md->title);
2203                 width /= columns;
2204         }
2205         else width= 0;
2206
2207         for(a=0; a<md->nitems; a++) {
2208                 xmax= UI_GetStringWidth(md->items[a].str);
2209                 if(xmax>width) width= xmax;
2210
2211                 if(strcmp(md->items[a].str, "%l")==0) height+= PUP_LABELH;
2212                 else height+= MENU_BUTTON_HEIGHT;
2213         }
2214
2215         width+= 10;
2216         if (width<50) width=50;
2217         
2218         wm_window_get_size(CTX_wm_window(C), &xmax, &ymax);
2219
2220         /* set first item */
2221         lastselected= 0;
2222         if(pupmenu_set) {
2223                 lastselected= pupmenu_set-1;
2224                 pupmenu_set= 0;
2225         }
2226         else if(md->nitems>1) {
2227                 lastselected= pupmenu_memory(info->instr, -1);
2228         }
2229
2230         startx= info->mx-(0.8*(width));
2231         starty= info->my-height+MENU_BUTTON_HEIGHT/2;
2232         if(lastselected>=0 && lastselected<md->nitems) {
2233                 for(a=0; a<md->nitems; a++) {
2234                         if(a==lastselected) break;
2235                         if( strcmp(md->items[a].str, "%l")==0) starty+= PUP_LABELH;
2236                         else starty+=MENU_BUTTON_HEIGHT;
2237                 }
2238                 
2239                 //starty= info->my-height+MENU_BUTTON_HEIGHT/2+lastselected*MENU_BUTTON_HEIGHT;
2240         }
2241         
2242         if(startx<10) {
2243                 startx= 10;
2244         }
2245         if(starty<10) {
2246                 mousemove[1]= 10-starty;
2247                 starty= 10;
2248         }
2249         
2250         endx= startx+width*columns;
2251         endy= starty+height;
2252
2253         if(endx>xmax) {
2254                 endx= xmax-10;
2255                 startx= endx-width*columns;
2256         }
2257         if(endy>ymax-20) {
2258                 mousemove[1]= ymax-endy-20;
2259                 endy= ymax-20;
2260                 starty= endy-height;
2261         }
2262
2263         if(mousemove[0] || mousemove[1]) {
2264                 ui_warp_pointer(info->mx+mousemove[0], info->my+mousemove[1]);
2265                 mousemove[0]= info->mx;
2266                 mousemove[1]= info->my;
2267                 mousewarp= 1;
2268         }
2269
2270         /* here we go! */
2271         if(md->title) {
2272                 uiBut *bt;
2273                 char titlestr[256];
2274
2275                 if(md->titleicon) {
2276                         width+= 20;
2277                         sprintf(titlestr, " %s", md->title);
2278                         uiDefIconTextBut(block, LABEL, 0, md->titleicon, titlestr, startx, (short)(starty+height), width, MENU_BUTTON_HEIGHT, NULL, 0.0, 0.0, 0, 0, "");
2279                 }
2280                 else {
2281                         bt= uiDefBut(block, LABEL, 0, md->title, startx, (short)(starty+height), columns*width, MENU_BUTTON_HEIGHT, NULL, 0.0, 0.0, 0, 0, "");
2282                         bt->flag= UI_TEXT_LEFT;
2283                 }
2284                 
2285                 //uiDefBut(block, SEPR, 0, "", startx, (short)(starty+height)-MENU_SEPR_HEIGHT, width, MENU_SEPR_HEIGHT, NULL, 0.0, 0.0, 0, 0, "");
2286         }
2287
2288         x1= startx + width*((int)a/rows);
2289         y1= starty + height - MENU_BUTTON_HEIGHT; // - MENU_SEPR_HEIGHT;
2290                 
2291         for(a=0; a<md->nitems; a++) {
2292                 char *name= md->items[a].str;
2293                 int icon = md->items[a].icon;
2294
2295                 if(strcmp(name, "%l")==0) {
2296                         uiDefBut(block, SEPR, B_NOP, "", x1, y1, width, PUP_LABELH, NULL, 0, 0.0, 0, 0, "");
2297                         y1 -= PUP_LABELH;
2298                 }
2299                 else if (icon) {
2300                         uiDefIconButF(block, BUTM, B_NOP, icon, x1, y1, width+16, MENU_BUTTON_HEIGHT-1, &handle->retvalue, (float) md->items[a].retval, 0.0, 0, 0, "");
2301                         y1 -= MENU_BUTTON_HEIGHT;
2302                 }
2303                 else {
2304                         uiDefButF(block, BUTM, B_NOP, name, x1, y1, width, MENU_BUTTON_HEIGHT-1, &handle->retvalue, (float) md->items[a].retval, 0.0, 0, 0, "");
2305                         y1 -= MENU_BUTTON_HEIGHT;
2306                 }
2307         }
2308         
2309         uiBoundsBlock(block, 1);
2310         uiEndBlock(C, block);
2311
2312         menudata_free(md);
2313
2314         /* XXX 2.5 need to store last selected */
2315 #if 0
2316         /* calculate last selected */
2317         if(event & ui_return_ok) {
2318                 lastselected= 0;
2319                 for(a=0; a<md->nitems; a++) {
2320                         if(val==md->items[a].retval) lastselected= a;
2321                 }
2322                 
2323                 pupmenu_memory(info->instr, lastselected);
2324         }
2325 #endif
2326         
2327         /* XXX 2.5 need to warp back */
2328 #if 0
2329         if(mousemove[1] && (event & ui_return_out)==0)
2330                 ui_warp_pointer(mousemove[0], mousemove[1]);
2331         return val;
2332 #endif
2333
2334         return block;
2335 }
2336
2337 uiBlock *ui_block_func_PUPMENUCOL(bContext *C, uiPopupBlockHandle *handle, void *arg_info)
2338 {
2339         uiBlock *block;
2340         uiPupMenuInfo *info;
2341         int columns, rows, mousemove[2]= {0, 0}, mousewarp;
2342         int width, height, xmax, ymax, maxrow;
2343         int a, startx, starty, endx, endy, x1, y1;
2344         float fvalue;
2345         MenuData *md;
2346
2347         info= arg_info;
2348         maxrow= info->maxrow;
2349         height= 0;
2350
2351         /* block stuff first, need to know the font */
2352         block= uiBeginBlock(C, handle->region, "menu", UI_EMBOSSP);
2353         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1|UI_BLOCK_NUMSELECT);
2354         block->direction= UI_DOWN;
2355         
2356         md= decompose_menu_string(info->instr);
2357
2358         /* columns and row calculation */
2359         columns= (md->nitems+maxrow)/maxrow;
2360         if (columns<1) columns= 1;
2361         
2362         if(columns > 8) {
2363                 maxrow += 5;
2364                 columns= (md->nitems+maxrow)/maxrow;
2365         }
2366         
2367         rows= (int) md->nitems/columns;
2368         if (rows<1) rows= 1;
2369         
2370         while (rows*columns<(md->nitems+columns) ) rows++;
2371
2372         /* size and location, title slightly bigger for bold */
2373         if(md->title) {
2374                 width= 2*strlen(md->title)+UI_GetStringWidth(md->title);
2375                 width /= columns;
2376         }
2377         else width= 0;
2378
2379         for(a=0; a<md->nitems; a++) {
2380                 xmax= UI_GetStringWidth(md->items[a].str);
2381                 if(xmax>width) width= xmax;
2382         }
2383
2384         width+= 10;
2385         if (width<50) width=50;
2386         
2387         height= rows*MENU_BUTTON_HEIGHT;
2388         if (md->title) height+= MENU_BUTTON_HEIGHT;
2389         
2390         wm_window_get_size(CTX_wm_window(C), &xmax, &ymax);
2391
2392         /* find active item */
2393         fvalue= handle->retvalue;
2394         for(a=0; a<md->nitems; a++) {
2395                 if( md->items[a].retval== (int)fvalue ) break;
2396         }
2397
2398         /* no active item? */
2399         if(a==md->nitems) {
2400                 if(md->title) a= -1;
2401                 else a= 0;
2402         }
2403
2404         if(a>0)
2405                 startx = info->mx-width/2 - ((int)(a)/rows)*width;
2406         else
2407                 startx= info->mx-width/2;
2408         starty = info->my-height + MENU_BUTTON_HEIGHT/2 + ((a)%rows)*MENU_BUTTON_HEIGHT;
2409
2410         if (md->title) starty+= MENU_BUTTON_HEIGHT;
2411         
2412         if(startx<10) {
2413                 mousemove[0]= 10-startx;
2414                 startx= 10;
2415         }
2416         if(starty<10) {
2417                 mousemove[1]= 10-starty;
2418                 starty= 10;
2419         }
2420         
2421         endx= startx+width*columns;
2422         endy= starty+height;
2423
2424         if(endx>xmax) {
2425                 mousemove[0]= xmax-endx-10;
2426                 endx= xmax-10;
2427                 startx= endx-width*columns;
2428         }
2429         if(endy>ymax) {
2430                 mousemove[1]= ymax-endy-10;
2431                 endy= ymax-10;
2432                 starty= endy-height;
2433         }
2434
2435         if(mousemove[0] || mousemove[1]) {
2436                 ui_warp_pointer(info->mx+mousemove[0], info->my+mousemove[1]);
2437                 mousemove[0]= info->mx;
2438                 mousemove[1]= info->my;
2439                 mousewarp= 1;
2440         }
2441
2442         /* here we go! */
2443         if(md->title) {
2444                 uiBut *bt;
2445
2446                 if(md->titleicon) {
2447                 }
2448                 else {
2449                         bt= uiDefBut(block, LABEL, 0, md->title, startx, (short)(starty+rows*MENU_BUTTON_HEIGHT), columns*width, MENU_BUTTON_HEIGHT, NULL, 0.0, 0.0, 0, 0, "");
2450                         bt->flag= UI_TEXT_LEFT;
2451                 }
2452         }
2453
2454         for(a=0; a<md->nitems; a++) {
2455                 char *name= md->items[a].str;
2456                 int icon = md->items[a].icon;
2457
2458                 x1= startx + width*((int)a/rows);
2459                 y1= starty - MENU_BUTTON_HEIGHT*(a%rows) + (rows-1)*MENU_BUTTON_HEIGHT; 
2460                 
2461                 if(strcmp(name, "%l")==0) {
2462                         uiDefBut(block, SEPR, B_NOP, "", x1, y1, width, PUP_LABELH, NULL, 0, 0.0, 0, 0, "");
2463                         y1 -= PUP_LABELH;
2464                 }
2465                 else if (icon) {
2466                         uiDefIconButF(block, BUTM, B_NOP, icon, x1, y1, width+16, MENU_BUTTON_HEIGHT-1, &handle->retvalue, (float) md->items[a].retval, 0.0, 0, 0, "");
2467                         y1 -= MENU_BUTTON_HEIGHT;
2468                 }
2469                 else {
2470                         uiDefButF(block, BUTM, B_NOP, name, x1, y1, width, MENU_BUTTON_HEIGHT-1, &handle->retvalue, (float) md->items[a].retval, 0.0, 0, 0, "");
2471                         y1 -= MENU_BUTTON_HEIGHT;
2472                 }
2473         }
2474         
2475         uiBoundsBlock(block, 1);
2476         uiEndBlock(C, block);
2477         
2478         menudata_free(md);
2479         
2480         /* XXX 2.5 need to warp back */
2481 #if 0
2482         if((event & UI_RETURN_OUT)==0)
2483                 ui_warp_pointer(mousemove[0], mousemove[1]);
2484 #endif
2485
2486         return block;
2487 }
2488
2489 /************************** Menu Definitions ***************************/
2490
2491 /* prototype */
2492 static uiBlock *ui_block_func_MENU_ITEM(bContext *C, uiPopupBlockHandle *handle, void *arg_info);
2493
2494 struct uiPopupMenu {
2495         uiBlock *block;
2496         uiLayout *layout;
2497 };
2498
2499 typedef struct uiMenuInfo {
2500         uiPopupMenu *pup;
2501         int mx, my, popup, slideout;
2502         int startx, starty;
2503 } uiMenuInfo;
2504
2505 /************************ Menu Definitions to uiBlocks ***********************/
2506
2507 static uiBlock *ui_block_func_MENU_ITEM(bContext *C, uiPopupBlockHandle *handle, void *arg_info)
2508 {
2509         uiBlock *block;
2510         uiMenuInfo *info= arg_info;
2511         uiPopupMenu *pup;
2512         ScrArea *sa;
2513         ARegion *ar;
2514         
2515         pup= info->pup;
2516         block= pup->block;
2517         
2518         /* block stuff first, need to know the font */
2519         uiBlockSetRegion(block, handle->region);
2520         block->direction= UI_DOWN;
2521
2522         uiBlockLayoutResolve(C, block, NULL, NULL);
2523
2524         if(info->popup) {
2525                 uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT|UI_BLOCK_RET_1);
2526                 uiBlockSetDirection(block, UI_DOWN);
2527
2528                 /* here we set an offset for the mouse position */
2529                 uiMenuPopupBoundsBlock(block, 1, 0, 1.5*MENU_BUTTON_HEIGHT);
2530         }
2531         else {
2532                 /* for a header menu we set the direction automatic */
2533                 if(!info->slideout) {
2534                         sa= CTX_wm_area(C);
2535                         ar= CTX_wm_region(C);
2536
2537                         if(sa && sa->headertype==HEADERDOWN) {
2538                                 if(ar && ar->regiontype == RGN_TYPE_HEADER) {
2539                                         uiBlockSetDirection(block, UI_TOP);
2540                                         uiBlockFlipOrder(block);
2541                                 }
2542                         }
2543                 }
2544
2545                 uiTextBoundsBlock(block, 50);
2546         }
2547
2548         /* if menu slides out of other menu, override direction */
2549         if(info->slideout)
2550                 uiBlockSetDirection(block, UI_RIGHT);
2551
2552         uiEndBlock(C, block);
2553         
2554         return block;
2555 }
2556
2557 uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut *but, uiMenuCreateFunc menu_func, void *arg)
2558 {
2559         uiStyle *style= U.uistyles.first;
2560         uiPopupBlockHandle *handle;
2561         uiPopupMenu *pup;
2562         uiMenuInfo info;
2563         
2564         pup= MEM_callocN(sizeof(uiPopupMenu), "menu dummy");
2565         pup->block= uiBeginBlock(C, NULL, "ui_popup_menu_create", UI_EMBOSSP);
2566         pup->layout= uiBlockLayout(pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, style);
2567         uiLayoutSetOperatorContext(pup->layout, WM_OP_INVOKE_REGION_WIN);
2568
2569         /* create in advance so we can let buttons point to retval already */
2570         pup->block->handle= MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
2571
2572         menu_func(C, pup->layout, arg);
2573         
2574         memset(&info, 0, sizeof(info));
2575         info.pup= pup;
2576         info.slideout= (but && (but->block->flag & UI_BLOCK_LOOP));
2577         
2578         handle= ui_popup_block_create(C, butregion, but, NULL, ui_block_func_MENU_ITEM, &info);
2579         
2580         MEM_freeN(pup);
2581
2582         return handle;
2583 }
2584
2585 /*************************** Menu Creating API **************************/
2586
2587
2588 /*************************** Popup Menu API **************************/
2589
2590 /* only return handler, and set optional title */
2591 uiPopupMenu *uiPupMenuBegin(bContext *C, const char *title, int icon)
2592 {
2593         uiStyle *style= U.uistyles.first;
2594         uiPopupMenu *pup= MEM_callocN(sizeof(uiPopupMenu), "menu start");
2595         uiBut *but;
2596         
2597         pup->block= uiBeginBlock(C, NULL, "uiPupMenuBegin", UI_EMBOSSP);
2598         pup->layout= uiBlockLayout(pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, style);
2599         uiLayoutSetOperatorContext(pup->layout, WM_OP_EXEC_REGION_WIN);
2600
2601         /* create in advance so we can let buttons point to retval already */
2602         pup->block->handle= MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
2603         
2604         /* create title button */
2605         if(title && title[0]) {
2606                 char titlestr[256];
2607                 
2608                 if(icon) {
2609                         sprintf(titlestr, " %s", title);
2610                         uiDefIconTextBut(pup->block, LABEL, 0, icon, titlestr, 0, 0, 200, MENU_BUTTON_HEIGHT, NULL, 0.0, 0.0, 0, 0, "");
2611                 }
2612                 else {
2613                         but= uiDefBut(pup->block, LABEL, 0, (char*)title, 0, 0, 200, MENU_BUTTON_HEIGHT, NULL, 0.0, 0.0, 0, 0, "");
2614                         but->flag= UI_TEXT_LEFT;
2615                 }
2616                 
2617                 //uiDefBut(block, SEPR, 0, "", startx, (short)(starty+height)-MENU_SEPR_HEIGHT, width, MENU_SEPR_HEIGHT, NULL, 0.0, 0.0, 0, 0, "");
2618         }
2619
2620         return pup;
2621 }
2622
2623 /* set the whole structure to work */
2624 void uiPupMenuEnd(bContext *C, uiPopupMenu *pup)
2625 {
2626         wmWindow *window= CTX_wm_window(C);
2627         uiMenuInfo info;
2628         uiPopupBlockHandle *menu;
2629         
2630         memset(&info, 0, sizeof(info));
2631         info.popup= 1;
2632         info.mx= window->eventstate->x;
2633         info.my= window->eventstate->y;
2634         info.pup= pup;
2635         
2636         menu= ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_MENU_ITEM, &info);
2637         menu->popup= 1;
2638         
2639         UI_add_popup_handlers(C, &window->handlers, menu);
2640         WM_event_add_mousemove(C);
2641         
2642         MEM_freeN(pup);
2643 }
2644
2645 uiLayout *uiPupMenuLayout(uiPopupMenu *pup)
2646 {
2647         return pup->layout;
2648 }
2649
2650 /* ************** standard pupmenus *************** */
2651
2652 /* this one can called with operatortype name and operators */
2653 static uiPopupBlockHandle *ui_pup_menu(bContext *C, int maxrow, uiMenuHandleFunc func, void *arg, char *str, ...)
2654 {
2655         wmWindow *window= CTX_wm_window(C);
2656         uiPupMenuInfo info;
2657         uiPopupBlockHandle *menu;
2658
2659         memset(&info, 0, sizeof(info));
2660         info.mx= window->eventstate->x;
2661         info.my= window->eventstate->y;
2662         info.maxrow= maxrow;
2663         info.instr= str;
2664
2665         menu= ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_PUPMENU, &info);
2666         menu->popup= 1;
2667
2668         UI_add_popup_handlers(C, &window->handlers, menu);
2669         WM_event_add_mousemove(C);
2670
2671         menu->popup_func= func;
2672         menu->popup_arg= arg;
2673         
2674         return menu;
2675 }
2676
2677 static void operator_name_cb(bContext *C, void *arg, int retval)
2678 {
2679         const char *opname= arg;
2680
2681         if(opname && retval > 0)
2682                 WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL);
2683 }
2684
2685 static void vconfirm_opname(bContext *C, char *opname, char *title, char *itemfmt, va_list ap)
2686 {
2687         char *s, buf[512];
2688
2689         s= buf;
2690         if (title) s+= sprintf(s, "%s%%t|", title);
2691         vsprintf(s, itemfmt, ap);
2692
2693         ui_pup_menu(C, 0, operator_name_cb, opname, buf);
2694 }
2695
2696 static void operator_cb(bContext *C, void *arg, int retval)
2697 {
2698         wmOperator *op= arg;
2699         
2700         if(op && retval > 0)
2701                 WM_operator_call(C, op);
2702         else
2703                 WM_operator_free(op);
2704 }
2705
2706 static void confirm_cancel_operator(void *opv)
2707 {
2708         WM_operator_free(opv);
2709 }
2710
2711 static void confirm_operator(bContext *C, wmOperator *op, char *title, char *item)
2712 {
2713         uiPopupBlockHandle *handle;
2714         char *s, buf[512];
2715         
2716         s= buf;
2717         if (title) s+= sprintf(s, "%s%%t|%s", title, item);
2718         
2719         handle= ui_pup_menu(C, 0, operator_cb, op, buf);
2720         handle->cancel_func= confirm_cancel_operator;
2721 }
2722
2723
2724 void uiPupMenuOkee(bContext *C, char *opname, char *str, ...)
2725 {
2726         va_list ap;
2727         char titlestr[256];
2728
2729         sprintf(titlestr, "OK? %%i%d", ICON_QUESTION);
2730
2731         va_start(ap, str);
2732         vconfirm_opname(C, opname, titlestr, str, ap);
2733         va_end(ap);
2734 }
2735
2736
2737 void uiPupMenuSaveOver(bContext *C, wmOperator *op, char *filename)
2738 {
2739         size_t len= strlen(filename);
2740
2741         if(len==0)
2742                 return;
2743
2744         if(filename[len-1]=='/' || filename[len-1]=='\\') {
2745                 uiPupMenuError(C, "Cannot overwrite a directory");
2746                 WM_operator_free(op);
2747                 return;
2748         }
2749         if(BLI_exists(filename)==0)
2750                 operator_cb(C, op, 1);
2751         else
2752                 confirm_operator(C, op, "Save over", filename);
2753 }
2754
2755 void uiPupMenuNotice(bContext *C, char *str, ...)
2756 {
2757         va_list ap;
2758
2759         va_start(ap, str);
2760         vconfirm_opname(C, NULL, NULL, str, ap);
2761         va_end(ap);
2762 }
2763
2764 void uiPupMenuError(bContext *C, char *str, ...)
2765 {
2766         va_list ap;
2767         char nfmt[256];
2768         char titlestr[256];
2769
2770         sprintf(titlestr, "Error %%i%d", ICON_ERROR);
2771
2772         sprintf(nfmt, "%s", str);
2773
2774         va_start(ap, str);
2775         vconfirm_opname(C, NULL, titlestr, nfmt, ap);
2776         va_end(ap);
2777 }
2778
2779 void uiPupMenuReports(bContext *C, ReportList *reports)
2780 {
2781         Report *report;
2782         DynStr *ds;
2783         char *str;
2784
2785         if(!reports || !reports->list.first)
2786                 return;
2787         if(!CTX_wm_window(C))
2788                 return;
2789
2790         ds= BLI_dynstr_new();
2791
2792         for(report=reports->list.first; report; report=report->next) {
2793                 if(report->type >= RPT_ERROR)
2794                         BLI_dynstr_appendf(ds, "Error %%i%d%%t|%s", ICON_ERROR, report->message);
2795                 else if(report->type >= RPT_WARNING)
2796                         BLI_dynstr_appendf(ds, "Warning %%i%d%%t|%s", ICON_ERROR, report->message);
2797                 else if(report->type >= RPT_INFO)
2798                         BLI_dynstr_appendf(ds, "Info %%t|%s", report->message);
2799         }
2800
2801         str= BLI_dynstr_get_cstring(ds);
2802         ui_pup_menu(C, 0, NULL, NULL, str);
2803         MEM_freeN(str);
2804
2805         BLI_dynstr_free(ds);
2806 }
2807
2808 /*************************** Popup Block API **************************/
2809
2810 void uiPupBlockO(bContext *C, uiBlockCreateFunc func, void *arg, char *opname, int opcontext)
2811 {
2812         wmWindow *window= CTX_wm_window(C);
2813         uiPopupBlockHandle *handle;
2814         
2815         handle= ui_popup_block_create(C, NULL, NULL, func, NULL, arg);
2816         handle->popup= 1;
2817         handle->optype= (opname)? WM_operatortype_find(opname, 0): NULL;
2818         handle->opcontext= opcontext;
2819         
2820         UI_add_popup_handlers(C, &window->handlers, handle);
2821         WM_event_add_mousemove(C);
2822 }
2823
2824 void uiPupBlock(bContext *C, uiBlockCreateFunc func, void *arg)
2825 {
2826         uiPupBlockO(C, func, arg, NULL, 0);
2827 }
2828
2829 void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int opcontext)
2830 {
2831         wmWindow *window= CTX_wm_window(C);
2832         uiPopupBlockHandle *handle;
2833         
2834         handle= ui_popup_block_create(C, NULL, NULL, func, NULL, op);
2835         handle->popup= 1;
2836         handle->retvalue= 1;
2837
2838         handle->popup_arg= op;
2839         handle->popup_func= operator_cb;
2840         handle->cancel_func= confirm_cancel_operator;
2841         handle->opcontext= opcontext;
2842         
2843         UI_add_popup_handlers(C, &window->handlers, handle);
2844         WM_event_add_mousemove(C);
2845 }