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