style cleanup, brackets in else/if, some indentation.
[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                                 /* -- convert to rna ? */
779                                 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,
780                                                 TIP_("Apply modifier to editing cage during Editmode"));
781                                 if (index < cageIndex)
782                                         uiButSetFlag(but, UI_BUT_DISABLED);
783                                 uiButSetFunc(but, modifiers_setOnCage, ob, md);
784                         }
785                         else {
786                                 uiBlockEndAlign(block);
787
788                                 /* place holder button */
789                                 uiBlockSetEmboss(block, UI_EMBOSSN);
790                                 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);
791                                 uiButSetFlag(but, UI_BUT_DISABLED);
792                                 uiBlockSetEmboss(block, UI_EMBOSS);
793                         }
794                 } /* tessellation point for curve-typed objects */
795                 else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
796                         /* some modifiers could work with pre-tesselated curves only */
797                         if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
798                                 /* add disabled pre-tesselated button, so users could have
799                                  * message for this modifiers */
800                                 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,
801                                                 TIP_("This modifier could be applied on splines' points only"));
802                                 uiButSetFlag(but, UI_BUT_DISABLED);
803                         } else if (mti->type != eModifierTypeType_Constructive) {
804                                 /* constructive modifiers tessellates curve before applying */
805                                 uiItemR(row, &ptr, "use_apply_on_spline", 0, "", ICON_NONE);
806                         }
807                 }
808
809                 uiBlockEndAlign(block);
810                 
811                 /* Up/Down + Delete ........................... */
812                 uiBlockBeginAlign(block);
813                 uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_modifier_move_up");
814                 uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_modifier_move_down");
815                 uiBlockEndAlign(block);
816                 
817                 uiBlockSetEmboss(block, UI_EMBOSSN);
818                 // When Modifier is a simulation, show button to switch to context rather than the delete button. 
819                 if (modifier_can_delete(md) && !modifier_is_simulation(md))
820                         uiItemO(row, "", ICON_X, "OBJECT_OT_modifier_remove");
821                 if (modifier_is_simulation(md) == 1)
822                         uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PHYSICS");
823                 else if (modifier_is_simulation(md) == 2)
824                         uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PARTICLES");
825                 uiBlockSetEmboss(block, UI_EMBOSS);
826         }
827
828         
829         /* modifier settings (under the header) --------------------------------------------------- */
830         if (!isVirtual && (md->mode & eModifierMode_Expanded)) {
831                 /* apply/convert/copy */
832                 box= uiLayoutBox(column);
833                 row= uiLayoutRow(box, 0);
834                 
835                 if (!ELEM(md->type, eModifierType_Collision, eModifierType_Surface)) {
836                         /* only here obdata, the rest of modifiers is ob level */
837                         uiBlockSetButLock(block, object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
838                         
839                         if (md->type==eModifierType_ParticleSystem) {
840                                 ParticleSystem *psys= ((ParticleSystemModifierData *)md)->psys;
841                                 
842                                 if (!(ob->mode & OB_MODE_PARTICLE_EDIT) && psys->pathcache) {
843                                         if(ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB))
844                                                 uiItemO(row, "Convert", ICON_NONE, "OBJECT_OT_duplicates_make_real");
845                                         else if(psys->part->ren_as == PART_DRAW_PATH)
846                                                 uiItemO(row, "Convert", ICON_NONE, "OBJECT_OT_modifier_convert");
847                                 }
848                         }
849                         else {
850                                 uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
851                                 uiItemEnumO(row, "OBJECT_OT_modifier_apply", IFACE_("Apply"), 0, "apply_as", MODIFIER_APPLY_DATA);
852                                 
853                                 if (modifier_sameTopology(md) && !modifier_nonGeometrical(md))
854                                         uiItemEnumO(row, "OBJECT_OT_modifier_apply", IFACE_("Apply as Shape Key"), 0, "apply_as", MODIFIER_APPLY_SHAPE);
855                         }
856                         
857                         uiBlockClearButLock(block);
858                         uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
859                         
860                         if (!ELEM5(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, eModifierType_Cloth, eModifierType_Smoke))
861                                 uiItemO(row, IFACE_("Copy"), ICON_NONE, "OBJECT_OT_modifier_copy");
862                 }
863                 
864                 /* result is the layout block inside the box, that we return so that modifier settings can be drawn */
865                 result= uiLayoutColumn(box, 0);
866                 block= uiLayoutAbsoluteBlock(box);
867         }
868         
869         /* error messages */
870         if(md->error) {
871                 box = uiLayoutBox(column);
872                 row = uiLayoutRow(box, 0);
873                 uiItemL(row, md->error, ICON_ERROR);
874         }
875         
876         return result;
877 }
878
879 uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
880 {
881         Scene *scene = CTX_data_scene(C);
882         Object *ob;
883         ModifierData *md, *vmd;
884         int i, lastCageIndex, cageIndex;
885
886         /* verify we have valid data */
887         if(!RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
888                 RNA_warning("Expected modifier on object");
889                 return NULL;
890         }
891
892         ob= ptr->id.data;
893         md= ptr->data;
894
895         if(!ob || !(GS(ob->id.name) == ID_OB)) {
896                 RNA_warning("Expected modifier on object");
897                 return NULL;
898         }
899         
900         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
901         
902         /* find modifier and draw it */
903         cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
904
905         // XXX virtual modifiers are not accesible for python
906         vmd = modifiers_getVirtualModifierList(ob);
907
908         for(i=0; vmd; i++, vmd=vmd->next) {
909                 if(md == vmd)
910                         return draw_modifier(layout, scene, ob, md, i, cageIndex, lastCageIndex);
911                 else if(vmd->mode & eModifierMode_Virtual)
912                         i--;
913         }
914
915         return NULL;
916 }
917
918 /************************ Constraint Template *************************/
919
920 #include "DNA_constraint_types.h"
921
922 #include "BKE_action.h"
923 #include "BKE_constraint.h"
924
925 #define REDRAWIPO                                       1
926 #define REDRAWNLA                                       2
927 #define REDRAWBUTSOBJECT                        3               
928 #define REDRAWACTION                            4
929 #define B_CONSTRAINT_TEST                       5
930 #define B_CONSTRAINT_CHANGETARGET       6
931 #define REMAKEIPO                                       8
932 #define B_DIFF                                          9
933
934 static void do_constraint_panels(bContext *C, void *ob_pt, int event)
935 {
936         Main *bmain= CTX_data_main(C);
937         Scene *scene= CTX_data_scene(C);
938         Object *ob= (Object *)ob_pt;
939         
940         switch(event) {
941         case B_CONSTRAINT_TEST:
942                 break;  // no handling
943         case B_CONSTRAINT_CHANGETARGET:
944                 if (ob->pose) ob->pose->flag |= POSE_RECALC;    // checks & sorts pose channels
945                 DAG_scene_sort(bmain, scene);
946                 break;
947         default:
948                 break;
949         }
950
951         // note: RNA updates now call this, commenting else it gets called twice.
952         // if there are problems because of this, then rna needs changed update functions.
953         // 
954         // object_test_constraints(ob);
955         // if(ob->pose) update_pose_constraint_flags(ob->pose);
956         
957         if(ob->type==OB_ARMATURE) DAG_id_tag_update(&ob->id, OB_RECALC_DATA|OB_RECALC_OB);
958         else DAG_id_tag_update(&ob->id, OB_RECALC_OB);
959
960         WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
961 }
962
963 static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
964 {
965         ED_object_constraint_set_active(ob_v, con_v);
966 }
967
968 /* draw panel showing settings for a constraint */
969 static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
970 {
971         bPoseChannel *pchan= get_active_posechannel(ob);
972         bConstraintTypeInfo *cti;
973         uiBlock *block;
974         uiLayout *result= NULL, *col, *box, *row;
975         PointerRNA ptr;
976         char typestr[32];
977         short proxy_protected, xco=0, yco=0;
978         // int rb_col; // UNUSED
979
980         /* get constraint typeinfo */
981         cti= constraint_get_typeinfo(con);
982         if (cti == NULL) {
983                 /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
984                 BLI_strncpy(typestr, (con->type == CONSTRAINT_TYPE_NULL) ? "Null" : "Unknown", sizeof(typestr));
985         }
986         else
987                 BLI_strncpy(typestr, cti->name, sizeof(typestr));
988                 
989         /* determine whether constraint is proxy protected or not */
990         if (proxylocked_constraints_owner(ob, pchan))
991                 proxy_protected= (con->flag & CONSTRAINT_PROXY_LOCAL)==0;
992         else
993                 proxy_protected= 0;
994
995         /* unless button has own callback, it adds this callback to button */
996         block= uiLayoutGetBlock(layout);
997         uiBlockSetHandleFunc(block, do_constraint_panels, ob);
998         uiBlockSetFunc(block, constraint_active_func, ob, con);
999
1000         RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
1001
1002         col= uiLayoutColumn(layout, 1);
1003         uiLayoutSetContextPointer(col, "constraint", &ptr);
1004
1005         box= uiLayoutBox(col);
1006         row = uiLayoutRow(box, 0);
1007         block= uiLayoutGetBlock(box);
1008
1009         /* Draw constraint header */
1010
1011         /* open/close */
1012         uiBlockSetEmboss(block, UI_EMBOSSN);
1013         uiItemR(row, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
1014         uiBlockSetEmboss(block, UI_EMBOSS);
1015         
1016         /* name */
1017         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco+10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1018
1019         if (con->flag & CONSTRAINT_DISABLE)
1020                 uiLayoutSetRedAlert(row, 1);
1021         
1022         if(proxy_protected == 0) {
1023                 uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
1024         }
1025         else
1026                 uiItemL(row, con->name, ICON_NONE);
1027         
1028         uiLayoutSetRedAlert(row, 0);
1029         
1030         /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
1031         if (proxy_protected) {
1032                 uiBlockSetEmboss(block, UI_EMBOSSN);
1033                 
1034                 /* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
1035                 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"));
1036                 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"));
1037                 
1038                 uiBlockSetEmboss(block, UI_EMBOSS);
1039         }
1040         else {
1041                 short prev_proxylock, show_upbut, show_downbut;
1042                 
1043                 /* Up/Down buttons: 
1044                  *      Proxy-constraints are not allowed to occur after local (non-proxy) constraints
1045                  *      as that poses problems when restoring them, so disable the "up" button where
1046                  *      it may cause this situation. 
1047                  *
1048                  *      Up/Down buttons should only be shown (or not greyed - todo) if they serve some purpose. 
1049                  */
1050                 if (proxylocked_constraints_owner(ob, pchan)) {
1051                         if (con->prev) {
1052                                 prev_proxylock= (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
1053                         }
1054                         else
1055                                 prev_proxylock= 0;
1056                 }
1057                 else
1058                         prev_proxylock= 0;
1059                         
1060                 show_upbut= ((prev_proxylock == 0) && (con->prev));
1061                 show_downbut= (con->next) ? 1 : 0;
1062                 
1063                 /* enabled */
1064                 uiBlockSetEmboss(block, UI_EMBOSSN);
1065                 uiItemR(row, &ptr, "mute", 0, "", (con->flag & CONSTRAINT_OFF) ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF);
1066                 uiBlockSetEmboss(block, UI_EMBOSS);
1067                 
1068                 uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
1069                 
1070                 /* up/down */
1071                 if (show_upbut || show_downbut) {
1072                         uiBlockBeginAlign(block);
1073                         if (show_upbut)
1074                                 uiItemO(row, "", ICON_TRIA_UP, "CONSTRAINT_OT_move_up");
1075                                 
1076                         if (show_downbut)
1077                                 uiItemO(row, "", ICON_TRIA_DOWN, "CONSTRAINT_OT_move_down");
1078                         uiBlockEndAlign(block);
1079                 }
1080                 
1081                 /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
1082                 uiBlockSetEmboss(block, UI_EMBOSSN);
1083                 uiItemO(row, "", ICON_X, "CONSTRAINT_OT_delete");
1084                 uiBlockSetEmboss(block, UI_EMBOSS);
1085         }
1086
1087         /* Set but-locks for protected settings (magic numbers are used here!) */
1088         if (proxy_protected)
1089                 uiBlockSetButLock(block, 1, "Cannot edit Proxy-Protected Constraint");
1090
1091         /* Draw constraint data */
1092         if ((con->flag & CONSTRAINT_EXPAND) == 0) {
1093                 (yco) -= 21;
1094         }
1095         else {
1096                 box= uiLayoutBox(col);
1097                 block= uiLayoutAbsoluteBlock(box);
1098                 result= box;
1099         }
1100
1101         /* clear any locks set up for proxies/lib-linking */
1102         uiBlockClearButLock(block);
1103
1104         return result;
1105 }
1106
1107 uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
1108 {
1109         Object *ob;
1110         bConstraint *con;
1111
1112         /* verify we have valid data */
1113         if(!RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
1114                 RNA_warning("Expected constraint on object");
1115                 return NULL;
1116         }
1117
1118         ob= ptr->id.data;
1119         con= ptr->data;
1120
1121         if(!ob || !(GS(ob->id.name) == ID_OB)) {
1122                 RNA_warning("Expected constraint on object");
1123                 return NULL;
1124         }
1125         
1126         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
1127
1128         /* hrms, the temporal constraint should not draw! */
1129         if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
1130                 bKinematicConstraint *data= con->data;
1131                 if(data->flag & CONSTRAINT_IK_TEMP)
1132                         return NULL;
1133         }
1134
1135         return draw_constraint(layout, ob, con);
1136 }
1137
1138
1139 /************************* Preview Template ***************************/
1140
1141 #include "DNA_lamp_types.h"
1142 #include "DNA_material_types.h"
1143 #include "DNA_world_types.h"
1144
1145 #define B_MATPRV 1
1146
1147 static void do_preview_buttons(bContext *C, void *arg, int event)
1148 {
1149         switch(event) {
1150                 case B_MATPRV:
1151                         WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, arg);
1152                         break;
1153         }
1154 }
1155
1156 void uiTemplatePreview(uiLayout *layout, ID *id, int show_buttons, ID *parent, MTex *slot)
1157 {
1158         uiLayout *row, *col;
1159         uiBlock *block;
1160         Material *ma= NULL;
1161         Tex *tex = (Tex*)id;
1162         ID *pid, *pparent;
1163         short *pr_texture= NULL;
1164         PointerRNA material_ptr;
1165         PointerRNA texture_ptr;
1166
1167         if(id && !ELEM4(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA)) {
1168                 RNA_warning("Expected ID of type material, texture, lamp or world");
1169                 return;
1170         }
1171
1172         /* decide what to render */
1173         pid= id;
1174         pparent= NULL;
1175
1176         if(id && (GS(id->name) == ID_TE)) {
1177                 if(parent && (GS(parent->name) == ID_MA))
1178                         pr_texture= &((Material*)parent)->pr_texture;
1179                 else if(parent && (GS(parent->name) == ID_WO))
1180                         pr_texture= &((World*)parent)->pr_texture;
1181                 else if(parent && (GS(parent->name) == ID_LA))
1182                         pr_texture= &((Lamp*)parent)->pr_texture;
1183
1184                 if(pr_texture) {
1185                         if(*pr_texture == TEX_PR_OTHER)
1186                                 pid= parent;
1187                         else if(*pr_texture == TEX_PR_BOTH)
1188                                 pparent= parent;
1189                 }
1190         }
1191
1192         /* layout */
1193         block= uiLayoutGetBlock(layout);
1194         row= uiLayoutRow(layout, 0);
1195         col= uiLayoutColumn(row, 0);
1196         uiLayoutSetKeepAspect(col, 1);
1197         
1198         /* add preview */
1199         uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, pid, 0.0, 0.0, 0, 0, "");
1200         uiBlockSetDrawExtraFunc(block, ED_preview_draw, pparent, slot);
1201         uiBlockSetHandleFunc(block, do_preview_buttons, NULL);
1202         
1203         /* add buttons */
1204         if (pid && show_buttons) {
1205                 if(GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) {
1206                         if(GS(pid->name) == ID_MA) ma= (Material*)pid;
1207                         else ma= (Material*)pparent;
1208                         
1209                         /* Create RNA Pointer */
1210                         RNA_pointer_create(id, &RNA_Material, ma, &material_ptr);
1211
1212                         col = uiLayoutColumn(row, 1);
1213                         uiLayoutSetScaleX(col, 1.5);
1214                         uiItemR(col, &material_ptr, "preview_render_type", UI_ITEM_R_EXPAND, "", ICON_NONE);
1215                 }
1216
1217                 if(pr_texture) {
1218                         /* Create RNA Pointer */
1219                         RNA_pointer_create(id, &RNA_Texture, tex, &texture_ptr);
1220                         
1221                         uiLayoutRow(layout, 1);
1222                         uiDefButS(block, ROW, B_MATPRV, IFACE_("Texture"),  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_TEXTURE, 0, 0, "");
1223                         if(GS(parent->name) == ID_MA)
1224                                 uiDefButS(block, ROW, B_MATPRV, IFACE_("Material"),  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1225                         else if(GS(parent->name) == ID_LA)
1226                                 uiDefButS(block, ROW, B_MATPRV, IFACE_("Lamp"),  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1227                         else if(GS(parent->name) == ID_WO)
1228                                 uiDefButS(block, ROW, B_MATPRV, IFACE_("World"),  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1229                         uiDefButS(block, ROW, B_MATPRV, IFACE_("Both"),  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_BOTH, 0, 0, "");
1230                         
1231                         /* Alpha button for texture preview */
1232                         if(*pr_texture!=TEX_PR_OTHER) {
1233                                 row = uiLayoutRow(layout, 0);
1234                                 uiItemR(row, &texture_ptr, "use_preview_alpha", 0, NULL, ICON_NONE);
1235                         }
1236                 }
1237         }
1238 }
1239
1240 /********************** ColorRamp Template **************************/
1241
1242
1243 typedef struct RNAUpdateCb {
1244         PointerRNA ptr;
1245         PropertyRNA *prop;
1246 } RNAUpdateCb;
1247
1248 static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
1249 {
1250         RNAUpdateCb *cb= (RNAUpdateCb*)arg_cb;
1251
1252         /* we call update here on the pointer property, this way the
1253          * owner of the curve mapping can still define it's own update
1254          * and notifier, even if the CurveMapping struct is shared. */
1255         RNA_property_update(C, &cb->ptr, cb->prop);
1256 }
1257
1258 #define B_BANDCOL 1
1259
1260 static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
1261 {
1262         ColorBand *coba= coba_v;
1263         float pos= 0.5f;
1264
1265         if(coba->tot > 1) {
1266                 if(coba->cur > 0)       pos= (coba->data[coba->cur-1].pos + coba->data[coba->cur].pos) * 0.5f;
1267                 else                            pos= (coba->data[coba->cur+1].pos + coba->data[coba->cur].pos) * 0.5f;
1268         }
1269
1270         if(colorband_element_add(coba, pos)) {
1271                 rna_update_cb(C, cb_v, NULL);
1272                 ED_undo_push(C, "Add colorband");       
1273         }
1274 }
1275
1276 static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v)
1277 {
1278         ColorBand *coba= coba_v;
1279
1280         if(colorband_element_remove(coba, coba->cur)) {
1281                 ED_undo_push(C, "Delete colorband");
1282                 rna_update_cb(C, cb_v, NULL);
1283         }
1284 }
1285
1286 static void colorband_flip_cb(bContext *C, void *cb_v, void *coba_v)
1287 {
1288         CBData data_tmp[MAXCOLORBAND];
1289
1290         ColorBand *coba= coba_v;
1291         int a;
1292
1293         for(a=0; a<coba->tot; a++) {
1294                 data_tmp[a]= coba->data[coba->tot - (a + 1)];
1295         }
1296         for(a=0; a<coba->tot; a++) {
1297                 data_tmp[a].pos = 1.0f - data_tmp[a].pos;
1298                 coba->data[a]= data_tmp[a];
1299         }
1300
1301         /* may as well flip the cur*/
1302         coba->cur= coba->tot - (coba->cur + 1);
1303
1304         ED_undo_push(C, "Flip colorband");
1305
1306         rna_update_cb(C, cb_v, NULL);
1307 }
1308
1309 static void colorband_update_cb(bContext *UNUSED(C), void *bt_v, void *coba_v)
1310 {
1311         uiBut *bt= bt_v;
1312         ColorBand *coba= coba_v;
1313
1314         /* sneaky update here, we need to sort the colorband points to be in order,
1315          * however the RNA pointer then is wrong, so we update it */
1316         colorband_update_sort(coba);
1317         bt->rnapoin.data = coba->data + coba->cur;
1318 }
1319
1320 /* offset aligns from bottom, standard width 300, height 115 */
1321 static void colorband_buttons_large(uiLayout *layout, uiBlock *block, ColorBand *coba, int xoffs, int yoffs, RNAUpdateCb *cb)
1322 {
1323         uiBut *bt;
1324         uiLayout *row;
1325         const int line1_y= yoffs + 65 + UI_UNIT_Y + 2; /* 2 for some space between the buttons */
1326         const int line2_y= yoffs + 65;
1327
1328         if(coba==NULL) return;
1329
1330         bt= uiDefBut(block, BUT, 0,     IFACE_("Add"), 0+xoffs,line1_y,40,UI_UNIT_Y, NULL, 0, 0, 0, 0,
1331                         TIP_("Add a new color stop to the colorband"));
1332         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1333
1334         bt= uiDefBut(block, BUT, 0,     IFACE_("Delete"), 45+xoffs,line1_y,45,UI_UNIT_Y, NULL, 0, 0, 0, 0,
1335                         TIP_("Delete the active position"));
1336         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1337
1338
1339         /* XXX, todo for later - convert to operator - campbell */
1340         bt= uiDefBut(block, BUT, 0,     "F",            95+xoffs,line1_y,20,UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Flip colorband"));
1341         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1342
1343         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"));
1344
1345         bt= uiDefButS(block, MENU, 0,           IFACE_("Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4"),
1346                         210+xoffs, line1_y, 90, UI_UNIT_Y,              &coba->ipotype, 0.0, 0.0, 0, 0, TIP_("Set interpolation between color stops"));
1347         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1348         uiBlockEndAlign(block);
1349
1350         bt= uiDefBut(block, BUT_COLORBAND, 0, "",       xoffs,line2_y,300,UI_UNIT_Y, coba, 0, 0, 0, 0, "");
1351         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1352
1353
1354
1355         if(coba->tot) {
1356                 CBData *cbd= coba->data + coba->cur;
1357
1358                 /* better to use rna so we can animate them */
1359                 PointerRNA ptr;
1360                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1361                 row= uiLayoutRow(layout, 0);
1362
1363                 uiItemR(row, &ptr, "position", 0, "Pos", ICON_NONE);
1364                 bt= block->buttons.last;
1365                 uiButSetFunc(bt, colorband_update_cb, bt, coba);
1366
1367                 uiItemR(row, &ptr, "color", 0, "", ICON_NONE);
1368         }
1369
1370 }
1371
1372 static void colorband_buttons_small(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb)
1373 {
1374         uiBut *bt;
1375         float unit= (butr->xmax-butr->xmin)/14.0f;
1376         float xs= butr->xmin;
1377
1378         uiBlockBeginAlign(block);
1379         bt= uiDefBut(block, BUT, 0,     IFACE_("Add"), xs,butr->ymin+UI_UNIT_Y,2.0f*unit,UI_UNIT_Y,     NULL, 0, 0, 0, 0,
1380                         TIP_("Add a new color stop to the colorband"));
1381         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1382         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,
1383                      TIP_("Delete the active position"));
1384         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1385         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"));
1386         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1387         uiBlockEndAlign(block);
1388
1389         if(coba->tot) {
1390                 CBData *cbd= coba->data + coba->cur;
1391                 PointerRNA ptr;
1392                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1393                 uiItemR(layout, &ptr, "color", 0, "", ICON_NONE);
1394         }
1395
1396         bt= uiDefButS(block, MENU, 0, TIP_("Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4"),
1397                         xs+10.0f*unit, butr->ymin+UI_UNIT_Y, unit*4, UI_UNIT_Y,         &coba->ipotype, 0.0, 0.0, 0, 0,
1398                         TIP_("Set interpolation between color stops"));
1399         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1400
1401         bt= uiDefBut(block, BUT_COLORBAND, 0, "",               xs,butr->ymin,butr->xmax-butr->xmin,UI_UNIT_Y, coba, 0, 0, 0, 0, "");
1402         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1403
1404         uiBlockEndAlign(block);
1405 }
1406
1407 static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, int small, RNAUpdateCb *cb)
1408 {
1409         if(small)
1410                 colorband_buttons_small(layout, block, coba, butr, cb);
1411         else
1412                 colorband_buttons_large(layout, block, coba, 0, 0, cb);
1413 }
1414
1415 void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, int expand)
1416 {
1417         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1418         PointerRNA cptr;
1419         RNAUpdateCb *cb;
1420         uiBlock *block;
1421         rctf rect;
1422
1423         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1424                 return;
1425
1426         cptr= RNA_property_pointer_get(ptr, prop);
1427         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp))
1428                 return;
1429
1430         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1431         cb->ptr= *ptr;
1432         cb->prop= prop;
1433
1434         rect.xmin= 0; rect.xmax= 200;
1435         rect.ymin= 0; rect.ymax= 190;
1436
1437         block= uiLayoutAbsoluteBlock(layout);
1438         colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1439
1440         MEM_freeN(cb);
1441 }
1442
1443 /********************* Histogram Template ************************/
1444
1445 void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
1446 {
1447         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1448         PointerRNA cptr;
1449         RNAUpdateCb *cb;
1450         uiBlock *block;
1451         uiBut *bt;
1452         Histogram *hist;
1453         rctf rect;
1454         
1455         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1456                 return;
1457         
1458         cptr= RNA_property_pointer_get(ptr, prop);
1459         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Histogram))
1460                 return;
1461         
1462         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1463         cb->ptr= *ptr;
1464         cb->prop= prop;
1465         
1466         rect.xmin= 0; rect.xmax= 200;
1467         rect.ymin= 0; rect.ymax= 190;
1468         
1469         block= uiLayoutAbsoluteBlock(layout);
1470         //colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1471
1472         hist = (Histogram *)cptr.data;
1473
1474         hist->height= (hist->height<=UI_UNIT_Y)?UI_UNIT_Y:hist->height;
1475
1476         bt= uiDefBut(block, HISTOGRAM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, hist->height, hist, 0, 0, 0, 0, "");
1477         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1478
1479         MEM_freeN(cb);
1480 }
1481
1482 /********************* Waveform Template ************************/
1483
1484 void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
1485 {
1486         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1487         PointerRNA cptr;
1488         RNAUpdateCb *cb;
1489         uiBlock *block;
1490         uiBut *bt;
1491         Scopes *scopes;
1492         rctf rect;
1493         
1494         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1495                 return;
1496         
1497         cptr= RNA_property_pointer_get(ptr, prop);
1498         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1499                 return;
1500         scopes = (Scopes *)cptr.data;
1501         
1502         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1503         cb->ptr= *ptr;
1504         cb->prop= prop;
1505         
1506         rect.xmin= 0; rect.xmax= 200;
1507         rect.ymin= 0; rect.ymax= 190;
1508         
1509         block= uiLayoutAbsoluteBlock(layout);
1510         
1511         scopes->wavefrm_height= (scopes->wavefrm_height<=UI_UNIT_Y)?UI_UNIT_Y:scopes->wavefrm_height;
1512
1513         bt= uiDefBut(block, WAVEFORM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->wavefrm_height, scopes, 0, 0, 0, 0, "");
1514         (void)bt; // UNUSED
1515         
1516         MEM_freeN(cb);
1517 }
1518
1519 /********************* Vectorscope Template ************************/
1520
1521 void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
1522 {
1523         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1524         PointerRNA cptr;
1525         RNAUpdateCb *cb;
1526         uiBlock *block;
1527         uiBut *bt;
1528         Scopes *scopes;
1529         rctf rect;
1530         
1531         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1532                 return;
1533         
1534         cptr= RNA_property_pointer_get(ptr, prop);
1535         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1536                 return;
1537         scopes = (Scopes *)cptr.data;
1538
1539         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1540         cb->ptr= *ptr;
1541         cb->prop= prop;
1542         
1543         rect.xmin= 0; rect.xmax= 200;
1544         rect.ymin= 0; rect.ymax= 190;
1545         
1546         block= uiLayoutAbsoluteBlock(layout);
1547
1548         scopes->vecscope_height= (scopes->vecscope_height<=UI_UNIT_Y)?UI_UNIT_Y:scopes->vecscope_height;
1549         
1550         bt= uiDefBut(block, VECTORSCOPE, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->vecscope_height, scopes, 0, 0, 0, 0, "");
1551         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1552         
1553         MEM_freeN(cb);
1554 }
1555
1556 /********************* CurveMapping Template ************************/
1557
1558
1559 static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *UNUSED(arg))
1560 {
1561         CurveMapping *cumap = cumap_v;
1562         float d;
1563
1564         /* we allow 20 times zoom */
1565         if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1566                 d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin);
1567                 cumap->curr.xmin+= d;
1568                 cumap->curr.xmax-= d;
1569                 d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin);
1570                 cumap->curr.ymin+= d;
1571                 cumap->curr.ymax-= d;
1572         }
1573
1574         ED_region_tag_redraw(CTX_wm_region(C));
1575 }
1576
1577 static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *UNUSED(unused))
1578 {
1579         CurveMapping *cumap = cumap_v;
1580         float d, d1;
1581
1582         /* we allow 20 times zoom, but dont view outside clip */
1583         if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1584                 d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin);
1585
1586                 if(cumap->flag & CUMA_DO_CLIP) 
1587                         if(cumap->curr.xmin-d < cumap->clipr.xmin)
1588                                 d1= cumap->curr.xmin - cumap->clipr.xmin;
1589                 cumap->curr.xmin-= d1;
1590
1591                 d1= d;
1592                 if(cumap->flag & CUMA_DO_CLIP) 
1593                         if(cumap->curr.xmax+d > cumap->clipr.xmax)
1594                                 d1= -cumap->curr.xmax + cumap->clipr.xmax;
1595                 cumap->curr.xmax+= d1;
1596
1597                 d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin);
1598
1599                 if(cumap->flag & CUMA_DO_CLIP) 
1600                         if(cumap->curr.ymin-d < cumap->clipr.ymin)
1601                                 d1= cumap->curr.ymin - cumap->clipr.ymin;
1602                 cumap->curr.ymin-= d1;
1603
1604                 d1= d;
1605                 if(cumap->flag & CUMA_DO_CLIP) 
1606                         if(cumap->curr.ymax+d > cumap->clipr.ymax)
1607                                 d1= -cumap->curr.ymax + cumap->clipr.ymax;
1608                 cumap->curr.ymax+= d1;
1609         }
1610
1611         ED_region_tag_redraw(CTX_wm_region(C));
1612 }
1613
1614 static void curvemap_buttons_setclip(bContext *UNUSED(C), void *cumap_v, void *UNUSED(arg))
1615 {
1616         CurveMapping *cumap = cumap_v;
1617
1618         curvemapping_changed(cumap, 0);
1619 }       
1620
1621 static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v)
1622 {
1623         CurveMapping *cumap = cumap_v;
1624
1625         curvemap_remove(cumap->cm+cumap->cur, SELECT);
1626         curvemapping_changed(cumap, 0);
1627
1628         rna_update_cb(C, cb_v, NULL);
1629 }
1630
1631 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
1632 static uiBlock *curvemap_clipping_func(bContext *C, struct ARegion *ar, void *cumap_v)
1633 {
1634         CurveMapping *cumap = cumap_v;
1635         uiBlock *block;
1636         uiBut *bt;
1637         float width= 8*UI_UNIT_X;
1638
1639         block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
1640
1641         /* use this for a fake extra empy space around the buttons */
1642         uiDefBut(block, LABEL, 0, "",                   -4, 16, width+8, 6*UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
1643
1644         bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",    
1645                         0,5*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->flag, 0.0, 0.0, 10, 0, "");
1646         uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
1647
1648         uiBlockBeginAlign(block);
1649         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, "");
1650         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, "");
1651         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, "");
1652         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, "");
1653
1654         uiBlockSetDirection(block, UI_RIGHT);
1655
1656         uiEndBlock(C, block);
1657         return block;
1658 }
1659
1660 static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
1661 {
1662         CurveMapping *cumap = cumap_v;
1663         CurveMap *cuma= cumap->cm+cumap->cur;
1664
1665         switch(event) {
1666                 case 0: /* reset */
1667                         curvemap_reset(cuma, &cumap->clipr,     cumap->preset, CURVEMAP_SLOPE_POSITIVE);
1668                         curvemapping_changed(cumap, 0);
1669                         break;
1670                 case 1:
1671                         cumap->curr= cumap->clipr;
1672                         break;
1673                 case 2: /* set vector */
1674                         curvemap_sethandle(cuma, 1);
1675                         curvemapping_changed(cumap, 0);
1676                         break;
1677                 case 3: /* set auto */
1678                         curvemap_sethandle(cuma, 0);
1679                         curvemapping_changed(cumap, 0);
1680                         break;
1681                 case 4: /* extend horiz */
1682                         cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
1683                         curvemapping_changed(cumap, 0);
1684                         break;
1685                 case 5: /* extend extrapolate */
1686                         cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
1687                         curvemapping_changed(cumap, 0);
1688                         break;
1689         }
1690         ED_region_tag_redraw(CTX_wm_region(C));
1691 }
1692
1693 static uiBlock *curvemap_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1694 {
1695         uiBlock *block;
1696         short yco= 0, menuwidth=10*UI_UNIT_X;
1697
1698         block= uiBeginBlock(C, ar, __func__, UI_EMBOSS);
1699         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1700
1701         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, "");
1702         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, "");
1703         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, "");
1704         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, "");
1705         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, "");
1706         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, "");
1707
1708         uiBlockSetDirection(block, UI_RIGHT);
1709         uiTextBoundsBlock(block, 50);
1710
1711         uiEndBlock(C, block);
1712         return block;
1713 }
1714
1715 static uiBlock *curvemap_brush_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1716 {
1717         uiBlock *block;
1718         short yco= 0, menuwidth=10*UI_UNIT_X;
1719
1720         block= uiBeginBlock(C, ar, __func__, UI_EMBOSS);
1721         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1722
1723         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, "");
1724         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, "");
1725         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, "");
1726         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, "");
1727
1728         uiBlockSetDirection(block, UI_RIGHT);
1729         uiTextBoundsBlock(block, 50);
1730
1731         uiEndBlock(C, block);
1732         return block;
1733 }
1734
1735 static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
1736 {
1737         ED_region_tag_redraw(CTX_wm_region(C));
1738 }
1739
1740 static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
1741 {
1742         CurveMapping *cumap = cumap_v;
1743         int a;
1744         
1745         cumap->preset = CURVE_PRESET_LINE;
1746         for(a=0; a<CM_TOT; a++)
1747                 curvemap_reset(cumap->cm+a, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
1748         
1749         cumap->black[0]=cumap->black[1]=cumap->black[2]= 0.0f;
1750         cumap->white[0]=cumap->white[1]=cumap->white[2]= 1.0f;
1751         curvemapping_set_black_white(cumap, NULL, NULL);
1752         
1753         curvemapping_changed(cumap, 0);
1754
1755         rna_update_cb(C, cb_v, NULL);
1756 }
1757
1758 /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
1759 static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels, int brush, RNAUpdateCb *cb)
1760 {
1761         CurveMapping *cumap= ptr->data;
1762         uiLayout *row, *sub, *split;
1763         uiBlock *block;
1764         uiBut *bt;
1765         float dx= UI_UNIT_X;
1766         int icon, size;
1767         int bg=-1;
1768
1769         block= uiLayoutGetBlock(layout);
1770
1771         /* curve chooser */
1772         row= uiLayoutRow(layout, 0);
1773
1774         if(labeltype=='v') {
1775                 /* vector */
1776                 sub= uiLayoutRow(row, 1);
1777                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1778
1779                 if(cumap->cm[0].curve) {
1780                         bt= uiDefButI(block, ROW, 0, "X", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1781                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1782                 }
1783                 if(cumap->cm[1].curve) {
1784                         bt= uiDefButI(block, ROW, 0, "Y", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1785                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1786                 }
1787                 if(cumap->cm[2].curve) {
1788                         bt= uiDefButI(block, ROW, 0, "Z", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1789                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1790                 }
1791         }
1792         else if(labeltype=='c') {
1793                 /* color */
1794                 sub= uiLayoutRow(row, 1);
1795                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1796
1797                 if(cumap->cm[3].curve) {
1798                         bt= uiDefButI(block, ROW, 0, "C", 0, 0, dx, dx, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
1799                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1800                 }
1801                 if(cumap->cm[0].curve) {
1802                         bt= uiDefButI(block, ROW, 0, "R", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1803                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1804                 }
1805                 if(cumap->cm[1].curve) {
1806                         bt= uiDefButI(block, ROW, 0, "G", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1807                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1808                 }
1809                 if(cumap->cm[2].curve) {
1810                         bt= uiDefButI(block, ROW, 0, "B", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1811                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1812                 }
1813         }
1814         else if (labeltype == 'h') {
1815                 /* HSV */
1816                 sub= uiLayoutRow(row, 1);
1817                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1818                 
1819                 if(cumap->cm[0].curve) {
1820                         bt= uiDefButI(block, ROW, 0, "H", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1821                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1822                 }
1823                 if(cumap->cm[1].curve) {
1824                         bt= uiDefButI(block, ROW, 0, "S", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1825                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1826                 }
1827                 if(cumap->cm[2].curve) {
1828                         bt= uiDefButI(block, ROW, 0, "V", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1829                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1830                 }
1831         }
1832         else
1833                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
1834         
1835         if (labeltype=='h')
1836                 bg = UI_GRAD_H;
1837
1838         /* operation buttons */
1839         sub= uiLayoutRow(row, 1);
1840
1841         uiBlockSetEmboss(block, UI_EMBOSSN);
1842
1843         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom in"));
1844         uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
1845
1846         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMOUT, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom out"));
1847         uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
1848
1849         if(brush)
1850                 bt= uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, TIP_("Tools"));
1851         else
1852                 bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, TIP_("Tools"));
1853
1854         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1855
1856         if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT;
1857         bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
1858         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1859
1860         bt= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete points"));
1861         uiButSetNFunc(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
1862
1863         uiBlockSetEmboss(block, UI_EMBOSS);
1864
1865         uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
1866
1867         /* curve itself */
1868         size= uiLayoutGetWidth(layout);
1869         row= uiLayoutRow(layout, 0);
1870         uiDefBut(block, BUT_CURVE, 0, "", 0, 0, size, MIN2(size, 200), cumap, 0.0f, 1.0f, bg, 0, "");
1871
1872         /* black/white levels */
1873         if(levels) {
1874                 split= uiLayoutSplit(layout, 0, 0);
1875                 uiItemR(uiLayoutColumn(split, 0), ptr, "black_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1876                 uiItemR(uiLayoutColumn(split, 0), ptr, "white_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1877
1878                 uiLayoutRow(layout, 0);
1879                 bt=uiDefBut(block, BUT, 0, IFACE_("Reset"),     0, 0, UI_UNIT_X*10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
1880                                 TIP_("Reset Black/White point and curves"));
1881                 uiButSetNFunc(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
1882         }
1883
1884         uiBlockSetNFunc(block, NULL, NULL, NULL);
1885 }
1886
1887 void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, int levels, int brush)
1888 {
1889         RNAUpdateCb *cb;
1890         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1891         PointerRNA cptr;
1892
1893         if(!prop) {
1894                 RNA_warning("curve property not found: %s.%s",
1895                             RNA_struct_identifier(ptr->type), propname);
1896                 return;
1897         }
1898
1899         if(RNA_property_type(prop) != PROP_POINTER) {
1900                 RNA_warning("curve is not a pointer: %s.%s",
1901                             RNA_struct_identifier(ptr->type), propname);
1902                 return;
1903         }
1904
1905         cptr= RNA_property_pointer_get(ptr, prop);
1906         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveMapping))
1907                 return;
1908
1909         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1910         cb->ptr= *ptr;
1911         cb->prop= prop;
1912
1913         curvemap_buttons_layout(layout, &cptr, type, levels, brush, cb);
1914
1915         MEM_freeN(cb);
1916 }
1917
1918 /********************* ColorWheel Template ************************/
1919
1920 #define WHEEL_SIZE      100
1921
1922 void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic)
1923 {
1924         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1925         uiBlock *block= uiLayoutGetBlock(layout);
1926         uiLayout *col, *row;
1927         uiBut *but;
1928         float softmin, softmax, step, precision;
1929         
1930         if (!prop) {
1931                 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1932                 return;
1933         }
1934
1935         RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
1936         
1937         col = uiLayoutColumn(layout, 0);
1938         row= uiLayoutRow(col, 1);
1939         
1940         but= uiDefButR_prop(block, HSVCIRCLE, 0, "",    0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop, -1, 0.0, 0.0, 0, 0, "");
1941
1942         if(lock) {
1943                 but->flag |= UI_BUT_COLOR_LOCK;
1944         }
1945
1946         if(lock_luminosity) {
1947                 float color[4]; /* incase of alpha */
1948                 but->flag |= UI_BUT_VEC_SIZE_LOCK;
1949                 RNA_property_float_get_array(ptr, prop, color);
1950                 but->a2= len_v3(color);
1951         }
1952
1953         if(cubic)
1954                 but->flag |= UI_BUT_COLOR_CUBIC;
1955
1956         uiItemS(row);
1957         
1958         if (value_slider)
1959                 uiDefButR_prop(block, HSVCUBE, 0, "", WHEEL_SIZE+6, 0, 14, WHEEL_SIZE, ptr, prop, -1, softmin, softmax, UI_GRAD_V_ALT, 0, "");
1960 }
1961
1962 /********************* Layer Buttons Template ************************/
1963
1964 static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
1965 {
1966         uiBut *but = arg1;
1967         int cur = GET_INT_FROM_POINTER(arg2);
1968         wmWindow *win= CTX_wm_window(C);
1969         int i, tot, shift= win->eventstate->shift;
1970
1971         if(!shift) {
1972                 tot= RNA_property_array_length(&but->rnapoin, but->rnaprop);
1973                 
1974                 /* Normally clicking only selects one layer */
1975                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, TRUE);
1976                 for(i = 0; i < tot; ++i) {
1977                         if(i != cur)
1978                                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, FALSE);
1979                 }
1980         }
1981         
1982         /* view3d layer change should update depsgraph (invisible object changed maybe) */
1983         /* see view3d_header.c */
1984 }
1985
1986 // TODO:
1987 //      - for now, grouping of layers is determined by dividing up the length of 
1988 //        the array of layer bitflags
1989
1990 void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
1991                           PointerRNA *used_ptr, const char *used_propname, int active_layer)
1992 {
1993         uiLayout *uRow, *uCol;
1994         PropertyRNA *prop, *used_prop= NULL;
1995         int groups, cols, layers;
1996         int group, col, layer, row;
1997         int cols_per_group = 5;
1998
1999         prop= RNA_struct_find_property(ptr, propname);
2000         if (!prop) {
2001                 RNA_warning("layers property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2002                 return;
2003         }
2004         
2005         /* the number of layers determines the way we group them 
2006          *      - we want 2 rows only (for now)
2007          *      - the number of columns (cols) is the total number of buttons per row
2008          *        the 'remainder' is added to this, as it will be ok to have first row slightly wider if need be
2009          *      - for now, only split into groups if group will have at least 5 items
2010          */
2011         layers= RNA_property_array_length(ptr, prop);
2012         cols= (layers / 2) + (layers % 2);
2013         groups= ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group);
2014
2015         if(used_ptr && used_propname) {
2016                 used_prop= RNA_struct_find_property(used_ptr, used_propname);
2017                 if (!used_prop) {
2018                         RNA_warning("used layers property not found: %s.%s", RNA_struct_identifier(ptr->type), used_propname);
2019                         return;
2020                 }
2021
2022                 if(RNA_property_array_length(used_ptr, used_prop) < layers)
2023                         used_prop = NULL;
2024         }
2025         
2026         /* layers are laid out going across rows, with the columns being divided into groups */
2027         
2028         for (group= 0; group < groups; group++) {
2029                 uCol= uiLayoutColumn(layout, 1);
2030                 
2031                 for (row= 0; row < 2; row++) {
2032                         uiBlock *block;
2033                         uiBut *but;
2034
2035                         uRow= uiLayoutRow(uCol, 1);
2036                         block= uiLayoutGetBlock(uRow);
2037                         layer= groups*cols_per_group*row + cols_per_group*group;
2038                         
2039                         /* add layers as toggle buts */
2040                         for (col= 0; (col < cols_per_group) && (layer < layers); col++, layer++) {
2041                                 int icon = 0;
2042                                 int butlay = 1 << layer;
2043
2044                                 if(active_layer & butlay)
2045                                         icon = ICON_LAYER_ACTIVE;
2046                                 else if(used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, layer))
2047                                         icon = ICON_LAYER_USED;
2048                                 
2049                                 but= uiDefAutoButR(block, ptr, prop, layer, "", icon, 0, 0, UI_UNIT_X/2, UI_UNIT_Y/2);
2050                                 uiButSetFunc(but, handle_layer_buttons, but, SET_INT_IN_POINTER(layer));
2051                                 but->type= TOG;
2052                         }
2053                 }
2054         }
2055 }
2056
2057
2058 /************************* List Template **************************/
2059
2060 static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon, int big)
2061 {
2062         ID *id= NULL;
2063         int icon;
2064
2065         if(!itemptr->data)
2066                 return rnaicon;
2067
2068         /* try ID, material or texture slot */
2069         if(RNA_struct_is_ID(itemptr->type)) {
2070                 id= itemptr->id.data;
2071         }
2072         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2073                 id= RNA_pointer_get(itemptr, "material").data;
2074         }
2075         else if(RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) {
2076                 id= RNA_pointer_get(itemptr, "texture").data;
2077         }
2078         else if(RNA_struct_is_a(itemptr->type, &RNA_DynamicPaintSurface)) {
2079                 DynamicPaintSurface *surface= (DynamicPaintSurface*)itemptr->data;
2080
2081                 if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) return ICON_TEXTURE_SHADED;
2082                 else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) return ICON_OUTLINER_DATA_MESH;
2083                 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return ICON_FILE_IMAGE;
2084         }
2085
2086         /* get icon from ID */
2087         if(id) {
2088                 icon= ui_id_icon_get(C, id, big);
2089
2090                 if(icon)
2091                         return icon;
2092         }
2093
2094         return rnaicon;
2095 }
2096
2097 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)
2098 {
2099         uiBlock *block= uiLayoutGetBlock(layout);
2100         uiBut *but;
2101         uiLayout *split, *overlap, *sub, *row;
2102         char *namebuf;
2103         const char *name;
2104         int icon;
2105
2106         overlap= uiLayoutOverlap(layout);
2107
2108         /* list item behind label & other buttons */
2109         sub= uiLayoutRow(overlap, 0);
2110
2111         but= uiDefButR_prop(block, LISTROW, 0, "", 0,0, UI_UNIT_X*10,UI_UNIT_Y, activeptr, activeprop, 0, 0, i, 0, 0, "");
2112         uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2113
2114         sub= uiLayoutRow(overlap, 0);
2115
2116         /* retrieve icon and name */
2117         icon= list_item_icon_get(C, itemptr, rnaicon, 0);
2118         if(icon == ICON_NONE || icon == ICON_DOT)
2119                 icon= 0;
2120
2121         namebuf= RNA_struct_name_get_alloc(itemptr, NULL, 0, NULL);
2122         name= (namebuf)? namebuf: "";
2123
2124         /* hardcoded types */
2125         if(itemptr->type == &RNA_MeshTexturePolyLayer || itemptr->type == &RNA_MeshLoopColorLayer) {
2126                 uiItemL(sub, name, icon);
2127                 uiBlockSetEmboss(block, UI_EMBOSSN);
2128                 uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", 0, 0, 0, 0, 0, NULL);
2129                 uiBlockSetEmboss(block, UI_EMBOSS);
2130         }
2131         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) {
2132                 uiItemL(sub, name, icon);
2133                 uiBlockSetEmboss(block, UI_EMBOSS);
2134                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0,  NULL);
2135         }
2136         else if(RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
2137                 uiItemL(sub, name, icon);
2138                 uiBlockSetEmboss(block, UI_EMBOSS);
2139                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0,  NULL);
2140         }
2141         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2142                 /* provision to draw active node name */
2143                 Material *ma, *manode;
2144                 Scene *scene= CTX_data_scene(C);
2145                 Object *ob= (Object*)ptr->id.data;
2146                 int index= (Material**)itemptr->data - ob->mat;
2147                 
2148                 /* default item with material base name */
2149                 uiItemL(sub, name, icon);
2150                 
2151                 ma= give_current_material(ob, index+1);
2152                 if (ma && !scene_use_new_shading_nodes(scene)){
2153                         manode= give_node_material(ma);
2154                         if(manode) {
2155                                 char str[MAX_ID_NAME + 12];
2156                                 BLI_snprintf(str, sizeof(str), "Node %s", manode->id.name+2);
2157                                 uiItemL(sub, str, ui_id_icon_get(C, &manode->id, 1));
2158                         }
2159                         else if(ma->use_nodes) {
2160                                 uiItemL(sub, "Node <none>", ICON_NONE);
2161                         }
2162                 }
2163         }
2164         else if(itemptr->type == &RNA_ShapeKey) {
2165                 Object *ob= (Object*)activeptr->data;
2166                 Key *key= (Key*)itemptr->id.data;
2167
2168                 split= uiLayoutSplit(sub, 0.66f, 0);
2169
2170                 uiItemL(split, name, icon);
2171
2172                 uiBlockSetEmboss(block, UI_EMBOSSN);
2173                 row= uiLayoutRow(split, 1);
2174                 if(i == 0 || (key->type != KEY_RELATIVE)) uiItemL(row, "", ICON_NONE);
2175                 else uiItemR(row, itemptr, "value", 0, "", ICON_NONE);
2176                 uiItemR(row, itemptr, "mute", 0, "", 0);
2177
2178                 if( (key->flag & KEYBLOCK_MUTE) ||
2179                     (ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH)) )
2180                 {
2181                         uiLayoutSetActive(row, 0);
2182                 }
2183                 uiBlockSetEmboss(block, UI_EMBOSS);
2184         }
2185         else if(itemptr->type == &RNA_VertexGroup) {
2186                 bDeformGroup *dg= (bDeformGroup *)itemptr->data;
2187                 uiItemL(sub, name, icon);
2188                 /* RNA does not allow nice lock icons, use lower level buttons */
2189 #if 0
2190                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "lock_weight", 0, 0, 0, 0, 0,  NULL);
2191 #else
2192                 uiBlockSetEmboss(block, UI_EMBOSSN);
2193                 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");
2194                 uiBlockSetEmboss(block, UI_EMBOSS);
2195 #endif
2196         }
2197         else if(itemptr->type == &RNA_KeyingSetPath) {
2198                 KS_Path *ksp = (KS_Path*)itemptr->data;
2199                 
2200                 /* icon needs to be the type of ID which is currently active */
2201                 RNA_enum_icon_from_value(id_type_items, ksp->idtype, &icon);
2202                 
2203                 /* nothing else special to do... */
2204                 uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
2205         }
2206         else if(itemptr->type == &RNA_DynamicPaintSurface) {
2207                 char name_final[96];
2208                 const char *enum_name;
2209                 PropertyRNA *prop = RNA_struct_find_property(itemptr, "surface_type");
2210                 DynamicPaintSurface *surface= (DynamicPaintSurface*)itemptr->data;
2211
2212                 RNA_property_enum_name(C, itemptr, prop, RNA_property_enum_get(itemptr, prop), &enum_name);
2213
2214                 BLI_snprintf(name_final, sizeof(name_final), "%s (%s)",name,enum_name);
2215                 uiItemL(sub, name_final, icon);
2216                 if (dynamicPaint_surfaceHasColorPreview(surface)) {
2217                         uiBlockSetEmboss(block, UI_EMBOSSN);
2218                         uiDefIconButR(block, OPTION, 0, (surface->flags & MOD_DPAINT_PREVIEW) ? ICON_RESTRICT_VIEW_OFF : ICON_RESTRICT_VIEW_ON,
2219                                 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "show_preview", 0, 0, 0, 0, 0, NULL);
2220                         uiBlockSetEmboss(block, UI_EMBOSS);
2221                 }
2222                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "is_active", i, 0, 0, 0, 0,  NULL);
2223         }
2224         else if(itemptr->type == &RNA_MovieTrackingObject) {
2225                 MovieTrackingObject *tracking_object= (MovieTrackingObject*)itemptr->data;
2226
2227                 split= uiLayoutSplit(sub, 0.75f, 0);
2228                 if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
2229                         uiItemL(split, name, ICON_CAMERA_DATA);
2230                 }
2231                 else {
2232                         uiItemL(split, name, ICON_OBJECT_DATA);
2233                 }
2234         }
2235
2236         /* There is a last chance to display custom controls (in addition to the name/label):
2237          * If the given item property group features a string property named as prop_list,
2238          * this tries to add controls for all properties of the item listed in that string property.
2239          * (colon-separated names).
2240          *
2241          * This is especially useful for python. E.g., if you list a collection of this property
2242          * group:
2243          *
2244          * class TestPropertyGroup(bpy.types.PropertyGroup):
2245          *     bool    = BoolProperty(default=False)
2246          *     integer = IntProperty()
2247          *     string  = StringProperty()
2248          * 
2249          *     # A string of all identifiers (colon-separated) which property’s controls should be
2250          *     # displayed in a template_list.
2251          *     template_list_controls = StringProperty(default="integer:bool:string", options={"HIDDEN"})
2252          *
2253          * … you’ll get a numfield for the integer prop, a check box for the bool prop, and a textfield
2254          * for the string prop, after the name of each item of the collection.
2255          */
2256         else if (prop_list_id) {
2257                 row = uiLayoutRow(sub, 1);
2258                 uiItemL(row, name, icon);
2259
2260                 /* XXX: Check, as sometimes we get an itemptr looking like
2261                  *      {id = {data = 0x0}, type = 0x0, data = 0x0}
2262                  *      which would obviously produce a sigsev… */
2263                 if (itemptr->type) {
2264                         /* If the special property is set for the item, and it is a collection… */
2265                         PropertyRNA *prop_list= RNA_struct_find_property(itemptr, prop_list_id);
2266
2267                         if(prop_list && RNA_property_type(prop_list) == PROP_STRING) {
2268                                 int prop_names_len;
2269                                 char *prop_names = RNA_property_string_get_alloc(itemptr, prop_list, NULL, 0, &prop_names_len);
2270                                 char *prop_names_end= prop_names + prop_names_len;
2271                                 char *id= prop_names;
2272                                 char *id_next;
2273                                 while (id < prop_names_end) {
2274                                         if ((id_next= strchr(id, ':'))) *id_next++= '\0';
2275                                         else id_next= prop_names_end;
2276                                         uiItemR(row, itemptr, id, 0, NULL, 0);
2277                                         id= id_next;
2278                                 }
2279                                 MEM_freeN(prop_names);
2280                         }
2281                 }
2282         }
2283
2284         else
2285                 uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
2286
2287         /* free name */
2288         if (namebuf) {
2289                 MEM_freeN(namebuf);
2290         }
2291 }
2292
2293 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)
2294 {
2295         //Scene *scene= CTX_data_scene(C);
2296         PropertyRNA *prop= NULL, *activeprop;
2297         PropertyType type, activetype;
2298         StructRNA *ptype;
2299         uiLayout *box, *row, *col;
2300         uiBlock *block;
2301         uiBut *but;
2302         Panel *pa;
2303         const char *name;
2304         char numstr[32];
2305         int rnaicon=0, icon=0, i= 0, activei= 0, len= 0, items, found, min, max;
2306
2307         /* validate arguments */
2308         block= uiLayoutGetBlock(layout);
2309         pa= block->panel;
2310
2311         if(!pa) {
2312                 RNA_warning("Only works inside a panel");
2313                 return;
2314         }
2315
2316         if(!activeptr->data)
2317                 return;
2318         
2319         if(ptr->data) {
2320                 prop= RNA_struct_find_property(ptr, propname);
2321                 if(!prop) {
2322                         RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2323                         return;
2324                 }
2325         }
2326
2327         activeprop= RNA_struct_find_property(activeptr, activepropname);
2328         if(!activeprop) {
2329                 RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), activepropname);
2330                 return;
2331         }
2332
2333         if(prop) {
2334                 type= RNA_property_type(prop);
2335                 if(type != PROP_COLLECTION) {
2336                         RNA_warning("uiExpected collection property");
2337                         return;
2338                 }
2339         }
2340
2341         activetype= RNA_property_type(activeprop);
2342         if(activetype != PROP_INT) {
2343                 RNA_warning("Expected integer property");
2344                 return;
2345         }
2346
2347         /* get icon */
2348         if(ptr->data && prop) {
2349                 ptype= RNA_property_pointer_type(ptr, prop);
2350                 rnaicon= RNA_struct_ui_icon(ptype);
2351         }
2352
2353         /* get active data */
2354         activei= RNA_property_int_get(activeptr, activeprop);
2355
2356         if(listtype == 'i') {
2357                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2358                 col= uiLayoutColumn(box, 1);
2359                 row= uiLayoutRow(col, 0);
2360
2361                 if(ptr->data && prop) {
2362                         /* create list items */
2363                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2364                                 /* create button */
2365                                 if(!(i % 9))
2366                                         row= uiLayoutRow(col, 0);
2367
2368                                 icon= list_item_icon_get(C, &itemptr, rnaicon, 1);
2369                                 but= uiDefIconButR_prop(block, LISTROW, 0, icon, 0,0,UI_UNIT_X*10,UI_UNIT_Y, activeptr, activeprop, 0, 0, i, 0, 0, "");
2370                                 uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2371                                 
2372
2373                                 i++;
2374                         }
2375                         RNA_PROP_END;
2376                 }
2377         }
2378         else if(listtype == 'c') {
2379                 /* compact layout */
2380
2381                 row= uiLayoutRow(layout, 1);
2382
2383                 if(ptr->data && prop) {
2384                         /* create list items */
2385                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2386                                 found= (activei == i);
2387
2388                                 if(found) {
2389                                         /* create button */
2390                                         name= RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL);
2391                                         icon= list_item_icon_get(C, &itemptr, rnaicon, 0);
2392                                         uiItemL(row, (name)? name: "", icon);
2393
2394                                         if (name) {
2395                                                 MEM_freeN((void *)name);
2396                                         }
2397                                 }
2398
2399                                 i++;
2400                         }
2401                         RNA_PROP_END;
2402                 }
2403
2404                 /* if not found, add in dummy button */
2405                 if(i == 0)
2406                         uiItemL(row, "", ICON_NONE);
2407
2408                 /* next/prev button */
2409                 BLI_snprintf(numstr, sizeof(numstr), "%d :", i);
2410                 but= uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0,0,UI_UNIT_X*5,UI_UNIT_Y, activeptr, activeprop, 0, 0, 0, 0, 0, "");
2411                 if(i == 0)
2412                         uiButSetFlag(but, UI_BUT_DISABLED);
2413         }
2414         else {
2415                 /* default rows */
2416                 if(rows == 0)
2417                         rows= 5;
2418                 if (maxrows == 0)
2419                         maxrows = 5;
2420                 if(pa->list_grip_size != 0)
2421                         rows= pa->list_grip_size;
2422
2423                 /* layout */
2424                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2425                 row= uiLayoutRow(box, 0);
2426                 col = uiLayoutColumn(row, 1);
2427
2428                 /* init numbers */
2429                 RNA_property_int_range(activeptr, activeprop, &min, &max);
2430
2431                 if(prop)
2432                         len= RNA_property_collection_length(ptr, prop);
2433                 items= CLAMPIS(len, rows, MAX2(rows, maxrows));
2434
2435                 /* if list length changes and active is out of view, scroll to it */
2436                 if(pa->list_last_len != len)
2437                         if((activei < pa->list_scroll || activei >= pa->list_scroll+items))
2438                                 pa->list_scroll= activei;
2439
2440                 pa->list_scroll= MIN2(pa->list_scroll, len-items);
2441                 pa->list_scroll= MAX2(pa->list_scroll, 0);
2442                 pa->list_size= items;
2443                 pa->list_last_len= len;
2444
2445                 if(ptr->data && prop) {
2446                         /* create list items */
2447                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2448                                 if(i >= pa->list_scroll && i<pa->list_scroll+items)
2449                                         list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activeprop, prop_list);
2450
2451                                 i++;
2452                         }
2453                         RNA_PROP_END;
2454                 }
2455
2456                 /* add dummy buttons to fill space */
2457                 while(i < pa->list_scroll+items) {
2458                         if(i >= pa->list_scroll)
2459                                 uiItemL(col, "", ICON_NONE);
2460                         i++;
2461                 }
2462
2463                 /* add scrollbar */
2464                 if(len > items) {
2465                         col= uiLayoutColumn(row, 0);
2466                         uiDefButI(block, SCROLL, 0, "", 0,0,UI_UNIT_X*0.75,UI_UNIT_Y*items, &pa->list_scroll, 0, len-items, items, 0, "");
2467                 }
2468         }
2469 }
2470
2471 /************************* Operator Search Template **************************/
2472
2473 static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
2474 {
2475         wmOperatorType *ot= arg2;
2476         
2477         if(ot)
2478                 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
2479 }
2480
2481 static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
2482 {
2483         GHashIterator *iter= WM_operatortype_iter();
2484
2485         for( ; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
2486                 wmOperatorType *ot= BLI_ghashIterator_getValue(iter);
2487
2488                 if(BLI_strcasestr(ot->name, str)) {
2489                         if(WM_operator_poll((bContext*)C, ot)) {
2490                                 char name[256];
2491                                 int len= strlen(ot->name);
2492                                 
2493                                 /* display name for menu, can hold hotkey */
2494                                 BLI_strncpy(name, ot->name, sizeof(name));
2495                                 
2496                                 /* check for hotkey */
2497                                 if(len < sizeof(name)-6) {
2498                                         if (WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, TRUE,
2499                                                                          &name[len+1], sizeof(name)-len-1))
2500                                         {
2501                                                 name[len]= '|';
2502                                         }
2503                                 }
2504                                 
2505                                 if(0==uiSearchItemAdd(items, name, ot, 0))
2506                                         break;
2507                         }
2508                 }
2509         }
2510         BLI_ghashIterator_free(iter);
2511 }
2512
2513 void uiTemplateOperatorSearch(uiLayout *layout)
2514 {
2515         uiBlock *block;
2516         uiBut *but;
2517         static char search[256]= "";
2518                 
2519         block= uiLayoutGetBlock(layout);
2520         uiBlockSetCurLayout(block, layout);
2521
2522         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, 0, 0, "");
2523         uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
2524 }
2525
2526 /************************* Running Jobs Template **************************/
2527
2528 #define B_STOPRENDER    1
2529 #define B_STOPCAST              2
2530 #define B_STOPANIM              3
2531 #define B_STOPCOMPO             4
2532 #define B_STOPSEQ               5
2533 #define B_STOPCLIP              6
2534
2535 static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
2536 {
2537         switch(event) {
2538                 case B_STOPRENDER:
2539                         G.afbreek= 1;
2540                         break;
2541                 case B_STOPCAST:
2542                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C), NULL);
2543                         break;
2544                 case B_STOPANIM:
2545                         WM_operator_name_call(C, "SCREEN_OT_animation_play", WM_OP_INVOKE_SCREEN, NULL);
2546                         break;
2547                 case B_STOPCOMPO:
2548                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2549                         break;
2550                 case B_STOPSEQ:
2551                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2552                         break;
2553                 case B_STOPCLIP:
2554                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2555                         break;
2556         }
2557 }
2558
2559 void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
2560 {
2561         bScreen *screen= CTX_wm_screen(C);
2562         wmWindowManager *wm= CTX_wm_manager(C);
2563         ScrArea *sa= CTX_wm_area(C);
2564         uiBlock *block;
2565         void *owner= NULL;
2566         int handle_event;
2567         
2568         block= uiLayoutGetBlock(layout);
2569         uiBlockSetCurLayout(block, layout);
2570
2571         uiBlockSetHandleFunc(block, do_running_jobs, NULL);
2572
2573         if(sa->spacetype==SPACE_NODE) {
2574                 if(WM_jobs_test(wm, sa))
2575                    owner = sa;
2576                 handle_event= B_STOPCOMPO;
2577         } else if (sa->spacetype==SPACE_SEQ) {
2578                 if(WM_jobs_test(wm, sa))
2579                         owner = sa;
2580                 handle_event = B_STOPSEQ;
2581         } else if(sa->spacetype==SPACE_CLIP) {
2582                 if(WM_jobs_test(wm, sa))
2583                    owner = sa;
2584                 handle_event= B_STOPCLIP;
2585         } else {
2586                 Scene *scene;
2587                 /* another scene can be rendering too, for example via compositor */
2588                 for(scene= CTX_data_main(C)->scene.first; scene; scene= scene->id.next)
2589                         if(WM_jobs_test(wm, scene))
2590                                 break;
2591                 owner = scene;
2592                 handle_event= B_STOPRENDER;
2593         }
2594
2595         if(owner) {
2596                 uiLayout *ui_abs;
2597                 
2598                 ui_abs= uiLayoutAbsolute(layout, 0);
2599                 (void)ui_abs; // UNUSED
2600                 
2601                 uiDefIconBut(block, BUT, handle_event, ICON_PANEL_CLOSE, 
2602                                 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"));
2603                 uiDefBut(block, PROGRESSBAR, 0, WM_jobs_name(wm, owner), 
2604                                 UI_UNIT_X, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, TIP_("Progress"));
2605                 
2606                 uiLayoutRow(layout, 0);
2607         }
2608         if(WM_jobs_test(wm, screen))
2609                 uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, IFACE_("Capture"), 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
2610                                 TIP_("Stop screencast"));
2611         if(screen->animtimer)
2612                 uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_CANCEL, TIP_("Anim Player"), 0,0,100,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
2613                                 TIP_("Stop animation playback"));
2614 }
2615
2616 /************************* Reports for Last Operator Template **************************/
2617
2618 void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
2619 {
2620         ReportList *reports = CTX_wm_reports(C);
2621         Report *report= BKE_reports_last_displayable(reports);
2622         ReportTimerInfo *rti;
2623         
2624         uiLayout *ui_abs;
2625         uiBlock *block;
2626         uiBut *but;
2627         uiStyle *style= UI_GetStyle();
2628         int width;
2629         int icon=0;
2630         
2631         /* if the report display has timed out, don't show */
2632         if (!reports->reporttimer) return;
2633         
2634         rti= (ReportTimerInfo *)reports->reporttimer->customdata;
2635         
2636         if (!rti || rti->widthfac==0.0f || !report) return;
2637         
2638         ui_abs= uiLayoutAbsolute(layout, 0);
2639         block= uiLayoutGetBlock(ui_abs);
2640         
2641         width = BLF_width(style->widget.uifont_id, report->message);
2642         width = MIN2(rti->widthfac*width, width);
2643         width = MAX2(width, 10);
2644         
2645         /* make a box around the report to make it stand out */
2646         uiBlockBeginAlign(block);
2647         but= uiDefBut(block, ROUNDBOX, 0, "", 0, 0, UI_UNIT_X+10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2648         /* set the report's bg color in but->col - ROUNDBOX feature */
2649         rgb_float_to_uchar(but->col, rti->col);
2650         but->col[3]= 255; 
2651
2652         but= uiDefBut(block, ROUNDBOX, 0, "", UI_UNIT_X+10, 0, UI_UNIT_X+width, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2653         but->col[0]= but->col[1]= but->col[2]= FTOCHAR(rti->greyscale);
2654         but->col[3]= 255;
2655
2656         uiBlockEndAlign(block);
2657         
2658         
2659         /* icon and report message on top */
2660         if(report->type & RPT_ERROR_ALL)
2661                 icon = ICON_ERROR;
2662         else if(report->type & RPT_WARNING_ALL)
2663                 icon = ICON_ERROR;
2664         else if(report->type & RPT_INFO_ALL)
2665                 icon = ICON_INFO;
2666         
2667         /* XXX: temporary operator to dump all reports to a text block, but only if more than 1 report 
2668          * to be shown instead of icon when appropriate...
2669          */
2670         uiBlockSetEmboss(block, UI_EMBOSSN);
2671
2672         if (reports->list.first != reports->list.last)
2673                 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'"));
2674         else
2675                 uiDefIconBut(block, LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2676
2677         uiBlockSetEmboss(block, UI_EMBOSS);
2678         
2679         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, "");
2680 }
2681
2682 /********************************* Keymap *************************************/
2683
2684 static void keymap_item_modified(bContext *UNUSED(C), void *kmi_p, void *UNUSED(unused))
2685 {
2686         wmKeyMapItem *kmi= (wmKeyMapItem*)kmi_p;
2687         WM_keyconfig_update_tag(NULL, kmi);
2688 }
2689
2690 static void template_keymap_item_properties(uiLayout *layout, const char *title, PointerRNA *ptr)
2691 {
2692         uiLayout *flow;
2693
2694         uiItemS(layout);
2695
2696         if(title)
2697                 uiItemL(layout, title, ICON_NONE);
2698         
2699         flow= uiLayoutColumnFlow(layout, 2, 0);
2700
2701         RNA_STRUCT_BEGIN(ptr, prop) {
2702                 int flag= RNA_property_flag(prop);
2703
2704                 if(flag & PROP_HIDDEN)
2705                         continue;
2706
2707                 /* recurse for nested properties */
2708                 if(RNA_property_type(prop) == PROP_POINTER) {
2709                         PointerRNA propptr= RNA_property_pointer_get(ptr, prop);
2710                         const char *name= RNA_property_ui_name(prop);
2711
2712                         if(propptr.data && RNA_struct_is_a(propptr.type, &RNA_OperatorProperties)) {
2713                                 template_keymap_item_properties(layout, name, &propptr);
2714                                 continue;
2715                         }
2716                 }
2717
2718                 /* add property */
2719                 uiItemR(flow, ptr, RNA_property_identifier(prop), 0, NULL, ICON_NONE);
2720         }
2721         RNA_STRUCT_END;
2722 }
2723
2724 void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
2725 {
2726         PointerRNA propptr= RNA_pointer_get(ptr, "properties");
2727
2728         if(propptr.data) {
2729                 uiBut *but= uiLayoutGetBlock(layout)->buttons.last;
2730
2731                 template_keymap_item_properties(layout, NULL, &propptr);
2732
2733                 /* attach callbacks to compensate for missing properties update,
2734                  * we don't know which keymap (item) is being modified there */
2735                 for(; but; but=but->next)
2736                         uiButSetFunc(but, keymap_item_modified, ptr->data, NULL);
2737         }
2738 }
2739