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