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