Drag and drop 2.5 integration! Finally, slashdot regulars can use
[blender.git] / source / blender / editors / interface / interface_templates.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * Contributor(s): Blender Foundation 2009.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include <stdlib.h>
26 #include <stddef.h>
27 #include <string.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "DNA_color_types.h"
32 #include "DNA_scene_types.h"
33 #include "DNA_screen_types.h"
34
35 #include "BLI_string.h"
36
37 #include "BKE_colortools.h"
38 #include "BKE_context.h"
39 #include "BKE_icons.h"
40 #include "BKE_global.h"
41 #include "BKE_library.h"
42 #include "BKE_main.h"
43 #include "BKE_utildefines.h"
44
45 #include "ED_screen.h"
46 #include "ED_render.h"
47
48 #include "RNA_access.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52
53 #include "UI_interface.h"
54 #include "UI_resources.h"
55 #include "interface_intern.h"
56
57 void ui_template_fix_linking()
58 {
59 }
60
61 /********************** Header Template *************************/
62
63 void uiTemplateHeader(uiLayout *layout, bContext *C, int menus)
64 {
65         uiBlock *block;
66
67         block= uiLayoutAbsoluteBlock(layout);
68         if(menus) ED_area_header_standardbuttons(C, block, 0);
69         else ED_area_header_switchbutton(C, block, 0);
70 }
71
72 /********************** DopeSheet Filter Template *************************/
73
74 void uiTemplateDopeSheetFilter(uiLayout *layout, bContext *C, PointerRNA *ptr)
75 {
76         Main *mainptr= CTX_data_main(C);
77         ScrArea *sa= CTX_wm_area(C);
78         uiLayout *row= layout;
79         short nlaActive= ((sa) && (sa->spacetype==SPACE_NLA));
80
81         /* more 'generic' filtering options */
82         if (nlaActive)
83                 row= uiLayoutRow(layout, 1);
84
85         uiItemR(row, "", 0, ptr, "only_selected", 0);
86
87         if (nlaActive)
88                 uiItemR(row, "", 0, ptr, "include_missing_nla", 0);
89
90         if (nlaActive)
91                 row= layout;
92
93         /* datatype based - only available datatypes are shown */
94         row= uiLayoutRow(layout, 1);
95
96         uiItemR(row, "", 0, ptr, "display_scene", 0);
97         uiItemR(row, "", 0, ptr, "display_world", 0);
98         uiItemR(row, "", 0, ptr, "display_node", 0);
99
100         if (mainptr && mainptr->mesh.first)
101                 uiItemR(row, "", 0, ptr, "display_mesh", 0);
102         if (mainptr && mainptr->key.first)
103                 uiItemR(row, "", 0, ptr, "display_shapekeys", 0);
104         if (mainptr && mainptr->mat.first)
105                 uiItemR(row, "", 0, ptr, "display_material", 0);
106         if (mainptr && mainptr->lamp.first)
107                 uiItemR(row, "", 0, ptr, "display_lamp", 0);
108         if (mainptr && mainptr->camera.first)
109                 uiItemR(row, "", 0, ptr, "display_camera", 0);
110         if (mainptr && mainptr->curve.first)
111                 uiItemR(row, "", 0, ptr, "display_curve", 0);
112         if (mainptr && mainptr->mball.first)
113                 uiItemR(row, "", 0, ptr, "display_metaball", 0);
114         if (mainptr && mainptr->armature.first)
115                 uiItemR(row, "", 0, ptr, "display_armature", 0);
116         if (mainptr && mainptr->particle.first)
117                 uiItemR(row, "", 0, ptr, "display_particle", 0);
118         
119         /* group-based filtering (only when groups are available */
120         if (mainptr && mainptr->group.first) {
121                 row= uiLayoutRow(layout, 1);
122                 
123                 uiItemR(row, "", 0, ptr, "only_group_objects", 0);
124                 
125                 /* if enabled, show the group selection field too */
126                 if (RNA_boolean_get(ptr, "only_group_objects"))
127                         uiItemR(row, "", 0, ptr, "filtering_group", 0);
128         }
129 }
130
131 /********************** Search Callbacks *************************/
132
133 typedef struct TemplateID {
134         PointerRNA ptr;
135         PropertyRNA *prop;
136
137         ListBase *idlb;
138         int prv_rows, prv_cols;
139 } TemplateID;
140
141 /* Search browse menu, assign  */
142 static void id_search_call_cb(bContext *C, void *arg_template, void *item)
143 {
144         TemplateID *template= (TemplateID*)arg_template;
145
146         /* ID */
147         if(item) {
148                 PointerRNA idptr;
149
150                 RNA_id_pointer_create(item, &idptr);
151                 RNA_property_pointer_set(&template->ptr, template->prop, idptr);
152                 RNA_property_update(C, &template->ptr, template->prop);
153         }
154 }
155
156 /* ID Search browse menu, do the search */
157 static void id_search_cb(const bContext *C, void *arg_template, char *str, uiSearchItems *items)
158 {
159         TemplateID *template= (TemplateID*)arg_template;
160         ListBase *lb= template->idlb;
161         ID *id;
162         int iconid;
163
164         /* ID listbase */
165         for(id= lb->first; id; id= id->next) {
166                 if(BLI_strcasestr(id->name+2, str)) {
167                         iconid= ui_id_icon_get((bContext*)C, id, 0);
168
169                         if(!uiSearchItemAdd(items, id->name+2, id, iconid))
170                                 break;
171                 }
172         }
173 }
174
175 /* ID Search browse menu, open */
176 static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
177 {
178         static char search[256];
179         static TemplateID template;
180         PointerRNA idptr;
181         wmEvent event;
182         wmWindow *win= CTX_wm_window(C);
183         uiBlock *block;
184         uiBut *but;
185         
186         /* clear initial search string, then all items show */
187         search[0]= 0;
188         /* arg_litem is malloced, can be freed by parent button */
189         template= *((TemplateID*)arg_litem);
190         
191         /* get active id for showing first item */
192         idptr= RNA_property_pointer_get(&template.ptr, template.prop);
193
194         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
195         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
196         
197         /* preview thumbnails */
198         if (template.prv_rows > 0 && template.prv_cols > 0) {
199                 int w = 96 * template.prv_cols;
200                 int h = 96 * template.prv_rows + 20;
201                 
202                 /* fake button, it holds space for search items */
203                 uiDefBut(block, LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
204                 
205                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, w, 19, template.prv_rows, template.prv_cols, "");
206                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
207         }
208         /* list view */
209         else {
210                 /* fake button, it holds space for search items */
211                 uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
212                 
213                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, 0, 0, "");
214                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
215         }
216                 
217         
218         uiBoundsBlock(block, 6);
219         uiBlockSetDirection(block, UI_DOWN);    
220         uiEndBlock(C, block);
221         
222         event= *(win->eventstate);      /* XXX huh huh? make api call */
223         event.type= EVT_BUT_OPEN;
224         event.val= KM_PRESS;
225         event.customdata= but;
226         event.customdatafree= FALSE;
227         wm_event_add(win, &event);
228         
229         return block;
230 }
231
232 /************************ ID Template ***************************/
233 /* This is for browsing and editing the ID-blocks used */
234
235 /* for new/open operators */
236 void uiIDContextProperty(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
237 {
238         TemplateID *template;
239         ARegion *ar= CTX_wm_region(C);
240         uiBlock *block;
241         uiBut *but;
242
243         memset(ptr, 0, sizeof(*ptr));
244         *prop= NULL;
245
246         if(!ar)
247                 return;
248
249         for(block=ar->uiblocks.first; block; block=block->next) {
250                 for(but=block->buttons.first; but; but= but->next) {
251                         /* find the button before the active one */
252                         if((but->flag & (UI_BUT_LAST_ACTIVE|UI_ACTIVE))) {
253                                 if(but->func_argN) {
254                                         template= but->func_argN;
255                                         *ptr= template->ptr;
256                                         *prop= template->prop;
257                                         return;
258                                 }
259                         }
260                 }
261         }
262 }
263
264
265 static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
266 {
267         TemplateID *template= (TemplateID*)arg_litem;
268         PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
269         ID *id= idptr.data, *newid;
270         int event= GET_INT_FROM_POINTER(arg_event);
271         
272         switch(event) {
273                 case UI_ID_BROWSE:
274                 case UI_ID_PIN:
275                         printf("warning, id event %d shouldnt come here\n", event);
276                         break;
277                 case UI_ID_OPEN:
278                 case UI_ID_ADD_NEW:
279                         /* these call uiIDContextPropertySet */
280                         break;
281                 case UI_ID_DELETE:
282                         memset(&idptr, 0, sizeof(idptr));
283                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
284                         RNA_property_update(C, &template->ptr, template->prop);
285                         break;
286                 case UI_ID_FAKE_USER:
287                         if(id) {
288                                 if(id->flag & LIB_FAKEUSER) id->us++;
289                                 else id->us--;
290                         }
291                         else return;
292                         break;
293                 case UI_ID_LOCAL:
294                         if(id) {
295                                 if(id_make_local(id, 0)) {
296                                         /* reassign to get get proper updates/notifiers */
297                                         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
298                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
299                                         RNA_property_update(C, &template->ptr, template->prop);
300                                 }
301                         }
302                         break;
303                 case UI_ID_ALONE:
304                         if(id) {
305                                 /* make copy */
306                                 if(id_copy(id, &newid, 0) && newid) {
307                                         /* us is 1 by convention, but RNA_property_pointer_set
308                                            will also incremement it, so set it to zero */
309                                         newid->us= 0;
310
311                                         /* assign copy */
312                                         RNA_id_pointer_create(newid, &idptr);
313                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
314                                         RNA_property_update(C, &template->ptr, template->prop);
315                                 }
316                         }
317                         break;
318 #if 0
319                 case UI_ID_AUTO_NAME:
320                         break;
321 #endif
322         }
323 }
324
325 static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, char *newop, char *openop, char *unlinkop)
326 {
327         uiBut *but;
328         uiBlock *block;
329         PointerRNA idptr;
330         ListBase *lb;
331         ID *id, *idfrom;
332
333         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
334         id= idptr.data;
335         idfrom= template->ptr.id.data;
336         lb= template->idlb;
337
338         block= uiLayoutGetBlock(layout);
339         uiBlockBeginAlign(block);
340
341         if(idptr.type)
342                 type= idptr.type;
343
344         if(flag & UI_ID_PREVIEWS) {
345
346                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, "Browse ID data");
347                 if(type) {
348                         but->icon= RNA_struct_ui_icon(type);
349                         if (id) but->icon = ui_id_icon_get(C, id, 1);
350                         uiButSetFlag(but, UI_HAS_ICON|UI_ICON_PREVIEW);
351                 }
352                 if((idfrom && idfrom->lib))
353                         uiButSetFlag(but, UI_BUT_DISABLED);
354                 
355                 
356                 uiLayoutRow(layout, 1);
357         } else 
358                 
359         if(flag & UI_ID_BROWSE) {
360                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*1.6, UI_UNIT_Y, "Browse ID data");
361                 if(type) {
362                         but->icon= RNA_struct_ui_icon(type);
363                         /* default dragging of icon for id browse buttons */
364                         uiButSetDragID(but, id);
365                         uiButSetFlag(but, UI_HAS_ICON|UI_ICON_LEFT);
366                 }
367
368                 if((idfrom && idfrom->lib))
369                         uiButSetFlag(but, UI_BUT_DISABLED);
370         }
371
372         /* text button with name */
373         if(id) {
374                 char name[64];
375
376                 //text_idbutton(id, name);
377                 name[0]= '\0';
378                 but= uiDefButR(block, TEX, 0, name, 0, 0, UI_UNIT_X*6, UI_UNIT_Y, &idptr, "name", -1, 0, 0, -1, -1, NULL);
379                 uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
380
381                 if(id->lib) {
382                         if(id->flag & LIB_INDIRECT) {
383                                 but= uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_INDIRECT, 0,0,UI_UNIT_X,UI_UNIT_Y, 0, 0, 0, 0, 0,
384                                         "Indirect library datablock, cannot change.");
385                                 uiButSetFlag(but, UI_BUT_DISABLED);
386                         }
387                         else {
388                                 but= uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0,0,UI_UNIT_X,UI_UNIT_Y, 0, 0, 0, 0, 0,
389                                         "Direct linked library datablock, click to make local.");
390                                 if(!id_make_local(id, 1 /* test */) || (idfrom && idfrom->lib))
391                                         uiButSetFlag(but, UI_BUT_DISABLED);
392                         }
393
394                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL));
395                 }
396
397                 if(id->us > 1) {
398                         char str[32];
399
400                         sprintf(str, "%d", id->us);
401
402                         if(id->us<10)
403                                 but= uiDefBut(block, BUT, 0, str, 0,0,UI_UNIT_X,UI_UNIT_Y, 0, 0, 0, 0, 0, "Displays number of users of this data. Click to make a single-user copy.");
404                         else
405                                 but= uiDefBut(block, BUT, 0, str, 0,0,UI_UNIT_X+10,UI_UNIT_Y, 0, 0, 0, 0, 0, "Displays number of users of this data. Click to make a single-user copy.");
406
407                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
408                         if(!id_copy(id, NULL, 1 /* test only */) || (idfrom && idfrom->lib))
409                                 uiButSetFlag(but, UI_BUT_DISABLED);
410                 }
411         }
412         
413         if(flag & UI_ID_ADD_NEW) {
414                 int w= id?UI_UNIT_X: (flag & UI_ID_OPEN)? UI_UNIT_X*3: UI_UNIT_X*6;
415                 
416                 if(newop) {
417                         but= uiDefIconTextButO(block, BUT, newop, WM_OP_EXEC_DEFAULT, ICON_ZOOMIN, (id)? "": "New", 0, 0, w, UI_UNIT_Y, NULL);
418                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
419                 }
420                 else {
421                         but= uiDefIconTextBut(block, BUT, 0, ICON_ZOOMIN, (id)? "": "New", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
422                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
423                 }
424
425                 if((idfrom && idfrom->lib))
426                         uiButSetFlag(but, UI_BUT_DISABLED);
427         }
428
429         if(flag & UI_ID_OPEN) {
430                 int w= id?UI_UNIT_X: (flag & UI_ID_ADD_NEW)? UI_UNIT_X*3: UI_UNIT_X*6;
431                 
432                 if(openop) {
433                         but= uiDefIconTextButO(block, BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id)? "": "Open", 0, 0, w, UI_UNIT_Y, NULL);
434                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
435                 }
436                 else {
437                         but= uiDefIconTextBut(block, BUT, 0, ICON_FILESEL, (id)? "": "Open", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
438                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
439                 }
440
441                 if((idfrom && idfrom->lib))
442                         uiButSetFlag(but, UI_BUT_DISABLED);
443         }
444         
445         /* delete button */
446         if(id && (flag & UI_ID_DELETE)) {
447                 if(unlinkop) {
448                         but= uiDefIconButO(block, BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
449                 }
450                 else {
451                         but= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
452                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
453                 }
454
455                 if((idfrom && idfrom->lib))
456                         uiButSetFlag(but, UI_BUT_DISABLED);
457         }
458         
459         uiBlockEndAlign(block);
460 }
461
462 static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, int flag, int prv_rows, int prv_cols)
463 {
464         TemplateID *template;
465         PropertyRNA *prop;
466         StructRNA *type;
467
468         prop= RNA_struct_find_property(ptr, propname);
469
470         if(!prop || RNA_property_type(prop) != PROP_POINTER) {
471                 printf("uiTemplateID: pointer property not found: %s\n", propname);
472                 return;
473         }
474
475         template= MEM_callocN(sizeof(TemplateID), "TemplateID");
476         template->ptr= *ptr;
477         template->prop= prop;
478         template->prv_rows = prv_rows;
479         template->prv_cols = prv_cols;
480         
481         if(newop)
482                 flag |= UI_ID_ADD_NEW;
483         if(openop)
484                 flag |= UI_ID_OPEN;
485         
486         type= RNA_property_pointer_type(ptr, prop);
487         template->idlb= wich_libbase(CTX_data_main(C), RNA_type_to_ID_code(type));
488         
489         /* create UI elements for this template
490          *      - template_ID makes a copy of the template data and assigns it to the relevant buttons
491          */
492         if(template->idlb) {
493                 uiLayoutRow(layout, 1);
494                 template_ID(C, layout, template, type, flag, newop, openop, unlinkop);
495         }
496
497         MEM_freeN(template);
498         
499 }
500
501 void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
502 {
503         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE, 0, 0);
504 }
505
506 void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
507 {
508         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME, 0, 0);
509 }
510
511 void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, int rows, int cols)
512 {
513         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE|UI_ID_PREVIEWS, rows, cols);
514 }
515
516 /************************ ID Chooser Template ***************************/
517
518 /* This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use 
519  *
520  * - propname: property identifier for property that ID-pointer gets stored to
521  * - proptypename: property identifier for property used to determine the type of ID-pointer that can be used
522  */
523 void uiTemplateAnyID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *proptypename, char *text)
524 {
525         PropertyRNA *propID, *propType;
526         uiLayout *row;
527         
528         /* get properties... */
529         propID= RNA_struct_find_property(ptr, propname);
530         propType= RNA_struct_find_property(ptr, proptypename);
531
532         if (!propID || RNA_property_type(propID) != PROP_POINTER) {
533                 printf("uiTemplateAnyID: pointer property not found: %s\n", propname);
534                 return;
535         }
536         if (!propType || RNA_property_type(propType) != PROP_ENUM) { 
537                 printf("uiTemplateAnyID: pointer-type property not found: %s\n", proptypename);
538                 return;
539         }
540         
541         /* Start drawing UI Elements using standard defines */
542         row= uiLayoutRow(layout, 1);
543         
544         /* Label - either use the provided text, or will become "ID-Block:" */
545         if (text)
546                 uiItemL(row, text, 0);
547         else
548                 uiItemL(row, "ID-Block:", 0);
549         
550         /* ID-Type Selector - just have a menu of icons */
551         // FIXME: the icon-only setting doesn't work when we supply a blank name
552         uiItemFullR(row, "", 0, ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY);
553         
554         /* ID-Block Selector - just use pointer widget... */
555         uiItemFullR(row, "", 0, ptr, propID, 0, 0, 0);
556 }
557
558 /********************* RNA Path Builder Template ********************/
559
560 /* ---------- */
561
562 /* This is creating/editing RNA-Paths 
563  *
564  * - ptr: struct which holds the path property
565  * - propname: property identifier for property that path gets stored to
566  * - root_ptr: struct that path gets built from
567  */
568 void uiTemplatePathBuilder(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, PointerRNA *root_ptr, char *text)
569 {
570         PropertyRNA *propPath;
571         uiLayout *row;
572         
573         /* check that properties are valid */
574         propPath= RNA_struct_find_property(ptr, propname);
575         if (!propPath || RNA_property_type(propPath) != PROP_STRING) {
576                 printf("uiTemplatePathBuilder: path property not found: %s\n", propname);
577                 return;
578         }
579         
580         /* Start drawing UI Elements using standard defines */
581         row= uiLayoutRow(layout, 1);
582         
583         /* Path (existing string) Widget */
584         uiItemR(row, text, ICON_RNA, ptr, propname, 0);
585         
586         // TODO: attach something to this to make allow searching of nested properties to 'build' the path
587 }
588
589 /************************ Modifier Template *************************/
590
591 #define ERROR_LIBDATA_MESSAGE "Can't edit external libdata"
592
593 #include <string.h>
594
595 #include "DNA_object_force.h"
596 #include "DNA_object_types.h"
597 #include "DNA_modifier_types.h"
598 #include "DNA_scene_types.h"
599
600 #include "BKE_depsgraph.h"
601 #include "BKE_DerivedMesh.h"
602 #include "BKE_global.h"
603 #include "BKE_modifier.h"
604 #include "BKE_object.h"
605 #include "BKE_particle.h"
606 #include "BKE_report.h"
607
608 #include "UI_resources.h"
609 #include "ED_util.h"
610
611 #include "BLI_math.h"
612 #include "BLI_listbase.h"
613
614 #include "ED_object.h"
615
616 static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v)
617 {
618         Scene *scene = CTX_data_scene(C);
619         Object *ob = ob_v;
620         ModifierData *md= md_v;
621         int i, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 0);
622
623         /* undo button operation */
624         md->mode ^= eModifierMode_OnCage;
625
626         for(i = 0, md=ob->modifiers.first; md; ++i, md=md->next) {
627                 if(md == md_v) {
628                         if(i >= cageIndex)
629                                 md->mode ^= eModifierMode_OnCage;
630                         break;
631                 }
632         }
633
634         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
635         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
636 }
637
638 static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
639 {
640         Object *ob = ob_v;
641         ModifierData *md = md_v;
642         ModifierData *nmd = modifier_new(md->type);
643
644         modifier_copyData(md, nmd);
645         nmd->mode &= ~eModifierMode_Virtual;
646
647         BLI_addhead(&ob->modifiers, nmd);
648         
649         modifier_unique_name(&ob->modifiers, nmd);
650
651         ob->partype = PAROBJECT;
652
653         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
654         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
655
656         ED_undo_push(C, "Modifier convert to real");
657 }
658
659 static int modifier_can_delete(ModifierData *md)
660 {
661         // fluid particle modifier can't be deleted here
662         if(md->type == eModifierType_ParticleSystem)
663                 if(((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID)
664                         return 0;
665
666         return 1;
667 }
668
669 static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob, ModifierData *md, int index, int cageIndex, int lastCageIndex, int compact)
670 {
671         ModifierTypeInfo *mti = modifierType_getInfo(md->type);
672         PointerRNA ptr;
673         uiBut *but;
674         uiBlock *block;
675         uiLayout *box, *column, *row, *col;
676         uiLayout *result= NULL;
677         int isVirtual = (md->mode & eModifierMode_Virtual);
678         char str[128];
679
680         /* create RNA pointer */
681         RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr);
682
683         column= uiLayoutColumn(layout, 1);
684         uiLayoutSetContextPointer(column, "modifier", &ptr);
685
686         /* rounded header ------------------------------------------------------------------- */
687         box= uiLayoutBox(column);
688         
689         if (isVirtual) {
690                 row= uiLayoutRow(box, 0);
691                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_EXPAND);
692                 block= uiLayoutGetBlock(row);
693                 /* VIRTUAL MODIFIER */
694                 // XXX this is not used now, since these cannot be accessed via RNA
695                 sprintf(str, "%s parent deform", md->name);
696                 uiDefBut(block, LABEL, 0, str, 0, 0, 185, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Modifier name"); 
697                 
698                 but = uiDefBut(block, BUT, 0, "Make Real", 0, 0, 80, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Convert virtual modifier to a real modifier");
699                 uiButSetFunc(but, modifiers_convertToReal, ob, md);
700         }
701         else {
702                 /* REAL MODIFIER */
703                 uiLayout *split;
704                 
705                 split = uiLayoutSplit(box, 0.16, 0);
706                 
707                 col= uiLayoutColumn(split, 0);
708                 row = uiLayoutRow(col, 1);
709                 
710                 block = uiLayoutGetBlock(row);
711                 
712                 uiBlockSetEmboss(block, UI_EMBOSSN);
713                 
714                 /* Open/Close .................................  */
715                 uiItemR(row, "", 0, &ptr, "expanded", 0);
716                 
717                 /* modifier-type icon */
718                 uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
719                 
720                 uiBlockSetEmboss(block, UI_EMBOSS);
721                 
722         
723                 /* 'Middle Column' ............................ 
724                  *      - first row is the name of the modifier 
725                  *      - second row is the visibility settings, since the layouts were not wide enough to show all
726                  */
727                 col= uiLayoutColumn(split, 0);
728                 
729                 row= uiLayoutRow(col, 0);
730                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_EXPAND);
731                 
732                 block = uiLayoutGetBlock(row);
733                 
734                 /* modifier name */
735                 uiItemR(row, "", 0, &ptr, "name", 0);
736                 
737                 if (compact) {
738                         /* insert delete button at end of top row before splitting to second line */
739                         uiBlockSetEmboss(block, UI_EMBOSSN);
740                         if (modifier_can_delete(md))
741                                 uiItemO(row, "", ICON_X, "OBJECT_OT_modifier_remove");
742                         uiBlockSetEmboss(block, UI_EMBOSS);
743                         
744                         split = uiLayoutSplit(box, 0.17, 0);
745                         col= uiLayoutColumn(split, 0);
746                         uiItemL(col, "", 0);
747                         col= uiLayoutColumn(split, 0);
748                         row = uiLayoutRow(col, 1);
749                 }
750                 
751                 /* mode enabling buttons */
752                 uiBlockBeginAlign(block);
753                 /* Softbody not allowed in this situation, enforce! */
754                 if ( ((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) 
755                         && (md->type!=eModifierType_Surface) ) 
756                 {
757                         uiItemR(row, "", 0, &ptr, "render", 0);
758                         uiItemR(row, "", 0, &ptr, "realtime", 0);
759                         
760                         if (mti->flags & eModifierTypeFlag_SupportsEditmode)
761                                 uiItemR(row, "", 0, &ptr, "editmode", 0);
762                 }
763                 if ((ob->type==OB_MESH) && modifier_couldBeCage(scene, md) && (index <= lastCageIndex)) 
764                 {
765                         /* -- convert to rna ? */
766                         but = uiDefIconButBitI(block, TOG, eModifierMode_OnCage, 0, ICON_MESH_DATA, 0, 0, 16, 20, &md->mode, 0.0, 0.0, 0.0, 0.0, "Apply modifier to editing cage during Editmode");
767                         if (index < cageIndex)
768                                 uiButSetFlag(but, UI_BUT_DISABLED);
769                         uiButSetFunc(but, modifiers_setOnCage, ob, md);
770                 }
771                 uiBlockEndAlign(block);
772                 
773                 /* Up/Down + Delete ........................... */
774                 uiBlockBeginAlign(block);
775                 uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_modifier_move_up");
776                 uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_modifier_move_down");
777                 uiBlockEndAlign(block);
778                 
779                 if(!compact) {
780                         uiBlockSetEmboss(block, UI_EMBOSSN);
781                         if (modifier_can_delete(md))
782                                 uiItemO(row, "", ICON_X, "OBJECT_OT_modifier_remove");
783                         uiBlockSetEmboss(block, UI_EMBOSS);
784                 }
785         }
786
787         
788         /* modifier settings (under the header) --------------------------------------------------- */
789         if (!isVirtual && (md->mode & eModifierMode_Expanded)) {
790                 /* apply/convert/copy */
791                 box= uiLayoutBox(column);
792                 row= uiLayoutRow(box, 0);
793                 
794                 if (!ELEM(md->type, eModifierType_Collision, eModifierType_Surface)) {
795                         /* only here obdata, the rest of modifiers is ob level */
796                         uiBlockSetButLock(block, object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
797                         
798                         if (md->type==eModifierType_ParticleSystem) {
799                         ParticleSystem *psys= ((ParticleSystemModifierData *)md)->psys;
800                                 
801                         if (!(ob->mode & OB_MODE_PARTICLE_EDIT) && psys->pathcache) {
802                                         if(ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB))
803                                                 uiItemO(row, "Convert", 0, "OBJECT_OT_duplicates_make_real");
804                                         else if(psys->part->ren_as == PART_DRAW_PATH)
805                                                 uiItemO(row, "Convert", 0, "OBJECT_OT_modifier_convert");
806                                 }
807                         }
808                         else {
809                                 uiItemEnumO(row, "Apply", 0, "OBJECT_OT_modifier_apply", "apply_as", MODIFIER_APPLY_DATA);
810                                 
811                                 if (modifier_sameTopology(md))
812                                         uiItemEnumO(row, "Apply as Shape", 0, "OBJECT_OT_modifier_apply", "apply_as", MODIFIER_APPLY_SHAPE);
813                         }
814                         
815                         uiBlockClearButLock(block);
816                         uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
817                         
818                         if (!ELEM4(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, eModifierType_Cloth))
819                                 uiItemO(row, "Copy", 0, "OBJECT_OT_modifier_copy");
820                 }
821                 
822                 /* result is the layout block inside the box, that we return so that modifier settings can be drawn */
823                 result= uiLayoutColumn(box, 0);
824                 block= uiLayoutAbsoluteBlock(box);
825         }
826         
827         /* error messages */
828         if(md->error) {
829                 box = uiLayoutBox(column);
830                 row = uiLayoutRow(box, 0);
831                 uiItemL(row, md->error, ICON_ERROR);
832         }
833         
834         return result;
835 }
836
837 uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr, int compact)
838 {
839         Scene *scene = CTX_data_scene(C);
840         Object *ob;
841         ModifierData *md, *vmd;
842         int i, lastCageIndex, cageIndex;
843
844         /* verify we have valid data */
845         if(!RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
846                 printf("uiTemplateModifier: expected modifier on object.\n");
847                 return NULL;
848         }
849
850         ob= ptr->id.data;
851         md= ptr->data;
852
853         if(!ob || !(GS(ob->id.name) == ID_OB)) {
854                 printf("uiTemplateModifier: expected modifier on object.\n");
855                 return NULL;
856         }
857         
858         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
859         
860         /* find modifier and draw it */
861         cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
862
863         // XXX virtual modifiers are not accesible for python
864         vmd = modifiers_getVirtualModifierList(ob);
865
866         for(i=0; vmd; i++, vmd=vmd->next) {
867                 if(md == vmd)
868                         return draw_modifier(layout, scene, ob, md, i, cageIndex, lastCageIndex, compact);
869                 else if(vmd->mode & eModifierMode_Virtual)
870                         i--;
871         }
872
873         return NULL;
874 }
875
876 /************************ Constraint Template *************************/
877
878 #include "DNA_action_types.h"
879 #include "DNA_constraint_types.h"
880
881 #include "BKE_action.h"
882 #include "BKE_constraint.h"
883
884 #define REDRAWIPO                                       1
885 #define REDRAWNLA                                       2
886 #define REDRAWBUTSOBJECT                        3               
887 #define REDRAWACTION                            4
888 #define B_CONSTRAINT_TEST                       5
889 #define B_CONSTRAINT_CHANGETARGET       6
890 #define B_CONSTRAINT_INF                        7
891 #define REMAKEIPO                                       8
892 #define B_DIFF                                          9
893
894 void do_constraint_panels(bContext *C, void *arg, int event)
895 {
896         Scene *scene= CTX_data_scene(C);
897         Object *ob= CTX_data_active_object(C);
898         
899         switch(event) {
900         case B_CONSTRAINT_TEST:
901                 // XXX allqueue(REDRAWVIEW3D, 0);
902                 // XXX allqueue(REDRAWBUTSOBJECT, 0);
903                 // XXX allqueue(REDRAWBUTSEDIT, 0);
904                 break;  // no handling
905         case B_CONSTRAINT_INF:
906                 /* influence; do not execute actions for 1 dag_flush */
907                 if (ob->pose)
908                         ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
909                 break;
910         case B_CONSTRAINT_CHANGETARGET:
911                 if (ob->pose) ob->pose->flag |= POSE_RECALC;    // checks & sorts pose channels
912                 DAG_scene_sort(scene);
913                 break;
914         default:
915                 break;
916         }
917
918         object_test_constraints(ob);
919         
920         if(ob->pose) update_pose_constraint_flags(ob->pose);
921         
922         if(ob->type==OB_ARMATURE) DAG_id_flush_update(&ob->id, OB_RECALC_DATA|OB_RECALC_OB);
923         else DAG_id_flush_update(&ob->id, OB_RECALC_OB);
924
925         WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
926         
927         // XXX allqueue(REDRAWVIEW3D, 0);
928         // XXX allqueue(REDRAWBUTSOBJECT, 0);
929         // XXX allqueue(REDRAWBUTSEDIT, 0);
930 }
931
932 static void constraint_active_func(bContext *C, void *ob_v, void *con_v)
933 {
934         ED_object_constraint_set_active(ob_v, con_v);
935 }
936
937 static void verify_constraint_name_func (bContext *C, void *con_v, void *dummy)
938 {
939         Object *ob= CTX_data_active_object(C);
940         bConstraint *con= con_v;
941         
942         if (!con)
943                 return;
944         
945         ED_object_constraint_rename(ob, con, NULL);
946         ED_object_constraint_set_active(ob, con);
947         // XXX allqueue(REDRAWACTION, 0); 
948 }
949
950 /* some commonly used macros in the constraints drawing code */
951 #define is_armature_target(target) (target && target->type==OB_ARMATURE)
952 #define is_armature_owner(ob) ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE))
953 #define is_geom_target(target) (target && (ELEM(target->type, OB_MESH, OB_LATTICE)) )
954
955 /* Helper function for draw constraint - draws constraint space stuff 
956  * This function should not be called if no menus are required 
957  * owner/target: -1 = don't draw menu; 0= not posemode, 1 = posemode 
958  */
959 static void draw_constraint_spaceselect (uiBlock *block, bConstraint *con, short xco, short yco, short owner, short target)
960 {
961         short tarx, ownx, iconx;
962         short bwidth;
963         short iconwidth = 20;
964         
965         /* calculate sizes and placement of menus */
966         if (owner == -1) {
967                 bwidth = 125;
968                 tarx = 120;
969                 ownx = 0;
970         }
971         else if (target == -1) {
972                 bwidth = 125;
973                 tarx = 0;
974                 ownx = 120;
975         }
976         else {
977                 bwidth = 100;
978                 tarx = 85;
979                 iconx = tarx + bwidth + 5;
980                 ownx = tarx + bwidth + iconwidth + 10;
981         }
982         
983         
984         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Convert:", xco, yco, 80,18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
985
986         /* Target-Space */
987         if (target == 1) {
988                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x2|Local with Parent %x3|Local Space %x1", 
989                                                                                                 tarx, yco, bwidth, 18, &con->tarspace, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
990         }
991         else if (target == 0) {
992                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Local (Without Parent) Space %x1", 
993                                                                                 tarx, yco, bwidth, 18, &con->tarspace, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
994         }
995         
996         if ((target != -1) && (owner != -1))
997                 uiDefIconBut(block, LABEL, 0, ICON_ARROW_LEFTRIGHT,
998                         iconx, yco, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "");
999         
1000         /* Owner-Space */
1001         if (owner == 1) {
1002                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Pose Space %x2|Local with Parent %x3|Local Space %x1", 
1003                                                                                                 ownx, yco, bwidth, 18, &con->ownspace, 0, 0, 0, 0, "Choose space that owner is evaluated in");  
1004         }
1005         else if (owner == 0) {
1006                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Local (Without Parent) Space %x1", 
1007                                                                                 ownx, yco, bwidth, 18, &con->ownspace, 0, 0, 0, 0, "Choose space that owner is evaluated in");  
1008         }
1009 }
1010
1011 static void test_obpoin_but(bContext *C, char *name, ID **idpp)
1012 {
1013         ID *id= BLI_findstring(&CTX_data_main(C)->object, name, offsetof(ID, name) + 2);
1014         *idpp= id; /* can be NULL */
1015         
1016         if(id)
1017                 id_lib_extern(id);      /* checks lib data, sets correct flag for saving then */
1018 }
1019
1020 /* draw panel showing settings for a constraint */
1021 static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
1022 {
1023         bPoseChannel *pchan= get_active_posechannel(ob);
1024         bConstraintTypeInfo *cti;
1025         uiBlock *block;
1026         uiLayout *result= NULL, *col, *box, *row, *subrow;
1027         uiBut *but;
1028         PointerRNA ptr;
1029         char typestr[32];
1030         short width = 265;
1031         short proxy_protected, xco=0, yco=0;
1032         int rb_col;
1033
1034         /* get constraint typeinfo */
1035         cti= constraint_get_typeinfo(con);
1036         if (cti == NULL) {
1037                 /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
1038                 if (con->type == CONSTRAINT_TYPE_NULL)
1039                         strcpy(typestr, "Null");
1040                 else
1041                         strcpy(typestr, "Unknown");
1042         }
1043         else
1044                 strcpy(typestr, cti->name);
1045                 
1046         /* determine whether constraint is proxy protected or not */
1047         if (proxylocked_constraints_owner(ob, pchan))
1048                 proxy_protected= (con->flag & CONSTRAINT_PROXY_LOCAL)==0;
1049         else
1050                 proxy_protected= 0;
1051
1052         /* unless button has own callback, it adds this callback to button */
1053         block= uiLayoutGetBlock(layout);
1054         uiBlockSetHandleFunc(block, do_constraint_panels, NULL);
1055         uiBlockSetFunc(block, constraint_active_func, ob, con);
1056
1057         RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
1058
1059         col= uiLayoutColumn(layout, 1);
1060         uiLayoutSetContextPointer(col, "constraint", &ptr);
1061
1062         box= uiLayoutBox(col);
1063         row= uiLayoutRow(box, 0);
1064
1065         block= uiLayoutGetBlock(box);
1066
1067         subrow= uiLayoutRow(row, 0);
1068         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT);
1069
1070         /* Draw constraint header */
1071         uiBlockSetEmboss(block, UI_EMBOSSN);
1072         
1073         /* rounded header */
1074         rb_col= (con->flag & CONSTRAINT_ACTIVE)?50:20;
1075         
1076         /* open/close */
1077         uiDefIconButBitS(block, ICONTOG, CONSTRAINT_EXPAND, B_CONSTRAINT_TEST, ICON_TRIA_RIGHT, xco-10, yco, 20, 20, &con->flag, 0.0, 0.0, 0.0, 0.0, "Collapse/Expand Constraint");
1078         
1079         /* name */      
1080         uiBlockSetEmboss(block, UI_EMBOSS);
1081         
1082         /* XXX if (con->flag & CONSTRAINT_DISABLE)
1083                 uiBlockSetCol(block, TH_REDALERT);*/
1084         
1085         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco+10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1086         
1087         if(proxy_protected == 0) {
1088                 but = uiDefBut(block, TEX, B_CONSTRAINT_TEST, "", xco+120, yco, 85, 18, con->name, 0.0, 29.0, 0.0, 0.0, "Constraint name"); 
1089                 uiButSetFunc(but, verify_constraint_name_func, con, con->name);
1090         }
1091         else
1092                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, con->name, xco+120, yco-1, 135, 19, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1093
1094         // XXX uiBlockSetCol(block, TH_AUTO);   
1095
1096         subrow= uiLayoutRow(row, 0);
1097         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT);
1098         
1099         /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
1100         if (proxy_protected) {
1101                 uiBlockSetEmboss(block, UI_EMBOSSN);
1102                 
1103                 /* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
1104                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_GHOST, xco+244, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
1105                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_LOCKED, xco+262, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
1106                 
1107                 uiBlockSetEmboss(block, UI_EMBOSS);
1108         }
1109         else {
1110                 short prev_proxylock, show_upbut, show_downbut;
1111                 
1112                 /* Up/Down buttons: 
1113                  *      Proxy-constraints are not allowed to occur after local (non-proxy) constraints
1114                  *      as that poses problems when restoring them, so disable the "up" button where
1115                  *      it may cause this situation. 
1116                  *
1117                  *      Up/Down buttons should only be shown (or not greyed - todo) if they serve some purpose. 
1118                  */
1119                 if (proxylocked_constraints_owner(ob, pchan)) {
1120                         if (con->prev) {
1121                                 prev_proxylock= (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
1122                         }
1123                         else
1124                                 prev_proxylock= 0;
1125                 }
1126                 else
1127                         prev_proxylock= 0;
1128                         
1129                 show_upbut= ((prev_proxylock == 0) && (con->prev));
1130                 show_downbut= (con->next) ? 1 : 0;
1131                 
1132                 if (show_upbut || show_downbut) {
1133                         uiBlockBeginAlign(block);
1134                                 uiBlockSetEmboss(block, UI_EMBOSS);
1135                                 
1136                                 if (show_upbut)
1137                                         uiDefIconButO(block, BUT, "CONSTRAINT_OT_move_up", WM_OP_INVOKE_DEFAULT, ICON_TRIA_UP, xco+width-50, yco, 16, 18, "Move constraint up in constraint stack");
1138                                 
1139                                 if (show_downbut)
1140                                         uiDefIconButO(block, BUT, "CONSTRAINT_OT_move_down", WM_OP_INVOKE_DEFAULT, ICON_TRIA_DOWN, xco+width-50+18, yco, 16, 18, "Move constraint down in constraint stack");
1141                         uiBlockEndAlign(block);
1142                 }
1143         
1144                 /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
1145                 uiBlockSetEmboss(block, UI_EMBOSSN);
1146                         uiDefIconButBitS(block, ICONTOGN, CONSTRAINT_OFF, B_CONSTRAINT_TEST, ICON_CHECKBOX_DEHLT, xco+243, yco, 19, 19, &con->flag, 0.0, 0.0, 0.0, 0.0, "enable/disable constraint");
1147                         
1148                         uiDefIconButO(block, BUT, "CONSTRAINT_OT_delete", WM_OP_INVOKE_DEFAULT, ICON_X, xco+262, yco, 19, 19, "Delete constraint");
1149                 uiBlockSetEmboss(block, UI_EMBOSS);
1150         }
1151         
1152         /* Set but-locks for protected settings (magic numbers are used here!) */
1153         if (proxy_protected)
1154                 uiBlockSetButLock(block, 1, "Cannot edit Proxy-Protected Constraint");
1155         
1156         /* Draw constraint data */
1157         if ((con->flag & CONSTRAINT_EXPAND) == 0) {
1158                 (yco) -= 21;
1159         }
1160         else {
1161                 box= uiLayoutBox(col);
1162                 block= uiLayoutAbsoluteBlock(box);
1163
1164                 switch (con->type) {
1165 #ifndef DISABLE_PYTHON
1166                 case CONSTRAINT_TYPE_PYTHON:
1167                         {
1168                                 bPythonConstraint *data = con->data;
1169                                 bConstraintTarget *ct;
1170                                 // uiBut *but2;
1171                                 int tarnum, theight;
1172                                 // static int pyconindex=0;
1173                                 // char *menustr;
1174                                 
1175                                 theight = (data->tarnum)? (data->tarnum * 38) : (38);
1176                                 
1177                                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Script:", xco+60, yco-24, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1178                                 
1179                                 /* do the scripts menu */
1180                                 /* XXX menustr = buildmenu_pyconstraints(data->text, &pyconindex);
1181                                 but2 = uiDefButI(block, MENU, B_CONSTRAINT_TEST, menustr,
1182                                       xco+120, yco-24, 150, 20, &pyconindex,
1183                                       0, 0, 0, 0, "Set the Script Constraint to use");
1184                                 uiButSetFunc(but2, validate_pyconstraint_cb, data, &pyconindex);
1185                                 MEM_freeN(menustr);      */
1186                                 
1187                                 /* draw target(s) */
1188                                 if (data->flag & PYCON_USETARGETS) {
1189                                         /* Draw target parameters */ 
1190                                         for (ct=data->targets.first, tarnum=1; ct; ct=ct->next, tarnum++) {
1191                                                 char tarstr[32];
1192                                                 short yoffset= ((tarnum-1) * 38);
1193         
1194                                                 /* target label */
1195                                                 sprintf(tarstr, "Target %d:", tarnum);
1196                                                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, tarstr, xco+45, yco-(48+yoffset), 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1197                                                 
1198                                                 /* target space-selector - per target */
1199                                                 if (is_armature_target(ct->tar)) {
1200                                                         uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x3|Local with Parent %x4|Local Space %x1", 
1201                                                                                                                         xco+10, yco-(66+yoffset), 100, 18, &ct->space, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
1202                                                 }
1203                                                 else {
1204                                                         uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Local (Without Parent) Space %x1", 
1205                                                                                                                         xco+10, yco-(66+yoffset), 100, 18, &ct->space, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
1206                                                 }
1207                                                 
1208                                                 uiBlockBeginAlign(block);
1209                                                         /* target object */
1210                                                         uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", xco+120, yco-(48+yoffset), 150, 18, &ct->tar, "Target Object"); 
1211                                                         
1212                                                         /* subtarget */
1213                                                         if (is_armature_target(ct->tar)) {
1214                                                                 but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", xco+120, yco-(66+yoffset),150,18, &ct->subtarget, 0, 24, 0, 0, "Subtarget Bone");
1215                                                                 //uiButSetCompleteFunc(but, autocomplete_bone, (void *)ct->tar);
1216                                                         }
1217                                                         else if (is_geom_target(ct->tar)) {
1218                                                                 but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", xco+120, yco-(66+yoffset),150,18, &ct->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
1219                                                                 //uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ct->tar);
1220                                                         }
1221                                                         else {
1222                                                                 strcpy(ct->subtarget, "");
1223                                                         }
1224                                                 uiBlockEndAlign(block);
1225                                         }
1226                                 }
1227                                 else {
1228                                         /* Draw indication that no target needed */
1229                                         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", xco+60, yco-48, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1230                                         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Not Applicable", xco+120, yco-48, 150, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1231                                 }
1232                                 
1233                                 /* settings */
1234                                 uiBlockBeginAlign(block);
1235                                         but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Options", xco, yco-(52+theight), (width/2),18, NULL, 0, 24, 0, 0, "Change some of the constraint's settings.");
1236                                         // XXX uiButSetFunc(but, BPY_pyconstraint_settings, data, NULL);
1237                                         
1238                                         but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Refresh", xco+((width/2)+10), yco-(52+theight), (width/2),18, NULL, 0, 24, 0, 0, "Force constraint to refresh it's settings");
1239                                 uiBlockEndAlign(block);
1240                                 
1241                                 /* constraint space settings */
1242                                 draw_constraint_spaceselect(block, con, xco, yco-(73+theight), is_armature_owner(ob), -1);
1243                         }
1244                         break;
1245 #endif 
1246
1247                 case CONSTRAINT_TYPE_NULL:
1248                         {
1249                                 uiItemL(box, "", 0);
1250                         }
1251                         break;
1252                 default:
1253                         result= box;
1254                         break;
1255                 }
1256         }
1257         
1258         /* clear any locks set up for proxies/lib-linking */
1259         uiBlockClearButLock(block);
1260
1261         return result;
1262 }
1263
1264 uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
1265 {
1266         Object *ob;
1267         bConstraint *con;
1268
1269         /* verify we have valid data */
1270         if(!RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
1271                 printf("uiTemplateConstraint: expected constraint on object.\n");
1272                 return NULL;
1273         }
1274
1275         ob= ptr->id.data;
1276         con= ptr->data;
1277
1278         if(!ob || !(GS(ob->id.name) == ID_OB)) {
1279                 printf("uiTemplateConstraint: expected constraint on object.\n");
1280                 return NULL;
1281         }
1282         
1283         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
1284
1285         /* hrms, the temporal constraint should not draw! */
1286         if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
1287                 bKinematicConstraint *data= con->data;
1288                 if(data->flag & CONSTRAINT_IK_TEMP)
1289                         return NULL;
1290         }
1291
1292         return draw_constraint(layout, ob, con);
1293 }
1294
1295
1296 /************************* Preview Template ***************************/
1297
1298 #include "DNA_lamp_types.h"
1299 #include "DNA_material_types.h"
1300 #include "DNA_world_types.h"
1301
1302 #define B_MATPRV 1
1303
1304 static void do_preview_buttons(bContext *C, void *arg, int event)
1305 {
1306         switch(event) {
1307                 case B_MATPRV:
1308                         WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, arg);
1309                         break;
1310         }
1311 }
1312
1313 void uiTemplatePreview(uiLayout *layout, ID *id, ID *parent, MTex *slot)
1314 {
1315         uiLayout *row, *col;
1316         uiBlock *block;
1317         Material *ma= NULL;
1318         ID *pid, *pparent;
1319         short *pr_texture= NULL;
1320
1321         if(id && !ELEM4(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA)) {
1322                 printf("uiTemplatePreview: expected ID of type material, texture, lamp or world.\n");
1323                 return;
1324         }
1325
1326         /* decide what to render */
1327         pid= id;
1328         pparent= NULL;
1329
1330         if(id && (GS(id->name) == ID_TE)) {
1331                 if(parent && (GS(parent->name) == ID_MA))
1332                         pr_texture= &((Material*)parent)->pr_texture;
1333                 else if(parent && (GS(parent->name) == ID_WO))
1334                         pr_texture= &((World*)parent)->pr_texture;
1335                 else if(parent && (GS(parent->name) == ID_LA))
1336                         pr_texture= &((Lamp*)parent)->pr_texture;
1337
1338                 if(pr_texture) {
1339                         if(*pr_texture == TEX_PR_OTHER)
1340                                 pid= parent;
1341                         else if(*pr_texture == TEX_PR_BOTH)
1342                                 pparent= parent;
1343                 }
1344         }
1345
1346         /* layout */
1347         block= uiLayoutGetBlock(layout);
1348         row= uiLayoutRow(layout, 0);
1349         col= uiLayoutColumn(row, 0);
1350         uiLayoutSetKeepAspect(col, 1);
1351         
1352         /* add preview */
1353         uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, pid, 0.0, 0.0, 0, 0, "");
1354         uiBlockSetDrawExtraFunc(block, ED_preview_draw, pparent, slot);
1355         uiBlockSetHandleFunc(block, do_preview_buttons, NULL);
1356         
1357         /* add buttons */
1358         if(pid) {
1359                 if(GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) {
1360                         if(GS(pid->name) == ID_MA) ma= (Material*)pid;
1361                         else ma= (Material*)pparent;
1362
1363                         uiLayoutColumn(row, 1);
1364
1365                         uiDefIconButC(block, ROW, B_MATPRV, ICON_MATPLANE,  0, 0,UI_UNIT_X*1.5,UI_UNIT_Y, &(ma->pr_type), 10, MA_FLAT, 0, 0, "Preview type: Flat XY plane");
1366                         uiDefIconButC(block, ROW, B_MATPRV, ICON_MATSPHERE, 0, 0,UI_UNIT_X*1.5,UI_UNIT_Y, &(ma->pr_type), 10, MA_SPHERE, 0, 0, "Preview type: Sphere");
1367                         uiDefIconButC(block, ROW, B_MATPRV, ICON_MATCUBE,   0, 0,UI_UNIT_X*1.5,UI_UNIT_Y, &(ma->pr_type), 10, MA_CUBE, 0, 0, "Preview type: Cube");
1368                         uiDefIconButC(block, ROW, B_MATPRV, ICON_MONKEY,    0, 0,UI_UNIT_X*1.5,UI_UNIT_Y, &(ma->pr_type), 10, MA_MONKEY, 0, 0, "Preview type: Monkey");
1369                         uiDefIconButC(block, ROW, B_MATPRV, ICON_HAIR,      0, 0,UI_UNIT_X*1.5,UI_UNIT_Y, &(ma->pr_type), 10, MA_HAIR, 0, 0, "Preview type: Hair strands");
1370                         uiDefIconButC(block, ROW, B_MATPRV, ICON_MAT_SPHERE_SKY, 0, 0,UI_UNIT_X*1.5,UI_UNIT_Y, &(ma->pr_type), 10, MA_SPHERE_A, 0, 0, "Preview type: Large sphere with sky");
1371                 }
1372
1373                 if(pr_texture) {
1374                         uiLayoutRow(layout, 1);
1375
1376                         uiDefButS(block, ROW, B_MATPRV, "Texture",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_TEXTURE, 0, 0, "");
1377                         if(GS(parent->name) == ID_MA)
1378                                 uiDefButS(block, ROW, B_MATPRV, "Material",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1379                         else if(GS(parent->name) == ID_LA)
1380                                 uiDefButS(block, ROW, B_MATPRV, "Lamp",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1381                         else if(GS(parent->name) == ID_WO)
1382                                 uiDefButS(block, ROW, B_MATPRV, "World",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1383                         uiDefButS(block, ROW, B_MATPRV, "Both",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_BOTH, 0, 0, "");
1384                 }
1385         }
1386 }
1387
1388 /********************** ColorRamp Template **************************/
1389
1390 #include "BKE_texture.h"
1391
1392 typedef struct RNAUpdateCb {
1393         PointerRNA ptr;
1394         PropertyRNA *prop;
1395 } RNAUpdateCb;
1396
1397 static void rna_update_cb(bContext *C, void *arg_cb, void *arg_unused)
1398 {
1399         RNAUpdateCb *cb= (RNAUpdateCb*)arg_cb;
1400
1401         /* we call update here on the pointer property, this way the
1402            owner of the curve mapping can still define it's own update
1403            and notifier, even if the CurveMapping struct is shared. */
1404         RNA_property_update(C, &cb->ptr, cb->prop);
1405 }
1406
1407 #define B_BANDCOL 1
1408
1409 static int vergcband(const void *a1, const void *a2)
1410 {
1411         const CBData *x1=a1, *x2=a2;
1412
1413         if( x1->pos > x2->pos ) return 1;
1414         else if( x1->pos < x2->pos) return -1;
1415         return 0;
1416 }
1417
1418 static void colorband_pos_cb(bContext *C, void *cb_v, void *coba_v)
1419 {
1420         ColorBand *coba= coba_v;
1421         int a;
1422
1423         if(coba->tot<2) return;
1424
1425         for(a=0; a<coba->tot; a++) coba->data[a].cur= a;
1426         qsort(coba->data, coba->tot, sizeof(CBData), vergcband);
1427         for(a=0; a<coba->tot; a++) {
1428                 if(coba->data[a].cur==coba->cur) {
1429                         coba->cur= a;
1430                         break;
1431                 }
1432         }
1433
1434         rna_update_cb(C, cb_v, NULL);
1435 }
1436
1437 static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
1438 {
1439         ColorBand *coba= coba_v;
1440
1441         if(coba->tot < MAXCOLORBAND-1) coba->tot++;
1442         coba->cur= coba->tot-1;
1443
1444         colorband_pos_cb(C, cb_v, coba_v);
1445
1446         ED_undo_push(C, "Add colorband");
1447 }
1448
1449 static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v)
1450 {
1451         ColorBand *coba= coba_v;
1452         int a;
1453
1454         if(coba->tot<2) return;
1455
1456         for(a=coba->cur; a<coba->tot; a++) {
1457                 coba->data[a]= coba->data[a+1];
1458         }
1459         if(coba->cur) coba->cur--;
1460         coba->tot--;
1461
1462         ED_undo_push(C, "Delete colorband");
1463
1464         rna_update_cb(C, cb_v, NULL);
1465 }
1466
1467
1468 /* offset aligns from bottom, standard width 300, height 115 */
1469 static void colorband_buttons_large(uiLayout *layout, uiBlock *block, ColorBand *coba, int xoffs, int yoffs, RNAUpdateCb *cb)
1470 {
1471         
1472         uiBut *bt;
1473         uiLayout *row;
1474
1475         if(coba==NULL) return;
1476
1477         bt= uiDefBut(block, BUT, 0,     "Add",                  0+xoffs,100+yoffs,50,20, 0, 0, 0, 0, 0, "Add a new color stop to the colorband");
1478         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1479
1480         bt= uiDefBut(block, BUT, 0,     "Delete",               60+xoffs,100+yoffs,50,20, 0, 0, 0, 0, 0, "Delete the active position");
1481         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1482
1483         uiDefButS(block, NUM, 0,                "",                             120+xoffs,100+yoffs,80, 20, &coba->cur, 0.0, (float)(MAX2(0, coba->tot-1)), 0, 0, "Choose active color stop");
1484
1485         bt= uiDefButS(block, MENU, 0,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
1486                         210+xoffs, 100+yoffs, 90, 20,           &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
1487         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1488         uiBlockEndAlign(block);
1489
1490         bt= uiDefBut(block, BUT_COLORBAND, 0, "",       xoffs,65+yoffs,300,30, coba, 0, 0, 0, 0, "");
1491         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1492
1493         if(coba->tot) {
1494                 CBData *cbd= coba->data + coba->cur;
1495
1496                 /* better to use rna so we can animate them */
1497                 PointerRNA ptr;
1498                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1499                 row= uiLayoutRow(layout, 0);
1500                 uiItemR(row, "Pos", 0, &ptr, "position", 0);
1501                 uiItemR(row, "", 0, &ptr, "color", 0);
1502         }
1503
1504 }
1505
1506 static void colorband_buttons_small(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb)
1507 {
1508         uiBut *bt;
1509         float unit= (butr->xmax-butr->xmin)/14.0f;
1510         float xs= butr->xmin;
1511
1512         uiBlockBeginAlign(block);
1513         bt= uiDefBut(block, BUT, 0,     "Add",                  xs,butr->ymin+20.0f,2.0f*unit,20,       NULL, 0, 0, 0, 0, "Add a new color stop to the colorband");
1514         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1515         bt= uiDefBut(block, BUT, 0,     "Delete",               xs+2.0f*unit,butr->ymin+20.0f,2.0f*unit,20,     NULL, 0, 0, 0, 0, "Delete the active position");
1516         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1517         uiBlockEndAlign(block);
1518
1519         if(coba->tot) {
1520                 CBData *cbd= coba->data + coba->cur;
1521                 PointerRNA ptr;
1522                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1523                 uiItemR(layout, "", 0, &ptr, "color", 0);
1524         }
1525
1526         bt= uiDefButS(block, MENU, 0,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
1527                         xs+10.0f*unit, butr->ymin+20.0f, unit*4, 20,            &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
1528         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1529
1530         bt= uiDefBut(block, BUT_COLORBAND, 0, "",               xs,butr->ymin,butr->xmax-butr->xmin,20.0f, coba, 0, 0, 0, 0, "");
1531         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1532
1533         uiBlockEndAlign(block);
1534 }
1535
1536 static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, int small, RNAUpdateCb *cb)
1537 {
1538         if(small)
1539                 colorband_buttons_small(layout, block, coba, butr, cb);
1540         else
1541                 colorband_buttons_large(layout, block, coba, 0, 0, cb);
1542 }
1543
1544 void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, char *propname, int expand)
1545 {
1546         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1547         PointerRNA cptr;
1548         RNAUpdateCb *cb;
1549         uiBlock *block;
1550         rctf rect;
1551
1552         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1553                 return;
1554
1555         cptr= RNA_property_pointer_get(ptr, prop);
1556         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp))
1557                 return;
1558
1559         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1560         cb->ptr= *ptr;
1561         cb->prop= prop;
1562
1563         rect.xmin= 0; rect.xmax= 200;
1564         rect.ymin= 0; rect.ymax= 190;
1565
1566         block= uiLayoutAbsoluteBlock(layout);
1567         colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1568
1569         MEM_freeN(cb);
1570 }
1571
1572 /********************* Histogram Template ************************/
1573
1574 void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, char *propname, int expand)
1575 {
1576         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1577         PointerRNA cptr;
1578         RNAUpdateCb *cb;
1579         uiBlock *block;
1580         uiBut *bt;
1581         Histogram *hist;
1582         rctf rect;
1583         
1584         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1585                 return;
1586         
1587         cptr= RNA_property_pointer_get(ptr, prop);
1588         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Histogram))
1589                 return;
1590         
1591         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1592         cb->ptr= *ptr;
1593         cb->prop= prop;
1594         
1595         rect.xmin= 0; rect.xmax= 200;
1596         rect.ymin= 0; rect.ymax= 190;
1597         
1598         block= uiLayoutAbsoluteBlock(layout);
1599         //colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1600         
1601         hist = (Histogram *)cptr.data;
1602         
1603         bt= uiDefBut(block, HISTOGRAM, 0, "",           rect.xmin, rect.ymin, rect.xmax-rect.xmin, 100.0f, hist, 0, 0, 0, 0, "");
1604         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1605         
1606         MEM_freeN(cb);
1607 }
1608
1609 /********************* CurveMapping Template ************************/
1610
1611 #include "BKE_colortools.h"
1612
1613 static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *unused)
1614 {
1615         CurveMapping *cumap = cumap_v;
1616         float d;
1617
1618         /* we allow 20 times zoom */
1619         if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1620                 d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin);
1621                 cumap->curr.xmin+= d;
1622                 cumap->curr.xmax-= d;
1623                 d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin);
1624                 cumap->curr.ymin+= d;
1625                 cumap->curr.ymax-= d;
1626         }
1627
1628         ED_region_tag_redraw(CTX_wm_region(C));
1629 }
1630
1631 static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *unused)
1632 {
1633         CurveMapping *cumap = cumap_v;
1634         float d, d1;
1635
1636         /* we allow 20 times zoom, but dont view outside clip */
1637         if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1638                 d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin);
1639
1640                 if(cumap->flag & CUMA_DO_CLIP) 
1641                         if(cumap->curr.xmin-d < cumap->clipr.xmin)
1642                                 d1= cumap->curr.xmin - cumap->clipr.xmin;
1643                 cumap->curr.xmin-= d1;
1644
1645                 d1= d;
1646                 if(cumap->flag & CUMA_DO_CLIP) 
1647                         if(cumap->curr.xmax+d > cumap->clipr.xmax)
1648                                 d1= -cumap->curr.xmax + cumap->clipr.xmax;
1649                 cumap->curr.xmax+= d1;
1650
1651                 d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin);
1652
1653                 if(cumap->flag & CUMA_DO_CLIP) 
1654                         if(cumap->curr.ymin-d < cumap->clipr.ymin)
1655                                 d1= cumap->curr.ymin - cumap->clipr.ymin;
1656                 cumap->curr.ymin-= d1;
1657
1658                 d1= d;
1659                 if(cumap->flag & CUMA_DO_CLIP) 
1660                         if(cumap->curr.ymax+d > cumap->clipr.ymax)
1661                                 d1= -cumap->curr.ymax + cumap->clipr.ymax;
1662                 cumap->curr.ymax+= d1;
1663         }
1664
1665         ED_region_tag_redraw(CTX_wm_region(C));
1666 }
1667
1668 static void curvemap_buttons_setclip(bContext *C, void *cumap_v, void *unused)
1669 {
1670         CurveMapping *cumap = cumap_v;
1671
1672         curvemapping_changed(cumap, 0);
1673 }       
1674
1675 static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v)
1676 {
1677         CurveMapping *cumap = cumap_v;
1678
1679         curvemap_remove(cumap->cm+cumap->cur, SELECT);
1680         curvemapping_changed(cumap, 0);
1681
1682         rna_update_cb(C, cb_v, NULL);
1683 }
1684
1685 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
1686 static uiBlock *curvemap_clipping_func(bContext *C, struct ARegion *ar, void *cumap_v)
1687 {
1688         CurveMapping *cumap = cumap_v;
1689         uiBlock *block;
1690         uiBut *bt;
1691
1692         block= uiBeginBlock(C, ar, "curvemap_clipping_func", UI_EMBOSS);
1693
1694         /* use this for a fake extra empy space around the buttons */
1695         uiDefBut(block, LABEL, 0, "",                   -4, 16, 128, 106, NULL, 0, 0, 0, 0, "");
1696
1697         bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",    
1698                         0,100,120,18, &cumap->flag, 0.0, 0.0, 10, 0, "");
1699         uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
1700
1701         uiBlockBeginAlign(block);
1702         uiDefButF(block, NUM, 0, "Min X ",       0,74,120,18, &cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 0, "");
1703         uiDefButF(block, NUM, 0, "Min Y ",       0,56,120,18, &cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 0, "");
1704         uiDefButF(block, NUM, 0, "Max X ",       0,38,120,18, &cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 0, "");
1705         uiDefButF(block, NUM, 0, "Max Y ",       0,20,120,18, &cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 0, "");
1706
1707         uiBlockSetDirection(block, UI_RIGHT);
1708
1709         uiEndBlock(C, block);
1710         return block;
1711 }
1712
1713 static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
1714 {
1715         CurveMapping *cumap = cumap_v;
1716         CurveMap *cuma= cumap->cm+cumap->cur;
1717
1718         switch(event) {
1719                 case 0: /* reset */
1720                         curvemap_reset(cuma, &cumap->clipr, CURVE_PRESET_LINE);
1721                         curvemapping_changed(cumap, 0);
1722                         break;
1723                 case 1:
1724                         cumap->curr= cumap->clipr;
1725                         break;
1726                 case 2: /* set vector */
1727                         curvemap_sethandle(cuma, 1);
1728                         curvemapping_changed(cumap, 0);
1729                         break;
1730                 case 3: /* set auto */
1731                         curvemap_sethandle(cuma, 0);
1732                         curvemapping_changed(cumap, 0);
1733                         break;
1734                 case 4: /* extend horiz */
1735                         cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
1736                         curvemapping_changed(cumap, 0);
1737                         break;
1738                 case 5: /* extend extrapolate */
1739                         cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
1740                         curvemapping_changed(cumap, 0);
1741                         break;
1742                 case 6: /* reset smooth */
1743                         curvemap_reset(cuma, &cumap->clipr, CURVE_PRESET_SMOOTH);
1744                         curvemapping_changed(cumap, 0);
1745                         break;
1746         }
1747         ED_region_tag_redraw(CTX_wm_region(C));
1748 }
1749
1750 static uiBlock *curvemap_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1751 {
1752         uiBlock *block;
1753         short yco= 0, menuwidth=120;
1754
1755         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
1756         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1757
1758         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View",                             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
1759         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
1760         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
1761         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Horizontal",              0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
1762         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Extrapolated",    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
1763         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
1764
1765         uiBlockSetDirection(block, UI_RIGHT);
1766         uiTextBoundsBlock(block, 50);
1767
1768         uiEndBlock(C, block);
1769         return block;
1770 }
1771
1772 static uiBlock *curvemap_brush_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1773 {
1774         uiBlock *block;
1775         short yco= 0, menuwidth=120;
1776
1777         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
1778         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1779
1780         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View",                             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
1781         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
1782         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
1783         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
1784
1785         uiBlockSetDirection(block, UI_RIGHT);
1786         uiTextBoundsBlock(block, 50);
1787
1788         uiEndBlock(C, block);
1789         return block;
1790 }
1791
1792 static void curvemap_buttons_redraw(bContext *C, void *arg1, void *arg2)
1793 {
1794         ED_region_tag_redraw(CTX_wm_region(C));
1795 }
1796
1797 static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
1798 {
1799         CurveMapping *cumap = cumap_v;
1800         int a;
1801         
1802         for(a=0; a<CM_TOT; a++)
1803                 curvemap_reset(cumap->cm+a, &cumap->clipr, CURVE_PRESET_LINE);
1804         
1805         cumap->black[0]=cumap->black[1]=cumap->black[2]= 0.0f;
1806         cumap->white[0]=cumap->white[1]=cumap->white[2]= 1.0f;
1807         curvemapping_set_black_white(cumap, NULL, NULL);
1808         
1809         curvemapping_changed(cumap, 0);
1810
1811         rna_update_cb(C, cb_v, NULL);
1812 }
1813
1814 /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
1815 static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels, int brush, RNAUpdateCb *cb)
1816 {
1817         CurveMapping *cumap= ptr->data;
1818         uiLayout *row, *sub, *split;
1819         uiBlock *block;
1820         uiBut *bt;
1821         float dx= UI_UNIT_X;
1822         int icon, size;
1823         int bg=-1;
1824
1825         block= uiLayoutGetBlock(layout);
1826
1827         /* curve chooser */
1828         row= uiLayoutRow(layout, 0);
1829
1830         if(labeltype=='v') {
1831                 /* vector */
1832                 sub= uiLayoutRow(row, 1);
1833                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1834
1835                 if(cumap->cm[0].curve) {
1836                         bt= uiDefButI(block, ROW, 0, "X", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1837                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1838                 }
1839                 if(cumap->cm[1].curve) {
1840                         bt= uiDefButI(block, ROW, 0, "Y", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1841                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1842                 }
1843                 if(cumap->cm[2].curve) {
1844                         bt= uiDefButI(block, ROW, 0, "Z", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1845                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1846                 }
1847         }
1848         else if(labeltype=='c') {
1849                 /* color */
1850                 sub= uiLayoutRow(row, 1);
1851                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1852
1853                 if(cumap->cm[3].curve) {
1854                         bt= uiDefButI(block, ROW, 0, "C", 0, 0, dx, 16, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
1855                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1856                 }
1857                 if(cumap->cm[0].curve) {
1858                         bt= uiDefButI(block, ROW, 0, "R", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1859                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1860                 }
1861                 if(cumap->cm[1].curve) {
1862                         bt= uiDefButI(block, ROW, 0, "G", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1863                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1864                 }
1865                 if(cumap->cm[2].curve) {
1866                         bt= uiDefButI(block, ROW, 0, "B", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1867                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1868                 }
1869         }
1870         else if (labeltype == 'h') {
1871                 /* HSV */
1872                 sub= uiLayoutRow(row, 1);
1873                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1874                 
1875                 if(cumap->cm[0].curve) {
1876                         bt= uiDefButI(block, ROW, 0, "H", 0, 0, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1877                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1878                 }
1879                 if(cumap->cm[1].curve) {
1880                         bt= uiDefButI(block, ROW, 0, "S", 0, 0, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1881                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1882                 }
1883                 if(cumap->cm[2].curve) {
1884                         bt= uiDefButI(block, ROW, 0, "V", 0, 0, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1885                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1886                 }
1887         }
1888         else
1889                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
1890         
1891         if (labeltype=='h')
1892                 bg = UI_GRAD_H;
1893
1894         /* operation buttons */
1895         sub= uiLayoutRow(row, 1);
1896
1897         uiBlockSetEmboss(block, UI_EMBOSSN);
1898
1899         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, 0, 0, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom in");
1900         uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
1901
1902         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMOUT, 0, 0, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom out");
1903         uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
1904
1905         if(brush)
1906                 bt= uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, 18, "Tools");
1907         else
1908                 bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, 18, "Tools");
1909
1910         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1911
1912         if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT;
1913         bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, 18, "Clipping Options");
1914         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1915
1916         bt= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Delete points");
1917         uiButSetNFunc(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
1918
1919         uiBlockSetEmboss(block, UI_EMBOSS);
1920
1921         uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
1922
1923         /* curve itself */
1924         size= uiLayoutGetWidth(layout);
1925         row= uiLayoutRow(layout, 0);
1926         uiDefBut(block, BUT_CURVE, 0, "", 0, 0, size, MIN2(size, 200), cumap, 0.0f, 1.0f, bg, 0, "");
1927
1928         /* black/white levels */
1929         if(levels) {
1930                 split= uiLayoutSplit(layout, 0, 0);
1931                 uiItemR(uiLayoutColumn(split, 0), NULL, 0, ptr, "black_level", UI_ITEM_R_EXPAND);
1932                 uiItemR(uiLayoutColumn(split, 0), NULL, 0, ptr, "white_level", UI_ITEM_R_EXPAND);
1933
1934                 uiLayoutRow(layout, 0);
1935                 bt=uiDefBut(block, BUT, 0, "Reset",     0, 0, UI_UNIT_X*10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Reset Black/White point and curves");
1936                 uiButSetNFunc(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
1937         }
1938
1939         uiBlockSetNFunc(block, NULL, NULL, NULL);
1940 }
1941
1942 void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, char *propname, int type, int levels, int brush)
1943 {
1944         RNAUpdateCb *cb;
1945         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1946         PointerRNA cptr;
1947
1948         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1949                 return;
1950
1951         cptr= RNA_property_pointer_get(ptr, prop);
1952         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveMapping))
1953                 return;
1954
1955         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1956         cb->ptr= *ptr;
1957         cb->prop= prop;
1958
1959         curvemap_buttons_layout(layout, &cptr, type, levels, brush, cb);
1960
1961         MEM_freeN(cb);
1962 }
1963
1964 /********************* ColorWheel Template ************************/
1965
1966 #define WHEEL_SIZE      100
1967
1968 void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, char *propname, int value_slider)
1969 {
1970         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1971         uiBlock *block= uiLayoutGetBlock(layout);
1972         uiLayout *col, *row;
1973         
1974         if (!prop) {
1975                 printf("uiTemplateColorWheel: property not found: %s\n", propname);
1976                 return;
1977         }
1978         
1979         col = uiLayoutColumn(layout, 0);
1980         row= uiLayoutRow(col, 1);
1981         
1982         uiDefButR(block, HSVCIRCLE, 0, "",      0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, propname, -1, 0.0, 0.0, 0, 0, "");
1983         
1984         uiItemS(row);
1985         
1986         if (value_slider)
1987                 uiDefButR(block, HSVCUBE, 0, "", WHEEL_SIZE+6, 0, 14, WHEEL_SIZE, ptr, propname, -1, 0.0, 0.0, 9, 0, "");
1988
1989         /* maybe a switch for this?
1990         row= uiLayoutRow(col, 0);
1991         if(ELEM(RNA_property_subtype(prop), PROP_COLOR, PROP_COLOR_GAMMA) && RNA_property_array_length(ptr, prop) == 4) {
1992                 but= uiDefAutoButR(block, ptr, prop, 3, "A:", 0, 0, 0, WHEEL_SIZE+20, UI_UNIT_Y);
1993         }
1994         */
1995         
1996 }
1997
1998
1999 /********************* TriColor (ThemeWireColorSet) Template ************************/
2000
2001 void uiTemplateTriColorSet(uiLayout *layout, PointerRNA *ptr, char *propname)
2002 {
2003         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
2004         uiLayout *row;
2005         PointerRNA csPtr;
2006
2007         if (!prop) {
2008                 printf("uiTemplateTriColorSet: property not found: %s\n", propname);
2009                 return;
2010         }
2011         
2012         /* we lay out the data in a row as 3 color swatches */
2013         row= uiLayoutRow(layout, 1);
2014         
2015         /* nselected, selected, active color swatches */
2016         csPtr= RNA_property_pointer_get(ptr, prop);
2017         
2018         uiItemR(row, "", 0, &csPtr, "normal", 0);
2019         uiItemR(row, "", 0, &csPtr, "selected", 0);
2020         uiItemR(row, "", 0, &csPtr, "active", 0);
2021 }
2022
2023 /********************* Layer Buttons Template ************************/
2024
2025 static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
2026 {
2027         uiBut *but = arg1;
2028         int cur = GET_INT_FROM_POINTER(arg2);
2029         wmWindow *win= CTX_wm_window(C);
2030         int i, tot, shift= win->eventstate->shift;
2031
2032         if(!shift) {
2033                 tot= RNA_property_array_length(&but->rnapoin, but->rnaprop);
2034                 
2035                 /* Normally clicking only selects one layer */
2036                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, 1);
2037                 for(i = 0; i < tot; ++i) {
2038                         if(i != cur)
2039                                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, 0);
2040                 }
2041         }
2042 }
2043
2044 // TODO:
2045 //      - for now, grouping of layers is determined by dividing up the length of 
2046 //        the array of layer bitflags
2047
2048 void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, char *propname,
2049                       PointerRNA *used_ptr, char *used_propname, int active_layer)
2050 {
2051         uiLayout *uRow, *uCol;
2052         PropertyRNA *prop, *used_prop= NULL;
2053         int groups, cols, layers;
2054         int group, col, layer, row;
2055         int cols_per_group = 5;
2056         const char *desc;
2057         
2058         prop= RNA_struct_find_property(ptr, propname);
2059         if (!prop) {
2060                 printf("uiTemplateLayer: layers property not found: %s\n", propname);
2061                 return;
2062         }
2063
2064         desc= RNA_property_description(prop);
2065         
2066         /* the number of layers determines the way we group them 
2067          *      - we want 2 rows only (for now)
2068          *      - the number of columns (cols) is the total number of buttons per row
2069          *        the 'remainder' is added to this, as it will be ok to have first row slightly wider if need be
2070          *      - for now, only split into groups if group will have at least 5 items
2071          */
2072         layers= RNA_property_array_length(ptr, prop);
2073         cols= (layers / 2) + (layers % 2);
2074         groups= ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group);
2075
2076         if(used_ptr && used_propname) {
2077                 used_prop= RNA_struct_find_property(used_ptr, used_propname);
2078                 if (!used_prop) {
2079                         printf("uiTemplateLayer: used layers property not found: %s\n", used_propname);
2080                         return;
2081                 }
2082
2083                 if(RNA_property_array_length(used_ptr, used_prop) < layers)
2084                         used_prop = NULL;
2085         }
2086         
2087         /* layers are laid out going across rows, with the columns being divided into groups */
2088         
2089         for (group= 0; group < groups; group++) {
2090                 uCol= uiLayoutColumn(layout, 1);
2091                 
2092                 for (row= 0; row < 2; row++) {
2093                         uiBlock *block;
2094                         uiBut *but;
2095
2096                         uRow= uiLayoutRow(uCol, 1);
2097                         block= uiLayoutGetBlock(uRow);
2098                         layer= groups*cols_per_group*row + cols_per_group*group;
2099                         
2100                         /* add layers as toggle buts */
2101                         for (col= 0; (col < cols_per_group) && (layer < layers); col++, layer++) {
2102                                 int icon = 0;
2103                                 int butlay = 1 << layer;
2104
2105                                 if(active_layer & butlay)
2106                                         icon = ICON_LAYER_ACTIVE;
2107                                 else if(used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, layer))
2108                                         icon = ICON_LAYER_USED;
2109                                 
2110                                 but= uiDefAutoButR(block, ptr, prop, layer, "", icon, 0, 0, 10, 10);
2111                                 uiButSetFunc(but, handle_layer_buttons, but, SET_INT_IN_POINTER(layer));
2112                                 but->type= TOG;
2113                         }
2114                 }
2115         }
2116 }
2117
2118
2119 /************************* List Template **************************/
2120
2121 static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon)
2122 {
2123         ID *id= NULL;
2124         int icon;
2125
2126         if(!itemptr->data)
2127                 return rnaicon;
2128
2129         /* try ID, material or texture slot */
2130         if(RNA_struct_is_ID(itemptr->type)) {
2131                 id= itemptr->id.data;
2132         }
2133         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2134                 id= RNA_pointer_get(itemptr, "material").data;
2135         }
2136         else if(RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) {
2137                 id= RNA_pointer_get(itemptr, "texture").data;
2138         }
2139
2140         /* get icon from ID */
2141         if(id) {
2142                 icon= ui_id_icon_get(C, id, 1);
2143
2144                 if(icon)
2145                         return icon;
2146         }
2147
2148         return rnaicon;
2149 }
2150
2151 static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *itemptr, int i, int rnaicon, PointerRNA *activeptr, char *activepropname)
2152 {
2153         Object *ob;
2154         uiBlock *block= uiLayoutGetBlock(layout);
2155         uiBut *but;
2156         uiLayout *split, *overlap, *sub, *row;
2157         char *name, *namebuf;
2158         int icon;
2159
2160         overlap= uiLayoutOverlap(layout);
2161
2162         /* list item behind label & other buttons */
2163         sub= uiLayoutRow(overlap, 0);
2164
2165         if(itemptr->type == &RNA_ShapeKey) {
2166                 ob= (Object*)activeptr->data;
2167                 if(ob->mode == OB_MODE_EDIT && !(ob->type == OB_MESH))
2168                         uiLayoutSetEnabled(sub, 0);
2169         }
2170
2171         but= uiDefButR(block, LISTROW, 0, "", 0,0, UI_UNIT_X*10,UI_UNIT_Y, activeptr, activepropname, 0, 0, i, 0, 0, "");
2172         uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2173
2174         sub= uiLayoutRow(overlap, 0);
2175
2176         /* retrieve icon and name */
2177         icon= list_item_icon_get(C, itemptr, rnaicon);
2178         if(!icon || icon == ICON_DOT)
2179                 icon= 0;
2180
2181         namebuf= RNA_struct_name_get_alloc(itemptr, NULL, 0);
2182         name= (namebuf)? namebuf: "";
2183
2184         /* hardcoded types */
2185         if(itemptr->type == &RNA_MeshTextureFaceLayer || itemptr->type == &RNA_MeshColorLayer) {
2186                 uiItemL(sub, name, icon);
2187                 uiBlockSetEmboss(block, UI_EMBOSSN);
2188                 uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", 0, 0, 0, 0, 0, NULL);
2189                 uiBlockSetEmboss(block, UI_EMBOSS);
2190         }
2191         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) {
2192                 uiItemL(sub, name, icon);
2193                 uiBlockSetEmboss(block, UI_EMBOSS);
2194                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0,  NULL);
2195         }
2196         else if(RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
2197                 uiItemL(sub, name, icon);
2198                 uiBlockSetEmboss(block, UI_EMBOSS);
2199                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "enabled", 0, 0, 0, 0, 0,  NULL);
2200         }
2201         else if(itemptr->type == &RNA_ShapeKey) {
2202                 ob= (Object*)activeptr->data;
2203
2204                 split= uiLayoutSplit(sub, 0.75f, 0);
2205
2206                 uiItemL(split, name, icon);
2207
2208                 uiBlockSetEmboss(block, UI_EMBOSSN);
2209                 row= uiLayoutRow(split, 1);
2210                 if(i == 0) uiItemL(row, "", 0);
2211                 else uiItemR(row, "", 0, itemptr, "value", 0);
2212
2213                 if(ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH))
2214                         uiLayoutSetActive(row, 0);
2215                 //uiItemR(row, "", ICON_MUTE_IPO_OFF, itemptr, "mute", 0);
2216                 uiBlockSetEmboss(block, UI_EMBOSS);
2217         }
2218         else
2219                 uiItemLDrag(sub, itemptr, name, icon); /* fails, backdrop LISTROW... */
2220
2221         /* free name */
2222         if(namebuf)
2223                 MEM_freeN(namebuf);
2224 }
2225
2226 void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, PointerRNA *activeptr, char *activepropname, int rows, int maxrows, int listtype)
2227 {
2228         //Scene *scene= CTX_data_scene(C);
2229         PropertyRNA *prop= NULL, *activeprop;
2230         PropertyType type, activetype;
2231         StructRNA *ptype;
2232         uiLayout *box, *row, *col;
2233         uiBlock *block;
2234         uiBut *but;
2235         Panel *pa;
2236         char *name, str[32];
2237         int rnaicon=0, icon=0, i= 0, activei= 0, len= 0, items, found, min, max;
2238
2239         /* validate arguments */
2240         block= uiLayoutGetBlock(layout);
2241         pa= block->panel;
2242
2243         if(!pa) {
2244                 printf("uiTemplateList: only works inside a panel.\n");
2245                 return;
2246         }
2247
2248         if(!activeptr->data)
2249                 return;
2250         
2251         if(ptr->data) {
2252                 prop= RNA_struct_find_property(ptr, propname);
2253                 if(!prop) {
2254                         printf("uiTemplateList: property not found: %s\n", propname);
2255                         return;
2256                 }
2257         }
2258
2259         activeprop= RNA_struct_find_property(activeptr, activepropname);
2260         if(!activeprop) {
2261                 printf("uiTemplateList: property not found: %s\n", activepropname);
2262                 return;
2263         }
2264
2265         if(prop) {
2266                 type= RNA_property_type(prop);
2267                 if(type != PROP_COLLECTION) {
2268                         printf("uiTemplateList: expected collection property.\n");
2269                         return;
2270                 }
2271         }
2272
2273         activetype= RNA_property_type(activeprop);
2274         if(activetype != PROP_INT) {
2275                 printf("uiTemplateList: expected integer property.\n");
2276                 return;
2277         }
2278
2279         /* get icon */
2280         if(ptr->data && prop) {
2281                 ptype= RNA_property_pointer_type(ptr, prop);
2282                 rnaicon= RNA_struct_ui_icon(ptype);
2283         }
2284
2285         /* get active data */
2286         activei= RNA_property_int_get(activeptr, activeprop);
2287
2288         if(listtype == 'i') {
2289                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2290                 col= uiLayoutColumn(box, 1);
2291                 row= uiLayoutRow(col, 0);
2292
2293                 if(ptr->data && prop) {
2294                         /* create list items */
2295                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2296                                 /* create button */
2297                                 if(i == 9)
2298                                         row= uiLayoutRow(col, 0);
2299
2300                                 icon= list_item_icon_get(C, &itemptr, rnaicon);
2301                                 but= uiDefIconButR(block, LISTROW, 0, icon, 0,0,UI_UNIT_X*10,UI_UNIT_Y, activeptr, activepropname, 0, 0, i, 0, 0, "");
2302                                 uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2303                                 
2304
2305                                 i++;
2306                         }
2307                         RNA_PROP_END;
2308                 }
2309         }
2310         else if(listtype == 'c') {
2311                 /* compact layout */
2312                 found= 0;
2313
2314                 row= uiLayoutRow(layout, 1);
2315
2316                 if(ptr->data && prop) {
2317                         /* create list items */
2318                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2319                                 found= (activei == i);
2320
2321                                 if(found) {
2322                                         /* create button */
2323                                         name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
2324                                         icon= list_item_icon_get(C, &itemptr, rnaicon);
2325                                         uiItemL(row, (name)? name: "", icon);
2326
2327                                         if(name)
2328                                                 MEM_freeN(name);
2329                                 }
2330
2331                                 i++;
2332                         }
2333                         RNA_PROP_END;
2334                 }
2335
2336                 /* if not found, add in dummy button */
2337                 if(i == 0)
2338                         uiItemL(row, "", 0);
2339
2340                 /* next/prev button */
2341                 sprintf(str, "%d :", i);
2342                 but= uiDefIconTextButR(block, NUM, 0, 0, str, 0,0,UI_UNIT_X*5,UI_UNIT_Y, activeptr, activepropname, 0, 0, 0, 0, 0, "");
2343                 if(i == 0)
2344                         uiButSetFlag(but, UI_BUT_DISABLED);
2345         }
2346         else {
2347                 /* default rows */
2348                 if(rows == 0)
2349                         rows= 5;
2350                 if (maxrows == 0)
2351                         maxrows = 5;
2352                 if(pa->list_grip_size != 0)
2353                         rows= pa->list_grip_size;
2354
2355                 /* layout */
2356                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2357                 row= uiLayoutRow(box, 0);
2358                 col = uiLayoutColumn(row, 1);
2359
2360                 /* init numbers */
2361                 RNA_property_int_range(activeptr, activeprop, &min, &max);
2362
2363                 if(prop)
2364                         len= RNA_property_collection_length(ptr, prop);
2365                 items= CLAMPIS(len, rows, MAX2(rows, maxrows));
2366
2367                 /* if list length changes and active is out of view, scroll to it */
2368                 if(pa->list_last_len != len)
2369                         if((activei < pa->list_scroll || activei >= pa->list_scroll+items))
2370                                 pa->list_scroll= activei;
2371
2372                 pa->list_scroll= MIN2(pa->list_scroll, len-items);
2373                 pa->list_scroll= MAX2(pa->list_scroll, 0);
2374                 pa->list_size= items;
2375                 pa->list_last_len= len;
2376
2377                 if(ptr->data && prop) {
2378                         /* create list items */
2379                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2380                                 if(i >= pa->list_scroll && i<pa->list_scroll+items)
2381                                         list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activepropname);
2382
2383                                 i++;
2384                         }
2385                         RNA_PROP_END;
2386                 }
2387
2388                 /* add dummy buttons to fill space */
2389                 while(i < pa->list_scroll+items) {
2390                         if(i >= pa->list_scroll)
2391                                 uiItemL(col, "", 0);
2392                         i++;
2393                 }
2394
2395                 /* add scrollbar */
2396                 if(len > items) {
2397                         col= uiLayoutColumn(row, 0);
2398                         uiDefButI(block, SCROLL, 0, "", 0,0,UI_UNIT_X*0.75,UI_UNIT_Y*items, &pa->list_scroll, 0, len-items, items, 0, "");
2399                 }
2400         }
2401 }
2402
2403 /************************* Operator Search Template **************************/
2404
2405 static void operator_call_cb(bContext *C, void *arg1, void *arg2)
2406 {
2407         wmOperatorType *ot= arg2;
2408         
2409         if(ot)
2410                 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
2411 }
2412
2413 static void operator_search_cb(const bContext *C, void *arg, char *str, uiSearchItems *items)
2414 {
2415         wmOperatorType *ot = WM_operatortype_first();
2416         
2417         for(; ot; ot= ot->next) {
2418                 
2419                 if(BLI_strcasestr(ot->name, str)) {
2420                         if(WM_operator_poll((bContext*)C, ot)) {
2421                                 char name[256];
2422                                 int len= strlen(ot->name);
2423                                 
2424                                 /* display name for menu, can hold hotkey */
2425                                 BLI_strncpy(name, ot->name, 256);
2426                                 
2427                                 /* check for hotkey */
2428                                 if(len < 256-6) {
2429                                         if(WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, &name[len+1], 256-len-1))
2430                                                 name[len]= '|';
2431                                 }
2432                                 
2433                                 if(0==uiSearchItemAdd(items, name, ot, 0))
2434                                         break;
2435                         }
2436                 }
2437         }
2438 }
2439
2440 void uiTemplateOperatorSearch(uiLayout *layout)
2441 {
2442         uiBlock *block;
2443         uiBut *but;
2444         static char search[256]= "";
2445                 
2446         block= uiLayoutGetBlock(layout);
2447         uiBlockSetCurLayout(block, layout);
2448
2449         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, 0, 0, "");
2450         uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
2451 }
2452
2453 /************************* Running Jobs Template **************************/
2454
2455 #define B_STOPRENDER    1
2456 #define B_STOPCAST              2
2457 #define B_STOPANIM              3
2458
2459 static void do_running_jobs(bContext *C, void *arg, int event)
2460 {
2461         switch(event) {
2462                 case B_STOPRENDER:
2463                         G.afbreek= 1;
2464                         break;
2465                 case B_STOPCAST:
2466                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C));
2467                         break;
2468                 case B_STOPANIM:
2469                         WM_operator_name_call(C, "SCREEN_OT_animation_play", WM_OP_INVOKE_SCREEN, NULL);
2470                         break;
2471         }
2472 }
2473
2474 void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
2475 {
2476         bScreen *screen= CTX_wm_screen(C);
2477         Scene *scene= CTX_data_scene(C);
2478         wmWindowManager *wm= CTX_wm_manager(C);
2479         uiBlock *block;
2480
2481         block= uiLayoutGetBlock(layout);
2482         uiBlockSetCurLayout(block, layout);
2483
2484         uiBlockSetHandleFunc(block, do_running_jobs, NULL);
2485
2486         if(WM_jobs_test(wm, scene))
2487                 uiDefIconTextBut(block, BUT, B_STOPRENDER, ICON_CANCEL, "Render", 0,0,75,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop rendering");
2488         if(WM_jobs_test(wm, screen))
2489                 uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, "Capture", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop screencast");
2490         if(screen->animtimer)
2491                 uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_CANCEL, "Anim Player", 0,0,100,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop animation playback");
2492 }
2493
2494