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