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