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