6ed02a38ca1bbae1f2c9c85caa35457c8d4d1687
[blender.git] / source / blender / editors / interface / interface_layout.c
1
2 #include <limits.h>
3 #include <math.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include "MEM_guardedalloc.h"
8
9 #include "DNA_ID.h"
10 #include "DNA_scene_types.h"
11 #include "DNA_screen_types.h"
12 #include "DNA_userdef_types.h"
13 #include "DNA_windowmanager_types.h"
14
15 #include "BLI_listbase.h"
16 #include "BLI_string.h"
17
18 #include "BKE_context.h"
19 #include "BKE_global.h"
20 #include "BKE_idprop.h"
21 #include "BKE_library.h"
22 #include "BKE_screen.h"
23 #include "BKE_utildefines.h"
24
25 #include "RNA_access.h"
26
27 #include "UI_interface.h"
28 #include "UI_resources.h"
29 #include "UI_view2d.h"
30
31 #include "BIF_gl.h"
32
33 #include "ED_util.h"
34 #include "ED_types.h"
35 #include "ED_screen.h"
36
37 #include "WM_api.h"
38 #include "WM_types.h"
39
40 #include "interface_intern.h"
41
42 /************************ Structs and Defines *************************/
43
44 #define RNA_NO_INDEX    -1
45 #define RNA_ENUM_VALUE  -2
46
47 #define EM_UNIT_X               XIC
48 #define EM_UNIT_Y               YIC
49
50 #define EM_SEPR_X               6
51 #define EM_SEPR_Y               6
52
53 /* Item */
54
55 typedef enum uiItemType {
56         ITEM_OPERATOR,
57         ITEM_RNA_PROPERTY,
58         ITEM_MENU,
59         ITEM_LABEL,
60         ITEM_VALUE,
61         ITEM_SEPARATOR
62 } uiItemType;
63
64 enum uiItemFlag {
65         ITEM_ICON,
66         ITEM_TEXT
67 };
68
69 typedef struct uiItem {
70         struct uiItem *next, *prev;
71         uiItemType type;
72         int slot;
73
74         char *name;
75         char namestr[UI_MAX_NAME_STR];
76         int icon;
77         int disabled;
78 } uiItem;
79
80 typedef struct uiItemRNA {
81         uiItem item;
82
83         PointerRNA ptr;
84         PropertyRNA *prop;
85         int index, value;
86         int expand;
87 } uiItemRNA;
88
89 typedef struct uiItemOp {
90         uiItem item;
91
92         wmOperatorType *ot;
93         IDProperty *properties;
94         int context;
95 } uiItemOp;
96
97 typedef struct uiItemMenu {
98         uiItem item;
99
100         char *menuname;
101         uiMenuCreateFunc func;
102         void *arg, *argN;
103 } uiItemMenu;
104
105 typedef struct uiItemValue {
106         uiItem item;
107
108         int argval;
109 } uiItemValue;
110
111 /* Template */
112
113 typedef enum uiTemplateType {
114         TEMPLATE_ROW,
115         TEMPLATE_COLUMN,
116         TEMPLATE_COLUMN_FLOW,
117         TEMPLATE_SPLIT,
118         TEMPLATE_BOX,
119
120         TEMPLATE_HEADER,
121         TEMPLATE_HEADER_ID
122 } uiTemplateType;
123
124 typedef struct uiTemplate {
125         struct uiTemplate *next, *prev;
126         uiTemplateType type;
127
128         ListBase items;
129         int slot;
130 } uiTemplate;
131
132 typedef struct uiTemplateFlow {
133         uiTemplate template;
134         int number;
135 } uiTemplateFlow;
136
137 typedef struct uiTemplateSplt {
138         uiTemplate template;
139         int number;
140         int lr;
141         uiLayout **sublayout;
142 } uiTemplateSplt;
143
144 typedef struct uiTemplateBx {
145         uiTemplate template;
146         uiLayout *sublayout;
147 } uiTemplateBx;
148
149 typedef struct uiTemplateHeadID {
150         uiTemplate template;
151
152         PointerRNA ptr;
153         PropertyRNA *prop;
154
155         int flag;
156         short browse;
157         char *newop;
158         char *openop;
159         char *unlinkop;
160 } uiTemplateHeadID;
161
162 /* Layout */
163
164 struct uiLayout {
165         ListBase templates;
166         int opcontext;
167         int dir, type;
168         int x, y, w, h;
169         int emw, emh;
170
171         uiMenuHandleFunc handlefunc;
172         void *argv;
173
174         uiStyle *style;
175 };
176
177 void ui_layout_free(uiLayout *layout);
178 void ui_layout_end(const bContext *C, uiBlock *block, uiLayout *layout, int *x, int *y);
179
180 /************************** Item ***************************/
181
182 static void ui_item_name(uiItem *item, char *name)
183 {
184         if(!item->name && name) {
185                 BLI_strncpy(item->namestr, name, sizeof(item->namestr));
186                 item->name= item->namestr;
187         }
188 }
189 static void ui_item_name_add_colon(uiItem *item)
190 {
191         int len= strlen(item->namestr);
192
193         if(len != 0 && len+1 < sizeof(item->namestr)) {
194                 item->namestr[len]= ':';
195                 item->namestr[len+1]= '\0';
196         }
197 }
198
199 #define UI_FIT_EXPAND 1
200
201 static int ui_item_fit(int item, int pos, int all, int available, int spacing, int last, int flag)
202 {
203         if(all > available-spacing) {
204                 /* contents is bigger than available space */
205                 if(last)
206                         return available-pos;
207                 else
208                         return (item*(available-spacing))/all;
209         }
210         else {
211                 /* contents is smaller or equal to available space */
212                 if(flag & UI_FIT_EXPAND) {
213                         if(last)
214                                 return available-pos;
215                         else
216                                 return (item*(available-spacing))/all;
217                 }
218                 else
219                         return item;
220         }
221 }
222
223 /* create buttons for an item with an RNA array */
224 static void ui_item_array(uiLayout *layout, uiBlock *block, uiItemRNA *rnaitem, int len, int x, int y, int w, int h)
225 {
226         uiStyle *style= layout->style;
227         PropertyType type;
228         PropertySubType subtype;
229         int a;
230
231         /* retrieve type and subtype */
232         type= RNA_property_type(rnaitem->prop);
233         subtype= RNA_property_subtype(rnaitem->prop);
234
235         /* create label */
236         if(strcmp(rnaitem->item.name, "") != 0)
237                 uiDefBut(block, LABEL, 0, rnaitem->item.name, x, y + h - EM_UNIT_Y, w, EM_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
238
239         /* create buttons */
240         uiBlockBeginAlign(block);
241
242         if(type == PROP_BOOLEAN && len == 20) {
243                 /* special check for layer layout */
244                 int butw, buth;
245
246                 butw= ui_item_fit(EM_UNIT_X, 0, EM_UNIT_X*10 + style->buttonspacex, w, 0, 0, UI_FIT_EXPAND);
247                 buth= MIN2(EM_UNIT_Y, butw);
248
249                 y += 2*(EM_UNIT_Y - buth);
250
251                 uiBlockBeginAlign(block);
252                 for(a=0; a<5; a++)
253                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a, "", ICON_BLANK1, x + butw*a, y+buth, butw, buth);
254                 for(a=0; a<5; a++)
255                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a+10, "", ICON_BLANK1, x + butw*a, y, butw, buth);
256                 uiBlockEndAlign(block);
257
258                 x += 5*butw + style->buttonspacex;
259
260                 uiBlockBeginAlign(block);
261                 for(a=0; a<5; a++)
262                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a+5, "", ICON_BLANK1, x + butw*a, y+buth, butw, buth);
263                 for(a=0; a<5; a++)
264                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a+15, "", ICON_BLANK1, x + butw*a, y, butw, buth);
265                 uiBlockEndAlign(block);
266         }
267         else if(subtype == PROP_MATRIX) {
268                 /* matrix layout */
269                 int row, col;
270
271                 len= ceil(sqrt(len));
272
273                 h /= len;
274                 w /= len;
275
276                 // XXX test
277                 for(a=0; a<len; a++) {
278                         col= a%len;
279                         row= a/len;
280
281                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a, "", 0, x + w*col, y+(row-a-1)*EM_UNIT_Y, w, EM_UNIT_Y);
282                 }
283         }
284         else if(len <= 4 && ELEM3(subtype, PROP_ROTATION, PROP_VECTOR, PROP_COLOR)) {
285                 /* layout for known array subtypes */
286                 static char vectoritem[4]= {'X', 'Y', 'Z', 'W'};
287                 static char quatitem[4]= {'W', 'X', 'Y', 'Z'};
288                 static char coloritem[4]= {'R', 'G', 'B', 'A'};
289                 char str[3];
290
291                 for(a=0; a<len; a++) {
292                         if(len == 4 && subtype == PROP_ROTATION)
293                                 str[0]= quatitem[a];
294                         else if(subtype == PROP_VECTOR || subtype == PROP_ROTATION)
295                                 str[0]= vectoritem[a];
296                         else
297                                 str[0]= coloritem[a];
298
299                         if(type == PROP_BOOLEAN) {
300                                 str[1]= '\0';
301                         }
302                         else {
303                                 str[1]= ':';
304                                 str[2]= '\0';
305                         }
306
307                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a, str, 0, x, y+(len-a-1)*EM_UNIT_Y, w, EM_UNIT_Y);
308                 }
309         }
310         else {
311                 /* default array layout */
312                 for(a=0; a<len; a++)
313                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a, "", 0, x, y+(len-a-1)*EM_UNIT_Y, w, EM_UNIT_Y);
314         }
315
316         uiBlockEndAlign(block);
317 }
318
319 static void ui_item_enum_row(uiBlock *block, uiItemRNA *rnaitem, int x, int y, int w, int h)
320 {
321         const EnumPropertyItem *item;
322         int a, totitem, pos, itemw;
323         const char *propname;
324         
325         propname= RNA_property_identifier(rnaitem->prop);
326         RNA_property_enum_items(&rnaitem->ptr, rnaitem->prop, &item, &totitem);
327
328         uiBlockBeginAlign(block);
329         pos= 0;
330         for(a=0; a<totitem; a++) {
331                 itemw= ui_item_fit(1, pos, totitem, w, 0, a == totitem-1, UI_FIT_EXPAND);
332                 uiDefButR(block, ROW, 0, NULL, x+pos, y, itemw, h, &rnaitem->ptr, propname, -1, 0, item[a].value, -1, -1, NULL);
333                 pos += itemw;
334         }
335         uiBlockEndAlign(block);
336 }
337
338 /* create label + button for RNA property */
339 static void ui_item_with_label(uiBlock *block, uiItemRNA *rnaitem, int x, int y, int w, int h)
340 {
341         if(strcmp(rnaitem->item.name, "") != 0) {
342                 w= w/2;
343                 uiDefBut(block, LABEL, 0, rnaitem->item.name, x, y, w, h, NULL, 0.0, 0.0, 0, 0, "");
344                 x += w;
345         }
346
347         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, rnaitem->index, "", rnaitem->item.icon, x, y, w, h);
348 }
349
350 /* create buttons for an arbitrary item */
351 static void ui_item_buts(uiLayout *layout, uiBlock *block, uiItem *item, int x, int y, int w, int h)
352 {
353         if(item->type == ITEM_RNA_PROPERTY) {
354                 /* RNA property */
355                 uiItemRNA *rnaitem= (uiItemRNA*)item;
356                 PropertyType type;
357                 int len;
358                 
359                 /* retrieve info */
360                 type= RNA_property_type(rnaitem->prop);
361                 len= RNA_property_array_length(rnaitem->prop);
362
363                 /* array property */
364                 if(rnaitem->index == RNA_NO_INDEX && len > 0)
365                         ui_item_array(layout, block, rnaitem, len, x, y, w, h);
366                 /* enum item */
367                 else if(type == PROP_ENUM && rnaitem->index == RNA_ENUM_VALUE) {
368                         char *identifier= (char*)RNA_property_identifier(rnaitem->prop);
369
370                         if(item->icon && strcmp(item->name, "") != 0)
371                                 uiDefIconTextButR(block, ROW, 0, item->icon, item->name, x, y, w, h, &rnaitem->ptr, identifier, -1, 0, rnaitem->value, -1, -1, NULL);
372                         else if(item->icon)
373                                 uiDefIconButR(block, ROW, 0, item->icon, x, y, w, h, &rnaitem->ptr, identifier, -1, 0, rnaitem->value, -1, -1, NULL);
374                         else
375                                 uiDefButR(block, ROW, 0, item->name, x, y, w, h, &rnaitem->ptr, identifier, -1, 0, rnaitem->value, -1, -1, NULL);
376                 }
377                 /* expanded enum */
378                 else if(type == PROP_ENUM && rnaitem->expand)
379                         ui_item_enum_row(block, rnaitem, x, y, w, h);
380                 /* property with separate label */
381                 else if(type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER)
382                         ui_item_with_label(block, rnaitem, x, y, w, h);
383                 /* single button */
384                 else
385                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, rnaitem->index, (char*)item->name, item->icon, x, y, w, h);
386         }
387         else if(item->type == ITEM_OPERATOR) {
388                 /* operator */
389                 uiItemOp *opitem= (uiItemOp*)item;
390                 uiBut *but;
391
392                 if(item->icon && strcmp(item->name, "") != 0)
393                         but= uiDefIconTextButO(block, BUT, opitem->ot->idname, opitem->context, item->icon, (char*)item->name, x, y, w, h, NULL);
394                 else if(item->icon)
395                         but= uiDefIconButO(block, BUT, opitem->ot->idname, opitem->context, item->icon, x, y, w, h, NULL);
396                 /* text only */
397                 else
398                         but= uiDefButO(block, BUT, opitem->ot->idname, opitem->context, (char*)item->name, x, y, w, h, NULL);
399
400                 if(but && opitem->properties) {
401                         /* assign properties */
402                         PointerRNA *opptr= uiButGetOperatorPtrRNA(but);
403                         opptr->data= opitem->properties;
404                         opitem->properties= NULL;
405                 }
406         }
407         else if(item->type == ITEM_MENU) {
408                 /* menu */
409                 uiBut *but;
410                 uiItemMenu *menuitem= (uiItemMenu*)item;
411
412                 if(layout->type == UI_LAYOUT_HEADER) { /* ugly .. */
413                         y -= 2;
414                         w -= 3;
415                         h += 4;
416                 }
417
418                 if(item->icon)
419                         but= uiDefIconTextMenuBut(block, menuitem->func, menuitem->arg, item->icon, (char*)item->name, x, y, w, h, "");
420                 else
421                         but= uiDefMenuBut(block, menuitem->func, menuitem->arg, (char*)item->name, x, y, w, h, "");
422
423                 if(menuitem->argN) { /* ugly .. */
424                         but->poin= (char*)but;
425                         but->func_argN= menuitem->argN;
426                 }
427         }
428         else if(item->type == ITEM_LABEL) {
429                 /* label */
430                 uiBut *but;
431
432                 if(item->icon && strcmp(item->name, "") != 0)
433                         but= uiDefIconTextBut(block, LABEL, 0, item->icon, (char*)item->name, x, y, w, h, NULL, 0.0, 0.0, 0, 0, "");
434                 else if(item->icon)
435                         but= uiDefIconBut(block, LABEL, 0, item->icon, x, y, w, h, NULL, 0.0, 0.0, 0, 0, "");
436                 else
437                         but= uiDefBut(block, LABEL, 0, (char*)item->name, x, y, w, h, NULL, 0.0, 0.0, 0, 0, "");
438
439                 if(item->disabled) {
440                         but->flag |= UI_BUT_DISABLED;
441                         but->lock = 1;
442                         but->lockstr = "";
443                 }
444         }
445         else if(item->type == ITEM_VALUE) {
446                 /* label */
447                 uiItemValue *vitem= (uiItemValue*)item;
448                 float *retvalue= (block->handle)? &block->handle->retvalue: NULL;
449
450                 if(item->icon && strcmp(item->name, "") != 0)
451                         uiDefIconTextButF(block, BUTM, 0, item->icon, (char*)item->name, x, y, w, h, retvalue, 0.0, 0.0, 0, vitem->argval, "");
452                 else if(item->icon)
453                         uiDefIconButF(block, BUTM, 0, item->icon, x, y, w, h, retvalue, 0.0, 0.0, 0, vitem->argval, "");
454                 else
455                         uiDefButF(block, BUTM, 0, (char*)item->name, x, y, w, h, retvalue, 0.0, 0.0, 0, vitem->argval, "");
456         }
457         else {
458                 /* separator */
459                 uiDefBut(block, SEPR, 0, "", x, y, w, h, NULL, 0.0, 0.0, 0, 0, "");
460         }
461 }
462
463 /* estimated size of text + icon */
464 static int ui_text_icon_width(char *name, int icon, int variable)
465 {
466         if(icon && strcmp(name, "") == 0)
467                 return EM_UNIT_X; /* icon only */
468         else if(icon)
469                 return (variable)? UI_GetStringWidth(name) + EM_UNIT_X: 10*EM_UNIT_X; /* icon + text */
470         else
471                 return (variable)? UI_GetStringWidth(name) + EM_UNIT_X: 10*EM_UNIT_X; /* text only */
472 }
473
474 /* estimated size of an item */
475 #define UI_ITEM_VARY_X  1
476 #define UI_ITEM_VARY_Y  2
477
478 static void ui_item_size(uiItem *item, int *r_w, int *r_h, int flag)
479 {
480         int w, h;
481
482         if(item->type == ITEM_RNA_PROPERTY) {
483                 /* RNA property */
484                 uiItemRNA *rnaitem= (uiItemRNA*)item;
485                 PropertyType type;
486                 PropertySubType subtype;
487                 int len;
488
489                 w= ui_text_icon_width(item->name, item->icon, flag & UI_ITEM_VARY_X);
490                 h= EM_UNIT_Y;
491
492                 /* arbitrary extended width by type */
493                 type= RNA_property_type(rnaitem->prop);
494                 subtype= RNA_property_subtype(rnaitem->prop);
495                 len= RNA_property_array_length(rnaitem->prop);
496
497                 if(type == PROP_STRING)
498                         w += 10*EM_UNIT_X;
499
500                 /* increase height for arrays */
501                 if(rnaitem->index == RNA_NO_INDEX && len > 0) {
502                         if(strcmp(item->name, "") == 0 && item->icon == 0)
503                                 h= 0;
504
505                         if(type == PROP_BOOLEAN && len == 20)
506                                 h += 2*EM_UNIT_Y;
507                         else if(subtype == PROP_MATRIX)
508                                 h += ceil(sqrt(len))*EM_UNIT_Y;
509                         else
510                                 h += len*EM_UNIT_Y;
511                 }
512                 else if(flag & UI_ITEM_VARY_X) {
513                         if(type == PROP_BOOLEAN && strcmp(item->name, "") != 0)
514                                 w += EM_UNIT_X;
515                 }
516         }
517         else {
518                 /* other */
519                 if(item->type == ITEM_SEPARATOR) {
520                         w= EM_SEPR_X;
521                         h= EM_SEPR_Y;
522                 }
523                 else {
524                         w= ui_text_icon_width(item->name, item->icon, flag & UI_ITEM_VARY_X);
525                         h= EM_UNIT_Y;
526                 }
527         }
528
529         if(r_w) *r_w= w;
530         if(r_h) *r_h= h;
531 }
532
533 static void ui_item_free(uiItem *item)
534 {
535         if(item->type == ITEM_OPERATOR) {
536                 uiItemOp *opitem= (uiItemOp*)item;
537
538                 if(opitem->properties) {
539                         IDP_FreeProperty(opitem->properties);
540                         MEM_freeN(opitem->properties);
541                 }
542         }
543 }
544
545 /* disabled item */
546 static void ui_item_disabled(uiLayout *layout, char *name)
547 {
548         uiTemplate *template= layout->templates.last;
549         uiItem *item;
550         
551         if(!template)
552                 return;
553
554         item= MEM_callocN(sizeof(uiItem), "uiItem");
555
556         ui_item_name(item, name);
557         item->disabled= 1;
558         item->type= ITEM_LABEL;
559         item->slot= template->slot;
560
561         BLI_addtail(&template->items, item);
562 }
563
564 /* operator items */
565 void uiItemFullO(uiLayout *layout, char *name, int icon, char *idname, IDProperty *properties, int context)
566 {
567         uiTemplate *template= layout->templates.last;
568         wmOperatorType *ot= WM_operatortype_find(idname);
569         uiItemOp *opitem;
570
571         if(!template)
572                 return;
573         if(!ot) {
574                 ui_item_disabled(layout, idname);
575                 return;
576         }
577
578         opitem= MEM_callocN(sizeof(uiItemOp), "uiItemOp");
579
580         ui_item_name(&opitem->item, name);
581         opitem->item.icon= icon;
582         opitem->item.type= ITEM_OPERATOR;
583         opitem->item.slot= template->slot;
584
585         opitem->ot= ot;
586         opitem->properties= properties;
587         opitem->context= context;
588
589         BLI_addtail(&template->items, opitem);
590 }
591
592 static char *ui_menu_enumpropname(char *opname, char *propname, int retval)
593 {
594         wmOperatorType *ot= WM_operatortype_find(opname);
595         PointerRNA ptr;
596         PropertyRNA *prop;
597
598         if(!ot || !ot->srna)
599                 return "";
600         
601         RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
602         prop= RNA_struct_find_property(&ptr, propname);
603         
604         if(prop) {
605                 const EnumPropertyItem *item;
606                 int totitem, i;
607                 
608                 RNA_property_enum_items(&ptr, prop, &item, &totitem);
609                 
610                 for (i=0; i<totitem; i++) {
611                         if(item[i].value==retval)
612                                 return (char*)item[i].name;
613                 }
614         }
615
616         return "";
617 }
618
619 void uiItemEnumO(uiLayout *layout, char *name, int icon, char *opname, char *propname, int value)
620 {
621         PointerRNA ptr;
622
623         WM_operator_properties_create(&ptr, opname);
624         RNA_enum_set(&ptr, propname, value);
625
626         if(!name)
627                 name= ui_menu_enumpropname(opname, propname, value);
628
629         uiItemFullO(layout, name, icon, opname, ptr.data, layout->opcontext);
630 }
631
632 void uiItemsEnumO(uiLayout *layout, char *opname, char *propname)
633 {
634         wmOperatorType *ot= WM_operatortype_find(opname);
635         PointerRNA ptr;
636         PropertyRNA *prop;
637
638         if(!ot || !ot->srna) {
639                 ui_item_disabled(layout, opname);
640                 return;
641         }
642
643         RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
644         prop= RNA_struct_find_property(&ptr, propname);
645
646         if(prop && RNA_property_type(prop) == PROP_ENUM) {
647                 const EnumPropertyItem *item;
648                 int totitem, i;
649
650                 RNA_property_enum_items(&ptr, prop, &item, &totitem);
651
652                 for(i=0; i<totitem; i++)
653                         uiItemEnumO(layout, NULL, 0, opname, propname, item[i].value);
654         }
655 }
656
657 void uiItemBooleanO(uiLayout *layout, char *name, int icon, char *opname, char *propname, int value)
658 {
659         PointerRNA ptr;
660
661         WM_operator_properties_create(&ptr, opname);
662         RNA_boolean_set(&ptr, propname, value);
663
664         uiItemFullO(layout, name, icon, opname, ptr.data, layout->opcontext);
665 }
666
667 void uiItemIntO(uiLayout *layout, char *name, int icon, char *opname, char *propname, int value)
668 {
669         PointerRNA ptr;
670
671         WM_operator_properties_create(&ptr, opname);
672         RNA_int_set(&ptr, propname, value);
673
674         uiItemFullO(layout, name, icon, opname, ptr.data, layout->opcontext);
675 }
676
677 void uiItemFloatO(uiLayout *layout, char *name, int icon, char *opname, char *propname, float value)
678 {
679         PointerRNA ptr;
680
681         WM_operator_properties_create(&ptr, opname);
682         RNA_float_set(&ptr, propname, value);
683
684         uiItemFullO(layout, name, icon, opname, ptr.data, layout->opcontext);
685 }
686
687 void uiItemStringO(uiLayout *layout, char *name, int icon, char *opname, char *propname, char *value)
688 {
689         PointerRNA ptr;
690
691         WM_operator_properties_create(&ptr, opname);
692         RNA_string_set(&ptr, propname, value);
693
694         uiItemFullO(layout, name, icon, opname, ptr.data, layout->opcontext);
695 }
696
697 void uiItemO(uiLayout *layout, char *name, int icon, char *opname)
698 {
699         uiItemFullO(layout, name, icon, opname, NULL, layout->opcontext);
700 }
701
702 /* RNA property items */
703 void uiItemFullR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int value, int expand)
704 {
705         uiTemplate *template= layout->templates.last;
706         uiItemRNA *rnaitem;
707
708         if(!ptr->data || !prop)
709                 return;
710         if(!template)
711                 return;
712
713         rnaitem= MEM_callocN(sizeof(uiItemRNA), "uiItemRNA");
714
715         ui_item_name(&rnaitem->item, name);
716         rnaitem->item.icon= icon;
717         rnaitem->item.type= ITEM_RNA_PROPERTY;
718         rnaitem->item.slot= template->slot;
719
720         rnaitem->ptr= *ptr;
721         rnaitem->prop= prop;
722         rnaitem->index= index;
723         rnaitem->value= value;
724         rnaitem->expand= expand;
725
726         BLI_addtail(&template->items, rnaitem);
727 }
728
729 void uiItemR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, char *propname, int expand)
730 {
731         PropertyRNA *prop;
732
733         if(!ptr->data || !propname)
734                 return;
735
736         prop= RNA_struct_find_property(ptr, propname);
737
738         if(!prop) {
739                 ui_item_disabled(layout, propname);
740                 printf("uiItemR: property not found: %s\n", propname);
741                 return;
742         }
743         
744         uiItemFullR(layout, name, icon, ptr, prop, RNA_NO_INDEX, 0, expand);
745 }
746
747 void uiItemEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, int value)
748 {
749         PropertyRNA *prop;
750
751         if(!ptr->data || !propname)
752                 return;
753
754         prop= RNA_struct_find_property(ptr, propname);
755
756         if(!prop) {
757                 ui_item_disabled(layout, propname);
758                 printf("uiItemEnumR: property not found: %s\n", propname);
759                 return;
760         }
761         
762         uiItemFullR(layout, name, icon, ptr, prop, RNA_ENUM_VALUE, value, 0);
763 }
764
765 void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, char *propname)
766 {
767         PropertyRNA *prop;
768
769         prop= RNA_struct_find_property(ptr, propname);
770
771         if(!prop) {
772                 ui_item_disabled(layout, propname);
773                 return;
774         }
775
776         if(RNA_property_type(prop) == PROP_ENUM) {
777                 const EnumPropertyItem *item;
778                 int totitem, i;
779
780                 RNA_property_enum_items(ptr, prop, &item, &totitem);
781
782                 for(i=0; i<totitem; i++)
783                         uiItemEnumR(layout, (char*)item[i].name, 0, ptr, propname, item[i].value);
784         }
785 }
786
787 /* menu item */
788 static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
789 {
790         MenuType *mt= (MenuType*)arg_mt;
791         Menu menu = {0};
792
793         menu.type= mt;
794         menu.layout= layout;
795         mt->draw(C, &menu);
796 }
797
798 void uiItemM(uiLayout *layout, char *name, int icon, char *menuname)
799 {
800         uiTemplate *template= layout->templates.last;
801         uiItemMenu *menuitem;
802         
803         if(!template)
804                 return;
805         if(!menuname)
806                 return;
807
808         menuitem= MEM_callocN(sizeof(uiItemMenu), "uiItemMenu");
809
810         ui_item_name(&menuitem->item, name);
811         menuitem->item.icon= icon;
812         menuitem->item.type= ITEM_MENU;
813         menuitem->item.slot= template->slot;
814
815         menuitem->func= ui_item_menutype_func;
816         menuitem->menuname= menuname;
817
818         BLI_addtail(&template->items, menuitem);
819 }
820
821 /* label item */
822 void uiItemL(uiLayout *layout, char *name, int icon)
823 {
824         uiTemplate *template= layout->templates.last;
825         uiItem *item;
826         
827         if(!template)
828                 return;
829
830         item= MEM_callocN(sizeof(uiItem), "uiItem");
831
832         ui_item_name(item, name);
833         item->icon= icon;
834         item->type= ITEM_LABEL;
835         item->slot= template->slot;
836
837         BLI_addtail(&template->items, item);
838 }
839
840 /* value item */
841 void uiItemV(uiLayout *layout, char *name, int icon, int argval)
842 {
843         uiTemplate *template= layout->templates.last;
844         uiItemValue *vitem;
845         
846         if(!template)
847                 return;
848
849         vitem= MEM_callocN(sizeof(uiItemValue), "uiItemValue");
850
851         vitem->item.name= name;
852         vitem->item.icon= icon;
853         vitem->item.type= ITEM_VALUE;
854         vitem->item.slot= template->slot;
855         vitem->argval= argval;
856
857         BLI_addtail(&template->items, vitem);
858 }
859
860 /* separator item */
861 void uiItemS(uiLayout *layout)
862 {
863         uiTemplate *template= layout->templates.last;
864         uiItem *item;
865         
866         if(!template)
867                 return;
868
869         item= MEM_callocN(sizeof(uiItem), "uiItem");
870
871         item->type= ITEM_SEPARATOR;
872         item->slot= template->slot;
873
874         BLI_addtail(&template->items, item);
875 }
876
877 /* level items */
878 void uiItemMenuF(uiLayout *layout, char *name, int icon, uiMenuCreateFunc func)
879 {
880         uiTemplate *template= layout->templates.last;
881         uiItemMenu *menuitem;
882         
883         if(!template)
884                 return;
885         if(!func)
886                 return;
887
888         menuitem= MEM_callocN(sizeof(uiItemMenu), "uiItemMenu");
889
890         if(!icon && layout->type == UI_LAYOUT_MENU)
891                 icon= ICON_RIGHTARROW_THIN,
892
893         ui_item_name(&menuitem->item, name);
894         menuitem->item.icon= icon;
895         menuitem->item.type= ITEM_MENU;
896         menuitem->item.slot= template->slot;
897
898         menuitem->func= func;
899
900         BLI_addtail(&template->items, menuitem);
901 }
902
903 typedef struct MenuItemLevel {
904         int opcontext;
905         char *opname;
906         char *propname;
907         PointerRNA rnapoin;
908 } MenuItemLevel;
909
910 static void menu_item_enum_opname_menu(bContext *C, uiLayout *layout, void *arg)
911 {
912         MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
913
914         uiLayoutContext(layout, WM_OP_EXEC_REGION_WIN);
915         uiItemsEnumO(layout, lvl->opname, lvl->propname);
916 }
917
918 void uiItemMenuEnumO(uiLayout *layout, char *name, int icon, char *opname, char *propname)
919 {
920         wmOperatorType *ot= WM_operatortype_find(opname);
921         uiTemplate *template= layout->templates.last;
922         uiItemMenu *menuitem;
923         MenuItemLevel *lvl;
924
925         if(!ot || !ot->srna) {
926                 ui_item_disabled(layout, opname);
927                 return;
928         }
929         if(!template)
930                 return;
931
932         menuitem= MEM_callocN(sizeof(uiItemMenu), "uiItemMenu");
933
934         if(!icon && layout->type == UI_LAYOUT_MENU)
935                 icon= ICON_RIGHTARROW_THIN;
936         if(!name)
937                 name= ot->name;
938
939         ui_item_name(&menuitem->item, name);
940         menuitem->item.icon= icon;
941         menuitem->item.type= ITEM_MENU;
942         menuitem->item.slot= template->slot;
943
944         lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
945         lvl->opname= opname;
946         lvl->propname= propname;
947         lvl->opcontext= layout->opcontext;
948
949         menuitem->func= menu_item_enum_opname_menu;
950         menuitem->argN= lvl;
951
952         BLI_addtail(&template->items, menuitem);
953 }
954
955 static void menu_item_enum_rna_menu(bContext *C, uiLayout *layout, void *arg)
956 {
957         MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
958
959         uiLayoutContext(layout, lvl->opcontext);
960         uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
961 }
962
963 void uiItemMenuEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname)
964 {
965         uiTemplate *template= layout->templates.last;
966         uiItemMenu *menuitem;
967         MenuItemLevel *lvl;
968         PropertyRNA *prop;
969         
970         if(!template)
971                 return;
972
973         prop= RNA_struct_find_property(ptr, propname);
974         if(!prop) {
975                 ui_item_disabled(layout, propname);
976                 return;
977         }
978
979         menuitem= MEM_callocN(sizeof(uiItemMenu), "uiItemMenu");
980
981         if(!icon && layout->type == UI_LAYOUT_MENU)
982                 icon= ICON_RIGHTARROW_THIN;
983         if(!name)
984                 name= (char*)RNA_property_ui_name(prop);
985
986         ui_item_name(&menuitem->item, name);
987         menuitem->item.icon= icon;
988         menuitem->item.type= ITEM_MENU;
989         menuitem->item.slot= template->slot;
990
991         lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
992         lvl->rnapoin= *ptr;
993         lvl->propname= propname;
994         lvl->opcontext= layout->opcontext;
995
996         menuitem->func= menu_item_enum_rna_menu;
997         menuitem->argN= lvl;
998
999         BLI_addtail(&template->items, menuitem);
1000 }
1001
1002 /**************************** Template ***************************/
1003
1004 /* single row layout */
1005 static void ui_layout_row(uiLayout *layout, uiBlock *block, uiTemplate *template)
1006 {
1007         uiStyle *style= layout->style;
1008         uiItem *item;
1009         int tot=0, totw= 0, maxh= 0, itemw, itemh, x, w;
1010
1011         /* estimate total width of buttons */
1012         for(item=template->items.first; item; item=item->next) {
1013                 ui_item_size(item, &itemw, &itemh, UI_ITEM_VARY_Y);
1014                 totw += itemw;
1015                 maxh= MAX2(maxh, itemh);
1016                 tot++;
1017         }
1018
1019         if(totw == 0)
1020                 return;
1021         
1022         /* create buttons starting from left */
1023         x= 0;
1024         w= layout->w;
1025
1026         for(item=template->items.first; item; item=item->next) {
1027                 ui_item_size(item, &itemw, &itemh, UI_ITEM_VARY_Y);
1028                 itemw= ui_item_fit(itemw, x, totw, w, (tot-1)*style->buttonspacex, !item->next, UI_FIT_EXPAND);
1029
1030                 ui_item_buts(layout, block, item, layout->x+x, layout->y-itemh, itemw, itemh);
1031                 x += itemw+style->buttonspacex;
1032         }
1033
1034         layout->y -= maxh;
1035 }
1036
1037 /* multi-column layout */
1038 static void ui_layout_column(uiLayout *layout, uiBlock *block, uiTemplate *template)
1039 {
1040         uiStyle *style= layout->style;
1041         uiItem *item;
1042         int col, totcol= 0, x, y, miny, itemw, itemh, w;
1043
1044         /* compute number of columns */
1045         for(item=template->items.first; item; item=item->next)
1046                 totcol= MAX2(item->slot+1, totcol);
1047         
1048         if(totcol == 0)
1049                 return;
1050         
1051         x= 0;
1052         miny= 0;
1053         w= layout->w;
1054
1055         /* create column per column */
1056         for(col=0; col<totcol; col++) {
1057                 y= 0;
1058
1059                 itemw= ui_item_fit(1, x, totcol, w, (totcol-1)*style->columnspace, col == totcol-1, UI_FIT_EXPAND);
1060
1061                 for(item=template->items.first; item; item=item->next) {
1062                         if(item->slot != col)
1063                                 continue;
1064
1065                         ui_item_size(item, NULL, &itemh, UI_ITEM_VARY_Y);
1066
1067                         y -= itemh;
1068                         ui_item_buts(layout, block, item, layout->x+x, layout->y+y, itemw, itemh);
1069                         y -= style->buttonspacey;
1070                 }
1071
1072                 x += itemw + style->columnspace;
1073                 miny= MIN2(miny, y);
1074         }
1075
1076         layout->y += miny;
1077 }
1078
1079 /* multi-column layout, automatically flowing to the next */
1080 static void ui_layout_column_flow(uiLayout *layout, uiBlock *block, uiTemplate *template)
1081 {
1082         uiStyle *style= layout->style;
1083         uiTemplateFlow *flow= (uiTemplateFlow*)template;
1084         uiItem *item;
1085         int col, x, y, w, emh, emy, miny, itemw, itemh, maxw=0;
1086         int toth, totcol, totitem;
1087
1088         /* compute max needed width and total height */
1089         toth= 0;
1090         totitem= 0;
1091         for(item=template->items.first; item; item=item->next) {
1092                 ui_item_size(item, &itemw, &itemh, UI_ITEM_VARY_Y);
1093                 maxw= MAX2(maxw, itemw);
1094                 toth += itemh;
1095                 totitem++;
1096         }
1097
1098         if(flow->number <= 0) {
1099                 /* auto compute number of columns, not very good */
1100                 if(maxw == 0)
1101                         return;
1102
1103                 totcol= MAX2(layout->emw/maxw, 1);
1104                 totcol= MIN2(totcol, totitem);
1105         }
1106         else
1107                 totcol= flow->number;
1108
1109         /* compute sizes */
1110         x= 0;
1111         y= 0;
1112         emy= 0;
1113         miny= 0;
1114
1115         w= layout->w;
1116         emh= toth/totcol;
1117
1118         /* create column per column */
1119         col= 0;
1120         for(item=template->items.first; item; item=item->next) {
1121                 ui_item_size(item, NULL, &itemh, UI_ITEM_VARY_Y);
1122                 itemw= ui_item_fit(1, x, totcol, w, (totcol-1)*style->columnspace, col == totcol-1, UI_FIT_EXPAND);
1123         
1124                 y -= itemh;
1125                 emy -= itemh;
1126                 ui_item_buts(layout, block, item, layout->x+x, layout->y+y, itemw, itemh);
1127                 y -= style->buttonspacey;
1128                 miny= MIN2(miny, y);
1129
1130                 /* decide to go to next one */
1131                 if(col < totcol-1 && emy <= -emh) {
1132                         x += itemw + style->columnspace;
1133                         y= 0;
1134                         col++;
1135                 }
1136         }
1137
1138         layout->y += miny;
1139 }
1140
1141 #if 0
1142 /* left-right layout, with buttons aligned on both sides */
1143 static void ui_layout_split(uiLayout *layout, uiBlock *block, uiTemplate *template)
1144 {
1145         uiItem *item;
1146         int tot=0, totw= 0, maxh= 0, itemw, itemh, lx, rx, w;
1147
1148         /* estimate total width of buttons */
1149         for(item=template->items.first; item; item=item->next) {
1150                 ui_item_size(item, &itemw, &itemh, UI_ITEM_VARY_Y);
1151                 totw += itemw;
1152                 maxh= MAX2(maxh, itemh);
1153                 tot++;
1154         }
1155
1156         if(totw == 0)
1157                 return;
1158         
1159         /* create buttons starting from left and right */
1160         lx= 0;
1161         rx= 0;
1162         w= layout->w - style->buttonspacex*(tot-1) + style->buttonspacex;
1163
1164         for(item=template->items.first; item; item=item->next) {
1165                 ui_item_size(item, &itemw, &itemh, UI_ITEM_VARY_Y);
1166
1167                 if(item->slot == UI_TSLOT_LR_LEFT) {
1168                         itemw= ui_item_fit(itemw, lx, totw, w, 0, 0);
1169                         ui_item_buts(layout, block, item, layout->x+lx, layout->y-itemh, itemw, itemh);
1170                         lx += itemw + style->buttonspacex;
1171                 }
1172                 else {
1173                         itemw= ui_item_fit(itemw, totw + rx, totw, w, 0, 0);
1174                         rx -= itemw + style->buttonspacex;
1175                         ui_item_buts(layout, block, item, layout->x+layout->w+rx, layout->y-itemh, itemw, itemh);
1176                 }
1177         }
1178
1179         layout->y -= maxh;
1180 }
1181 #endif
1182
1183 /* split in columns */
1184 static void ui_layout_split(const bContext *C, uiLayout *layout, uiBlock *block, uiTemplate *template)
1185 {
1186         uiStyle *style= layout->style;
1187         uiTemplateSplt *split= (uiTemplateSplt*)template;
1188         uiLayout *sublayout;
1189         int a, x, y, miny, w= layout->w, h= layout->h, splitw;
1190
1191         x= 0;
1192         y= 0;
1193         miny= layout->y;
1194
1195         for(a=0; a<split->number; a++) {
1196                 sublayout= split->sublayout[a];
1197
1198                 splitw= ui_item_fit(1, x, split->number, w, (split->number-1)*style->columnspace, a == split->number-1, UI_FIT_EXPAND);
1199                 sublayout->x= layout->x + x;
1200                 sublayout->w= splitw;
1201                 sublayout->y= layout->y;
1202                 sublayout->h= h;
1203
1204                 sublayout->emw= layout->emw/split->number;
1205                 sublayout->emh= layout->emh;
1206
1207                 /* do layout for elements in sublayout */
1208                 ui_layout_end(C, block, sublayout, NULL, &y);
1209                 miny= MIN2(y, miny);
1210
1211                 x += splitw + style->columnspace;
1212         }
1213
1214         layout->y= miny;
1215 }
1216
1217 /* element in a box layout */
1218 static void ui_layout_box(const bContext *C, uiLayout *layout, uiBlock *block, uiTemplate *template)
1219 {
1220         uiStyle *style= layout->style;
1221         uiTemplateBx *box= (uiTemplateBx*)template;
1222         int starty, startx, w= layout->w, h= layout->h;
1223
1224         startx= layout->x;
1225         starty= layout->y;
1226
1227         /* some extra padding */
1228         box->sublayout->x= layout->x + style->boxspace;
1229         box->sublayout->w= w - 2*style->boxspace;
1230         box->sublayout->y= layout->y - style->boxspace;
1231         box->sublayout->h= h;
1232
1233         box->sublayout->emw= layout->emw;
1234         box->sublayout->emh= layout->emh;
1235
1236         /* do layout for elements in sublayout */
1237         ui_layout_end(C, block, box->sublayout, NULL, &layout->y);
1238
1239         /* roundbox around the sublayout */
1240         uiDefBut(block, ROUNDBOX, 0, "", startx, layout->y, w, starty - layout->y, NULL, 7.0, 0.0, 3, 20, "");
1241 }
1242
1243 static void ui_layout_header_buttons(uiLayout *layout, uiBlock *block, uiTemplate *template)
1244 {
1245         uiItem *item;
1246         int itemw, itemh;
1247         
1248         uiBlockBeginAlign(block);
1249
1250         for(item=template->items.first; item; item=item->next) {
1251                 ui_item_size(item, &itemw, &itemh, UI_ITEM_VARY_X);
1252                 ui_item_buts(layout, block, item, layout->x, layout->y, itemw, itemh);
1253                 layout->x += itemw;
1254         }
1255
1256         uiBlockEndAlign(block);
1257 }
1258
1259 static void ui_layout_header(const bContext *C, uiLayout *layout, uiBlock *block, uiTemplate *template)
1260 {
1261         ScrArea *sa= CTX_wm_area(C);
1262
1263         layout->x= ED_area_header_standardbuttons(C, block, layout->y);
1264
1265         if((sa->flag & HEADER_NO_PULLDOWN)==0) {
1266                 uiBlockSetEmboss(block, UI_EMBOSSP);
1267                 ui_layout_header_buttons(layout, block, template);
1268         }
1269
1270         uiBlockSetEmboss(block, UI_EMBOSS);
1271 }
1272
1273 static void header_id_cb(bContext *C, void *arg_template, void *arg_event)
1274 {
1275         uiTemplateHeadID *idtemplate= (uiTemplateHeadID*)arg_template;
1276         PointerRNA idptr= RNA_property_pointer_get(&idtemplate->ptr, idtemplate->prop);
1277         ID *idtest, *id= idptr.data;
1278         ListBase *lb= wich_libbase(CTX_data_main(C), ID_TXT); // XXX
1279         int nr, event= GET_INT_FROM_POINTER(arg_event);
1280         
1281         if(event == UI_ID_BROWSE && idtemplate->browse == 32767)
1282                 event= UI_ID_ADD_NEW;
1283         else if(event == UI_ID_BROWSE && idtemplate->browse == 32766)
1284                 event= UI_ID_OPEN;
1285
1286         switch(event) {
1287                 case UI_ID_BROWSE: {
1288                         if(id==0) id= lb->first;
1289                         if(id==0) return;
1290
1291                         if(idtemplate->browse== -2) {
1292                                 /* XXX implement or find a replacement
1293                                  * activate_databrowse((ID *)G.buts->lockpoin, GS(id->name), 0, B_MESHBROWSE, &idtemplate->browse, do_global_buttons); */
1294                                 return;
1295                         }
1296                         if(idtemplate->browse < 0)
1297                                 return;
1298
1299                         for(idtest=lb->first, nr=1; idtest; idtest=idtest->next, nr++) {
1300                                 if(nr==idtemplate->browse) {
1301                                         if(id == idtest)
1302                                                 return;
1303
1304                                         id= idtest;
1305                                         RNA_id_pointer_create(id, &idptr);
1306                                         RNA_property_pointer_set(&idtemplate->ptr, idtemplate->prop, idptr);
1307                                         RNA_property_update(C, &idtemplate->ptr, idtemplate->prop);
1308                                         /* XXX */
1309
1310                                         break;
1311                                 }
1312                         }
1313                         break;
1314                 }
1315 #if 0
1316                 case UI_ID_DELETE:
1317                         id= NULL;
1318                         break;
1319                 case UI_ID_FAKE_USER:
1320                         if(id) {
1321                                 if(id->flag & LIB_FAKEUSER) id->us++;
1322                                 else id->us--;
1323                         }
1324                         else return;
1325                         break;
1326 #endif
1327                 case UI_ID_PIN:
1328                         break;
1329                 case UI_ID_ADD_NEW:
1330                         WM_operator_name_call(C, idtemplate->newop, WM_OP_INVOKE_REGION_WIN, NULL);
1331                         break;
1332                 case UI_ID_OPEN:
1333                         WM_operator_name_call(C, idtemplate->openop, WM_OP_INVOKE_REGION_WIN, NULL);
1334                         break;
1335 #if 0
1336                 case UI_ID_ALONE:
1337                         if(!id || id->us < 1)
1338                                 return;
1339                         break;
1340                 case UI_ID_LOCAL:
1341                         if(!id || id->us < 1)
1342                                 return;
1343                         break;
1344                 case UI_ID_AUTO_NAME:
1345                         break;
1346 #endif
1347         }
1348 }
1349
1350 static void ui_layout_header_id(const bContext *C, uiLayout *layout, uiBlock *block, uiTemplate *template)
1351 {
1352         uiTemplateHeadID *duptemplate, *idtemplate= (uiTemplateHeadID*)template;
1353         uiBut *but;
1354         PointerRNA idptr= RNA_property_pointer_get(&idtemplate->ptr, idtemplate->prop);
1355         ListBase *lb= wich_libbase(CTX_data_main(C), ID_TXT); // XXX
1356
1357         if(idtemplate->flag & UI_ID_BROWSE) {
1358                 char *extrastr, *str;
1359                 
1360                 if((idtemplate->flag & UI_ID_ADD_NEW) && (idtemplate->flag && UI_ID_OPEN))
1361                         extrastr= "OPEN NEW %x 32766 |ADD NEW %x 32767";
1362                 else if(idtemplate->flag & UI_ID_ADD_NEW)
1363                         extrastr= "ADD NEW %x 32767";
1364                 else if(idtemplate->flag & UI_ID_OPEN)
1365                         extrastr= "OPEN NEW %x 32766";
1366                 else
1367                         extrastr= NULL;
1368
1369                 duptemplate= MEM_dupallocN(idtemplate);
1370                 IDnames_to_pupstring(&str, NULL, extrastr, lb, idptr.data, &duptemplate->browse);
1371
1372                 but= uiDefButS(block, MENU, 0, str, layout->x, layout->y, EM_UNIT_X, EM_UNIT_Y, &duptemplate->browse, 0, 0, 0, 0, "Browse existing choices, or add new");
1373                 uiButSetNFunc(but, header_id_cb, duptemplate, SET_INT_IN_POINTER(UI_ID_BROWSE));
1374                 layout->x+= EM_UNIT_X;
1375         
1376                 MEM_freeN(str);
1377         }
1378
1379         /* text button with name */
1380         if(idptr.data) {
1381                 char name[64];
1382
1383                 text_idbutton(idptr.data, name);
1384                 but= uiDefButR(block, TEX, 0, name, layout->x, layout->y, EM_UNIT_X*6, EM_UNIT_Y, &idptr, "name", -1, 0, 0, -1, -1, NULL);
1385                 uiButSetNFunc(but, header_id_cb, MEM_dupallocN(idtemplate), SET_INT_IN_POINTER(UI_ID_RENAME));
1386                 layout->x += EM_UNIT_X*6;
1387
1388                 /* delete button */
1389                 if(idtemplate->flag & UI_ID_DELETE) {
1390                         but= uiDefIconButO(block, BUT, idtemplate->unlinkop, WM_OP_EXEC_REGION_WIN, ICON_X, layout->x, layout->y, EM_UNIT_X, EM_UNIT_Y, NULL);
1391                         layout->x += EM_UNIT_X;
1392                 }
1393         }
1394 }
1395
1396 void ui_template_free(uiTemplate *template)
1397 {
1398         uiItem *item;
1399         int a;
1400
1401         if(template->type == TEMPLATE_BOX) {
1402                 uiTemplateBx *box= (uiTemplateBx*)template;
1403                 ui_layout_free(box->sublayout);
1404         }
1405         if(template->type == TEMPLATE_SPLIT) {
1406                 uiTemplateSplt *split= (uiTemplateSplt*)template;
1407
1408                 for(a=0; a<split->number; a++)
1409                         ui_layout_free(split->sublayout[a]);
1410                 MEM_freeN(split->sublayout);
1411         }
1412
1413         for(item=template->items.first; item; item=item->next)
1414                 ui_item_free(item);
1415
1416         BLI_freelistN(&template->items);
1417 }
1418
1419 /* template create functions */
1420 void uiLayoutRow(uiLayout *layout)
1421 {
1422         uiTemplate *template;
1423
1424         template= MEM_callocN(sizeof(uiTemplate), "uiTemplate");
1425         template->type= TEMPLATE_ROW;
1426
1427         BLI_addtail(&layout->templates, template);
1428 }
1429
1430 void uiLayoutColumn(uiLayout *layout)
1431 {
1432         uiTemplate *template;
1433
1434         template= MEM_callocN(sizeof(uiTemplate), "uiTemplate");
1435         template->type= TEMPLATE_COLUMN;
1436
1437         BLI_addtail(&layout->templates, template);
1438 }
1439
1440 void uiLayoutColumnFlow(uiLayout *layout, int number)
1441 {
1442         uiTemplateFlow *flow;
1443
1444         flow= MEM_callocN(sizeof(uiTemplateFlow), "uiTemplateFlow");
1445         flow->template.type= TEMPLATE_COLUMN_FLOW;
1446         flow->number= number;
1447         BLI_addtail(&layout->templates, flow);
1448 }
1449
1450 uiLayout *uiLayoutBox(uiLayout *layout)
1451 {
1452         uiTemplateBx *box;
1453
1454         box= MEM_callocN(sizeof(uiTemplateBx), "uiTemplateBx");
1455         box->template.type= TEMPLATE_BOX;
1456         box->sublayout= uiLayoutBegin(layout->dir, layout->type, 0, 0, 0, 0, layout->style);
1457         BLI_addtail(&layout->templates, box);
1458
1459         return box->sublayout;
1460 }
1461
1462 void uiLayoutSplit(uiLayout *layout, int number, int lr)
1463 {
1464         uiTemplateSplt *split;
1465         int a;
1466
1467         split= MEM_callocN(sizeof(uiTemplateSplt), "uiTemplateSplt");
1468         split->template.type= TEMPLATE_SPLIT;
1469         split->number= number;
1470         split->lr= lr;
1471         split->sublayout= MEM_callocN(sizeof(uiLayout*)*number, "uiTemplateSpltSub");
1472
1473         for(a=0; a<number; a++)
1474                 split->sublayout[a]= uiLayoutBegin(layout->dir, layout->type, 0, 0, 0, 0, layout->style);
1475
1476         BLI_addtail(&layout->templates, split);
1477 }
1478
1479 uiLayout *uiLayoutSub(uiLayout *layout, int n)
1480 {
1481         uiTemplate *template= layout->templates.last;
1482
1483         if(template) {
1484                 switch(template->type) {
1485                         case TEMPLATE_SPLIT:
1486                                 if(n >= 0 && n < ((uiTemplateSplt*)template)->number)
1487                                         return ((uiTemplateSplt*)template)->sublayout[n];
1488                                 break;
1489                         case TEMPLATE_BOX:
1490                                 return ((uiTemplateBx*)template)->sublayout;
1491                                 break;
1492                         default:
1493                                 break;
1494                 }
1495         }
1496
1497         return NULL;
1498 }
1499
1500 void uiTemplateHeader(uiLayout *layout)
1501 {
1502         uiTemplate *template;
1503
1504         template= MEM_callocN(sizeof(uiTemplate), "uiTemplate");
1505         template->type= TEMPLATE_HEADER;
1506
1507         BLI_addtail(&layout->templates, template);
1508 }
1509
1510 void uiTemplateHeaderID(uiLayout *layout, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
1511 {
1512         uiTemplateHeadID *idtemplate;
1513         PropertyRNA *prop;
1514
1515         if(!ptr->data)
1516                 return;
1517
1518         prop= RNA_struct_find_property(ptr, propname);
1519
1520         if(!prop) {
1521                 printf("uiTemplateHeaderID: property not found: %s\n", propname);
1522                 return;
1523         }
1524
1525         idtemplate= MEM_callocN(sizeof(uiTemplateHeadID), "uiTemplateHeadID");
1526         idtemplate->template.type= TEMPLATE_HEADER_ID;
1527         idtemplate->ptr= *ptr;
1528         idtemplate->prop= prop;
1529         idtemplate->flag= UI_ID_BROWSE|UI_ID_RENAME;
1530
1531         if(newop) {
1532                 idtemplate->flag |= UI_ID_ADD_NEW;
1533                 idtemplate->newop= newop;
1534         }
1535         if(openop) {
1536                 idtemplate->flag |= UI_ID_OPEN;
1537                 idtemplate->openop= openop;
1538         }
1539         if(unlinkop) {
1540                 idtemplate->flag |= UI_ID_DELETE;
1541                 idtemplate->unlinkop= unlinkop;
1542         }
1543
1544         BLI_addtail(&layout->templates, idtemplate);
1545 }
1546
1547 void uiTemplateSlot(uiLayout *layout, int slot)
1548 {
1549         uiTemplate *template= layout->templates.last;
1550
1551         if(template)
1552                 template->slot= slot;
1553 }
1554
1555 /********************** Layout *******************/
1556
1557 static void ui_layout_init_items(const bContext *C, uiLayout *layout)
1558 {
1559         ARegion *ar= CTX_wm_region(C);
1560         MenuType *mt;
1561         uiTemplate *template;
1562         uiItem *item;
1563         uiItemMenu *menuitem;
1564         uiItemRNA *rnaitem;
1565         uiItemOp *opitem;
1566         PropertyType type;
1567
1568         for(template=layout->templates.first; template; template=template->next) {
1569                 for(item=template->items.first; item; item=item->next) {
1570                         /* initialize buttons names */
1571                         if(item->type == ITEM_MENU) {
1572                                 menuitem= (uiItemMenu*)item;
1573
1574                                 if(menuitem->menuname) {
1575                                         for(mt=ar->type->menutypes.first; mt; mt=mt->next) {
1576                                                 if(strcmp(menuitem->menuname, mt->idname) == 0) {
1577                                                         menuitem->arg= mt;
1578                                                         ui_item_name(item, mt->label);
1579                                                         break;
1580                                                 }
1581                                         }
1582                                 }
1583                         }
1584                         else if(item->type == ITEM_RNA_PROPERTY) {
1585                                 rnaitem= (uiItemRNA*)item;
1586                                 type= RNA_property_type(rnaitem->prop);
1587
1588                                 ui_item_name(item, (char*)RNA_property_ui_name(rnaitem->prop));
1589
1590                                 if(ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_ENUM))
1591                                         ui_item_name_add_colon(item);
1592                         }
1593                         else if(item->type == ITEM_OPERATOR) {
1594                                 opitem= (uiItemOp*)item;
1595                                 ui_item_name(item, opitem->ot->name);
1596                         }
1597
1598                         ui_item_name(item, "");
1599
1600                         /* initialize icons */
1601                         if(layout->type == UI_LAYOUT_MENU) {
1602                                 if(item->type == ITEM_RNA_PROPERTY) {
1603                                         rnaitem= (uiItemRNA*)item;
1604                                         type= RNA_property_type(rnaitem->prop);
1605
1606                                         if(type == PROP_BOOLEAN)
1607                                                 item->icon= (RNA_property_boolean_get(&rnaitem->ptr, rnaitem->prop))? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT;
1608                                         else if(type == PROP_ENUM && rnaitem->index == RNA_ENUM_VALUE)
1609                                                 item->icon= (RNA_property_enum_get(&rnaitem->ptr, rnaitem->prop) == rnaitem->value)? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT; 
1610                                 }
1611
1612                                 if(!item->icon)
1613                                         item->icon= ICON_BLANK1;
1614                         }
1615                 }
1616         }
1617 }
1618
1619 static void ui_layout_templates(const bContext *C, uiBlock *block, uiLayout *layout)
1620 {
1621         uiStyle *style= layout->style;
1622         uiTemplate *template;
1623
1624         ui_layout_init_items(C, layout);
1625
1626         if(layout->dir == UI_LAYOUT_HORIZONTAL) {
1627                 for(template=layout->templates.first; template; template=template->next) {
1628                         switch(template->type) {
1629                                 case TEMPLATE_HEADER:
1630                                         ui_layout_header(C, layout, block, template);
1631                                         break;
1632                                 case TEMPLATE_HEADER_ID:
1633                                         ui_layout_header_id(C, layout, block, template);
1634                                         break;
1635                                 default:
1636                                         ui_layout_header_buttons(layout, block, template);
1637                                         break;
1638                         }
1639
1640                         layout->x += style->templatespace;
1641                 }
1642         }
1643         else {
1644                 for(template=layout->templates.first; template; template=template->next) {
1645                         switch(template->type) {
1646                                 case TEMPLATE_ROW:
1647                                         ui_layout_row(layout, block, template);
1648                                         break;
1649                                 case TEMPLATE_COLUMN_FLOW:
1650                                         ui_layout_column_flow(layout, block, template);
1651                                         break;
1652                                 case TEMPLATE_SPLIT:
1653                                         ui_layout_split(C, layout, block, template);
1654                                         break;
1655                                 case TEMPLATE_BOX:
1656                                         ui_layout_box(C, layout, block, template);
1657                                         break;
1658                                 case TEMPLATE_COLUMN:
1659                                 default:
1660                                         ui_layout_column(layout, block, template);
1661                                         break;
1662                         }
1663
1664                         layout->y -= style->templatespace;
1665                 }
1666         }
1667 }
1668
1669 void ui_layout_end(const bContext *C, uiBlock *block, uiLayout *layout, int *x, int *y)
1670 {
1671         if(layout->handlefunc)
1672                 uiBlockSetButmFunc(block, layout->handlefunc, layout->argv);
1673
1674         ui_layout_templates(C, block, layout);
1675
1676         if(x) *x= layout->x;
1677         if(y) *y= layout->y;
1678         
1679 }
1680
1681 void ui_layout_free(uiLayout *layout)
1682 {
1683         uiTemplate *template;
1684
1685         for(template=layout->templates.first; template; template=template->next)
1686                 ui_template_free(template);
1687
1688         BLI_freelistN(&layout->templates);
1689         MEM_freeN(layout);
1690 }
1691
1692 uiLayout *uiLayoutBegin(int dir, int type, int x, int y, int size, int em, uiStyle *style)
1693 {
1694         uiLayout *layout;
1695
1696         layout= MEM_callocN(sizeof(uiLayout), "uiLayout");
1697         layout->opcontext= WM_OP_INVOKE_REGION_WIN;
1698         layout->dir= dir;
1699         layout->type= type;
1700         layout->x= x;
1701         layout->y= y;
1702         layout->style= style;
1703
1704         if(dir == UI_LAYOUT_HORIZONTAL) {
1705                 layout->h= size;
1706                 layout->emh= em*EM_UNIT_Y;
1707         }
1708         else {
1709                 layout->w= size;
1710                 layout->emw= em*EM_UNIT_X;
1711         }
1712
1713         return layout;
1714 }
1715
1716 void uiLayoutContext(uiLayout *layout, int opcontext)
1717 {
1718         layout->opcontext= opcontext;
1719 }
1720
1721 void uiLayoutFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
1722 {
1723         layout->handlefunc= handlefunc;
1724         layout->argv= argv;
1725 }
1726
1727 void uiLayoutEnd(const bContext *C, uiBlock *block, uiLayout *layout, int *x, int *y)
1728 {
1729         ui_layout_end(C, block, layout, x, y);
1730         ui_layout_free(layout);
1731 }
1732
1733 /************************ Utilities ************************/
1734
1735 void uiRegionPanelLayout(const bContext *C, ARegion *ar, int vertical, char *context)
1736 {
1737         uiStyle *style= U.uistyles.first;
1738         uiBlock *block;
1739         PanelType *pt;
1740         Panel *panel;
1741         float col[3];
1742         int xco, yco, x=PNL_DIST, y=-PNL_HEADER-PNL_DIST, w, em;
1743
1744         // XXX this only hides cruft
1745
1746         /* clear */
1747         UI_GetThemeColor3fv(TH_BACK, col);
1748         glClearColor(col[0], col[1], col[2], 0.0);
1749         glClear(GL_COLOR_BUFFER_BIT);
1750         
1751         /* set view2d view matrix for scrolling (without scrollers) */
1752         UI_view2d_view_ortho(C, &ar->v2d);
1753         
1754         uiBeginPanels(C, ar);
1755
1756         for(pt= ar->type->paneltypes.first; pt; pt= pt->next) {
1757                 if(context)
1758                         if(!pt->context || strcmp(context, pt->context) != 0)
1759                                 continue;
1760
1761                 if(pt->draw && (!pt->poll || pt->poll(C, pt))) {
1762                         block= uiBeginBlock(C, ar, pt->idname, UI_EMBOSS);
1763                         panel= uiBeginPanel(ar, block, pt);
1764
1765                         if(panel) {
1766                                 if(vertical) {
1767                                         w= (ar->type->minsizex)? ar->type->minsizex-12: block->aspect*ar->winx-12;
1768                                         em= (ar->type->minsizex)? 10: 20;
1769                                 }
1770                                 else {
1771                                         w= (ar->type->minsizex)? ar->type->minsizex-12: UI_PANEL_WIDTH-12;
1772                                         em= (ar->type->minsizex)? 10: 20;
1773                                 }
1774
1775                                 panel->type= pt;
1776                                 panel->layout= uiLayoutBegin(UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, PNL_SAFETY, 0, w-2*PNL_SAFETY, em, style);
1777
1778                                 pt->draw(C, panel);
1779
1780                                 uiLayoutEnd(C, block, panel->layout, &xco, &yco);
1781                                 panel->layout= NULL;
1782                                 uiEndPanel(block, w, -yco + 12);
1783                         }
1784                         else {
1785                                 w= PNL_HEADER;
1786                                 yco= PNL_HEADER;
1787                         }
1788
1789                         uiEndBlock(C, block);
1790
1791                         if(vertical)
1792                                 y += yco+PNL_DIST;
1793                         else
1794                                 x += w+PNL_DIST;
1795                 }
1796         }
1797
1798         uiEndPanels(C, ar);
1799         
1800         /* restore view matrix? */
1801         UI_view2d_view_restore(C);
1802 }
1803
1804 void uiRegionHeaderLayout(const bContext *C, ARegion *ar)
1805 {
1806         uiStyle *style= U.uistyles.first;
1807         uiBlock *block;
1808         uiLayout *layout;
1809         HeaderType *ht;
1810         Header header = {0};
1811         float col[3];
1812         int xco, yco;
1813
1814         // XXX this only hides cruft
1815         
1816         /* clear */
1817         if(ED_screen_area_active(C))
1818                 UI_GetThemeColor3fv(TH_HEADER, col);
1819         else
1820                 UI_GetThemeColor3fv(TH_HEADERDESEL, col);
1821         
1822         glClearColor(col[0], col[1], col[2], 0.0);
1823         glClear(GL_COLOR_BUFFER_BIT);
1824         
1825         /* set view2d view matrix for scrolling (without scrollers) */
1826         UI_view2d_view_ortho(C, &ar->v2d);
1827
1828         xco= 8;
1829         yco= 3;
1830
1831         /* draw all headers types */
1832         for(ht= ar->type->headertypes.first; ht; ht= ht->next) {
1833                 block= uiBeginBlock(C, ar, "header buttons", UI_EMBOSS);
1834                 layout= uiLayoutBegin(UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, xco, yco, 24, 1, style);
1835
1836                 if(ht->draw) {
1837                         header.type= ht;
1838                         header.layout= layout;
1839                         ht->draw(C, &header);
1840                 }
1841
1842                 uiLayoutEnd(C, block, layout, &xco, &yco);
1843                 uiEndBlock(C, block);
1844                 uiDrawBlock(C, block);
1845         }
1846
1847         /* always as last  */
1848         UI_view2d_totRect_set(&ar->v2d, xco+XIC+80, ar->v2d.tot.ymax-ar->v2d.tot.ymin);
1849
1850         /* restore view matrix? */
1851         UI_view2d_view_restore(C);
1852 }
1853