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