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