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