70336eb9e0f33b91a305c11ae9d2d8a38a5706dd
[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                 } /* tessellation 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 tessellates 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_MeshTexturePolyLayer || itemptr->type == &RNA_MeshLoopColorLayer) {
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