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
16 #include "BKE_context.h"
17 #include "BKE_global.h"
18 #include "BKE_idprop.h"
19 #include "BKE_utildefines.h"
20
21 #include "RNA_access.h"
22
23 #include "UI_interface.h"
24 #include "UI_resources.h"
25 #include "UI_view2d.h"
26
27 #include "ED_util.h"
28 #include "ED_types.h"
29 #include "ED_screen.h"
30
31 #include "WM_api.h"
32 #include "WM_types.h"
33
34 /************************ Structs and Defines *************************/
35
36 #define COLUMN_SPACE    5
37 #define TEMPLATE_SPACE  5
38 #define STACK_SPACE             5
39 #define BUTTON_SPACE_X  5
40 #define BUTTON_SPACE_Y  2
41
42 #define RNA_NO_INDEX    -1
43
44 /* Item */
45
46 typedef enum uiItemType {
47         ITEM_OPERATOR,
48         ITEM_RNA_PROPERTY,
49         ITEM_MENU,
50         ITEM_LABEL
51 } uiItemType;
52
53 enum uiItemFlag {
54         ITEM_ICON,
55         ITEM_TEXT
56 };
57
58 typedef struct uiItem {
59         struct uiItem *next, *prev;
60         uiItemType type;
61         int slot;
62
63         const char *name;
64         int icon;
65 } uiItem;
66
67 typedef struct uiItemRNA {
68         uiItem item;
69
70         PointerRNA ptr;
71         PropertyRNA *prop;
72         int index;
73 } uiItemRNA;
74
75 typedef struct uiItemOp {
76         uiItem item;
77
78         wmOperatorType *ot;
79         IDProperty *properties;
80         int context;
81 } uiItemOp;
82
83 typedef struct uiItemLMenu {
84         uiItem item;
85
86         uiMenuCreateFunc func;
87 } uiItemLMenu;
88
89 /* Template */
90
91 typedef enum uiTemplateType {
92         TEMPLATE_COLUMN,
93         TEMPLATE_LR,
94         TEMPLATE_STACK,
95
96         TEMPLATE_HEADER_MENUS,
97         TEMPLATE_HEADER_BUTTONS,
98         TEMPLATE_HEADER_ID
99 } uiTemplateType;
100
101 typedef struct uiTemplate {
102         struct uiTemplate *next, *prev;
103         uiTemplateType type;
104
105         ListBase items;
106         int color;
107 } uiTemplate;
108
109 typedef struct uiTemplateStck {
110         uiTemplate template;
111         uiLayout *sublayout;
112 } uiTemplateStck;
113
114 typedef struct uiTemplateHeadID {
115         uiTemplate template;
116
117         PointerRNA ptr;
118         char *propname;
119         int flag;
120         uiIDPoinFunc func;
121 } uiTemplateHeadID;
122
123 /* Layout */
124
125 struct uiLayout {
126         ListBase templates;
127         int opcontext;
128         int dir;
129         int x, y, w, h;
130 };
131
132 void ui_layout_free(uiLayout *layout);
133 void ui_layout_end(const bContext *C, uiBlock *block, uiLayout *layout, int *x, int *y);
134
135 /************************** Item ***************************/
136
137 static int ui_item_fit(int item, int all, int available)
138 {
139         if(all > available)
140                 return (item*available)/all;
141         
142         return all;
143 }
144
145 /* create buttons for an item with an RNA array */
146 static void ui_item_array(uiBlock *block, uiItemRNA *rnaitem, int len, int x, int y, int w, int h)
147 {
148         PropertyType type;
149         PropertySubType subtype;
150         char *name;
151         int a;
152
153         /* retrieve type and subtype */
154         type= RNA_property_type(&rnaitem->ptr, rnaitem->prop);
155         subtype= RNA_property_subtype(&rnaitem->ptr, rnaitem->prop);
156
157         /* create label */
158         if(rnaitem->item.name)
159                 name= (char*)rnaitem->item.name;
160         else
161                 name= (char*)RNA_property_ui_name(&rnaitem->ptr, rnaitem->prop);
162
163         if(strcmp(name, "") != 0)
164                 uiDefBut(block, LABEL, 0, name, x, y + h - YIC, w, YIC, NULL, 0.0, 0.0, 0, 0, "");
165
166         /* create buttons */
167         uiBlockBeginAlign(block);
168
169         if(type == PROP_BOOLEAN && len == 20) {
170                 /* special check for layer layout */
171                 int butw, buth;
172
173                 butw= ui_item_fit(XIC, XIC*10 + BUTTON_SPACE_X, w);
174                 buth= MIN2(YIC, butw);
175
176                 y += 2*(YIC - buth);
177
178                 uiBlockBeginAlign(block);
179                 for(a=0; a<5; a++)
180                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a, "", ICON_BLANK1, x + butw*a, y+buth, butw, buth);
181                 for(a=0; a<5; a++)
182                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a+10, "", ICON_BLANK1, x + butw*a, y, butw, buth);
183                 uiBlockEndAlign(block);
184
185                 x += 5*butw + BUTTON_SPACE_X;
186
187                 uiBlockBeginAlign(block);
188                 for(a=0; a<5; a++)
189                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a+5, "", ICON_BLANK1, x + butw*a, y+buth, butw, buth);
190                 for(a=0; a<5; a++)
191                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a+15, "", ICON_BLANK1, x + butw*a, y, butw, buth);
192                 uiBlockEndAlign(block);
193         }
194         else if(subtype == PROP_MATRIX) {
195                 /* matrix layout */
196                 int row, col;
197
198                 len= ceil(sqrt(len));
199
200                 h /= len;
201                 w /= len;
202
203                 // XXX test
204                 for(a=0; a<len; a++) {
205                         col= a%len;
206                         row= a/len;
207
208                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a, "", 0, x + w*col, y+(row-a-1)*YIC, w, YIC);
209                 }
210         }
211         else if(len <= 4 && ELEM3(subtype, PROP_ROTATION, PROP_VECTOR, PROP_COLOR)) {
212                 /* layout for known array subtypes */
213                 static char vectoritem[4]= {'X', 'Y', 'Z', 'W'};
214                 static char quatitem[4]= {'W', 'X', 'Y', 'Z'};
215                 static char coloritem[4]= {'R', 'G', 'B', 'A'};
216                 char str[3];
217
218                 for(a=0; a<len; a++) {
219                         if(len == 4 && subtype == PROP_ROTATION)
220                                 str[0]= quatitem[a];
221                         else if(subtype == PROP_VECTOR || subtype == PROP_ROTATION)
222                                 str[0]= vectoritem[a];
223                         else
224                                 str[0]= coloritem[a];
225
226                         if(type == PROP_BOOLEAN) {
227                                 str[1]= '\0';
228                         }
229                         else {
230                                 str[1]= ':';
231                                 str[2]= '\0';
232                         }
233
234                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a, str, 0, x, y+(len-a-1)*YIC, w, YIC);
235                 }
236         }
237         else {
238                 /* default array layout */
239                 for(a=0; a<len; a++)
240                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, a, "", 0, x, y+(len-a-1)*YIC, w, YIC);
241         }
242
243         uiBlockEndAlign(block);
244 }
245
246 /* create lable + button for RNA property */
247 static void ui_item_with_label(uiBlock *block, uiItemRNA *rnaitem, int x, int y, int w, int h)
248 {
249         char *name;
250         int butw;
251
252         if(rnaitem->item.name)
253                 name= (char*)rnaitem->item.name;
254         else
255                 name= (char*)RNA_property_ui_name(&rnaitem->ptr, rnaitem->prop);
256         
257         if(strcmp(name, "") != 0) {
258                 butw= GetButStringLength(name);
259                 uiDefBut(block, LABEL, 0, name, x, y, butw, h, NULL, 0.0, 0.0, 0, 0, "");
260
261                 x += butw;
262                 w -= butw;
263         }
264
265         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, rnaitem->index, "", rnaitem->item.icon, x, y, w, h);
266 }
267
268 /* create buttons for an arbitrary item */
269 static void ui_item_buts(uiBlock *block, uiItem *item, int x, int y, int w, int h)
270 {
271         if(item->type == ITEM_RNA_PROPERTY) {
272                 /* RNA property */
273                 uiItemRNA *rnaitem= (uiItemRNA*)item;
274                 PropertyType type;
275                 int len;
276                 
277                 /* retrieve info */
278                 type= RNA_property_type(&rnaitem->ptr, rnaitem->prop);
279                 len= RNA_property_array_length(&rnaitem->ptr, rnaitem->prop);
280
281                 /* array property */
282                 if(rnaitem->index == RNA_NO_INDEX && len > 0)
283                         ui_item_array(block, rnaitem, len, x, y, w, h);
284                 /* property with separate label */
285                 else if(type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER)
286                         ui_item_with_label(block, rnaitem, x, y, w, h);
287                 /* single button */
288                 else
289                         uiDefAutoButR(block, &rnaitem->ptr, rnaitem->prop, rnaitem->index, (char*)item->name, item->icon, x, y, w, h);
290         }
291         else if(item->type == ITEM_OPERATOR) {
292                 /* operator */
293                 uiItemOp *opitem= (uiItemOp*)item;
294
295                 if(item->icon && item->name)
296                         uiDefIconTextButO(block, BUT, opitem->ot->idname, opitem->context, item->icon, (char*)item->name, x, y, w, h, NULL);
297                 else if(item->icon)
298                         uiDefIconButO(block, BUT, opitem->ot->idname, opitem->context, item->icon, x, y, w, h, NULL);
299                 /* text only */
300                 else
301                         uiDefButO(block, BUT, opitem->ot->idname, opitem->context, (char*)item->name, x, y, w, h, NULL);
302         }
303         else if(item->type == ITEM_MENU) {
304                 /* menu */
305                 uiItemLMenu *menuitem= (uiItemLMenu*)item;
306
307                 uiDefMenuBut(block, menuitem->func, NULL, (char*)item->name, x, y-2, w-3, h+4, "");
308         }
309         else if(item->type == ITEM_LABEL) {
310                 /* label */
311
312                 if(item->icon && item->name)
313                         uiDefIconTextBut(block, LABEL, 0, item->icon, (char*)item->name, x, y, w, h, NULL, 0.0, 0.0, 0, 0, "");
314                 else if(item->icon)
315                         uiDefIconBut(block, LABEL, 0, item->icon, x, y, w, h, NULL, 0.0, 0.0, 0, 0, "");
316                 else if((char*)item->name)
317                         uiDefBut(block, LABEL, 0, (char*)item->name, x, y, w, h, NULL, 0.0, 0.0, 0, 0, "");
318         }
319         else {
320                 /* separator */
321                 uiDefBut(block, SEPR, 0, "", x, y, w, h, NULL, 0.0, 0.0, 0, 0, "");
322         }
323 }
324
325 /* estimated size of text + icon */
326 static int ui_text_icon_width(const char *name, int icon)
327 {
328         if(icon && name && strcmp(name, "") == 0)
329                 return XIC; /* icon only */
330         else if(icon && name)
331                 return XIC + GetButStringLength((char*)name); /* icon + text */
332         else if(name)
333                 return GetButStringLength((char*)name); /* text only */
334         else
335                 return 0;
336 }
337
338 /* estimated size of an item */
339 static void ui_item_size(uiItem *item, int *r_w, int *r_h)
340 {
341         const char *name;
342         int w, h;
343
344         if(item->type == ITEM_RNA_PROPERTY) {
345                 /* RNA property */
346                 uiItemRNA *rnaitem= (uiItemRNA*)item;
347                 PropertyType type;
348                 PropertySubType subtype;
349                 int len;
350
351                 name= item->name;
352                 if(!name)
353                         name= RNA_property_ui_name(&rnaitem->ptr, rnaitem->prop);
354
355                 w= ui_text_icon_width(name, item->icon);
356                 h= YIC;
357
358                 /* arbitrary extended width by type */
359                 type= RNA_property_type(&rnaitem->ptr, rnaitem->prop);
360                 subtype= RNA_property_subtype(&rnaitem->ptr, rnaitem->prop);
361                 len= RNA_property_array_length(&rnaitem->ptr, rnaitem->prop);
362
363                 if(type == PROP_BOOLEAN && !item->icon)
364                         w += XIC;
365                 else if(type == PROP_INT || type == PROP_FLOAT)
366                         w += 2*XIC;
367                 else if(type == PROP_STRING)
368                         w += 8*XIC;
369
370                 /* increase height for arrays */
371                 if(rnaitem->index == RNA_NO_INDEX && len > 0) {
372                         if(name && strcmp(name, "") == 0 && item->icon == 0)
373                                 h= 0;
374
375                         if(type == PROP_BOOLEAN && len == 20)
376                                 h += 2*YIC;
377                         else if(subtype == PROP_MATRIX)
378                                 h += ceil(sqrt(len))*YIC;
379                         else
380                                 h += len*YIC;
381                 }
382         }
383         else if(item->type == ITEM_OPERATOR) {
384                 /* operator */
385                 uiItemOp *opitem= (uiItemOp*)item;
386
387                 name= item->name;
388                 if(!name)
389                         name= opitem->ot->name;
390
391                 w= ui_text_icon_width(name, item->icon);
392                 h= YIC;
393         }
394         else {
395                 /* other */
396                 w= ui_text_icon_width(item->name, item->icon);
397                 h= YIC;
398         }
399
400         if(r_w) *r_w= w;
401         if(r_h) *r_h= h;
402 }
403
404 static void ui_item_free(uiItem *item)
405 {
406         if(item->type == ITEM_OPERATOR) {
407                 uiItemOp *opitem= (uiItemOp*)item;
408
409                 if(opitem->properties) {
410                         IDP_FreeProperty(opitem->properties);
411                         MEM_freeN(opitem->properties);
412                 }
413         }
414 }
415
416 /* operator items */
417 void uiItemFullO(uiLayout *layout, int slot, const char *name, int icon, char *idname, IDProperty *properties, int context)
418 {
419         uiTemplate *template= layout->templates.last;
420         wmOperatorType *ot= WM_operatortype_find(idname);
421         uiItemOp *opitem;
422
423         if(!ot)
424                 return;
425
426         opitem= MEM_callocN(sizeof(uiItemOp), "uiItemOp");
427
428         opitem->item.name= name;
429         opitem->item.icon= icon;
430         opitem->item.type= ITEM_OPERATOR;
431         opitem->item.slot= slot;
432
433         opitem->ot= ot;
434         opitem->properties= properties;
435         opitem->context= context;
436
437         BLI_addtail(&template->items, opitem);
438 }
439
440 void uiItemEnumO(uiLayout *layout, int slot, const char *name, int icon, char *opname, char *propname, int value)
441 {
442         PointerRNA ptr;
443
444         WM_operator_properties_create(&ptr, opname);
445         RNA_enum_set(&ptr, propname, value);
446
447         uiItemFullO(layout, slot, name, icon, opname, ptr.data, layout->opcontext);
448 }
449
450 void uiItemsEnumO(uiLayout *layout, int slot, char *opname, char *propname)
451 {
452         wmOperatorType *ot= WM_operatortype_find(opname);
453         PointerRNA ptr;
454         PropertyRNA *prop;
455
456         if(!ot || !ot->srna)
457                 return;
458
459         RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
460         prop= RNA_struct_find_property(&ptr, propname);
461
462         if(prop && RNA_property_type(&ptr, prop) == PROP_ENUM) {
463                 const EnumPropertyItem *item;
464                 int totitem, i;
465
466                 RNA_property_enum_items(&ptr, prop, &item, &totitem);
467
468                 for(i=0; i<totitem; i++)
469                         uiItemEnumO(layout, slot, "", 0, opname, propname, item[i].value);
470         }
471 }
472
473 void uiItemBooleanO(uiLayout *layout, int slot, const char *name, int icon, char *opname, char *propname, int value)
474 {
475         PointerRNA ptr;
476
477         WM_operator_properties_create(&ptr, opname);
478         RNA_boolean_set(&ptr, propname, value);
479
480         uiItemFullO(layout, slot, name, icon, opname, ptr.data, layout->opcontext);
481 }
482
483 void uiItemIntO(uiLayout *layout, int slot, const char *name, int icon, char *opname, char *propname, int value)
484 {
485         PointerRNA ptr;
486
487         WM_operator_properties_create(&ptr, opname);
488         RNA_int_set(&ptr, propname, value);
489
490         uiItemFullO(layout, slot, name, icon, opname, ptr.data, layout->opcontext);
491 }
492
493 void uiItemFloatO(uiLayout *layout, int slot, const char *name, int icon, char *opname, char *propname, float value)
494 {
495         PointerRNA ptr;
496
497         WM_operator_properties_create(&ptr, opname);
498         RNA_float_set(&ptr, propname, value);
499
500         uiItemFullO(layout, slot, name, icon, opname, ptr.data, layout->opcontext);
501 }
502
503 void uiItemStringO(uiLayout *layout, int slot, const char *name, int icon, char *opname, char *propname, char *value)
504 {
505         PointerRNA ptr;
506
507         WM_operator_properties_create(&ptr, opname);
508         RNA_string_set(&ptr, propname, value);
509
510         uiItemFullO(layout, slot, name, icon, opname, ptr.data, layout->opcontext);
511 }
512
513 void uiItemO(uiLayout *layout, int slot, const char *name, int icon, char *opname)
514 {
515         uiItemFullO(layout, slot, name, icon, opname, NULL, layout->opcontext);
516 }
517
518 /* RNA property items */
519 void uiItemFullR(uiLayout *layout, int slot, const char *name, int icon, PointerRNA *ptr, char *propname, int index)
520 {
521         uiTemplate *template= layout->templates.last;
522         PropertyRNA *prop;
523         uiItemRNA *rnaitem;
524         
525         prop= RNA_struct_find_property(ptr, propname);
526         if(!prop)
527                 return;
528         
529         rnaitem= MEM_callocN(sizeof(uiItemRNA), "uiItemRNA");
530
531         rnaitem->item.name= name;
532         rnaitem->item.icon= icon;
533         rnaitem->item.type= ITEM_RNA_PROPERTY;
534         rnaitem->item.slot= slot;
535
536         rnaitem->ptr= *ptr;
537         rnaitem->prop= prop;
538         rnaitem->index= index;
539
540         BLI_addtail(&template->items, rnaitem);
541 }
542
543 void uiItemR(uiLayout *layout, int slot, const char *name, int icon, PointerRNA *ptr, char *propname)
544 {
545         uiItemFullR(layout, slot, name, icon, ptr, propname, RNA_NO_INDEX);
546 }
547
548 /* menu item */
549 void uiItemMenu(uiLayout *layout, int slot, const char *name, int icon, uiMenuCreateFunc func)
550 {
551         uiTemplate *template= layout->templates.last;
552         uiItemLMenu *menuitem= MEM_callocN(sizeof(uiItemLMenu), "uiItemLMenu");
553
554         menuitem->item.name= name;
555         menuitem->item.icon= icon;
556         menuitem->item.type= ITEM_MENU;
557         menuitem->item.slot= slot;
558
559         menuitem->func= func;
560
561         BLI_addtail(&template->items, menuitem);
562 }
563
564 /* label item */
565 void uiItemLabel(uiLayout *layout, int slot, const char *name, int icon)
566 {
567         uiTemplate *template= layout->templates.last;
568         uiItem *item= MEM_callocN(sizeof(uiItem), "uiItem");
569
570         item->name= name;
571         item->icon= icon;
572         item->type= ITEM_LABEL;
573         item->slot= slot;
574
575         BLI_addtail(&template->items, item);
576 }
577
578 /**************************** Template ***************************/
579
580 /* multi-column layout */
581 static void ui_layout_column(uiLayout *layout, uiBlock *block, uiTemplate *template, int *x, int *y, int w, int h)
582 {
583         uiItem *item;
584         int col, totcol= 0, colx, coly, colw, miny, itemw, itemh;
585
586         /* compute number of columns */
587         for(item=template->items.first; item; item=item->next)
588                 totcol= MAX2(item->slot+1, totcol);
589         
590         if(totcol == 0)
591                 return;
592         
593         colx= *x;
594         colw= (w - (totcol-1)*COLUMN_SPACE)/totcol;
595         miny= *y;
596
597         /* create column per column */
598         for(col=0; col<totcol; col++) {
599                 coly= *y;
600
601                 for(item=template->items.first; item; item=item->next) {
602                         if(item->slot != col)
603                                 continue;
604
605                         ui_item_size(item, &itemw, &itemh);
606
607                         coly -= itemh + BUTTON_SPACE_Y;
608                         ui_item_buts(block, item, colx, coly, colw, itemh);
609                 }
610
611                 colx += colw + COLUMN_SPACE;
612                 miny= MIN2(miny, coly);
613         }
614
615         *y= miny;
616 }
617
618 /* left-right layout, with buttons aligned on both sides */
619 static void ui_layout_lr(uiLayout *layout, uiBlock *block, uiTemplate *template, int *x, int *y, int w, int h)
620 {
621         uiItem *item;
622         int totw= 0, maxh= 0, itemw, itemh, leftx, rightx;
623
624         /* estimate total width of buttons */
625         for(item=template->items.first; item; item=item->next) {
626                 ui_item_size(item, &itemw, &itemh);
627                 totw += itemw;
628                 maxh= MAX2(maxh, itemh);
629         }
630
631         if(totw == 0)
632                 return;
633         
634         /* create buttons starting from left and right */
635         leftx= *x;
636         rightx= *x + w;
637
638         for(item=template->items.first; item; item=item->next) {
639                 ui_item_size(item, &itemw, &itemh);
640                 itemw= ui_item_fit(itemw, totw+BUTTON_SPACE_X, w);
641
642                 if(item->slot == UI_TSLOT_LR_LEFT) {
643                         ui_item_buts(block, item, leftx, *y-itemh, itemw, itemh);
644                         leftx += itemw;
645                 }
646                 else {
647                         rightx -= itemw;
648                         ui_item_buts(block, item, rightx, *y-itemh, itemw, itemh);
649                 }
650         }
651
652         *y -= maxh;
653 }
654
655 /* element in a stack layout */
656 static void ui_layout_stack(const bContext *C, uiLayout *layout, uiBlock *block, uiTemplate *template, int *x, int *y, int w, int h)
657 {
658         uiTemplateStck *stack= (uiTemplateStck*)template;
659         int starty, startx;
660
661         startx= *x;
662         starty= *y;
663
664         /* some extra padding */
665         stack->sublayout->x= *x + STACK_SPACE;
666         stack->sublayout->w= w - 2*STACK_SPACE;
667         stack->sublayout->y= *y - STACK_SPACE;
668         stack->sublayout->h= h;
669
670         /* do layout for elements in sublayout */
671         ui_layout_end(C, block, stack->sublayout, NULL, y);
672
673         /* roundbox around the sublayout */
674         uiDefBut(block, ROUNDBOX, 0, "", startx, *y, w, starty - *y, NULL, 7.0, 0.0, 3, 20, "");
675 }
676
677 static void ui_layout_header_buttons(uiLayout *layout, uiBlock *block, uiTemplate *template, int *x, int *y, int w, int h)
678 {
679         uiItem *item;
680         int itemw, itemh;
681         
682         uiBlockBeginAlign(block);
683
684         for(item=template->items.first; item; item=item->next) {
685                 ui_item_size(item, &itemw, &itemh);
686                 ui_item_buts(block, item, *x, *y, itemw, itemh);
687                 *x += itemw;
688         }
689
690         uiBlockEndAlign(block);
691 }
692
693 static void ui_layout_header_menus(const bContext *C, uiLayout *layout, uiBlock *block, uiTemplate *template, int *x, int *y, int w, int h)
694 {
695         ScrArea *sa= CTX_wm_area(C);
696
697         *x= ED_area_header_standardbuttons(C, block, *y);
698
699         if((sa->flag & HEADER_NO_PULLDOWN)==0) {
700                 uiBlockSetEmboss(block, UI_EMBOSSP);
701                 ui_layout_header_buttons(layout, block, template, x, y, w, h);
702         }
703
704         uiBlockSetEmboss(block, UI_EMBOSS);
705 }
706
707 static void ui_layout_header_id(const bContext *C, uiLayout *layout, uiBlock *block, uiTemplate *template, int *x, int *y, int w, int h)
708 {
709         uiTemplateHeadID *idtemplate= (uiTemplateHeadID*)template;
710         PointerRNA idptr;
711
712         idptr= RNA_pointer_get(&idtemplate->ptr, idtemplate->propname);
713
714         *x= uiDefIDPoinButs(block, CTX_data_main(C), NULL, (ID*)idptr.data, ID_TXT, NULL, *x, *y,
715                 idtemplate->func, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_ADD_NEW|UI_ID_OPEN|UI_ID_DELETE);
716 }
717
718 void ui_template_free(uiTemplate *template)
719 {
720         uiItem *item;
721
722         if(template->type == TEMPLATE_STACK) {
723                 uiTemplateStck *stack= (uiTemplateStck*)template;
724                 ui_layout_free(stack->sublayout);
725         }
726
727         for(item=template->items.first; item; item=item->next)
728                 ui_item_free(item);
729
730         BLI_freelistN(&template->items);
731 }
732
733 /* template create functions */
734 void uiTemplateColumn(uiLayout *layout)
735 {
736         uiTemplate *template;
737
738         template= MEM_callocN(sizeof(uiTemplate), "uiTemplate");
739         template->type= TEMPLATE_COLUMN;
740
741         BLI_addtail(&layout->templates, template);
742 }
743
744
745 void uiTemplateLeftRight(uiLayout *layout)
746 {
747         uiTemplate *template;
748
749         template= MEM_callocN(sizeof(uiTemplate), "uiTemplate");
750         template->type= TEMPLATE_LR;
751
752         BLI_addtail(&layout->templates, template);
753 }
754
755 uiLayout *uiTemplateStack(uiLayout *layout)
756 {
757         uiTemplateStck *stack;
758
759         stack= MEM_callocN(sizeof(uiTemplateStck), "uiTemplateStck");
760         stack->template.type= TEMPLATE_STACK;
761         stack->sublayout= uiLayoutBegin(layout->dir, 0, 0, 0, 0);
762         BLI_addtail(&layout->templates, stack);
763
764         return stack->sublayout;
765 }
766
767 void uiTemplateHeaderMenus(uiLayout *layout)
768 {
769         uiTemplate *template;
770
771         template= MEM_callocN(sizeof(uiTemplate), "uiTemplate");
772         template->type= TEMPLATE_HEADER_MENUS;
773
774         BLI_addtail(&layout->templates, template);
775 }
776
777 void uiTemplateHeaderButtons(uiLayout *layout)
778 {
779         uiTemplate *template;
780
781         template= MEM_callocN(sizeof(uiTemplate), "uiTemplate");
782         template->type= TEMPLATE_HEADER_BUTTONS;
783
784         BLI_addtail(&layout->templates, template);
785 }
786
787 void uiTemplateHeaderID(uiLayout *layout, PointerRNA *ptr, char *propname, int flag, uiIDPoinFunc func)
788 {
789         uiTemplateHeadID *idtemplate;
790
791         idtemplate= MEM_callocN(sizeof(uiTemplateHeadID), "uiTemplateHeadID");
792         idtemplate->template.type= TEMPLATE_HEADER_ID;
793         idtemplate->ptr= *ptr;
794         idtemplate->propname= propname;
795         idtemplate->flag= flag;
796         idtemplate->func= func;
797
798         BLI_addtail(&layout->templates, idtemplate);
799 }
800
801 void uiTemplateSetColor(uiLayout *layout, int color)
802 {
803         uiTemplate *template= layout->templates.last;
804
805         template->color= color;
806 }
807
808 /********************** Layout *******************/
809
810 static void ui_layout_templates(const bContext *C, uiBlock *block, uiLayout *layout)
811 {
812         uiTemplate *template;
813         int oldcolor= 0;
814
815         for(template=layout->templates.first; template; template=template->next) {
816                 if(template->color) {
817                         oldcolor= uiBlockGetCol(block);
818                         uiBlockSetCol(block, template->color);
819                 }
820
821                 switch(template->type) {
822                         case TEMPLATE_COLUMN:
823                                 ui_layout_column(layout, block, template, &layout->x, &layout->y, layout->w, layout->h);
824                                 break;
825                         case TEMPLATE_LR:
826                                 ui_layout_lr(layout, block, template, &layout->x, &layout->y, layout->w, layout->h);
827                                 break;
828                         case TEMPLATE_STACK:
829                                 ui_layout_stack(C, layout, block, template, &layout->x, &layout->y, layout->w, layout->h);
830                                 break;
831                         case TEMPLATE_HEADER_MENUS:
832                                 ui_layout_header_menus(C, layout, block, template, &layout->x, &layout->y, layout->w, layout->h);
833                                 break;
834                         case TEMPLATE_HEADER_BUTTONS:
835                                 ui_layout_header_buttons(layout, block, template, &layout->x, &layout->y, layout->w, layout->h);
836                                 break;
837                         case TEMPLATE_HEADER_ID:
838                                 ui_layout_header_id(C, layout, block, template, &layout->x, &layout->y, layout->w, layout->h);
839                                 break;
840                 }
841
842                 if(template->color)
843                         uiBlockSetCol(block, oldcolor);
844
845                 if(layout->dir == UI_LAYOUT_HORIZONTAL)
846                         layout->x += TEMPLATE_SPACE;
847                 else
848                         layout->y -= TEMPLATE_SPACE;
849         }
850 }
851
852 void ui_layout_end(const bContext *C, uiBlock *block, uiLayout *layout, int *x, int *y)
853 {
854         ui_layout_templates(C, block, layout);
855
856         if(x) *x= layout->x;
857         if(y) *y= layout->y;
858         
859         /* XXX temp, migration flag for drawing code */
860         uiBlockSetFlag(block, UI_BLOCK_2_50);
861 }
862
863 void ui_layout_free(uiLayout *layout)
864 {
865         uiTemplate *template;
866
867         for(template=layout->templates.first; template; template=template->next)
868                 ui_template_free(template);
869
870         BLI_freelistN(&layout->templates);
871         MEM_freeN(layout);
872 }
873
874 uiLayout *uiLayoutBegin(int dir, int x, int y, int w, int h)
875 {
876         uiLayout *layout;
877
878         layout= MEM_callocN(sizeof(uiLayout), "uiLayout");
879         layout->opcontext= WM_OP_INVOKE_REGION_WIN;
880         layout->dir= dir;
881         layout->x= x;
882         layout->y= y;
883         layout->w= w;
884         layout->h= h;
885
886         return layout;
887 }
888
889 void uiLayoutContext(uiLayout *layout, int opcontext)
890 {
891         layout->opcontext= opcontext;
892 }
893
894 void uiLayoutEnd(const bContext *C, uiBlock *block, uiLayout *layout, int *x, int *y)
895 {
896         ui_layout_end(C, block, layout, x, y);
897         ui_layout_free(layout);
898 }
899
900 /* Utilities */
901
902 static void ui_panel_layout(const bContext *C, ARegion *ar, char *blockname, char *panelname, char *tabname, uiPanelCreateFunc func, int order, int w)
903 {
904         uiBlock *block;
905         uiLayout *layout;
906         int xco, yco, x, y;
907
908         // XXX this only hides cruft
909
910         x= 20*order;
911         y= -100*(order+1);
912
913         block= uiBeginBlock(C, ar, blockname, UI_EMBOSS, UI_HELV);
914         if(uiNewPanel(C, ar, block, panelname, tabname, x, y, w, 0)==0) return;
915         
916         layout= uiLayoutBegin(UI_LAYOUT_VERTICAL, x, y, w, 0);
917
918         func(C, layout);
919
920         uiLayoutEnd(C, block, layout, &xco, &yco);
921         uiEndBlock(C, block);
922
923         uiNewPanelHeight(block, y - yco + 6);
924 }
925
926 void uiCompactPanelLayout(const bContext *C, ARegion *ar, char *blockname, char *panelname, char *tabname, uiPanelCreateFunc func, int order)
927 {
928         ui_panel_layout(C, ar, blockname, panelname, tabname, func, order, UI_COMPACT_PANEL_WIDTH-22);
929 }
930
931 void uiPanelLayout(const bContext *C, ARegion *ar, char *blockname, char *panelname, char *tabname, uiPanelCreateFunc func, int order)
932 {
933         ui_panel_layout(C, ar, blockname, panelname, tabname, func, order, UI_PANEL_WIDTH-22);
934 }
935
936 void uiHeaderLayout(const bContext *C, ARegion *ar, uiHeaderCreateFunc func)
937 {
938         uiBlock *block;
939         uiLayout *layout;
940         int xco, yco;
941
942         // XXX this only hides cruft
943
944         block= uiBeginBlock(C, ar, "header buttons", UI_EMBOSS, UI_HELV);
945         layout= uiLayoutBegin(UI_LAYOUT_HORIZONTAL, 8, 3, 0, 24);
946
947         func(C, layout);
948
949         uiLayoutEnd(C, block, layout, &xco, &yco);
950         uiEndBlock(C, block);
951         uiDrawBlock(C, block);
952
953         /* always as last  */
954         UI_view2d_totRect_set(&ar->v2d, xco+XIC+80, ar->v2d.tot.ymax-ar->v2d.tot.ymin);
955 }
956
957