ce3fe61b2f9948756ccae3ad310f8514edd9305c
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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_userdef_types.h"
34
35 #include "BLI_math.h"
36 #include "BLI_blenlib.h"
37 #include "BLI_dynstr.h"
38 #include "BLI_ghash.h"
39
40 #include "BKE_context.h"
41 #include "BKE_icons.h"
42 #include "BKE_report.h"
43 #include "BKE_screen.h"
44 #include "BKE_texture.h"
45 #include "BKE_utildefines.h"
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49 #include "wm_draw.h"
50 #include "wm_subwindow.h"
51 #include "wm_window.h"
52
53 #include "RNA_access.h"
54
55 #include "BIF_gl.h"
56
57 #include "UI_interface.h"
58 #include "UI_interface_icons.h"
59 #include "UI_view2d.h"
60
61 #include "BLF_api.h"
62
63 #include "ED_screen.h"
64
65 #include "interface_intern.h"
66
67 #define MENU_BUTTON_HEIGHT      20
68 #define MENU_SEPR_HEIGHT        6
69 #define B_NOP                   -1
70 #define MENU_SHADOW_SIDE        8
71 #define MENU_SHADOW_BOTTOM      10
72 #define MENU_TOP                        8
73
74 /*********************** Menu Data Parsing ********************* */
75
76 typedef struct MenuEntry {
77         char *str;
78         int retval;
79         int icon;
80         int sepr;
81 } MenuEntry;
82
83 typedef struct MenuData {
84         char *instr;
85         char *title;
86         int titleicon;
87         
88         MenuEntry *items;
89         int nitems, itemssize;
90 } MenuData;
91
92 static MenuData *menudata_new(char *instr)
93 {
94         MenuData *md= MEM_mallocN(sizeof(*md), "MenuData");
95
96         md->instr= instr;
97         md->title= NULL;
98         md->titleicon= 0;
99         md->items= NULL;
100         md->nitems= md->itemssize= 0;
101         
102         return md;
103 }
104
105 static void menudata_set_title(MenuData *md, char *title, int titleicon)
106 {
107         if (!md->title)
108                 md->title= title;
109         if (!md->titleicon)
110                 md->titleicon= titleicon;
111 }
112
113 static void menudata_add_item(MenuData *md, char *str, int retval, int icon, int sepr)
114 {
115         if (md->nitems==md->itemssize) {
116                 int nsize= md->itemssize?(md->itemssize<<1):1;
117                 MenuEntry *oitems= md->items;
118                 
119                 md->items= MEM_mallocN(nsize*sizeof(*md->items), "md->items");
120                 if (oitems) {
121                         memcpy(md->items, oitems, md->nitems*sizeof(*md->items));
122                         MEM_freeN(oitems);
123                 }
124                 
125                 md->itemssize= nsize;
126         }
127         
128         md->items[md->nitems].str= str;
129         md->items[md->nitems].retval= retval;
130         md->items[md->nitems].icon= icon;
131         md->items[md->nitems].sepr= sepr;
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|), (sss%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, sss%l indicates a label and
151          * new column.
152          * 
153          * @param str String to be parsed.
154          * @retval new menudata structure, free with menudata_free()
155          */
156 MenuData *decompose_menu_string(char *str) 
157 {
158         char *instr= BLI_strdup(str);
159         MenuData *md= menudata_new(instr);
160         char *nitem= NULL, *s= instr;
161         int nicon=0, nretval= 1, nitem_is_title= 0, nitem_is_sepr= 0;
162         
163         while (1) {
164                 char c= *s;
165
166                 if (c=='%') {
167                         if (s[1]=='x') {
168                                 nretval= atoi(s+2);
169
170                                 *s= '\0';
171                                 s++;
172                         } else if (s[1]=='t') {
173                                 nitem_is_title= 1;
174
175                                 *s= '\0';
176                                 s++;
177                         } else if (s[1]=='l') {
178                                 nitem_is_sepr= 1;
179                                 if(!nitem) nitem= "";
180
181                                 *s= '\0';
182                                 s++;
183                         } else if (s[1]=='i') {
184                                 nicon= atoi(s+2);
185                                 
186                                 *s= '\0';
187                                 s++;
188                         }
189                 } else if (c=='|' || c == '\n' || c=='\0') {
190                         if (nitem) {
191                                 *s= '\0';
192
193                                 if(nitem_is_title) {
194                                         menudata_set_title(md, nitem, nicon);
195                                         nitem_is_title= 0;
196                                 }
197                                 else if(nitem_is_sepr) {
198                                         /* prevent separator to get a value */
199                                         menudata_add_item(md, nitem, -1, nicon, 1);
200                                         nretval= md->nitems+1;
201                                         nitem_is_sepr= 0;
202                                 }
203                                 else {
204                                         menudata_add_item(md, nitem, nretval, nicon, 0);
205                                         nretval= md->nitems+1;
206                                 } 
207                                 
208                                 nitem= NULL;
209                                 nicon= 0;
210                         }
211                         
212                         if (c=='\0')
213                                 break;
214                 } else if (!nitem)
215                         nitem= s;
216                 
217                 s++;
218         }
219         
220         return md;
221 }
222
223 void ui_set_name_menu(uiBut *but, int value)
224 {
225         MenuData *md;
226         int i;
227         
228         md= decompose_menu_string(but->str);
229         for (i=0; i<md->nitems; i++)
230                 if (md->items[i].retval==value)
231                         strcpy(but->drawstr, md->items[i].str);
232         
233         menudata_free(md);
234 }
235
236 int ui_step_name_menu(uiBut *but, int step)
237 {
238         MenuData *md;
239         int value= ui_get_but_val(but);
240         int i;
241         
242         md= decompose_menu_string(but->str);
243         for (i=0; i<md->nitems; i++)
244                 if (md->items[i].retval==value)
245                         break;
246         
247         if(step==1) {
248                 /* skip separators */
249                 for(; i<md->nitems-1; i++) {
250                         if(md->items[i+1].retval != -1) {
251                                 value= md->items[i+1].retval;
252                                 break;
253                         }
254                 }
255         }
256         else {
257                 if(i>0) {
258                         /* skip separators */
259                         for(; i>0; i--) {
260                                 if(md->items[i-1].retval != -1) {
261                                         value= md->items[i-1].retval;
262                                         break;
263                                 }
264                         }
265                 }
266         }
267         
268         menudata_free(md);
269                 
270         return value;
271 }
272
273
274 /******************** Creating Temporary regions ******************/
275
276 ARegion *ui_add_temporary_region(bScreen *sc)
277 {
278         ARegion *ar;
279
280         ar= MEM_callocN(sizeof(ARegion), "area region");
281         BLI_addtail(&sc->regionbase, ar);
282
283         ar->regiontype= RGN_TYPE_TEMPORARY;
284         ar->alignment= RGN_ALIGN_FLOAT;
285
286         return ar;
287 }
288
289 void ui_remove_temporary_region(bContext *C, bScreen *sc, ARegion *ar)
290 {
291         if(CTX_wm_window(C))
292                 wm_draw_region_clear(CTX_wm_window(C), ar);
293
294         ED_region_exit(C, ar);
295         BKE_area_region_free(NULL, ar);         /* NULL: no spacetype */
296         BLI_freelinkN(&sc->regionbase, ar);
297 }
298
299 /************************* Creating Tooltips **********************/
300
301 #define MAX_TOOLTIP_LINES 8
302
303 typedef struct uiTooltipData {
304         rcti bbox;
305         uiFontStyle fstyle;
306         char lines[MAX_TOOLTIP_LINES][512];
307         int linedark[MAX_TOOLTIP_LINES];
308         int totline;
309         int toth, spaceh, lineh;
310 } uiTooltipData;
311
312 static void ui_tooltip_region_draw(const bContext *C, ARegion *ar)
313 {
314         uiTooltipData *data= ar->regiondata;
315         rcti bbox= data->bbox;
316         int a;
317         
318         ui_draw_menu_back(U.uistyles.first, NULL, &data->bbox);
319         
320         /* draw text */
321         uiStyleFontSet(&data->fstyle);
322
323         bbox.ymax= bbox.ymax - 0.5f*((bbox.ymax - bbox.ymin) - data->toth);
324         bbox.ymin= bbox.ymax - data->lineh;
325
326         for(a=0; a<data->totline; a++) {
327                 if(!data->linedark[a]) glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
328                 else glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
329
330                 uiStyleFontDraw(&data->fstyle, &bbox, data->lines[a]);
331                 bbox.ymin -= data->lineh + data->spaceh;
332                 bbox.ymax -= data->lineh + data->spaceh;
333         }
334 }
335
336 static void ui_tooltip_region_free(ARegion *ar)
337 {
338         uiTooltipData *data;
339
340         data= ar->regiondata;
341         MEM_freeN(data);
342         ar->regiondata= NULL;
343 }
344
345 ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
346 {
347         uiStyle *style= U.uistyles.first;       // XXX pass on as arg
348         static ARegionType type;
349         ARegion *ar;
350         uiTooltipData *data;
351         IDProperty *prop;
352         char buf[512];
353         float fonth, fontw, aspect= but->block->aspect;
354         float x1f, x2f, y1f, y2f;
355         int x1, x2, y1, y2, winx, winy, ofsx, ofsy, w, h, a;
356
357         if(but->flag & UI_BUT_NO_TOOLTIP)
358                 return NULL;
359
360         /* create tooltip data */
361         data= MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
362
363         if(but->tip && strlen(but->tip)) {
364                 BLI_strncpy(data->lines[data->totline], but->tip, sizeof(data->lines[0]));
365                 data->totline++;
366         }
367
368         if(but->optype && !(but->block->flag & UI_BLOCK_LOOP)) {
369                 /* operator keymap (not menus, they already have it) */
370                 prop= (but->opptr)? but->opptr->data: NULL;
371
372                 if(WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, buf, sizeof(buf))) {
373                         BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Shortcut: %s", buf);
374                         data->linedark[data->totline]= 1;
375                         data->totline++;
376                 }
377         }
378
379         if(ELEM3(but->type, TEX, IDPOIN, SEARCH_MENU)) {
380                 /* full string */
381                 ui_get_but_string(but, buf, sizeof(buf));
382                 if(buf[0]) {
383                         BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Value: %s", buf);
384                         data->linedark[data->totline]= 1;
385                         data->totline++;
386                 }
387         }
388
389         if(but->rnaprop) {
390                 int unit_type = RNA_SUBTYPE_UNIT(RNA_property_subtype(but->rnaprop));
391                 
392                 if (unit_type == PROP_UNIT_ROTATION) {
393                         if (RNA_property_type(but->rnaprop) == PROP_FLOAT) {
394                                 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Radians: %f", RNA_property_float_get_index(&but->rnapoin, but->rnaprop, but->rnaindex));
395                                 data->linedark[data->totline]= 1;
396                                 data->totline++;
397                         }
398                 }
399                 
400                 if(but->flag & UI_BUT_DRIVEN) {
401                         if(ui_but_anim_expression_get(but, buf, sizeof(buf))) {
402                                 /* expression */
403                                 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Expression: %s", buf);
404                                 data->linedark[data->totline]= 1;
405                                 data->totline++;
406                         }
407                 }
408
409                 /* rna info */
410                 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Python: %s.%s", RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop));
411                 data->linedark[data->totline]= 1;
412                 data->totline++;
413                 
414                 if(but->rnapoin.id.data) {
415                         ID *id= but->rnapoin.id.data;
416                         if(id->lib && id->lib->name) {
417                                 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Library: %s", id->lib->name);
418                                 data->linedark[data->totline]= 1;
419                                 data->totline++;
420                         }
421                 }
422         }
423         else if (but->optype) {
424                 PointerRNA *opptr;
425                 char *str;
426                 opptr= uiButGetOperatorPtrRNA(but); /* allocated when needed, the button owns it */
427
428                 str= WM_operator_pystring(C, but->optype, opptr, 0);
429
430                 /* operator info */
431                 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Python: %s", str);
432                 data->linedark[data->totline]= 1;
433                 data->totline++;
434
435                 MEM_freeN(str);
436         }
437
438         if(data->totline == 0) {
439                 MEM_freeN(data);
440                 return NULL;
441         }
442
443         /* create area region */
444         ar= ui_add_temporary_region(CTX_wm_screen(C));
445
446         memset(&type, 0, sizeof(ARegionType));
447         type.draw= ui_tooltip_region_draw;
448         type.free= ui_tooltip_region_free;
449         ar->type= &type;
450         
451         /* set font, get bb */
452         data->fstyle= style->widget; /* copy struct */
453         data->fstyle.align= UI_STYLE_TEXT_CENTER;
454         uiStyleFontSet(&data->fstyle);
455
456         h= BLF_height(data->lines[0]);
457
458         for(a=0, fontw=0, fonth=0; a<data->totline; a++) {
459                 w= BLF_width(data->lines[a]);
460                 fontw= MAX2(fontw, w);
461                 fonth += (a == 0)? h: h+5;
462         }
463
464         fontw *= aspect;
465
466         ar->regiondata= data;
467
468         data->toth= fonth;
469         data->lineh= h;
470         data->spaceh= 5;
471
472         /* compute position */
473         ofsx= (but->block->panel)? but->block->panel->ofsx: 0;
474         ofsy= (but->block->panel)? but->block->panel->ofsy: 0;
475
476         x1f= (but->x1+but->x2)/2.0f + ofsx - 16.0f*aspect;
477         x2f= x1f + fontw + 16.0f*aspect;
478         y2f= but->y1 + ofsy - 15.0f*aspect;
479         y1f= y2f - fonth*aspect - 15.0f*aspect;
480         
481         /* copy to int, gets projected if possible too */
482         x1= x1f; y1= y1f; x2= x2f; y2= y2f; 
483         
484         if(butregion) {
485                 /* XXX temp, region v2ds can be empty still */
486                 if(butregion->v2d.cur.xmin != butregion->v2d.cur.xmax) {
487                         UI_view2d_to_region_no_clip(&butregion->v2d, x1f, y1f, &x1, &y1);
488                         UI_view2d_to_region_no_clip(&butregion->v2d, x2f, y2f, &x2, &y2);
489                 }
490
491                 x1 += butregion->winrct.xmin;
492                 x2 += butregion->winrct.xmin;
493                 y1 += butregion->winrct.ymin;
494                 y2 += butregion->winrct.ymin;
495         }
496
497         wm_window_get_size(CTX_wm_window(C), &winx, &winy);
498
499         if(x2 > winx) {
500                 /* super size */
501                 if(x2 > winx + x1) {
502                         x2= winx;
503                         x1= 0;
504                 }
505                 else {
506                         x1 -= x2-winx;
507                         x2= winx;
508                 }
509         }
510         if(y1 < 0) {
511                 y1 += 56;
512                 y2 += 56;
513         }
514
515         /* widget rect, in region coords */
516         data->bbox.xmin= MENU_SHADOW_SIDE;
517         data->bbox.xmax= x2-x1 + MENU_SHADOW_SIDE;
518         data->bbox.ymin= MENU_SHADOW_BOTTOM;
519         data->bbox.ymax= y2-y1 + MENU_SHADOW_BOTTOM;
520         
521         /* region bigger for shadow */
522         ar->winrct.xmin= x1 - MENU_SHADOW_SIDE;
523         ar->winrct.xmax= x2 + MENU_SHADOW_SIDE;
524         ar->winrct.ymin= y1 - MENU_SHADOW_BOTTOM;
525         ar->winrct.ymax= y2 + MENU_TOP;
526
527         /* adds subwindow */
528         ED_region_init(C, ar);
529         
530         /* notify change and redraw */
531         ED_region_tag_redraw(ar);
532
533         return ar;
534 }
535
536 void ui_tooltip_free(bContext *C, ARegion *ar)
537 {
538         ui_remove_temporary_region(C, CTX_wm_screen(C), ar);
539 }
540
541
542 /************************* Creating Search Box **********************/
543
544 struct uiSearchItems {
545         int maxitem, totitem, maxstrlen;
546         
547         int offset, offset_i; /* offset for inserting in array */
548         int more;  /* flag indicating there are more items */
549         
550         char **names;
551         void **pointers;
552         int *icons;
553
554         AutoComplete *autocpl;
555         void *active;
556 };
557
558 typedef struct uiSearchboxData {
559         rcti bbox;
560         uiFontStyle fstyle;
561         uiSearchItems items;
562         int active;             /* index in items array */
563         int noback;             /* when menu opened with enough space for this */
564         int preview;    /* draw thumbnail previews, rather than list */
565         int prv_rows, prv_cols;
566 } uiSearchboxData;
567
568 #define SEARCH_ITEMS    10
569
570 /* exported for use by search callbacks */
571 /* returns zero if nothing to add */
572 int uiSearchItemAdd(uiSearchItems *items, const char *name, void *poin, int iconid)
573 {
574         /* hijack for autocomplete */
575         if(items->autocpl) {
576                 autocomplete_do_name(items->autocpl, name);
577                 return 1;
578         }
579         
580         /* hijack for finding active item */
581         if(items->active) {
582                 if(poin==items->active)
583                         items->offset_i= items->totitem;
584                 items->totitem++;
585                 return 1;
586         }
587         
588         if(items->totitem>=items->maxitem) {
589                 items->more= 1;
590                 return 0;
591         }
592         
593         /* skip first items in list */
594         if(items->offset_i > 0) {
595                 items->offset_i--;
596                 return 1;
597         }
598         
599         BLI_strncpy(items->names[items->totitem], name, items->maxstrlen);
600         items->pointers[items->totitem]= poin;
601         items->icons[items->totitem]= iconid;
602         
603         items->totitem++;
604         
605         return 1;
606 }
607
608 int uiSearchBoxhHeight(void)
609 {
610         return SEARCH_ITEMS*MENU_BUTTON_HEIGHT + 2*MENU_TOP;
611 }
612
613 /* ar is the search box itself */
614 static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step)
615 {
616         uiSearchboxData *data= ar->regiondata;
617         
618         /* apply step */
619         data->active+= step;
620         
621         if(data->items.totitem==0)
622                 data->active= 0;
623         else if(data->active > data->items.totitem) {
624                 if(data->items.more) {
625                         data->items.offset++;
626                         data->active= data->items.totitem;
627                         ui_searchbox_update(C, ar, but, 0);
628                 }
629                 else
630                         data->active= data->items.totitem;
631         }
632         else if(data->active < 1) {
633                 if(data->items.offset) {
634                         data->items.offset--;
635                         data->active= 1;
636                         ui_searchbox_update(C, ar, but, 0);
637                 }
638                 else if(data->active < 0)
639                         data->active= 0;
640         }
641         
642         ED_region_tag_redraw(ar);
643 }
644
645 static void ui_searchbox_butrect(rcti *rect, uiSearchboxData *data, int itemnr)
646 {
647         /* thumbnail preview */
648         if (data->preview) {
649                 int buth = (data->bbox.ymax - data->bbox.ymin - 2*MENU_TOP) / data->prv_rows;
650                 int butw = (data->bbox.xmax - data->bbox.xmin) / data->prv_cols;
651                 int row, col;
652                 
653                 *rect= data->bbox;
654                 
655                 col = itemnr % data->prv_cols;
656                 row = itemnr / data->prv_cols;
657                 
658                 rect->xmin += col * butw;
659                 rect->xmax = rect->xmin + butw;
660                 
661                 rect->ymax = data->bbox.ymax - (row * buth);
662                 rect->ymin = rect->ymax - buth;
663         }
664         /* list view */
665         else {
666                 int buth= (data->bbox.ymax-data->bbox.ymin - 2*MENU_TOP)/SEARCH_ITEMS;
667                 
668                 *rect= data->bbox;
669                 rect->xmin= data->bbox.xmin + 3.0f;
670                 rect->xmax= data->bbox.xmax - 3.0f;
671                 
672                 rect->ymax= data->bbox.ymax - MENU_TOP - itemnr*buth;
673                 rect->ymin= rect->ymax - buth;
674         }
675         
676 }
677
678 /* x and y in screencoords */
679 int ui_searchbox_inside(ARegion *ar, int x, int y)
680 {
681         uiSearchboxData *data= ar->regiondata;
682         
683         return(BLI_in_rcti(&data->bbox, x-ar->winrct.xmin, y-ar->winrct.ymin));
684 }
685
686 /* string validated to be of correct length (but->hardmax) */
687 void ui_searchbox_apply(uiBut *but, ARegion *ar)
688 {
689         uiSearchboxData *data= ar->regiondata;
690
691         but->func_arg2= NULL;
692         
693         if(data->active) {
694                 char *name= data->items.names[data->active-1];
695                 char *cpoin= strchr(name, '|');
696                 
697                 if(cpoin) cpoin[0]= 0;
698                 BLI_strncpy(but->editstr, name, data->items.maxstrlen);
699                 if(cpoin) cpoin[0]= '|';
700                 
701                 but->func_arg2= data->items.pointers[data->active-1];
702         }
703 }
704
705 void ui_searchbox_event(bContext *C, ARegion *ar, uiBut *but, wmEvent *event)
706 {
707         uiSearchboxData *data= ar->regiondata;
708         
709         switch(event->type) {
710                 case WHEELUPMOUSE:
711                 case UPARROWKEY:
712                         ui_searchbox_select(C, ar, but, -1);
713                         break;
714                 case WHEELDOWNMOUSE:
715                 case DOWNARROWKEY:
716                         ui_searchbox_select(C, ar, but, 1);
717                         break;
718                 case MOUSEMOVE:
719                         if(BLI_in_rcti(&ar->winrct, event->x, event->y)) {
720                                 rcti rect;
721                                 int a;
722                                 
723                                 for(a=0; a<data->items.totitem; a++) {
724                                         ui_searchbox_butrect(&rect, data, a);
725                                         if(BLI_in_rcti(&rect, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin)) {
726                                                 if( data->active!= a+1) {
727                                                         data->active= a+1;
728                                                         ui_searchbox_select(C, ar, but, 0);
729                                                         break;
730                                                 }
731                                         }
732                                 }
733                         }
734                         break;
735         }
736 }
737
738 /* ar is the search box itself */
739 void ui_searchbox_update(bContext *C, ARegion *ar, uiBut *but, int reset)
740 {
741         uiSearchboxData *data= ar->regiondata;
742         
743         /* reset vars */
744         data->items.totitem= 0;
745         data->items.more= 0;
746         if(reset==0) {
747                 data->items.offset_i= data->items.offset;
748         }
749         else {
750                 data->items.offset_i= data->items.offset= 0;
751                 data->active= 0;
752                 
753                 /* handle active */
754                 if(but->search_func && but->func_arg2) {
755                         data->items.active= but->func_arg2;
756                         but->search_func(C, but->search_arg, but->editstr, &data->items);
757                         data->items.active= NULL;
758                         
759                         /* found active item, calculate real offset by centering it */
760                         if(data->items.totitem) {
761                                 /* first case, begin of list */
762                                 if(data->items.offset_i < data->items.maxitem) {
763                                         data->active= data->items.offset_i+1;
764                                         data->items.offset_i= 0;
765                                 }
766                                 else {
767                                         /* second case, end of list */
768                                         if(data->items.totitem - data->items.offset_i <= data->items.maxitem) {
769                                                 data->active= 1 + data->items.offset_i - data->items.totitem + data->items.maxitem;
770                                                 data->items.offset_i= data->items.totitem - data->items.maxitem;
771                                         }
772                                         else {
773                                                 /* center active item */
774                                                 data->items.offset_i -= data->items.maxitem/2;
775                                                 data->active= 1 + data->items.maxitem/2;
776                                         }
777                                 }
778                         }
779                         data->items.offset= data->items.offset_i;
780                         data->items.totitem= 0;
781                 }
782         }
783         
784         /* callback */
785         if(but->search_func)
786                 but->search_func(C, but->search_arg, but->editstr, &data->items);
787         
788         /* handle case where editstr is equal to one of items */
789         if(reset && data->active==0) {
790                 int a;
791                 
792                 for(a=0; a<data->items.totitem; a++) {
793                         char *cpoin= strchr(data->items.names[a], '|');
794                         
795                         if(cpoin) cpoin[0]= 0;
796                         if(0==strcmp(but->editstr, data->items.names[a]))
797                                 data->active= a+1;
798                         if(cpoin) cpoin[0]= '|';
799                 }
800                 if(data->items.totitem==1 && but->editstr[0])
801                         data->active= 1;
802         }
803
804         /* validate selected item */
805         ui_searchbox_select(C, ar, but, 0);
806         
807         ED_region_tag_redraw(ar);
808 }
809
810 void ui_searchbox_autocomplete(bContext *C, ARegion *ar, uiBut *but, char *str)
811 {
812         uiSearchboxData *data= ar->regiondata;
813
814         if(str[0]) {
815                 data->items.autocpl= autocomplete_begin(str, ui_get_but_string_max_length(but));
816
817                 but->search_func(C, but->search_arg, but->editstr, &data->items);
818
819                 autocomplete_end(data->items.autocpl, str);
820                 data->items.autocpl= NULL;
821         }
822 }
823
824 static void ui_searchbox_region_draw(const bContext *C, ARegion *ar)
825 {
826         uiSearchboxData *data= ar->regiondata;
827         
828         /* pixel space */
829         wmOrtho2(-0.01f, ar->winx-0.01f, -0.01f, ar->winy-0.01f);
830
831         if(!data->noback)
832                 ui_draw_search_back(U.uistyles.first, NULL, &data->bbox);
833         
834         /* draw text */
835         if(data->items.totitem) {
836                 rcti rect;
837                 int a;
838                 
839                 if (data->preview) {
840                         /* draw items */
841                         for(a=0; a<data->items.totitem; a++) {
842                                 ui_searchbox_butrect(&rect, data, a);
843                                 
844                                 /* widget itself */
845                                 if (data->preview)
846                                         ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0);
847                                 else 
848                                         ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0);
849                         }
850                         
851                         /* indicate more */
852                         if(data->items.more) {
853                                 ui_searchbox_butrect(&rect, data, data->items.maxitem-1);
854                                 glEnable(GL_BLEND);
855                                 UI_icon_draw(rect.xmax-18, rect.ymin-7, ICON_TRIA_DOWN);
856                                 glDisable(GL_BLEND);
857                         }
858                         if(data->items.offset) {
859                                 ui_searchbox_butrect(&rect, data, 0);
860                                 glEnable(GL_BLEND);
861                                 UI_icon_draw(rect.xmin, rect.ymax-9, ICON_TRIA_UP);
862                                 glDisable(GL_BLEND);
863                         }
864                         
865                 } else {
866                         /* draw items */
867                         for(a=0; a<data->items.totitem; a++) {
868                                 ui_searchbox_butrect(&rect, data, a);
869                                 
870                                 /* widget itself */
871                                 ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0);
872                                 
873                         }
874                         /* indicate more */
875                         if(data->items.more) {
876                                 ui_searchbox_butrect(&rect, data, data->items.maxitem-1);
877                                 glEnable(GL_BLEND);
878                                 UI_icon_draw((rect.xmax-rect.xmin)/2, rect.ymin-9, ICON_TRIA_DOWN);
879                                 glDisable(GL_BLEND);
880                         }
881                         if(data->items.offset) {
882                                 ui_searchbox_butrect(&rect, data, 0);
883                                 glEnable(GL_BLEND);
884                                 UI_icon_draw((rect.xmax-rect.xmin)/2, rect.ymax-7, ICON_TRIA_UP);
885                                 glDisable(GL_BLEND);
886                         }
887                 }
888         }
889 }
890
891 static void ui_searchbox_region_free(ARegion *ar)
892 {
893         uiSearchboxData *data= ar->regiondata;
894         int a;
895
896         /* free search data */
897         for(a=0; a<data->items.maxitem; a++)
898                 MEM_freeN(data->items.names[a]);
899         MEM_freeN(data->items.names);
900         MEM_freeN(data->items.pointers);
901         MEM_freeN(data->items.icons);
902         
903         MEM_freeN(data);
904         ar->regiondata= NULL;
905 }
906
907 static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, uiBlock *block);
908
909 ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
910 {
911         uiStyle *style= U.uistyles.first;       // XXX pass on as arg
912         static ARegionType type;
913         ARegion *ar;
914         uiSearchboxData *data;
915         float aspect= but->block->aspect;
916         float x1f, x2f, y1f, y2f;
917         int x1, x2, y1, y2, winx, winy, ofsx, ofsy;
918         
919         /* create area region */
920         ar= ui_add_temporary_region(CTX_wm_screen(C));
921         
922         memset(&type, 0, sizeof(ARegionType));
923         type.draw= ui_searchbox_region_draw;
924         type.free= ui_searchbox_region_free;
925         ar->type= &type;
926         
927         /* create searchbox data */
928         data= MEM_callocN(sizeof(uiSearchboxData), "uiSearchboxData");
929
930         /* set font, get bb */
931         data->fstyle= style->widget; /* copy struct */
932         data->fstyle.align= UI_STYLE_TEXT_CENTER;
933         ui_fontscale(&data->fstyle.points, aspect);
934         uiStyleFontSet(&data->fstyle);
935         
936         ar->regiondata= data;
937         
938         /* special case, hardcoded feature, not draw backdrop when called from menus,
939            assume for design that popup already added it */
940         if(but->block->flag & UI_BLOCK_LOOP)
941                 data->noback= 1;
942         
943         if (but->a1 > 0 && but->a2 > 0) {
944                 data->preview = 1;
945                 data->prv_rows = but->a1;
946                 data->prv_cols = but->a2;
947         }
948         
949         /* compute position */
950         if(but->block->flag & UI_BLOCK_LOOP) {
951                 /* this case is search menu inside other menu */
952                 /* we copy region size */
953
954                 ar->winrct= butregion->winrct;
955                 
956                 /* widget rect, in region coords */
957                 data->bbox.xmin= MENU_SHADOW_SIDE;
958                 data->bbox.xmax= (ar->winrct.xmax-ar->winrct.xmin) - MENU_SHADOW_SIDE;
959                 data->bbox.ymin= MENU_SHADOW_BOTTOM;
960                 data->bbox.ymax= (ar->winrct.ymax-ar->winrct.ymin) - MENU_SHADOW_BOTTOM;
961                 
962                 /* check if button is lower half */
963                 if( but->y2 < (but->block->minx+but->block->maxx)/2 ) {
964                         data->bbox.ymin += (but->y2-but->y1);
965                 }
966                 else {
967                         data->bbox.ymax -= (but->y2-but->y1);
968                 }
969         }
970         else {
971                 x1f= but->x1 - 5;       /* align text with button */
972                 x2f= but->x2 + 5;       /* symmetrical */
973                 y2f= but->y1;
974                 y1f= y2f - uiSearchBoxhHeight();
975
976                 ofsx= (but->block->panel)? but->block->panel->ofsx: 0;
977                 ofsy= (but->block->panel)? but->block->panel->ofsy: 0;
978
979                 x1f += ofsx;
980                 x2f += ofsx;
981                 y1f += ofsy;
982                 y2f += ofsy;
983         
984                 /* minimal width */
985                 if(x2f - x1f < 150) x2f= x1f+150; // XXX arbitrary
986                 
987                 /* copy to int, gets projected if possible too */
988                 x1= x1f; y1= y1f; x2= x2f; y2= y2f; 
989                 
990                 if(butregion) {
991                         if(butregion->v2d.cur.xmin != butregion->v2d.cur.xmax) {
992                                 UI_view2d_to_region_no_clip(&butregion->v2d, x1f, y1f, &x1, &y1);
993                                 UI_view2d_to_region_no_clip(&butregion->v2d, x2f, y2f, &x2, &y2);
994                         }
995                         
996                         x1 += butregion->winrct.xmin;
997                         x2 += butregion->winrct.xmin;
998                         y1 += butregion->winrct.ymin;
999                         y2 += butregion->winrct.ymin;
1000                 }
1001                 
1002                 wm_window_get_size(CTX_wm_window(C), &winx, &winy);
1003                 
1004                 if(x2 > winx) {
1005                         /* super size */
1006                         if(x2 > winx + x1) {
1007                                 x2= winx;
1008                                 x1= 0;
1009                         }
1010                         else {
1011                                 x1 -= x2-winx;
1012                                 x2= winx;
1013                         }
1014                 }
1015                 if(y1 < 0) {
1016                         int newy1;
1017                         UI_view2d_to_region_no_clip(&butregion->v2d, 0, but->y2 + ofsy, 0, &newy1);
1018                         newy1 += butregion->winrct.ymin;
1019
1020                         y2= y2-y1 + newy1;
1021                         y1= newy1;
1022                 }
1023
1024                 /* widget rect, in region coords */
1025                 data->bbox.xmin= MENU_SHADOW_SIDE;
1026                 data->bbox.xmax= x2-x1 + MENU_SHADOW_SIDE;
1027                 data->bbox.ymin= MENU_SHADOW_BOTTOM;
1028                 data->bbox.ymax= y2-y1 + MENU_SHADOW_BOTTOM;
1029                 
1030                 /* region bigger for shadow */
1031                 ar->winrct.xmin= x1 - MENU_SHADOW_SIDE;
1032                 ar->winrct.xmax= x2 + MENU_SHADOW_SIDE;
1033                 ar->winrct.ymin= y1 - MENU_SHADOW_BOTTOM;
1034                 ar->winrct.ymax= y2;
1035         }
1036         
1037         /* adds subwindow */
1038         ED_region_init(C, ar);
1039         
1040         /* notify change and redraw */
1041         ED_region_tag_redraw(ar);
1042         
1043         /* prepare search data */
1044         if (data->preview) {
1045                 data->items.maxitem= data->prv_rows * data->prv_cols;
1046         } else {
1047                 data->items.maxitem= SEARCH_ITEMS;
1048         }
1049         data->items.maxstrlen= but->hardmax;
1050         data->items.totitem= 0;
1051         data->items.names= MEM_callocN(data->items.maxitem*sizeof(void *), "search names");
1052         data->items.pointers= MEM_callocN(data->items.maxitem*sizeof(void *), "search pointers");
1053         data->items.icons= MEM_callocN(data->items.maxitem*sizeof(int), "search icons");
1054         for(x1=0; x1<data->items.maxitem; x1++)
1055                 data->items.names[x1]= MEM_callocN(but->hardmax+1, "search pointers");
1056         
1057         return ar;
1058 }
1059
1060 void ui_searchbox_free(bContext *C, ARegion *ar)
1061 {
1062         ui_remove_temporary_region(C, CTX_wm_screen(C), ar);
1063 }
1064
1065
1066 /************************* Creating Menu Blocks **********************/
1067
1068 /* position block relative to but, result is in window space */
1069 static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, uiBlock *block)
1070 {
1071         uiBut *bt;
1072         uiSafetyRct *saferct;
1073         rctf butrct;
1074         float aspect;
1075         int xsize, ysize, xof=0, yof=0, center;
1076         short dir1= 0, dir2=0;
1077         
1078         /* transform to window coordinates, using the source button region/block */
1079         butrct.xmin= but->x1; butrct.xmax= but->x2;
1080         butrct.ymin= but->y1; butrct.ymax= but->y2;
1081
1082         ui_block_to_window_fl(butregion, but->block, &butrct.xmin, &butrct.ymin);
1083         ui_block_to_window_fl(butregion, but->block, &butrct.xmax, &butrct.ymax);
1084
1085         /* calc block rect */
1086         if(block->minx == 0.0f && block->maxx == 0.0f) {
1087                 if(block->buttons.first) {
1088                         block->minx= block->miny= 10000;
1089                         block->maxx= block->maxy= -10000;
1090                         
1091                         bt= block->buttons.first;
1092                         while(bt) {
1093                                 if(bt->x1 < block->minx) block->minx= bt->x1;
1094                                 if(bt->y1 < block->miny) block->miny= bt->y1;
1095
1096                                 if(bt->x2 > block->maxx) block->maxx= bt->x2;
1097                                 if(bt->y2 > block->maxy) block->maxy= bt->y2;
1098                                 
1099                                 bt= bt->next;
1100                         }
1101                 }
1102                 else {
1103                         /* we're nice and allow empty blocks too */
1104                         block->minx= block->miny= 0;
1105                         block->maxx= block->maxy= 20;
1106                 }
1107         }
1108         
1109         aspect= (float)(block->maxx - block->minx + 4);
1110         ui_block_to_window_fl(butregion, but->block, &block->minx, &block->miny);
1111         ui_block_to_window_fl(butregion, but->block, &block->maxx, &block->maxy);
1112
1113         //block->minx-= 2.0; block->miny-= 2.0;
1114         //block->maxx+= 2.0; block->maxy+= 2.0;
1115         
1116         xsize= block->maxx - block->minx+4; // 4 for shadow
1117         ysize= block->maxy - block->miny+4;
1118         aspect/= (float)xsize;
1119
1120         if(but) {
1121                 int left=0, right=0, top=0, down=0;
1122                 int winx, winy;
1123
1124                 wm_window_get_size(window, &winx, &winy);
1125
1126                 if(block->direction & UI_CENTER) center= ysize/2;
1127                 else center= 0;
1128
1129                 if( butrct.xmin-xsize > 0.0) left= 1;
1130                 if( butrct.xmax+xsize < winx) right= 1;
1131                 if( butrct.ymin-ysize+center > 0.0) down= 1;
1132                 if( butrct.ymax+ysize-center < winy) top= 1;
1133                 
1134                 dir1= block->direction & UI_DIRECTION;
1135
1136                 /* secundary directions */
1137                 if(dir1 & (UI_TOP|UI_DOWN)) {
1138                         if(dir1 & UI_LEFT) dir2= UI_LEFT;
1139                         else if(dir1 & UI_RIGHT) dir2= UI_RIGHT;
1140                         dir1 &= (UI_TOP|UI_DOWN);
1141                 }
1142
1143                 if(dir2==0) if(dir1==UI_LEFT || dir1==UI_RIGHT) dir2= UI_DOWN;
1144                 if(dir2==0) if(dir1==UI_TOP || dir1==UI_DOWN) dir2= UI_LEFT;
1145                 
1146                 /* no space at all? dont change */
1147                 if(left || right) {
1148                         if(dir1==UI_LEFT && left==0) dir1= UI_RIGHT;
1149                         if(dir1==UI_RIGHT && right==0) dir1= UI_LEFT;
1150                         /* this is aligning, not append! */
1151                         if(dir2==UI_LEFT && right==0) dir2= UI_RIGHT;
1152                         if(dir2==UI_RIGHT && left==0) dir2= UI_LEFT;
1153                 }
1154                 if(down || top) {
1155                         if(dir1==UI_TOP && top==0) dir1= UI_DOWN;
1156                         if(dir1==UI_DOWN && down==0) dir1= UI_TOP;
1157                         if(dir2==UI_TOP && top==0) dir2= UI_DOWN;
1158                         if(dir2==UI_DOWN && down==0) dir2= UI_TOP;
1159                 }
1160                 
1161                 if(dir1==UI_LEFT) {
1162                         xof= butrct.xmin - block->maxx;
1163                         if(dir2==UI_TOP) yof= butrct.ymin - block->miny-center;
1164                         else yof= butrct.ymax - block->maxy+center;
1165                 }
1166                 else if(dir1==UI_RIGHT) {
1167                         xof= butrct.xmax - block->minx;
1168                         if(dir2==UI_TOP) yof= butrct.ymin - block->miny-center;
1169                         else yof= butrct.ymax - block->maxy+center;
1170                 }
1171                 else if(dir1==UI_TOP) {
1172                         yof= butrct.ymax - block->miny;
1173                         if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
1174                         else xof= butrct.xmin - block->minx;
1175                         // changed direction? 
1176                         if((dir1 & block->direction)==0) {
1177                                 if(block->direction & UI_SHIFT_FLIPPED)
1178                                         xof+= dir2==UI_LEFT?25:-25;
1179                                 uiBlockFlipOrder(block);
1180                         }
1181                 }
1182                 else if(dir1==UI_DOWN) {
1183                         yof= butrct.ymin - block->maxy;
1184                         if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
1185                         else xof= butrct.xmin - block->minx;
1186                         // changed direction?
1187                         if((dir1 & block->direction)==0) {
1188                                 if(block->direction & UI_SHIFT_FLIPPED)
1189                                         xof+= dir2==UI_LEFT?25:-25;
1190                                 uiBlockFlipOrder(block);
1191                         }
1192                 }
1193
1194                 /* and now we handle the exception; no space below or to top */
1195                 if(top==0 && down==0) {
1196                         if(dir1==UI_LEFT || dir1==UI_RIGHT) {
1197                                 // align with bottom of screen 
1198                                 yof= ysize;
1199                         }
1200                 }
1201                 
1202                 /* or no space left or right */
1203                 if(left==0 && right==0) {
1204                         if(dir1==UI_TOP || dir1==UI_DOWN) {
1205                                 // align with left size of screen 
1206                                 xof= -block->minx+5;
1207                         }
1208                 }
1209                 
1210                 // apply requested offset in the block
1211                 xof += block->xofs/block->aspect;
1212                 yof += block->yofs/block->aspect;
1213         }
1214         
1215         /* apply */
1216         
1217         for(bt= block->buttons.first; bt; bt= bt->next) {
1218                 ui_block_to_window_fl(butregion, but->block, &bt->x1, &bt->y1);
1219                 ui_block_to_window_fl(butregion, but->block, &bt->x2, &bt->y2);
1220
1221                 bt->x1 += xof;
1222                 bt->x2 += xof;
1223                 bt->y1 += yof;
1224                 bt->y2 += yof;
1225
1226                 bt->aspect= 1.0;
1227                 // ui_check_but recalculates drawstring size in pixels
1228                 ui_check_but(bt);
1229         }
1230         
1231         block->minx += xof;
1232         block->miny += yof;
1233         block->maxx += xof;
1234         block->maxy += yof;
1235
1236         /* safety calculus */
1237         if(but) {
1238                 float midx= (butrct.xmin+butrct.xmax)/2.0;
1239                 float midy= (butrct.ymin+butrct.ymax)/2.0;
1240                 
1241                 /* when you are outside parent button, safety there should be smaller */
1242                 
1243                 // parent button to left
1244                 if( midx < block->minx ) block->safety.xmin= block->minx-3; 
1245                 else block->safety.xmin= block->minx-40;
1246                 // parent button to right
1247                 if( midx > block->maxx ) block->safety.xmax= block->maxx+3; 
1248                 else block->safety.xmax= block->maxx+40;
1249                 
1250                 // parent button on bottom
1251                 if( midy < block->miny ) block->safety.ymin= block->miny-3; 
1252                 else block->safety.ymin= block->miny-40;
1253                 // parent button on top
1254                 if( midy > block->maxy ) block->safety.ymax= block->maxy+3; 
1255                 else block->safety.ymax= block->maxy+40;
1256                 
1257                 // exception for switched pulldowns...
1258                 if(dir1 && (dir1 & block->direction)==0) {
1259                         if(dir2==UI_RIGHT) block->safety.xmax= block->maxx+3; 
1260                         if(dir2==UI_LEFT) block->safety.xmin= block->minx-3; 
1261                 }
1262                 block->direction= dir1;
1263         }
1264         else {
1265                 block->safety.xmin= block->minx-40;
1266                 block->safety.ymin= block->miny-40;
1267                 block->safety.xmax= block->maxx+40;
1268                 block->safety.ymax= block->maxy+40;
1269         }
1270
1271         /* keep a list of these, needed for pulldown menus */
1272         saferct= MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct");
1273         saferct->parent= butrct;
1274         saferct->safety= block->safety;
1275         BLI_freelistN(&block->saferct);
1276         if(but)
1277                 BLI_duplicatelist(&block->saferct, &but->block->saferct);
1278         BLI_addhead(&block->saferct, saferct);
1279 }
1280
1281 static void ui_block_region_draw(const bContext *C, ARegion *ar)
1282 {
1283         uiBlock *block;
1284
1285         for(block=ar->uiblocks.first; block; block=block->next)
1286                 uiDrawBlock(C, block);
1287 }
1288
1289 uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut *but, uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func, void *arg)
1290 {
1291         wmWindow *window= CTX_wm_window(C);
1292         static ARegionType type;
1293         ARegion *ar;
1294         uiBlock *block;
1295         uiBut *bt;
1296         uiPopupBlockHandle *handle;
1297         uiSafetyRct *saferct;
1298
1299         /* create handle */
1300         handle= MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
1301
1302         /* store context for operator */
1303         handle->ctx_area= CTX_wm_area(C);
1304         handle->ctx_region= CTX_wm_region(C);
1305         
1306         /* create area region */
1307         ar= ui_add_temporary_region(CTX_wm_screen(C));
1308         handle->region= ar;
1309
1310         memset(&type, 0, sizeof(ARegionType));
1311         type.draw= ui_block_region_draw;
1312         ar->type= &type;
1313
1314         UI_add_region_handlers(&ar->handlers);
1315
1316         /* create ui block */
1317         if(create_func)
1318                 block= create_func(C, handle->region, arg);
1319         else
1320                 block= handle_create_func(C, handle, arg);
1321         
1322         if(block->handle) {
1323                 memcpy(block->handle, handle, sizeof(uiPopupBlockHandle));
1324                 MEM_freeN(handle);
1325                 handle= block->handle;
1326         }
1327         else
1328                 block->handle= handle;
1329
1330         ar->regiondata= handle;
1331
1332         if(!block->endblock)
1333                 uiEndBlock(C, block);
1334
1335         /* if this is being created from a button */
1336         if(but) {
1337                 if(ELEM(but->type, BLOCK, PULLDOWN))
1338                         block->xofs = -2;       /* for proper alignment */
1339
1340                 /* only used for automatic toolbox, so can set the shift flag */
1341                 if(but->flag & UI_MAKE_TOP) {
1342                         block->direction= UI_TOP|UI_SHIFT_FLIPPED;
1343                         uiBlockFlipOrder(block);
1344                 }
1345                 if(but->flag & UI_MAKE_DOWN) block->direction= UI_DOWN|UI_SHIFT_FLIPPED;
1346                 if(but->flag & UI_MAKE_LEFT) block->direction |= UI_LEFT;
1347                 if(but->flag & UI_MAKE_RIGHT) block->direction |= UI_RIGHT;
1348
1349                 ui_block_position(window, butregion, but, block);
1350         }
1351         else {
1352                 /* keep a list of these, needed for pulldown menus */
1353                 saferct= MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct");
1354                 saferct->safety= block->safety;
1355                 BLI_addhead(&block->saferct, saferct);
1356                 block->flag |= UI_BLOCK_POPUP|UI_BLOCK_NUMSELECT;
1357         }
1358
1359         /* the block and buttons were positioned in window space as in 2.4x, now
1360          * these menu blocks are regions so we bring it back to region space.
1361          * additionally we add some padding for the menu shadow or rounded menus */
1362         ar->winrct.xmin= block->minx - MENU_SHADOW_SIDE;
1363         ar->winrct.xmax= block->maxx + MENU_SHADOW_SIDE;
1364         ar->winrct.ymin= block->miny - MENU_SHADOW_BOTTOM;
1365         ar->winrct.ymax= block->maxy + MENU_TOP;
1366
1367         block->minx -= ar->winrct.xmin;
1368         block->maxx -= ar->winrct.xmin;
1369         block->miny -= ar->winrct.ymin;
1370         block->maxy -= ar->winrct.ymin;
1371
1372         for(bt= block->buttons.first; bt; bt= bt->next) {
1373                 bt->x1 -= ar->winrct.xmin;
1374                 bt->x2 -= ar->winrct.xmin;
1375                 bt->y1 -= ar->winrct.ymin;
1376                 bt->y2 -= ar->winrct.ymin;
1377         }
1378
1379         block->flag |= UI_BLOCK_LOOP;
1380
1381         /* adds subwindow */
1382         ED_region_init(C, ar);
1383
1384         /* get winmat now that we actually have the subwindow */
1385         wmSubWindowSet(window, ar->swinid);
1386         
1387         wm_subwindow_getmatrix(window, ar->swinid, block->winmat);
1388         
1389         /* notify change and redraw */
1390         ED_region_tag_redraw(ar);
1391
1392         return handle;
1393 }
1394
1395 void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle)
1396 {
1397         ui_remove_temporary_region(C, CTX_wm_screen(C), handle->region);
1398         MEM_freeN(handle);
1399 }
1400
1401 /***************************** Menu Button ***************************/
1402
1403 static void ui_block_func_MENUSTR(bContext *C, uiLayout *layout, void *arg_str)
1404 {
1405         uiBlock *block= uiLayoutGetBlock(layout);
1406         uiPopupBlockHandle *handle= block->handle;
1407         uiLayout *split, *column=NULL;
1408         uiBut *bt;
1409         MenuData *md;
1410         MenuEntry *entry;
1411         char *instr= arg_str;
1412         int columns, rows, a, b;
1413
1414         uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
1415         
1416         /* compute menu data */
1417         md= decompose_menu_string(instr);
1418
1419         /* columns and row estimation */
1420         columns= (md->nitems+20)/20;
1421         if(columns<1)
1422                 columns= 1;
1423         if(columns>8)
1424                 columns= (md->nitems+25)/25;
1425         
1426         rows= md->nitems/columns;
1427         if(rows<1)
1428                 rows= 1;
1429         while(rows*columns<md->nitems)
1430                 rows++;
1431
1432         /* create title */
1433         if(md->title) {
1434                 if(md->titleicon) {
1435                         uiItemL(layout, md->title, md->titleicon);
1436                 }
1437                 else {
1438                         uiItemL(layout, md->title, 0);
1439                         bt= block->buttons.last;
1440                         bt->flag= UI_TEXT_LEFT;
1441                 }
1442         }
1443
1444         /* inconsistent, but menus with labels do not look good flipped */
1445         for(a=0, b=0; a<md->nitems; a++, b++) {
1446                 entry= &md->items[a];
1447
1448                 if(entry->sepr && entry->str[0])
1449                         block->flag |= UI_BLOCK_NO_FLIP;
1450         }
1451
1452         /* create items */
1453         split= uiLayoutSplit(layout, 0, 0);
1454
1455         for(a=0, b=0; a<md->nitems; a++, b++) {
1456                 if(block->flag & UI_BLOCK_NO_FLIP)
1457                         entry= &md->items[a];
1458                 else
1459                         entry= &md->items[md->nitems-a-1];
1460                 
1461                 /* new column on N rows or on separation label */
1462                 if((b % rows == 0) || (entry->sepr && entry->str[0])) {
1463                         column= uiLayoutColumn(split, 0);
1464                         b= 0;
1465                 }
1466
1467                 if(entry->sepr) {
1468                         uiItemL(column, entry->str, entry->icon);
1469                         bt= block->buttons.last;
1470                         bt->flag= UI_TEXT_LEFT;
1471                 }
1472                 else if(entry->icon) {
1473                         uiDefIconTextButF(block, BUTM|FLO, B_NOP, entry->icon, entry->str, 0, 0,
1474                                 UI_UNIT_X*5, UI_UNIT_Y, &handle->retvalue, (float) entry->retval, 0.0, 0, 0, "");
1475                 }
1476                 else {
1477                         uiDefButF(block, BUTM|FLO, B_NOP, entry->str, 0, 0,
1478                                 UI_UNIT_X*5, UI_UNIT_X, &handle->retvalue, (float) entry->retval, 0.0, 0, 0, "");
1479                 }
1480         }
1481         
1482         menudata_free(md);
1483 }
1484
1485 void ui_block_func_ICONROW(bContext *C, uiLayout *layout, void *arg_but)
1486 {
1487         uiBlock *block= uiLayoutGetBlock(layout);
1488         uiPopupBlockHandle *handle= block->handle;
1489         uiBut *but= arg_but;
1490         int a;
1491         
1492         uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
1493         
1494         for(a=(int)but->hardmin; a<=(int)but->hardmax; a++)
1495                 uiDefIconButF(block, BUTM|FLO, B_NOP, but->icon+(a-but->hardmin), 0, 0, UI_UNIT_X*5, UI_UNIT_Y,
1496                         &handle->retvalue, (float)a, 0.0, 0, 0, "");
1497 }
1498
1499 void ui_block_func_ICONTEXTROW(bContext *C, uiLayout *layout, void *arg_but)
1500 {
1501         uiBlock *block= uiLayoutGetBlock(layout);
1502         uiPopupBlockHandle *handle= block->handle;
1503         uiBut *but= arg_but, *bt;
1504         MenuData *md;
1505         MenuEntry *entry;
1506         int a;
1507         
1508         uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
1509
1510         md= decompose_menu_string(but->str);
1511
1512         /* title */
1513         if(md->title) {
1514                 bt= uiDefBut(block, LABEL, 0, md->title, 0, 0, UI_UNIT_X*5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1515                 bt->flag= UI_TEXT_LEFT;
1516         }
1517
1518         /* loop through the menu options and draw them out with icons & text labels */
1519         for(a=0; a<md->nitems; a++) {
1520                 entry= &md->items[md->nitems-a-1];
1521
1522                 if(entry->sepr)
1523                         uiItemS(layout);
1524                 else
1525                         uiDefIconTextButF(block, BUTM|FLO, B_NOP, (short)((but->icon)+(entry->retval-but->hardmin)), entry->str,
1526                                 0, 0, UI_UNIT_X*5, UI_UNIT_Y, &handle->retvalue, (float) entry->retval, 0.0, 0, 0, "");
1527         }
1528
1529         menudata_free(md);
1530 }
1531
1532 #if 0
1533 static void ui_warp_pointer(short x, short y)
1534 {
1535         /* XXX 2.50 which function to use for this? */
1536         /* OSX has very poor mousewarp support, it sends events;
1537            this causes a menu being pressed immediately ... */
1538         #ifndef __APPLE__
1539         warp_pointer(x, y);
1540         #endif
1541 }
1542 #endif
1543
1544 /********************* Color Button ****************/
1545
1546 /* picker sizes S hsize, F full size, D spacer, B button/pallette height  */
1547 #define SPICK   110.0
1548 #define FPICK   180.0
1549 #define DPICK   6.0
1550 #define BPICK   24.0
1551
1552 /* for picker, while editing hsv */
1553 void ui_set_but_hsv(uiBut *but)
1554 {
1555         float col[3];
1556         
1557         hsv_to_rgb(but->hsv[0], but->hsv[1], but->hsv[2], col, col+1, col+2);
1558         ui_set_but_vectorf(but, col);
1559 }
1560
1561 /* also used by small picker, be careful with name checks below... */
1562 void ui_update_block_buts_rgb(uiBlock *block, float *rgb)
1563 {
1564         uiBut *bt;
1565         float hsv[3];
1566         
1567         rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
1568         
1569         // this updates button strings, is hackish... but button pointers are on stack of caller function
1570         for(bt= block->buttons.first; bt; bt= bt->next) {
1571                 if (bt->rnaprop) {
1572                         
1573                         ui_set_but_vectorf(bt, rgb);
1574                         
1575                 }
1576                 else if(strcmp(bt->str, "Hex: ")==0) {
1577                         float rgb_gamma[3];
1578                         double intpart;
1579                         char col[16];
1580                         
1581                         /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */
1582                         
1583                         if (block->color_profile == BLI_PR_NONE) {
1584                                 copy_v3_v3(rgb_gamma, rgb);
1585                         } else {
1586                                 /* make an sRGB version, for Hex code */
1587                                 linearrgb_to_srgb_v3_v3(rgb_gamma, rgb);
1588                         }
1589                         
1590                         if (rgb_gamma[0] > 1.0f) rgb_gamma[0] = modf(rgb_gamma[0], &intpart);
1591                         if (rgb_gamma[1] > 1.0f) rgb_gamma[1] = modf(rgb_gamma[1], &intpart);
1592                         if (rgb_gamma[2] > 1.0f) rgb_gamma[2] = modf(rgb_gamma[2], &intpart);
1593
1594                         sprintf(col, "%02X%02X%02X", (unsigned int)(rgb_gamma[0]*255.0), (unsigned int)(rgb_gamma[1]*255.0), (unsigned int)(rgb_gamma[2]*255.0));
1595                         
1596                         strcpy(bt->poin, col);
1597                 }
1598                 else if(bt->str[1]==' ') {
1599                         if(bt->str[0]=='R') {
1600                                 ui_set_but_val(bt, rgb[0]);
1601                         }
1602                         else if(bt->str[0]=='G') {
1603                                 ui_set_but_val(bt, rgb[1]);
1604                         }
1605                         else if(bt->str[0]=='B') {
1606                                 ui_set_but_val(bt, rgb[2]);
1607                         }
1608                         else if(bt->str[0]=='H') {
1609                                 ui_set_but_val(bt, hsv[0]);
1610                         }
1611                         else if(bt->str[0]=='S') {
1612                                 ui_set_but_val(bt, hsv[1]);
1613                         }
1614                         else if(bt->str[0]=='V') {
1615                                 ui_set_but_val(bt, hsv[2]);
1616                         }
1617                 }               
1618
1619                 ui_check_but(bt);
1620         }
1621 }
1622
1623 static void do_picker_rna_cb(bContext *C, void *bt1, void *unused)
1624 {
1625         uiBut *but= (uiBut *)bt1;
1626         uiPopupBlockHandle *popup= but->block->handle;
1627         PropertyRNA *prop = but->rnaprop;
1628         PointerRNA ptr = but->rnapoin;
1629         float rgb[4];
1630         
1631         if (prop) {
1632                 RNA_property_float_get_array(&ptr, prop, rgb);
1633                 ui_update_block_buts_rgb(but->block, rgb);
1634         }
1635         
1636         if(popup)
1637                 popup->menuretval= UI_RETURN_UPDATE;
1638 }
1639
1640 static void do_hsv_rna_cb(bContext *C, void *bt1, void *hsv_arg)
1641 {
1642         uiBut *but= (uiBut *)bt1;
1643         uiPopupBlockHandle *popup= but->block->handle;
1644         float *hsv = (float *)hsv_arg;
1645         float rgb[3];
1646         
1647         hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2);
1648         
1649         ui_update_block_buts_rgb(but->block, rgb);
1650         
1651         if(popup)
1652                 popup->menuretval= UI_RETURN_UPDATE;
1653 }
1654
1655 static void do_hex_rna_cb(bContext *C, void *bt1, void *hexcl)
1656 {
1657         uiBut *but= (uiBut *)bt1;
1658         uiPopupBlockHandle *popup= but->block->handle;
1659         char *hexcol= (char *)hexcl;
1660         float rgb[3];
1661         
1662         hex_to_rgb(hexcol, rgb, rgb+1, rgb+2);
1663         
1664         /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */
1665         if (but->block->color_profile != BLI_PR_NONE) {
1666                 /* so we need to linearise it for Blender */
1667                 srgb_to_linearrgb_v3_v3(rgb, rgb);
1668         }
1669         
1670         ui_update_block_buts_rgb(but->block, rgb);
1671         
1672         if(popup)
1673                 popup->menuretval= UI_RETURN_UPDATE;
1674 }
1675
1676 static void close_popup_cb(bContext *C, void *bt1, void *arg)
1677 {
1678         uiBut *but= (uiBut *)bt1;
1679         uiPopupBlockHandle *popup= but->block->handle;
1680         
1681         if(popup)
1682                 popup->menuretval= UI_RETURN_OK;
1683 }
1684
1685 static void picker_new_hide_reveal(uiBlock *block, short colormode)
1686 {
1687         uiBut *bt;
1688         
1689         /* tag buttons */
1690         for(bt= block->buttons.first; bt; bt= bt->next) {
1691                 
1692                 if (bt->type == LABEL) {
1693                         if( bt->str[1]=='G') {
1694                                 if(colormode==2) bt->flag &= ~UI_HIDDEN;
1695                                 else bt->flag |= UI_HIDDEN;
1696                         }
1697                 }
1698                 
1699                 if(bt->type==NUMSLI || bt->type==TEX) {
1700                         if( bt->str[1]=='e') {
1701                                 if(colormode==2) bt->flag &= ~UI_HIDDEN;
1702                                 else bt->flag |= UI_HIDDEN;
1703                         }
1704                         else if( ELEM3(bt->str[0], 'R', 'G', 'B')) {
1705                                 if(colormode==0) bt->flag &= ~UI_HIDDEN;
1706                                 else bt->flag |= UI_HIDDEN;
1707                         }
1708                         else if( ELEM3(bt->str[0], 'H', 'S', 'V')) {
1709                                 if(colormode==1) bt->flag &= ~UI_HIDDEN;
1710                                 else bt->flag |= UI_HIDDEN;
1711                         }
1712                 }
1713         }
1714 }
1715
1716 static void do_picker_new_mode_cb(bContext *C, void *bt1, void *colv)
1717 {
1718         uiBut *bt= bt1;
1719         short colormode= ui_get_but_val(bt);
1720         picker_new_hide_reveal(bt->block, colormode);
1721 }
1722
1723 /* picker sizes S hsize, F full size, D spacer, B button/pallette height  */
1724 #define SPICK1  150.0
1725 #define DPICK1  6.0
1726
1727 #define PICKER_H        150
1728 #define PICKER_W        150
1729 #define PICKER_SPACE    6
1730 #define PICKER_BAR              14
1731
1732 #define PICKER_TOTAL_W  (PICKER_W+PICKER_SPACE+PICKER_BAR)
1733
1734 static void circle_picker(uiBlock *block, PointerRNA *ptr, const char *propname)
1735 {
1736         uiBut *bt;
1737         
1738         /* HS circle */
1739         bt= uiDefButR(block, HSVCIRCLE, 0, "",  0, 0, PICKER_H, PICKER_W, ptr, propname, 0, 0.0, 0.0, 0, 0, "");
1740         uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
1741         
1742         /* value */
1743         bt= uiDefButR(block, HSVCUBE, 0, "", PICKER_W+PICKER_SPACE,0,PICKER_BAR,PICKER_H, ptr, propname, 0, 0.0, 0.0, UI_GRAD_V_ALT, 0, "");
1744         uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
1745 }
1746
1747
1748 static void square_picker(uiBlock *block, PointerRNA *ptr, const char *propname, int type)
1749 {
1750         uiBut *bt;
1751         int bartype = type + 3;
1752         
1753         /* HS square */
1754         bt= uiDefButR(block, HSVCUBE, 0, "",    0, PICKER_BAR+PICKER_SPACE, PICKER_TOTAL_W, PICKER_H, ptr, propname, 0, 0.0, 0.0, type, 0, "");
1755         uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
1756         
1757         /* value */
1758         bt= uiDefButR(block, HSVCUBE, 0, "",            0, 0, PICKER_TOTAL_W, PICKER_BAR, ptr, propname, 0, 0.0, 0.0, bartype, 0, "");
1759         uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
1760 }
1761
1762
1763 /* a HS circle, V slider, rgb/hsv/hex sliders */
1764 static void uiBlockPicker(uiBlock *block, float *rgb, PointerRNA *ptr, PropertyRNA *prop)
1765 {
1766         static short colormode= 0;      /* temp? 0=rgb, 1=hsv, 2=hex */
1767         uiBut *bt;
1768         int width, butwidth;
1769         static char tip[50];
1770         static float hsv[3];
1771         static char hexcol[128];
1772         float rgb_gamma[3];
1773         const char *propname = RNA_property_identifier(prop);
1774         
1775         width= PICKER_TOTAL_W;
1776         butwidth = width - UI_UNIT_X - 10;
1777         
1778         /* existence of profile means storage is in linear colour space, with display correction */
1779         if (block->color_profile == BLI_PR_NONE) {
1780                 sprintf(tip, "Value in Display Color Space");
1781                 copy_v3_v3(rgb_gamma, rgb);
1782         } else {
1783                 sprintf(tip, "Value in Linear RGB Color Space");
1784                 /* make an sRGB version, for Hex code */
1785                 linearrgb_to_srgb_v3_v3(rgb_gamma, rgb);
1786         }
1787         
1788         RNA_property_float_get_array(ptr, prop, rgb);
1789         rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
1790
1791         switch (U.color_picker_type) {
1792                 case USER_CP_CIRCLE:
1793                         circle_picker(block, ptr, propname);
1794                         break;
1795                 case USER_CP_SQUARE_SV:
1796                         square_picker(block, ptr, propname, UI_GRAD_SV);
1797                         break;
1798                 case USER_CP_SQUARE_HS:
1799                         square_picker(block, ptr, propname, UI_GRAD_HS);
1800                         break;
1801                 case USER_CP_SQUARE_HV:
1802                         square_picker(block, ptr, propname, UI_GRAD_HV);
1803                         break;
1804         }
1805         
1806         /* mode */
1807         uiBlockBeginAlign(block);
1808         bt= uiDefButS(block, ROW, 0, "RGB",     0, -30, width/3, UI_UNIT_Y, &colormode, 0.0, 0.0, 0, 0, "");
1809         uiButSetFunc(bt, do_picker_new_mode_cb, bt, rgb);
1810         bt= uiDefButS(block, ROW, 0, "HSV",     width/3, -30, width/3, UI_UNIT_Y, &colormode, 0.0, 1.0, 0, 0, "");
1811         uiButSetFunc(bt, do_picker_new_mode_cb, bt, hsv);
1812         bt= uiDefButS(block, ROW, 0, "Hex",     2*width/3, -30, width/3, UI_UNIT_Y, &colormode, 0.0, 2.0, 0, 0, "");
1813         uiButSetFunc(bt, do_picker_new_mode_cb, bt, hexcol);
1814         uiBlockEndAlign(block);
1815
1816         bt= uiDefIconButO(block, BUT, "UI_OT_eyedropper", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, butwidth+10, -60, UI_UNIT_X, UI_UNIT_Y, NULL);
1817         uiButSetFunc(bt, close_popup_cb, bt, NULL);
1818         
1819         /* RGB values */
1820         uiBlockBeginAlign(block);
1821         bt= uiDefButR(block, NUMSLI, 0, "R ",   0, -60, butwidth, UI_UNIT_Y, ptr, propname, 0, 0.0, 0.0, 0, 0, "");
1822         uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
1823         bt= uiDefButR(block, NUMSLI, 0, "G ",   0, -80, butwidth, UI_UNIT_Y, ptr, propname, 1, 0.0, 0.0, 0, 0, "");
1824         uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
1825         bt= uiDefButR(block, NUMSLI, 0, "B ",   0, -100, butwidth, UI_UNIT_Y, ptr, propname, 2, 0.0, 0.0, 0, 0, "");
1826         uiButSetFunc(bt, do_picker_rna_cb, bt, NULL);
1827         // could use uiItemFullR(col, ptr, prop, -1, 0, UI_ITEM_R_EXPAND|UI_ITEM_R_SLIDER, "", 0);
1828         // but need to use uiButSetFunc for updating other fake buttons
1829         
1830         /* HSV values */
1831         uiBlockBeginAlign(block);
1832         bt= uiDefButF(block, NUMSLI, 0, "H ",   0, -60, butwidth, UI_UNIT_Y, hsv, 0.0, 1.0, 10, 3, "");
1833         uiButSetFunc(bt, do_hsv_rna_cb, bt, hsv);
1834         bt= uiDefButF(block, NUMSLI, 0, "S ",   0, -80, butwidth, UI_UNIT_Y, hsv+1, 0.0, 1.0, 10, 3, "");
1835         uiButSetFunc(bt, do_hsv_rna_cb, bt, hsv);
1836         bt= uiDefButF(block, NUMSLI, 0, "V ",   0, -100, butwidth, UI_UNIT_Y, hsv+2, 0.0, 1.0, 10, 3, "");
1837         uiButSetFunc(bt, do_hsv_rna_cb, bt, hsv);
1838         uiBlockEndAlign(block);
1839         
1840         rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
1841         
1842         sprintf(hexcol, "%02X%02X%02X", (unsigned int)(rgb_gamma[0]*255.0), (unsigned int)(rgb_gamma[1]*255.0), (unsigned int)(rgb_gamma[2]*255.0));    
1843
1844         bt= uiDefBut(block, TEX, 0, "Hex: ", 0, -60, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, "Hex triplet for color (#RRGGBB)");
1845         uiButSetFunc(bt, do_hex_rna_cb, bt, hexcol);
1846         uiDefBut(block, LABEL, 0, "(Gamma Corrected)", 0, -80, butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1847
1848         picker_new_hide_reveal(block, colormode);
1849 }
1850
1851
1852 static int ui_picker_small_wheel(const bContext *C, uiBlock *block, wmEvent *event)
1853 {
1854         float add= 0.0f;
1855         
1856         if(event->type==WHEELUPMOUSE)
1857                 add= 0.05f;
1858         else if(event->type==WHEELDOWNMOUSE)
1859                 add= -0.05f;
1860         
1861         if(add!=0.0f) {
1862                 uiBut *but;
1863                 
1864                 for(but= block->buttons.first; but; but= but->next) {
1865                         if(but->type==HSVCUBE && but->active==NULL) {
1866                                 uiPopupBlockHandle *popup= block->handle;
1867                                 float col[3];
1868                                 
1869                                 ui_get_but_vectorf(but, col);
1870                                 
1871                                 rgb_to_hsv(col[0], col[1], col[2], but->hsv, but->hsv+1, but->hsv+2);
1872                                 but->hsv[2]= CLAMPIS(but->hsv[2]+add, 0.0f, 1.0f);
1873                                 hsv_to_rgb(but->hsv[0], but->hsv[1], but->hsv[2], col, col+1, col+2);
1874
1875                                 ui_set_but_vectorf(but, col);
1876                                 
1877                                 ui_update_block_buts_rgb(block, col);
1878                                 if(popup)
1879                                         popup->menuretval= UI_RETURN_UPDATE;
1880                                 
1881                                 return 1;
1882                         }
1883                 }
1884         }
1885         return 0;
1886 }
1887
1888 uiBlock *ui_block_func_COL(bContext *C, uiPopupBlockHandle *handle, void *arg_but)
1889 {
1890         uiBut *but= arg_but;
1891         uiBlock *block;
1892         
1893         block= uiBeginBlock(C, handle->region, "colorpicker", UI_EMBOSS);
1894         
1895         if (but->rnaprop) {
1896                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
1897                         block->color_profile = BLI_PR_NONE;
1898                 }
1899         }
1900         
1901         uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
1902         
1903         VECCOPY(handle->retvec, but->editvec);
1904
1905         uiBlockPicker(block, handle->retvec, &but->rnapoin, but->rnaprop);
1906         block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_KEEP_OPEN;
1907         uiBoundsBlock(block, 10);
1908         
1909         block->block_event_func= ui_picker_small_wheel;
1910         
1911         /* and lets go */
1912         block->direction= UI_TOP;
1913         
1914         return block;
1915 }
1916
1917 /************************ Popup Menu Memory ****************************/
1918
1919 static int ui_popup_string_hash(char *str)
1920 {
1921         /* sometimes button contains hotkey, sometimes not, strip for proper compare */
1922         int hash;
1923         char *delimit= strchr(str, '|');
1924
1925         if(delimit) *delimit= 0;
1926         hash= BLI_ghashutil_strhash(str);
1927         if(delimit) *delimit= '|';
1928
1929         return hash;
1930 }
1931
1932 static int ui_popup_menu_hash(char *str)
1933 {
1934         return BLI_ghashutil_strhash(str);
1935 }
1936
1937 /* but == NULL read, otherwise set */
1938 uiBut *ui_popup_menu_memory(uiBlock *block, uiBut *but)
1939 {
1940         static int mem[256], first=1;
1941         int hash= block->puphash;
1942         
1943         if(first) {
1944                 /* init */
1945                 memset(mem, -1, sizeof(mem));
1946                 first= 0;
1947         }
1948
1949         if(but) {
1950                 /* set */
1951                 mem[hash & 255 ]= ui_popup_string_hash(but->str);
1952                 return NULL;
1953         }
1954         else {
1955                 /* get */
1956                 for(but=block->buttons.first; but; but=but->next)
1957                         if(ui_popup_string_hash(but->str) == mem[hash & 255])
1958                                 return but;
1959
1960                 return NULL;
1961         }
1962 }
1963
1964 /******************** Popup Menu with callback or string **********************/
1965
1966 struct uiPopupMenu {
1967         uiBlock *block;
1968         uiLayout *layout;
1969         uiBut *but;
1970
1971         int mx, my, popup, slideout;
1972         int startx, starty, maxrow;
1973
1974         uiMenuCreateFunc menu_func;
1975         void *menu_arg;
1976 };
1977
1978 static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, void *arg_pup)
1979 {
1980         uiBlock *block;
1981         uiBut *bt;
1982         ScrArea *sa;
1983         ARegion *ar;
1984         uiPopupMenu *pup= arg_pup;
1985         int offset[2], direction, minwidth, width, height, flip;
1986
1987         if(pup->menu_func) {
1988                 pup->block->handle= handle;
1989                 pup->menu_func(C, pup->layout, pup->menu_arg);
1990                 pup->block->handle= NULL;
1991         }
1992
1993         if(pup->but) {
1994                 /* minimum width to enforece */
1995                 minwidth= pup->but->x2 - pup->but->x1;
1996
1997                 if(pup->but->type == PULLDOWN || pup->but->menu_create_func) {
1998                         direction= UI_DOWN;
1999                         flip= 1;
2000                 }
2001                 else {
2002                         direction= UI_TOP;
2003                         flip= 0;
2004                 }
2005         }
2006         else {
2007                 minwidth= 50;
2008                 direction= UI_DOWN;
2009                 flip= 1;
2010         }
2011
2012         block= pup->block;
2013         
2014         /* in some cases we create the block before the region,
2015            so we set it delayed here if necessary */
2016         if(BLI_findindex(&handle->region->uiblocks, block) == -1)
2017                 uiBlockSetRegion(block, handle->region);
2018
2019         block->direction= direction;
2020
2021         uiBlockLayoutResolve(block, &width, &height);
2022
2023         uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
2024         
2025         if(pup->popup) {
2026                 uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT|UI_BLOCK_RET_1);
2027                 uiBlockSetDirection(block, direction);
2028
2029                 /* offset the mouse position, possibly based on earlier selection */
2030                 if((block->flag & UI_BLOCK_POPUP_MEMORY) &&
2031                         (bt= ui_popup_menu_memory(block, NULL))) {
2032                         /* position mouse on last clicked item, at 0.8*width of the
2033                            button, so it doesn't overlap the text too much, also note
2034                            the offset is negative because we are inverse moving the
2035                            block to be under the mouse */
2036                         offset[0]= -(bt->x1 + 0.8f*(bt->x2 - bt->x1));
2037                         offset[1]= -(bt->y1 + 0.5f*MENU_BUTTON_HEIGHT);
2038                 }
2039                 else {
2040                         /* position mouse at 0.8*width of the button and below the tile
2041                            on the first item */
2042                         offset[0]= 0;
2043                         for(bt=block->buttons.first; bt; bt=bt->next)
2044                                 offset[0]= MIN2(offset[0], -(bt->x1 + 0.8f*(bt->x2 - bt->x1)));
2045
2046                         offset[1]= 1.5*MENU_BUTTON_HEIGHT;
2047                 }
2048
2049                 block->minbounds= minwidth;
2050                 uiMenuPopupBoundsBlock(block, 1, offset[0], offset[1]);
2051         }
2052         else {
2053                 /* for a header menu we set the direction automatic */
2054                 if(!pup->slideout && flip) {
2055                         sa= CTX_wm_area(C);
2056                         ar= CTX_wm_region(C);
2057
2058                         if(sa && sa->headertype==HEADERDOWN) {
2059                                 if(ar && ar->regiontype == RGN_TYPE_HEADER) {
2060                                         uiBlockSetDirection(block, UI_TOP);
2061                                         uiBlockFlipOrder(block);
2062                                 }
2063                         }
2064                 }
2065
2066                 block->minbounds= minwidth;
2067                 uiTextBoundsBlock(block, 50);
2068         }
2069
2070         /* if menu slides out of other menu, override direction */
2071         if(pup->slideout)
2072                 uiBlockSetDirection(block, UI_RIGHT);
2073
2074         uiEndBlock(C, block);
2075
2076         return pup->block;
2077 }
2078
2079 uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut *but, uiMenuCreateFunc menu_func, void *arg, char *str)
2080 {
2081         wmWindow *window= CTX_wm_window(C);
2082         uiStyle *style= U.uistyles.first;
2083         uiPopupBlockHandle *handle;
2084         uiPopupMenu *pup;
2085         
2086         pup= MEM_callocN(sizeof(uiPopupMenu), "menu dummy");
2087         pup->block= uiBeginBlock(C, NULL, "ui_button_menu_create", UI_EMBOSSP);
2088         pup->layout= uiBlockLayout(pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, style);
2089         pup->slideout= (but && (but->block->flag & UI_BLOCK_LOOP));
2090         pup->but= but;
2091         uiLayoutSetOperatorContext(pup->layout, WM_OP_INVOKE_REGION_WIN);
2092
2093         if(!but) {
2094                 /* no button to start from, means we are a popup */
2095                 pup->mx= window->eventstate->x;
2096                 pup->my= window->eventstate->y;
2097                 pup->popup= 1;
2098                 pup->block->flag |= UI_BLOCK_NO_FLIP;
2099         }
2100
2101         if(str) {
2102                 /* menu is created from a string */
2103                 pup->menu_func= ui_block_func_MENUSTR;
2104                 pup->menu_arg= str;
2105         }
2106         else {
2107                 /* menu is created from a callback */
2108                 pup->menu_func= menu_func;
2109                 pup->menu_arg= arg;
2110         }
2111         
2112         handle= ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPUP, pup);
2113
2114         if(!but) {
2115                 handle->popup= 1;
2116
2117                 UI_add_popup_handlers(C, &window->modalhandlers, handle);
2118                 WM_event_add_mousemove(C);
2119         }
2120         
2121         MEM_freeN(pup);
2122
2123         return handle;
2124 }
2125
2126 /******************** Popup Menu API with begin and end ***********************/
2127
2128 /* only return handler, and set optional title */
2129 uiPopupMenu *uiPupMenuBegin(bContext *C, const char *title, int icon)
2130 {
2131         uiStyle *style= U.uistyles.first;
2132         uiPopupMenu *pup= MEM_callocN(sizeof(uiPopupMenu), "popup menu");
2133         uiBut *but;
2134         
2135         pup->block= uiBeginBlock(C, NULL, "uiPupMenuBegin", UI_EMBOSSP);
2136         pup->block->flag |= UI_BLOCK_POPUP_MEMORY;
2137         pup->block->puphash= ui_popup_menu_hash((char*)title);
2138         pup->layout= uiBlockLayout(pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, style);
2139         uiLayoutSetOperatorContext(pup->layout, WM_OP_EXEC_REGION_WIN);
2140
2141         /* create in advance so we can let buttons point to retval already */
2142         pup->block->handle= MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
2143         
2144         /* create title button */
2145         if(title && title[0]) {
2146                 char titlestr[256];
2147                 
2148                 if(icon) {
2149                         sprintf(titlestr, " %s", title);
2150                         uiDefIconTextBut(pup->block, LABEL, 0, icon, titlestr, 0, 0, 200, MENU_BUTTON_HEIGHT, NULL, 0.0, 0.0, 0, 0, "");
2151                 }
2152                 else {
2153                         but= uiDefBut(pup->block, LABEL, 0, (char*)title, 0, 0, 200, MENU_BUTTON_HEIGHT, NULL, 0.0, 0.0, 0, 0, "");
2154                         but->flag= UI_TEXT_LEFT;
2155                 }
2156         }
2157
2158         return pup;
2159 }
2160
2161 /* set the whole structure to work */
2162 void uiPupMenuEnd(bContext *C, uiPopupMenu *pup)
2163 {
2164         wmWindow *window= CTX_wm_window(C);
2165         uiPopupBlockHandle *menu;
2166         
2167         pup->popup= 1;
2168         pup->mx= window->eventstate->x;
2169         pup->my= window->eventstate->y;
2170         
2171         menu= ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPUP, pup);
2172         menu->popup= 1;
2173         
2174         UI_add_popup_handlers(C, &window->modalhandlers, menu);
2175         WM_event_add_mousemove(C);
2176         
2177         MEM_freeN(pup);
2178 }
2179
2180 uiLayout *uiPupMenuLayout(uiPopupMenu *pup)
2181 {
2182         return pup->layout;
2183 }
2184
2185 /*************************** Standard Popup Menus ****************************/
2186
2187 static void operator_name_cb(bContext *C, void *arg, int retval)
2188 {
2189         const char *opname= arg;
2190
2191         if(opname && retval > 0)
2192                 WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL);
2193 }
2194
2195 static void operator_cb(bContext *C, void *arg, int retval)
2196 {
2197         wmOperator *op= arg;
2198         
2199         if(op && retval > 0)
2200                 WM_operator_call(C, op);
2201         else
2202                 WM_operator_free(op);
2203 }
2204
2205 static void confirm_cancel_operator(void *opv)
2206 {
2207         WM_operator_free(opv);
2208 }
2209
2210 static void vconfirm_opname(bContext *C, char *opname, char *title, char *itemfmt, va_list ap)
2211 {
2212         uiPopupBlockHandle *handle;
2213         char *s, buf[512];
2214
2215         s= buf;
2216         if (title) s+= sprintf(s, "%s%%t|", title);
2217         vsprintf(s, itemfmt, ap);
2218
2219         handle= ui_popup_menu_create(C, NULL, NULL, NULL, NULL, buf);
2220
2221         handle->popup_func= operator_name_cb;
2222         handle->popup_arg= opname;
2223 }
2224
2225 static void confirm_operator(bContext *C, wmOperator *op, char *title, char *item)
2226 {
2227         uiPopupBlockHandle *handle;
2228         char *s, buf[512];
2229         
2230         s= buf;
2231         if (title) s+= sprintf(s, "%s%%t|%s", title, item);
2232         
2233         handle= ui_popup_menu_create(C, NULL, NULL, NULL, NULL, buf);
2234
2235         handle->popup_func= operator_cb;
2236         handle->popup_arg= op;
2237         handle->cancel_func= confirm_cancel_operator;
2238 }
2239
2240 void uiPupMenuOkee(bContext *C, char *opname, char *str, ...)
2241 {
2242         va_list ap;
2243         char titlestr[256];
2244
2245         sprintf(titlestr, "OK? %%i%d", ICON_QUESTION);
2246
2247         va_start(ap, str);
2248         vconfirm_opname(C, opname, titlestr, str, ap);
2249         va_end(ap);
2250 }
2251
2252 void uiPupMenuSaveOver(bContext *C, wmOperator *op, char *filename)
2253 {
2254         size_t len= strlen(filename);
2255
2256         if(len==0)
2257                 return;
2258
2259         if(filename[len-1]=='/' || filename[len-1]=='\\') {
2260                 uiPupMenuError(C, "Cannot overwrite a directory");
2261                 WM_operator_free(op);
2262                 return;
2263         }
2264         if(BLI_exists(filename)==0)
2265                 operator_cb(C, op, 1);
2266         else
2267                 confirm_operator(C, op, "Save Over", filename);
2268 }
2269
2270 void uiPupMenuNotice(bContext *C, char *str, ...)
2271 {
2272         va_list ap;
2273
2274         va_start(ap, str);
2275         vconfirm_opname(C, NULL, NULL, str, ap);
2276         va_end(ap);
2277 }
2278
2279 void uiPupMenuError(bContext *C, char *str, ...)
2280 {
2281         va_list ap;
2282         char nfmt[256];
2283         char titlestr[256];
2284
2285         sprintf(titlestr, "Error %%i%d", ICON_ERROR);
2286
2287         sprintf(nfmt, "%s", str);
2288
2289         va_start(ap, str);
2290         vconfirm_opname(C, NULL, titlestr, nfmt, ap);
2291         va_end(ap);
2292 }
2293
2294 void uiPupMenuReports(bContext *C, ReportList *reports)
2295 {
2296         Report *report;
2297         DynStr *ds;
2298         char *str;
2299
2300         if(!reports || !reports->list.first)
2301                 return;
2302         if(!CTX_wm_window(C))
2303                 return;
2304
2305         ds= BLI_dynstr_new();
2306
2307         for(report=reports->list.first; report; report=report->next) {
2308                 if(report->type <= reports->printlevel)
2309                         ; /* pass */
2310                 else if(report->type >= RPT_ERROR)
2311                         BLI_dynstr_appendf(ds, "Error %%i%d%%t|%s", ICON_ERROR, report->message);
2312                 else if(report->type >= RPT_WARNING)
2313                         BLI_dynstr_appendf(ds, "Warning %%i%d%%t|%s", ICON_ERROR, report->message);
2314                 else if(report->type >= RPT_INFO)
2315                         BLI_dynstr_appendf(ds, "Info %%i%d%%t|%s", ICON_INFO, report->message);
2316         }
2317
2318         str= BLI_dynstr_get_cstring(ds);
2319         if(str[0] != '\0')
2320                 ui_popup_menu_create(C, NULL, NULL, NULL, NULL, str);
2321         MEM_freeN(str);
2322
2323         BLI_dynstr_free(ds);
2324 }
2325
2326 void uiPupMenuInvoke(bContext *C, const char *idname)
2327 {
2328         uiPopupMenu *pup;
2329         uiLayout *layout;
2330         Menu menu;
2331         MenuType *mt= WM_menutype_find(idname, TRUE);
2332
2333         if(mt==NULL) {
2334                 printf("uiPupMenuInvoke: named menu \"%s\" not found\n", idname);
2335                 return;
2336         }
2337
2338         if(mt->poll && mt->poll(C, mt)==0)
2339                 return;
2340
2341         pup= uiPupMenuBegin(C, mt->label, 0);
2342         layout= uiPupMenuLayout(pup);
2343
2344         menu.layout= layout;
2345         menu.type= mt;
2346
2347         mt->draw(C, &menu);
2348
2349         uiPupMenuEnd(C, pup);
2350 }
2351
2352
2353 /*************************** Popup Block API **************************/
2354
2355 void uiPupBlockO(bContext *C, uiBlockCreateFunc func, void *arg, char *opname, int opcontext)
2356 {
2357         wmWindow *window= CTX_wm_window(C);
2358         uiPopupBlockHandle *handle;
2359         
2360         handle= ui_popup_block_create(C, NULL, NULL, func, NULL, arg);
2361         handle->popup= 1;
2362         handle->optype= (opname)? WM_operatortype_find(opname, 0): NULL;
2363         handle->opcontext= opcontext;
2364         
2365         UI_add_popup_handlers(C, &window->modalhandlers, handle);
2366         WM_event_add_mousemove(C);
2367 }
2368
2369 void uiPupBlock(bContext *C, uiBlockCreateFunc func, void *arg)
2370 {
2371         uiPupBlockO(C, func, arg, NULL, 0);
2372 }
2373
2374 void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int opcontext)
2375 {
2376         wmWindow *window= CTX_wm_window(C);
2377         uiPopupBlockHandle *handle;
2378         
2379         handle= ui_popup_block_create(C, NULL, NULL, func, NULL, op);
2380         handle->popup= 1;
2381         handle->retvalue= 1;
2382
2383         handle->popup_arg= op;
2384         handle->popup_func= operator_cb;
2385         handle->cancel_func= confirm_cancel_operator;
2386         handle->opcontext= opcontext;
2387         
2388         UI_add_popup_handlers(C, &window->modalhandlers, handle);
2389         WM_event_add_mousemove(C);
2390 }
2391
2392 void uiPupBlockClose(bContext *C, uiBlock *block)
2393 {
2394         if(block->handle) {
2395                 UI_remove_popup_handlers(&CTX_wm_window(C)->modalhandlers, block->handle);
2396                 ui_popup_block_free(C, block->handle);
2397         }
2398 }
2399