NLA-SoC: Merge from 2.5 branch 19863:20113
[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         ui_item_name(&menuitem->item, name);
891         menuitem->item.icon= icon;
892         menuitem->item.type= ITEM_MENU;
893         menuitem->item.slot= template->slot;
894
895         menuitem->func= func;
896
897         BLI_addtail(&template->items, menuitem);
898 }
899
900 typedef struct MenuItemLevel {
901         int opcontext;
902         char *opname;
903         char *propname;
904         PointerRNA rnapoin;
905 } MenuItemLevel;
906
907 static void menu_item_enum_opname_menu(bContext *C, uiLayout *layout, void *arg)
908 {
909         MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
910
911         uiLayoutContext(layout, WM_OP_EXEC_REGION_WIN);
912         uiItemsEnumO(layout, lvl->opname, lvl->propname);
913 }
914
915 void uiItemMenuEnumO(uiLayout *layout, char *name, int icon, char *opname, char *propname)
916 {
917         wmOperatorType *ot= WM_operatortype_find(opname);
918         uiTemplate *template= layout->templates.last;
919         uiItemMenu *menuitem;
920         MenuItemLevel *lvl;
921
922         if(!ot || !ot->srna) {
923                 ui_item_disabled(layout, opname);
924                 return;
925         }
926         if(!template)
927                 return;
928
929         menuitem= MEM_callocN(sizeof(uiItemMenu), "uiItemMenu");
930
931         if(!name)
932                 name= ot->name;
933
934         ui_item_name(&menuitem->item, name);
935         menuitem->item.icon= icon;
936         menuitem->item.type= ITEM_MENU;
937         menuitem->item.slot= template->slot;
938
939         lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
940         lvl->opname= opname;
941         lvl->propname= propname;
942         lvl->opcontext= layout->opcontext;
943
944         menuitem->func= menu_item_enum_opname_menu;
945         menuitem->argN= lvl;
946
947         BLI_addtail(&template->items, menuitem);
948 }
949
950 static void menu_item_enum_rna_menu(bContext *C, uiLayout *layout, void *arg)
951 {
952         MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
953
954         uiLayoutContext(layout, lvl->opcontext);
955         uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
956 }
957
958 void uiItemMenuEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname)
959 {
960         uiTemplate *template= layout->templates.last;
961         uiItemMenu *menuitem;
962         MenuItemLevel *lvl;
963         PropertyRNA *prop;
964         
965         if(!template)
966                 return;
967
968         prop= RNA_struct_find_property(ptr, propname);
969         if(!prop) {
970                 ui_item_disabled(layout, propname);
971                 return;
972         }
973
974         menuitem= MEM_callocN(sizeof(uiItemMenu), "uiItemMenu");
975
976         if(!name)
977                 name= (char*)RNA_property_ui_name(prop);
978
979         ui_item_name(&menuitem->item, name);
980         menuitem->item.icon= icon;
981         menuitem->item.type= ITEM_MENU;
982         menuitem->item.slot= template->slot;
983
984         lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
985         lvl->rnapoin= *ptr;
986         lvl->propname= propname;
987         lvl->opcontext= layout->opcontext;
988
989         menuitem->func= menu_item_enum_rna_menu;
990         menuitem->argN= lvl;
991
992         BLI_addtail(&template->items, menuitem);
993 }
994
995 /**************************** Template ***************************/
996
997 /* single row layout */
998 static void ui_layout_row(uiLayout *layout, uiBlock *block, uiTemplate *template)
999 {
1000         uiStyle *style= layout->style;
1001         uiItem *item;
1002         int tot=0, totw= 0, maxh= 0, itemw, itemh, x, w;
1003
1004         /* estimate total width of buttons */
1005         for(item=template->items.first; item; item=item->next) {
1006                 ui_item_size(item, &itemw, &itemh, UI_ITEM_VARY_Y);
1007                 totw += itemw;
1008                 maxh= MAX2(maxh, itemh);
1009                 tot++;
1010         }
1011
1012         if(totw == 0)
1013                 return;
1014         
1015         /* create buttons starting from left */
1016         x= 0;
1017         w= layout->w;
1018
1019         for(item=template->items.first; item; item=item->next) {
1020                 ui_item_size(item, &itemw, &itemh, UI_ITEM_VARY_Y);
1021                 itemw= ui_item_fit(itemw, x, totw, w, (tot-1)*style->buttonspacex, !item->next, UI_FIT_EXPAND);
1022
1023                 ui_item_buts(layout, block, item, layout->x+x, layout->y-itemh, itemw, itemh);
1024                 x += itemw+style->buttonspacex;
1025         }
1026
1027         layout->y -= maxh;
1028 }
1029
1030 /* multi-column layout */
1031 static void ui_layout_column(uiLayout *layout, uiBlock *block, uiTemplate *template)
1032 {
1033         uiStyle *style= layout->style;
1034         uiItem *item;
1035         int col, totcol= 0, x, y, miny, itemw, itemh, w;
1036
1037         /* compute number of columns */
1038         for(item=template->items.first; item; item=item->next)
1039                 totcol= MAX2(item->slot+1, totcol);
1040         
1041         if(totcol == 0)
1042                 return;
1043         
1044         x= 0;
1045         miny= 0;
1046         w= layout->w;
1047
1048         /* create column per column */
1049         for(col=0; col<totcol; col++) {
1050                 y= 0;
1051
1052                 itemw= ui_item_fit(1, x, totcol, w, (totcol-1)*style->columnspace, col == totcol-1, UI_FIT_EXPAND);
1053
1054                 for(item=template->items.first; item; item=item->next) {
1055                         if(item->slot != col)
1056                                 continue;
1057
1058                         ui_item_size(item, NULL, &itemh, UI_ITEM_VARY_Y);
1059
1060                         y -= itemh;
1061                         ui_item_buts(layout, block, item, layout->x+x, layout->y+y, itemw, itemh);
1062                         y -= style->buttonspacey;
1063                 }
1064
1065                 x += itemw + style->columnspace;
1066                 miny= MIN2(miny, y);
1067         }
1068
1069         layout->y += miny;
1070 }
1071
1072 /* multi-column layout, automatically flowing to the next */
1073 static void ui_layout_column_flow(uiLayout *layout, uiBlock *block, uiTemplate *template)
1074 {
1075         uiStyle *style= layout->style;
1076         uiTemplateFlow *flow= (uiTemplateFlow*)template;
1077         uiItem *item;
1078         int col, x, y, w, emh, emy, miny, itemw, itemh, maxw=0;
1079         int toth, totcol, totitem;
1080
1081         /* compute max needed width and total height */
1082         toth= 0;
1083         totitem= 0;
1084         for(item=template->items.first; item; item=item->next) {
1085                 ui_item_size(item, &itemw, &itemh, UI_ITEM_VARY_Y);
1086                 maxw= MAX2(maxw, itemw);
1087                 toth += itemh;
1088                 totitem++;
1089         }
1090
1091         if(flow->number <= 0) {
1092                 /* auto compute number of columns, not very good */
1093                 if(maxw == 0)
1094                         return;
1095
1096                 totcol= MAX2(layout->emw/maxw, 1);
1097                 totcol= MIN2(totcol, totitem);
1098         }
1099         else
1100                 totcol= flow->number;
1101
1102         /* compute sizes */
1103         x= 0;
1104         y= 0;
1105         emy= 0;
1106         miny= 0;
1107
1108         w= layout->w;
1109         emh= toth/totcol;
1110
1111         /* create column per column */
1112         col= 0;
1113         for(item=template->items.first; item; item=item->next) {
1114                 ui_item_size(item, NULL, &itemh, UI_ITEM_VARY_Y);
1115                 itemw= ui_item_fit(1, x, totcol, w, (totcol-1)*style->columnspace, col == totcol-1, UI_FIT_EXPAND);
1116         
1117                 y -= itemh;
1118                 emy -= itemh;
1119                 ui_item_buts(layout, block, item, layout->x+x, layout->y+y, itemw, itemh);
1120                 y -= style->buttonspacey;
1121                 miny= MIN2(miny, y);
1122
1123                 /* decide to go to next one */
1124                 if(col < totcol-1 && emy <= -emh) {
1125                         x += itemw + style->columnspace;
1126                         y= 0;
1127                         col++;
1128                 }
1129         }
1130
1131         layout->y += miny;
1132 }
1133
1134 #if 0
1135 /* left-right layout, with buttons aligned on both sides */
1136 static void ui_layout_split(uiLayout *layout, uiBlock *block, uiTemplate *template)
1137 {
1138         uiItem *item;
1139         int tot=0, totw= 0, maxh= 0, itemw, itemh, lx, rx, w;
1140
1141         /* estimate total width of buttons */
1142         for(item=template->items.first; item; item=item->next) {
1143                 ui_item_size(item, &itemw, &itemh, UI_ITEM_VARY_Y);
1144                 totw += itemw;
1145                 maxh= MAX2(maxh, itemh);
1146                 tot++;
1147         }
1148
1149         if(totw == 0)
1150                 return;
1151         
1152         /* create buttons starting from left and right */
1153         lx= 0;
1154         rx= 0;
1155         w= layout->w - style->buttonspacex*(tot-1) + style->buttonspacex;
1156
1157         for(item=template->items.first; item; item=item->next) {
1158                 ui_item_size(item, &itemw, &itemh, UI_ITEM_VARY_Y);
1159
1160                 if(item->slot == UI_TSLOT_LR_LEFT) {
1161                         itemw= ui_item_fit(itemw, lx, totw, w, 0, 0);
1162                         ui_item_buts(layout, block, item, layout->x+lx, layout->y-itemh, itemw, itemh);
1163                         lx += itemw + style->buttonspacex;
1164                 }
1165                 else {
1166                         itemw= ui_item_fit(itemw, totw + rx, totw, w, 0, 0);
1167                         rx -= itemw + style->buttonspacex;
1168                         ui_item_buts(layout, block, item, layout->x+layout->w+rx, layout->y-itemh, itemw, itemh);
1169                 }
1170         }
1171
1172         layout->y -= maxh;
1173 }
1174 #endif
1175
1176 /* split in columns */
1177 static void ui_layout_split(const bContext *C, uiLayout *layout, uiBlock *block, uiTemplate *template)
1178 {
1179         uiStyle *style= layout->style;
1180         uiTemplateSplt *split= (uiTemplateSplt*)template;
1181         uiLayout *sublayout;
1182         int a, x, y, miny, w= layout->w, h= layout->h, splitw;
1183
1184         x= 0;
1185         y= 0;
1186         miny= layout->y;
1187
1188         for(a=0; a<split->number; a++) {
1189                 sublayout= split->sublayout[a];
1190
1191                 splitw= ui_item_fit(1, x, split->number, w, (split->number-1)*style->columnspace, a == split->number-1, UI_FIT_EXPAND);
1192                 sublayout->x= layout->x + x;
1193                 sublayout->w= splitw;
1194                 sublayout->y= layout->y;
1195                 sublayout->h= h;
1196
1197                 sublayout->emw= layout->emw/split->number;
1198                 sublayout->emh= layout->emh;
1199
1200                 /* do layout for elements in sublayout */
1201                 ui_layout_end(C, block, sublayout, NULL, &y);
1202                 miny= MIN2(y, miny);
1203
1204                 x += splitw + style->columnspace;
1205         }
1206
1207         layout->y= miny;
1208 }
1209
1210 /* element in a box layout */
1211 static void ui_layout_box(const bContext *C, uiLayout *layout, uiBlock *block, uiTemplate *template)
1212 {
1213         uiStyle *style= layout->style;
1214         uiTemplateBx *box= (uiTemplateBx*)template;
1215         int starty, startx, w= layout->w, h= layout->h;
1216
1217         startx= layout->x;
1218         starty= layout->y;
1219
1220         /* some extra padding */
1221         box->sublayout->x= layout->x + style->boxspace;
1222         box->sublayout->w= w - 2*style->boxspace;
1223         box->sublayout->y= layout->y - style->boxspace;
1224         box->sublayout->h= h;
1225
1226         box->sublayout->emw= layout->emw;
1227         box->sublayout->emh= layout->emh;
1228
1229         /* do layout for elements in sublayout */
1230         ui_layout_end(C, block, box->sublayout, NULL, &layout->y);
1231
1232         /* roundbox around the sublayout */
1233         uiDefBut(block, ROUNDBOX, 0, "", startx, layout->y, w, starty - layout->y, NULL, 7.0, 0.0, 3, 20, "");
1234 }
1235
1236 static void ui_layout_header_buttons(uiLayout *layout, uiBlock *block, uiTemplate *template)
1237 {
1238         uiItem *item;
1239         int itemw, itemh;
1240         
1241         uiBlockBeginAlign(block);
1242
1243         for(item=template->items.first; item; item=item->next) {
1244                 ui_item_size(item, &itemw, &itemh, UI_ITEM_VARY_X);
1245                 ui_item_buts(layout, block, item, layout->x, layout->y, itemw, itemh);
1246                 layout->x += itemw;
1247         }
1248
1249         uiBlockEndAlign(block);
1250 }
1251
1252 static void ui_layout_header(const bContext *C, uiLayout *layout, uiBlock *block, uiTemplate *template)
1253 {
1254         ScrArea *sa= CTX_wm_area(C);
1255
1256         layout->x= ED_area_header_standardbuttons(C, block, layout->y);
1257
1258         if((sa->flag & HEADER_NO_PULLDOWN)==0) {
1259                 uiBlockSetEmboss(block, UI_EMBOSSP);
1260                 ui_layout_header_buttons(layout, block, template);
1261         }
1262
1263         uiBlockSetEmboss(block, UI_EMBOSS);
1264 }
1265
1266 static void header_id_cb(bContext *C, void *arg_template, void *arg_event)
1267 {
1268         uiTemplateHeadID *idtemplate= (uiTemplateHeadID*)arg_template;
1269         PointerRNA idptr= RNA_property_pointer_get(&idtemplate->ptr, idtemplate->prop);
1270         ID *idtest, *id= idptr.data;
1271         ListBase *lb= wich_libbase(CTX_data_main(C), ID_TXT); // XXX
1272         int nr, event= GET_INT_FROM_POINTER(arg_event);
1273         
1274         if(event == UI_ID_BROWSE && idtemplate->browse == 32767)
1275                 event= UI_ID_ADD_NEW;
1276         else if(event == UI_ID_BROWSE && idtemplate->browse == 32766)
1277                 event= UI_ID_OPEN;
1278
1279         switch(event) {
1280                 case UI_ID_BROWSE: {
1281                         if(id==0) id= lb->first;
1282                         if(id==0) return;
1283
1284                         if(idtemplate->browse== -2) {
1285                                 /* XXX implement or find a replacement
1286                                  * activate_databrowse((ID *)G.buts->lockpoin, GS(id->name), 0, B_MESHBROWSE, &idtemplate->browse, do_global_buttons); */
1287                                 return;
1288                         }
1289                         if(idtemplate->browse < 0)
1290                                 return;
1291
1292                         for(idtest=lb->first, nr=1; idtest; idtest=idtest->next, nr++) {
1293                                 if(nr==idtemplate->browse) {
1294                                         if(id == idtest)
1295                                                 return;
1296
1297                                         id= idtest;
1298                                         RNA_id_pointer_create(id, &idptr);
1299                                         RNA_property_pointer_set(&idtemplate->ptr, idtemplate->prop, idptr);
1300                                         RNA_property_update(C, &idtemplate->ptr, idtemplate->prop);
1301                                         /* XXX */
1302
1303                                         break;
1304                                 }
1305                         }
1306                         break;
1307                 }
1308 #if 0
1309                 case UI_ID_DELETE:
1310                         id= NULL;
1311                         break;
1312                 case UI_ID_FAKE_USER:
1313                         if(id) {
1314                                 if(id->flag & LIB_FAKEUSER) id->us++;
1315                                 else id->us--;
1316                         }
1317                         else return;
1318                         break;
1319 #endif
1320                 case UI_ID_PIN:
1321                         break;
1322                 case UI_ID_ADD_NEW:
1323                         WM_operator_name_call(C, idtemplate->newop, WM_OP_INVOKE_REGION_WIN, NULL);
1324                         break;
1325                 case UI_ID_OPEN:
1326                         WM_operator_name_call(C, idtemplate->openop, WM_OP_INVOKE_REGION_WIN, NULL);
1327                         break;
1328 #if 0
1329                 case UI_ID_ALONE:
1330                         if(!id || id->us < 1)
1331                                 return;
1332                         break;
1333                 case UI_ID_LOCAL:
1334                         if(!id || id->us < 1)
1335                                 return;
1336                         break;
1337                 case UI_ID_AUTO_NAME:
1338                         break;
1339 #endif
1340         }
1341 }
1342
1343 static void ui_layout_header_id(const bContext *C, uiLayout *layout, uiBlock *block, uiTemplate *template)
1344 {
1345         uiTemplateHeadID *duptemplate, *idtemplate= (uiTemplateHeadID*)template;
1346         uiBut *but;
1347         PointerRNA idptr= RNA_property_pointer_get(&idtemplate->ptr, idtemplate->prop);
1348         ListBase *lb= wich_libbase(CTX_data_main(C), ID_TXT); // XXX
1349
1350         if(idtemplate->flag & UI_ID_BROWSE) {
1351                 char *extrastr, *str;
1352                 
1353                 if((idtemplate->flag & UI_ID_ADD_NEW) && (idtemplate->flag && UI_ID_OPEN))
1354                         extrastr= "OPEN NEW %x 32766 |ADD NEW %x 32767";
1355                 else if(idtemplate->flag & UI_ID_ADD_NEW)
1356                         extrastr= "ADD NEW %x 32767";
1357                 else if(idtemplate->flag & UI_ID_OPEN)
1358                         extrastr= "OPEN NEW %x 32766";
1359                 else
1360                         extrastr= NULL;
1361
1362                 duptemplate= MEM_dupallocN(idtemplate);
1363                 IDnames_to_pupstring(&str, NULL, extrastr, lb, idptr.data, &duptemplate->browse);
1364
1365                 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");
1366                 uiButSetNFunc(but, header_id_cb, duptemplate, SET_INT_IN_POINTER(UI_ID_BROWSE));
1367                 layout->x+= EM_UNIT_X;
1368         
1369                 MEM_freeN(str);
1370         }
1371
1372         /* text button with name */
1373         if(idptr.data) {
1374                 char name[64];
1375
1376                 text_idbutton(idptr.data, name);
1377                 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);
1378                 uiButSetNFunc(but, header_id_cb, MEM_dupallocN(idtemplate), SET_INT_IN_POINTER(UI_ID_RENAME));
1379                 layout->x += EM_UNIT_X*6;
1380
1381                 /* delete button */
1382                 if(idtemplate->flag & UI_ID_DELETE) {
1383                         but= uiDefIconButO(block, BUT, idtemplate->unlinkop, WM_OP_EXEC_REGION_WIN, ICON_X, layout->x, layout->y, EM_UNIT_X, EM_UNIT_Y, NULL);
1384                         layout->x += EM_UNIT_X;
1385                 }
1386         }
1387 }
1388
1389 void ui_template_free(uiTemplate *template)
1390 {
1391         uiItem *item;
1392         int a;
1393
1394         if(template->type == TEMPLATE_BOX) {
1395                 uiTemplateBx *box= (uiTemplateBx*)template;
1396                 ui_layout_free(box->sublayout);
1397         }
1398         if(template->type == TEMPLATE_SPLIT) {
1399                 uiTemplateSplt *split= (uiTemplateSplt*)template;
1400
1401                 for(a=0; a<split->number; a++)
1402                         ui_layout_free(split->sublayout[a]);
1403                 MEM_freeN(split->sublayout);
1404         }
1405
1406         for(item=template->items.first; item; item=item->next)
1407                 ui_item_free(item);
1408
1409         BLI_freelistN(&template->items);
1410 }
1411
1412 /* template create functions */
1413 void uiLayoutRow(uiLayout *layout)
1414 {
1415         uiTemplate *template;
1416
1417         template= MEM_callocN(sizeof(uiTemplate), "uiTemplate");
1418         template->type= TEMPLATE_ROW;
1419
1420         BLI_addtail(&layout->templates, template);
1421 }
1422
1423 void uiLayoutColumn(uiLayout *layout)
1424 {
1425         uiTemplate *template;
1426
1427         template= MEM_callocN(sizeof(uiTemplate), "uiTemplate");
1428         template->type= TEMPLATE_COLUMN;
1429
1430         BLI_addtail(&layout->templates, template);
1431 }
1432
1433 void uiLayoutColumnFlow(uiLayout *layout, int number)
1434 {
1435         uiTemplateFlow *flow;
1436
1437         flow= MEM_callocN(sizeof(uiTemplateFlow), "uiTemplateFlow");
1438         flow->template.type= TEMPLATE_COLUMN_FLOW;
1439         flow->number= number;
1440         BLI_addtail(&layout->templates, flow);
1441 }
1442
1443 uiLayout *uiLayoutBox(uiLayout *layout)
1444 {
1445         uiTemplateBx *box;
1446
1447         box= MEM_callocN(sizeof(uiTemplateBx), "uiTemplateBx");
1448         box->template.type= TEMPLATE_BOX;
1449         box->sublayout= uiLayoutBegin(layout->dir, layout->type, 0, 0, 0, 0, layout->style);
1450         BLI_addtail(&layout->templates, box);
1451
1452         return box->sublayout;
1453 }
1454
1455 void uiLayoutSplit(uiLayout *layout, int number, int lr)
1456 {
1457         uiTemplateSplt *split;
1458         int a;
1459
1460         split= MEM_callocN(sizeof(uiTemplateSplt), "uiTemplateSplt");
1461         split->template.type= TEMPLATE_SPLIT;
1462         split->number= number;
1463         split->lr= lr;
1464         split->sublayout= MEM_callocN(sizeof(uiLayout*)*number, "uiTemplateSpltSub");
1465
1466         for(a=0; a<number; a++)
1467                 split->sublayout[a]= uiLayoutBegin(layout->dir, layout->type, 0, 0, 0, 0, layout->style);
1468
1469         BLI_addtail(&layout->templates, split);
1470 }
1471
1472 uiLayout *uiLayoutSub(uiLayout *layout, int n)
1473 {
1474         uiTemplate *template= layout->templates.last;
1475
1476         if(template) {
1477                 switch(template->type) {
1478                         case TEMPLATE_SPLIT:
1479                                 if(n >= 0 && n < ((uiTemplateSplt*)template)->number)
1480                                         return ((uiTemplateSplt*)template)->sublayout[n];
1481                                 break;
1482                         case TEMPLATE_BOX:
1483                                 return ((uiTemplateBx*)template)->sublayout;
1484                                 break;
1485                         default:
1486                                 break;
1487                 }
1488         }
1489
1490         return NULL;
1491 }
1492
1493 void uiTemplateHeader(uiLayout *layout)
1494 {
1495         uiTemplate *template;
1496
1497         template= MEM_callocN(sizeof(uiTemplate), "uiTemplate");
1498         template->type= TEMPLATE_HEADER;
1499
1500         BLI_addtail(&layout->templates, template);
1501 }
1502
1503 void uiTemplateHeaderID(uiLayout *layout, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
1504 {
1505         uiTemplateHeadID *idtemplate;
1506         PropertyRNA *prop;
1507
1508         if(!ptr->data)
1509                 return;
1510
1511         prop= RNA_struct_find_property(ptr, propname);
1512
1513         if(!prop) {
1514                 printf("uiTemplateHeaderID: property not found: %s\n", propname);
1515                 return;
1516         }
1517
1518         idtemplate= MEM_callocN(sizeof(uiTemplateHeadID), "uiTemplateHeadID");
1519         idtemplate->template.type= TEMPLATE_HEADER_ID;
1520         idtemplate->ptr= *ptr;
1521         idtemplate->prop= prop;
1522         idtemplate->flag= UI_ID_BROWSE|UI_ID_RENAME;
1523
1524         if(newop) {
1525                 idtemplate->flag |= UI_ID_ADD_NEW;
1526                 idtemplate->newop= newop;
1527         }
1528         if(openop) {
1529                 idtemplate->flag |= UI_ID_OPEN;
1530                 idtemplate->openop= openop;
1531         }
1532         if(unlinkop) {
1533                 idtemplate->flag |= UI_ID_DELETE;
1534                 idtemplate->unlinkop= unlinkop;
1535         }
1536
1537         BLI_addtail(&layout->templates, idtemplate);
1538 }
1539
1540 void uiTemplateSlot(uiLayout *layout, int slot)
1541 {
1542         uiTemplate *template= layout->templates.last;
1543
1544         if(template)
1545                 template->slot= slot;
1546 }
1547
1548 /********************** Layout *******************/
1549
1550 static void ui_layout_init_items(const bContext *C, uiLayout *layout)
1551 {
1552         ARegion *ar= CTX_wm_region(C);
1553         MenuType *mt;
1554         uiTemplate *template;
1555         uiItem *item;
1556         uiItemMenu *menuitem;
1557         uiItemRNA *rnaitem;
1558         uiItemOp *opitem;
1559         PropertyType type;
1560
1561         for(template=layout->templates.first; template; template=template->next) {
1562                 for(item=template->items.first; item; item=item->next) {
1563                         /* initialize buttons names */
1564                         if(item->type == ITEM_MENU) {
1565                                 menuitem= (uiItemMenu*)item;
1566
1567                                 if(menuitem->menuname) {
1568                                         for(mt=ar->type->menutypes.first; mt; mt=mt->next) {
1569                                                 if(strcmp(menuitem->menuname, mt->idname) == 0) {
1570                                                         menuitem->arg= mt;
1571                                                         ui_item_name(item, mt->label);
1572                                                         break;
1573                                                 }
1574                                         }
1575                                 }
1576                         }
1577                         else if(item->type == ITEM_RNA_PROPERTY) {
1578                                 rnaitem= (uiItemRNA*)item;
1579                                 type= RNA_property_type(rnaitem->prop);
1580
1581                                 ui_item_name(item, (char*)RNA_property_ui_name(rnaitem->prop));
1582
1583                                 if(ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_ENUM))
1584                                         ui_item_name_add_colon(item);
1585                         }
1586                         else if(item->type == ITEM_OPERATOR) {
1587                                 opitem= (uiItemOp*)item;
1588                                 ui_item_name(item, opitem->ot->name);
1589                         }
1590
1591                         ui_item_name(item, "");
1592
1593                         /* initialize icons */
1594                         if(layout->type == UI_LAYOUT_MENU) {
1595                                 if(item->type == ITEM_RNA_PROPERTY) {
1596                                         rnaitem= (uiItemRNA*)item;
1597                                         type= RNA_property_type(rnaitem->prop);
1598
1599                                         if(type == PROP_BOOLEAN)
1600                                                 item->icon= (RNA_property_boolean_get(&rnaitem->ptr, rnaitem->prop))? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT;
1601                                         else if(type == PROP_ENUM && rnaitem->index == RNA_ENUM_VALUE)
1602                                                 item->icon= (RNA_property_enum_get(&rnaitem->ptr, rnaitem->prop) == rnaitem->value)? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT; 
1603                                 }
1604
1605                                 if(!item->icon)
1606                                         item->icon= ICON_BLANK1;
1607                         }
1608                 }
1609         }
1610 }
1611
1612 static void ui_layout_templates(const bContext *C, uiBlock *block, uiLayout *layout)
1613 {
1614         uiStyle *style= layout->style;
1615         uiTemplate *template;
1616
1617         ui_layout_init_items(C, layout);
1618
1619         if(layout->dir == UI_LAYOUT_HORIZONTAL) {
1620                 for(template=layout->templates.first; template; template=template->next) {
1621                         switch(template->type) {
1622                                 case TEMPLATE_HEADER:
1623                                         ui_layout_header(C, layout, block, template);
1624                                         break;
1625                                 case TEMPLATE_HEADER_ID:
1626                                         ui_layout_header_id(C, layout, block, template);
1627                                         break;
1628                                 default:
1629                                         ui_layout_header_buttons(layout, block, template);
1630                                         break;
1631                         }
1632
1633                         layout->x += style->templatespace;
1634                 }
1635         }
1636         else {
1637                 for(template=layout->templates.first; template; template=template->next) {
1638                         switch(template->type) {
1639                                 case TEMPLATE_ROW:
1640                                         ui_layout_row(layout, block, template);
1641                                         break;
1642                                 case TEMPLATE_COLUMN_FLOW:
1643                                         ui_layout_column_flow(layout, block, template);
1644                                         break;
1645                                 case TEMPLATE_SPLIT:
1646                                         ui_layout_split(C, layout, block, template);
1647                                         break;
1648                                 case TEMPLATE_BOX:
1649                                         ui_layout_box(C, layout, block, template);
1650                                         break;
1651                                 case TEMPLATE_COLUMN:
1652                                 default:
1653                                         ui_layout_column(layout, block, template);
1654                                         break;
1655                         }
1656
1657                         layout->y -= style->templatespace;
1658                 }
1659         }
1660 }
1661
1662 void ui_layout_end(const bContext *C, uiBlock *block, uiLayout *layout, int *x, int *y)
1663 {
1664         if(layout->handlefunc)
1665                 uiBlockSetButmFunc(block, layout->handlefunc, layout->argv);
1666
1667         ui_layout_templates(C, block, layout);
1668
1669         if(x) *x= layout->x;
1670         if(y) *y= layout->y;
1671         
1672 }
1673
1674 void ui_layout_free(uiLayout *layout)
1675 {
1676         uiTemplate *template;
1677
1678         for(template=layout->templates.first; template; template=template->next)
1679                 ui_template_free(template);
1680
1681         BLI_freelistN(&layout->templates);
1682         MEM_freeN(layout);
1683 }
1684
1685 uiLayout *uiLayoutBegin(int dir, int type, int x, int y, int size, int em, uiStyle *style)
1686 {
1687         uiLayout *layout;
1688
1689         layout= MEM_callocN(sizeof(uiLayout), "uiLayout");
1690         layout->opcontext= WM_OP_INVOKE_REGION_WIN;
1691         layout->dir= dir;
1692         layout->type= type;
1693         layout->x= x;
1694         layout->y= y;
1695         layout->style= style;
1696
1697         if(dir == UI_LAYOUT_HORIZONTAL) {
1698                 layout->h= size;
1699                 layout->emh= em*EM_UNIT_Y;
1700         }
1701         else {
1702                 layout->w= size;
1703                 layout->emw= em*EM_UNIT_X;
1704         }
1705
1706         return layout;
1707 }
1708
1709 void uiLayoutContext(uiLayout *layout, int opcontext)
1710 {
1711         layout->opcontext= opcontext;
1712 }
1713
1714 void uiLayoutFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
1715 {
1716         layout->handlefunc= handlefunc;
1717         layout->argv= argv;
1718 }
1719
1720 void uiLayoutEnd(const bContext *C, uiBlock *block, uiLayout *layout, int *x, int *y)
1721 {
1722         ui_layout_end(C, block, layout, x, y);
1723         ui_layout_free(layout);
1724 }
1725
1726 /************************ Utilities ************************/
1727
1728 void uiRegionPanelLayout(const bContext *C, ARegion *ar, int vertical, char *context)
1729 {
1730         uiStyle *style= U.uistyles.first;
1731         uiBlock *block;
1732         PanelType *pt;
1733         Panel *panel;
1734         float col[3];
1735         int xco, yco, x=PNL_DIST, y=-PNL_HEADER-PNL_DIST, w, em;
1736
1737         // XXX this only hides cruft
1738
1739         /* clear */
1740         UI_GetThemeColor3fv(TH_BACK, col);
1741         glClearColor(col[0], col[1], col[2], 0.0);
1742         glClear(GL_COLOR_BUFFER_BIT);
1743         
1744         /* set view2d view matrix for scrolling (without scrollers) */
1745         UI_view2d_view_ortho(C, &ar->v2d);
1746         
1747         uiBeginPanels(C, ar);
1748
1749         for(pt= ar->type->paneltypes.first; pt; pt= pt->next) {
1750                 if(context)
1751                         if(!pt->context || strcmp(context, pt->context) != 0)
1752                                 continue;
1753
1754                 if(pt->draw && (!pt->poll || pt->poll(C, pt))) {
1755                         block= uiBeginBlock(C, ar, pt->idname, UI_EMBOSS);
1756                         panel= uiBeginPanel(ar, block, pt);
1757
1758                         if(panel) {
1759                                 if(vertical) {
1760                                         w= (ar->type->minsizex)? ar->type->minsizex-12: block->aspect*ar->winx-12;
1761                                         em= (ar->type->minsizex)? 10: 20;
1762                                 }
1763                                 else {
1764                                         w= (ar->type->minsizex)? ar->type->minsizex-12: UI_PANEL_WIDTH-12;
1765                                         em= (ar->type->minsizex)? 10: 20;
1766                                 }
1767
1768                                 panel->type= pt;
1769                                 panel->layout= uiLayoutBegin(UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, PNL_SAFETY, 0, w-2*PNL_SAFETY, em, style);
1770
1771                                 pt->draw(C, panel);
1772
1773                                 uiLayoutEnd(C, block, panel->layout, &xco, &yco);
1774                                 panel->layout= NULL;
1775                                 uiEndPanel(block, w, -yco + 12);
1776                         }
1777                         else {
1778                                 w= PNL_HEADER;
1779                                 yco= PNL_HEADER;
1780                         }
1781
1782                         uiEndBlock(C, block);
1783
1784                         if(vertical)
1785                                 y += yco+PNL_DIST;
1786                         else
1787                                 x += w+PNL_DIST;
1788                 }
1789         }
1790
1791         uiEndPanels(C, ar);
1792         
1793         /* restore view matrix? */
1794         UI_view2d_view_restore(C);
1795 }
1796
1797 void uiRegionHeaderLayout(const bContext *C, ARegion *ar)
1798 {
1799         uiStyle *style= U.uistyles.first;
1800         uiBlock *block;
1801         uiLayout *layout;
1802         HeaderType *ht;
1803         Header header = {0};
1804         float col[3];
1805         int xco, yco;
1806
1807         // XXX this only hides cruft
1808         
1809         /* clear */
1810         if(ED_screen_area_active(C))
1811                 UI_GetThemeColor3fv(TH_HEADER, col);
1812         else
1813                 UI_GetThemeColor3fv(TH_HEADERDESEL, col);
1814         
1815         glClearColor(col[0], col[1], col[2], 0.0);
1816         glClear(GL_COLOR_BUFFER_BIT);
1817         
1818         /* set view2d view matrix for scrolling (without scrollers) */
1819         UI_view2d_view_ortho(C, &ar->v2d);
1820
1821         xco= 8;
1822         yco= 3;
1823
1824         /* draw all headers types */
1825         for(ht= ar->type->headertypes.first; ht; ht= ht->next) {
1826                 block= uiBeginBlock(C, ar, "header buttons", UI_EMBOSS);
1827                 layout= uiLayoutBegin(UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, xco, yco, 24, 1, style);
1828
1829                 if(ht->draw) {
1830                         header.type= ht;
1831                         header.layout= layout;
1832                         ht->draw(C, &header);
1833                 }
1834
1835                 uiLayoutEnd(C, block, layout, &xco, &yco);
1836                 uiEndBlock(C, block);
1837                 uiDrawBlock(C, block);
1838         }
1839
1840         /* always as last  */
1841         UI_view2d_totRect_set(&ar->v2d, xco+XIC+80, ar->v2d.tot.ymax-ar->v2d.tot.ymin);
1842
1843         /* restore view matrix? */
1844         UI_view2d_view_restore(C);
1845 }
1846