ccca0c8f7cfafd0a1696bfbf7d34cc51fa0aaccd
[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, 256, 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, 256, 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"), 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
1309 /* offset aligns from bottom, standard width 300, height 115 */
1310 static void colorband_buttons_large(uiLayout *layout, uiBlock *block, ColorBand *coba, int xoffs, int yoffs, RNAUpdateCb *cb)
1311 {
1312         uiBut *bt;
1313         uiLayout *row;
1314         const int line1_y= yoffs + 65 + UI_UNIT_Y + 2; /* 2 for some space between the buttons */
1315         const int line2_y= yoffs + 65;
1316
1317         if(coba==NULL) return;
1318
1319         bt= uiDefBut(block, BUT, 0,     IFACE_("Add"), 0+xoffs,line1_y,40,UI_UNIT_Y, NULL, 0, 0, 0, 0,
1320                         TIP_("Add a new color stop to the colorband"));
1321         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1322
1323         bt= uiDefBut(block, BUT, 0,     IFACE_("Delete"), 45+xoffs,line1_y,45,UI_UNIT_Y, NULL, 0, 0, 0, 0,
1324                         TIP_("Delete the active position"));
1325         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1326
1327
1328         /* XXX, todo for later - convert to operator - campbell */
1329         bt= uiDefBut(block, BUT, 0,     "F",            95+xoffs,line1_y,20,UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Flip colorband"));
1330         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1331
1332         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"));
1333
1334         bt= uiDefButS(block, MENU, 0,           IFACE_("Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4"),
1335                         210+xoffs, line1_y, 90, UI_UNIT_Y,              &coba->ipotype, 0.0, 0.0, 0, 0, TIP_("Set interpolation between color stops"));
1336         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1337         uiBlockEndAlign(block);
1338
1339         bt= uiDefBut(block, BUT_COLORBAND, 0, "",       xoffs,line2_y,300,UI_UNIT_Y, coba, 0, 0, 0, 0, "");
1340         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1341
1342
1343
1344         if(coba->tot) {
1345                 CBData *cbd= coba->data + coba->cur;
1346
1347                 /* better to use rna so we can animate them */
1348                 PointerRNA ptr;
1349                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1350                 row= uiLayoutRow(layout, 0);
1351                 uiItemR(row, &ptr, "position", 0, "Pos", ICON_NONE);
1352                 uiItemR(row, &ptr, "color", 0, "", ICON_NONE);
1353         }
1354
1355 }
1356
1357 static void colorband_buttons_small(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb)
1358 {
1359         uiBut *bt;
1360         float unit= (butr->xmax-butr->xmin)/14.0f;
1361         float xs= butr->xmin;
1362
1363         uiBlockBeginAlign(block);
1364         bt= uiDefBut(block, BUT, 0,     IFACE_("Add"), xs,butr->ymin+UI_UNIT_Y,2.0f*unit,UI_UNIT_Y,     NULL, 0, 0, 0, 0,
1365                         TIP_("Add a new color stop to the colorband"));
1366         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1367         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,
1368                      TIP_("Delete the active position"));
1369         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1370         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"));
1371         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1372         uiBlockEndAlign(block);
1373
1374         if(coba->tot) {
1375                 CBData *cbd= coba->data + coba->cur;
1376                 PointerRNA ptr;
1377                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1378                 uiItemR(layout, &ptr, "color", 0, "", ICON_NONE);
1379         }
1380
1381         bt= uiDefButS(block, MENU, 0, TIP_("Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4"),
1382                         xs+10.0f*unit, butr->ymin+UI_UNIT_Y, unit*4, UI_UNIT_Y,         &coba->ipotype, 0.0, 0.0, 0, 0,
1383                         TIP_("Set interpolation between color stops"));
1384         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1385
1386         bt= uiDefBut(block, BUT_COLORBAND, 0, "",               xs,butr->ymin,butr->xmax-butr->xmin,UI_UNIT_Y, coba, 0, 0, 0, 0, "");
1387         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1388
1389         uiBlockEndAlign(block);
1390 }
1391
1392 static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, int small, RNAUpdateCb *cb)
1393 {
1394         if(small)
1395                 colorband_buttons_small(layout, block, coba, butr, cb);
1396         else
1397                 colorband_buttons_large(layout, block, coba, 0, 0, cb);
1398 }
1399
1400 void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, int expand)
1401 {
1402         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1403         PointerRNA cptr;
1404         RNAUpdateCb *cb;
1405         uiBlock *block;
1406         rctf rect;
1407
1408         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1409                 return;
1410
1411         cptr= RNA_property_pointer_get(ptr, prop);
1412         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp))
1413                 return;
1414
1415         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1416         cb->ptr= *ptr;
1417         cb->prop= prop;
1418
1419         rect.xmin= 0; rect.xmax= 200;
1420         rect.ymin= 0; rect.ymax= 190;
1421
1422         block= uiLayoutAbsoluteBlock(layout);
1423         colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1424
1425         MEM_freeN(cb);
1426 }
1427
1428 /********************* Histogram Template ************************/
1429
1430 void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
1431 {
1432         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1433         PointerRNA cptr;
1434         RNAUpdateCb *cb;
1435         uiBlock *block;
1436         uiBut *bt;
1437         Histogram *hist;
1438         rctf rect;
1439         
1440         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1441                 return;
1442         
1443         cptr= RNA_property_pointer_get(ptr, prop);
1444         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Histogram))
1445                 return;
1446         
1447         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1448         cb->ptr= *ptr;
1449         cb->prop= prop;
1450         
1451         rect.xmin= 0; rect.xmax= 200;
1452         rect.ymin= 0; rect.ymax= 190;
1453         
1454         block= uiLayoutAbsoluteBlock(layout);
1455         //colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1456
1457         hist = (Histogram *)cptr.data;
1458
1459         hist->height= (hist->height<=UI_UNIT_Y)?UI_UNIT_Y:hist->height;
1460
1461         bt= uiDefBut(block, HISTOGRAM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, hist->height, hist, 0, 0, 0, 0, "");
1462         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1463
1464         MEM_freeN(cb);
1465 }
1466
1467 /********************* Waveform Template ************************/
1468
1469 void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
1470 {
1471         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1472         PointerRNA cptr;
1473         RNAUpdateCb *cb;
1474         uiBlock *block;
1475         uiBut *bt;
1476         Scopes *scopes;
1477         rctf rect;
1478         
1479         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1480                 return;
1481         
1482         cptr= RNA_property_pointer_get(ptr, prop);
1483         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1484                 return;
1485         scopes = (Scopes *)cptr.data;
1486         
1487         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1488         cb->ptr= *ptr;
1489         cb->prop= prop;
1490         
1491         rect.xmin= 0; rect.xmax= 200;
1492         rect.ymin= 0; rect.ymax= 190;
1493         
1494         block= uiLayoutAbsoluteBlock(layout);
1495         
1496         scopes->wavefrm_height= (scopes->wavefrm_height<=UI_UNIT_Y)?UI_UNIT_Y:scopes->wavefrm_height;
1497
1498         bt= uiDefBut(block, WAVEFORM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->wavefrm_height, scopes, 0, 0, 0, 0, "");
1499         (void)bt; // UNUSED
1500         
1501         MEM_freeN(cb);
1502 }
1503
1504 /********************* Vectorscope Template ************************/
1505
1506 void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
1507 {
1508         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1509         PointerRNA cptr;
1510         RNAUpdateCb *cb;
1511         uiBlock *block;
1512         uiBut *bt;
1513         Scopes *scopes;
1514         rctf rect;
1515         
1516         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1517                 return;
1518         
1519         cptr= RNA_property_pointer_get(ptr, prop);
1520         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1521                 return;
1522         scopes = (Scopes *)cptr.data;
1523
1524         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1525         cb->ptr= *ptr;
1526         cb->prop= prop;
1527         
1528         rect.xmin= 0; rect.xmax= 200;
1529         rect.ymin= 0; rect.ymax= 190;
1530         
1531         block= uiLayoutAbsoluteBlock(layout);
1532
1533         scopes->vecscope_height= (scopes->vecscope_height<=UI_UNIT_Y)?UI_UNIT_Y:scopes->vecscope_height;
1534         
1535         bt= uiDefBut(block, VECTORSCOPE, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->vecscope_height, scopes, 0, 0, 0, 0, "");
1536         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1537         
1538         MEM_freeN(cb);
1539 }
1540
1541 /********************* CurveMapping Template ************************/
1542
1543
1544 static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *UNUSED(arg))
1545 {
1546         CurveMapping *cumap = cumap_v;
1547         float d;
1548
1549         /* we allow 20 times zoom */
1550         if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1551                 d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin);
1552                 cumap->curr.xmin+= d;
1553                 cumap->curr.xmax-= d;
1554                 d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin);
1555                 cumap->curr.ymin+= d;
1556                 cumap->curr.ymax-= d;
1557         }
1558
1559         ED_region_tag_redraw(CTX_wm_region(C));
1560 }
1561
1562 static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *UNUSED(unused))
1563 {
1564         CurveMapping *cumap = cumap_v;
1565         float d, d1;
1566
1567         /* we allow 20 times zoom, but dont view outside clip */
1568         if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1569                 d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin);
1570
1571                 if(cumap->flag & CUMA_DO_CLIP) 
1572                         if(cumap->curr.xmin-d < cumap->clipr.xmin)
1573                                 d1= cumap->curr.xmin - cumap->clipr.xmin;
1574                 cumap->curr.xmin-= d1;
1575
1576                 d1= d;
1577                 if(cumap->flag & CUMA_DO_CLIP) 
1578                         if(cumap->curr.xmax+d > cumap->clipr.xmax)
1579                                 d1= -cumap->curr.xmax + cumap->clipr.xmax;
1580                 cumap->curr.xmax+= d1;
1581
1582                 d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin);
1583
1584                 if(cumap->flag & CUMA_DO_CLIP) 
1585                         if(cumap->curr.ymin-d < cumap->clipr.ymin)
1586                                 d1= cumap->curr.ymin - cumap->clipr.ymin;
1587                 cumap->curr.ymin-= d1;
1588
1589                 d1= d;
1590                 if(cumap->flag & CUMA_DO_CLIP) 
1591                         if(cumap->curr.ymax+d > cumap->clipr.ymax)
1592                                 d1= -cumap->curr.ymax + cumap->clipr.ymax;
1593                 cumap->curr.ymax+= d1;
1594         }
1595
1596         ED_region_tag_redraw(CTX_wm_region(C));
1597 }
1598
1599 static void curvemap_buttons_setclip(bContext *UNUSED(C), void *cumap_v, void *UNUSED(arg))
1600 {
1601         CurveMapping *cumap = cumap_v;
1602
1603         curvemapping_changed(cumap, 0);
1604 }       
1605
1606 static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v)
1607 {
1608         CurveMapping *cumap = cumap_v;
1609
1610         curvemap_remove(cumap->cm+cumap->cur, SELECT);
1611         curvemapping_changed(cumap, 0);
1612
1613         rna_update_cb(C, cb_v, NULL);
1614 }
1615
1616 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
1617 static uiBlock *curvemap_clipping_func(bContext *C, struct ARegion *ar, void *cumap_v)
1618 {
1619         CurveMapping *cumap = cumap_v;
1620         uiBlock *block;
1621         uiBut *bt;
1622         float width= 8*UI_UNIT_X;
1623
1624         block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
1625
1626         /* use this for a fake extra empy space around the buttons */
1627         uiDefBut(block, LABEL, 0, "",                   -4, 16, width+8, 6*UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
1628
1629         bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",    
1630                         0,5*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->flag, 0.0, 0.0, 10, 0, "");
1631         uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
1632
1633         uiBlockBeginAlign(block);
1634         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, "");
1635         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, "");
1636         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, "");
1637         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, "");
1638
1639         uiBlockSetDirection(block, UI_RIGHT);
1640
1641         uiEndBlock(C, block);
1642         return block;
1643 }
1644
1645 static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
1646 {
1647         CurveMapping *cumap = cumap_v;
1648         CurveMap *cuma= cumap->cm+cumap->cur;
1649
1650         switch(event) {
1651                 case 0: /* reset */
1652                         curvemap_reset(cuma, &cumap->clipr,     cumap->preset, CURVEMAP_SLOPE_POSITIVE);
1653                         curvemapping_changed(cumap, 0);
1654                         break;
1655                 case 1:
1656                         cumap->curr= cumap->clipr;
1657                         break;
1658                 case 2: /* set vector */
1659                         curvemap_sethandle(cuma, 1);
1660                         curvemapping_changed(cumap, 0);
1661                         break;
1662                 case 3: /* set auto */
1663                         curvemap_sethandle(cuma, 0);
1664                         curvemapping_changed(cumap, 0);
1665                         break;
1666                 case 4: /* extend horiz */
1667                         cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
1668                         curvemapping_changed(cumap, 0);
1669                         break;
1670                 case 5: /* extend extrapolate */
1671                         cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
1672                         curvemapping_changed(cumap, 0);
1673                         break;
1674         }
1675         ED_region_tag_redraw(CTX_wm_region(C));
1676 }
1677
1678 static uiBlock *curvemap_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1679 {
1680         uiBlock *block;
1681         short yco= 0, menuwidth=10*UI_UNIT_X;
1682
1683         block= uiBeginBlock(C, ar, __func__, UI_EMBOSS);
1684         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1685
1686         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, "");
1687         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, "");
1688         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, "");
1689         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, "");
1690         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, "");
1691         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, "");
1692
1693         uiBlockSetDirection(block, UI_RIGHT);
1694         uiTextBoundsBlock(block, 50);
1695
1696         uiEndBlock(C, block);
1697         return block;
1698 }
1699
1700 static uiBlock *curvemap_brush_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1701 {
1702         uiBlock *block;
1703         short yco= 0, menuwidth=10*UI_UNIT_X;
1704
1705         block= uiBeginBlock(C, ar, __func__, UI_EMBOSS);
1706         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1707
1708         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, "");
1709         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, "");
1710         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, "");
1711         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, "");
1712
1713         uiBlockSetDirection(block, UI_RIGHT);
1714         uiTextBoundsBlock(block, 50);
1715
1716         uiEndBlock(C, block);
1717         return block;
1718 }
1719
1720 static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
1721 {
1722         ED_region_tag_redraw(CTX_wm_region(C));
1723 }
1724
1725 static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
1726 {
1727         CurveMapping *cumap = cumap_v;
1728         int a;
1729         
1730         cumap->preset = CURVE_PRESET_LINE;
1731         for(a=0; a<CM_TOT; a++)
1732                 curvemap_reset(cumap->cm+a, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
1733         
1734         cumap->black[0]=cumap->black[1]=cumap->black[2]= 0.0f;
1735         cumap->white[0]=cumap->white[1]=cumap->white[2]= 1.0f;
1736         curvemapping_set_black_white(cumap, NULL, NULL);
1737         
1738         curvemapping_changed(cumap, 0);
1739
1740         rna_update_cb(C, cb_v, NULL);
1741 }
1742
1743 /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
1744 static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels, int brush, RNAUpdateCb *cb)
1745 {
1746         CurveMapping *cumap= ptr->data;
1747         uiLayout *row, *sub, *split;
1748         uiBlock *block;
1749         uiBut *bt;
1750         float dx= UI_UNIT_X;
1751         int icon, size;
1752         int bg=-1;
1753
1754         block= uiLayoutGetBlock(layout);
1755
1756         /* curve chooser */
1757         row= uiLayoutRow(layout, 0);
1758
1759         if(labeltype=='v') {
1760                 /* vector */
1761                 sub= uiLayoutRow(row, 1);
1762                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1763
1764                 if(cumap->cm[0].curve) {
1765                         bt= uiDefButI(block, ROW, 0, "X", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1766                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1767                 }
1768                 if(cumap->cm[1].curve) {
1769                         bt= uiDefButI(block, ROW, 0, "Y", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1770                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1771                 }
1772                 if(cumap->cm[2].curve) {
1773                         bt= uiDefButI(block, ROW, 0, "Z", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1774                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1775                 }
1776         }
1777         else if(labeltype=='c') {
1778                 /* color */
1779                 sub= uiLayoutRow(row, 1);
1780                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1781
1782                 if(cumap->cm[3].curve) {
1783                         bt= uiDefButI(block, ROW, 0, "C", 0, 0, dx, dx, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
1784                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1785                 }
1786                 if(cumap->cm[0].curve) {
1787                         bt= uiDefButI(block, ROW, 0, "R", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1788                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1789                 }
1790                 if(cumap->cm[1].curve) {
1791                         bt= uiDefButI(block, ROW, 0, "G", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1792                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1793                 }
1794                 if(cumap->cm[2].curve) {
1795                         bt= uiDefButI(block, ROW, 0, "B", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1796                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1797                 }
1798         }
1799         else if (labeltype == 'h') {
1800                 /* HSV */
1801                 sub= uiLayoutRow(row, 1);
1802                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1803                 
1804                 if(cumap->cm[0].curve) {
1805                         bt= uiDefButI(block, ROW, 0, "H", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1806                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1807                 }
1808                 if(cumap->cm[1].curve) {
1809                         bt= uiDefButI(block, ROW, 0, "S", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1810                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1811                 }
1812                 if(cumap->cm[2].curve) {
1813                         bt= uiDefButI(block, ROW, 0, "V", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1814                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1815                 }
1816         }
1817         else
1818                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
1819         
1820         if (labeltype=='h')
1821                 bg = UI_GRAD_H;
1822
1823         /* operation buttons */
1824         sub= uiLayoutRow(row, 1);
1825
1826         uiBlockSetEmboss(block, UI_EMBOSSN);
1827
1828         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom in"));
1829         uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
1830
1831         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMOUT, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom out"));
1832         uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
1833
1834         if(brush)
1835                 bt= uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, TIP_("Tools"));
1836         else
1837                 bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, TIP_("Tools"));
1838
1839         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1840
1841         if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT;
1842         bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
1843         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1844
1845         bt= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete points"));
1846         uiButSetNFunc(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
1847
1848         uiBlockSetEmboss(block, UI_EMBOSS);
1849
1850         uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
1851
1852         /* curve itself */
1853         size= uiLayoutGetWidth(layout);
1854         row= uiLayoutRow(layout, 0);
1855         uiDefBut(block, BUT_CURVE, 0, "", 0, 0, size, MIN2(size, 200), cumap, 0.0f, 1.0f, bg, 0, "");
1856
1857         /* black/white levels */
1858         if(levels) {
1859                 split= uiLayoutSplit(layout, 0, 0);
1860                 uiItemR(uiLayoutColumn(split, 0), ptr, "black_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1861                 uiItemR(uiLayoutColumn(split, 0), ptr, "white_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1862
1863                 uiLayoutRow(layout, 0);
1864                 bt=uiDefBut(block, BUT, 0, IFACE_("Reset"),     0, 0, UI_UNIT_X*10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
1865                                 TIP_("Reset Black/White point and curves"));
1866                 uiButSetNFunc(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
1867         }
1868
1869         uiBlockSetNFunc(block, NULL, NULL, NULL);
1870 }
1871
1872 void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, int levels, int brush)
1873 {
1874         RNAUpdateCb *cb;
1875         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1876         PointerRNA cptr;
1877
1878         if(!prop) {
1879                 RNA_warning("curve property not found: %s.%s",
1880                             RNA_struct_identifier(ptr->type), propname);
1881                 return;
1882         }
1883
1884         if(RNA_property_type(prop) != PROP_POINTER) {
1885                 RNA_warning("curve is not a pointer: %s.%s",
1886                             RNA_struct_identifier(ptr->type), propname);
1887                 return;
1888         }
1889
1890         cptr= RNA_property_pointer_get(ptr, prop);
1891         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveMapping))
1892                 return;
1893
1894         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1895         cb->ptr= *ptr;
1896         cb->prop= prop;
1897
1898         curvemap_buttons_layout(layout, &cptr, type, levels, brush, cb);
1899
1900         MEM_freeN(cb);
1901 }
1902
1903 /********************* ColorWheel Template ************************/
1904
1905 #define WHEEL_SIZE      100
1906
1907 void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic)
1908 {
1909         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1910         uiBlock *block= uiLayoutGetBlock(layout);
1911         uiLayout *col, *row;
1912         uiBut *but;
1913         float softmin, softmax, step, precision;
1914         
1915         if (!prop) {
1916                 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1917                 return;
1918         }
1919
1920         RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
1921         
1922         col = uiLayoutColumn(layout, 0);
1923         row= uiLayoutRow(col, 1);
1924         
1925         but= uiDefButR_prop(block, HSVCIRCLE, 0, "",    0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop, -1, 0.0, 0.0, 0, 0, "");
1926
1927         if(lock) {
1928                 but->flag |= UI_BUT_COLOR_LOCK;
1929         }
1930
1931         if(lock_luminosity) {
1932                 float color[4]; /* incase of alpha */
1933                 but->flag |= UI_BUT_VEC_SIZE_LOCK;
1934                 RNA_property_float_get_array(ptr, prop, color);
1935                 but->a2= len_v3(color);
1936         }
1937
1938         if(cubic)
1939                 but->flag |= UI_BUT_COLOR_CUBIC;
1940
1941         uiItemS(row);
1942         
1943         if (value_slider)
1944                 uiDefButR_prop(block, HSVCUBE, 0, "", WHEEL_SIZE+6, 0, 14, WHEEL_SIZE, ptr, prop, -1, softmin, softmax, UI_GRAD_V_ALT, 0, "");
1945 }
1946
1947 /********************* Layer Buttons Template ************************/
1948
1949 static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
1950 {
1951         uiBut *but = arg1;
1952         int cur = GET_INT_FROM_POINTER(arg2);
1953         wmWindow *win= CTX_wm_window(C);
1954         int i, tot, shift= win->eventstate->shift;
1955
1956         if(!shift) {
1957                 tot= RNA_property_array_length(&but->rnapoin, but->rnaprop);
1958                 
1959                 /* Normally clicking only selects one layer */
1960                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, 1);
1961                 for(i = 0; i < tot; ++i) {
1962                         if(i != cur)
1963                                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, 0);
1964                 }
1965         }
1966         
1967         /* view3d layer change should update depsgraph (invisible object changed maybe) */
1968         /* see view3d_header.c */
1969 }
1970
1971 // TODO:
1972 //      - for now, grouping of layers is determined by dividing up the length of 
1973 //        the array of layer bitflags
1974
1975 void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
1976                           PointerRNA *used_ptr, const char *used_propname, int active_layer)
1977 {
1978         uiLayout *uRow, *uCol;
1979         PropertyRNA *prop, *used_prop= NULL;
1980         int groups, cols, layers;
1981         int group, col, layer, row;
1982         int cols_per_group = 5;
1983
1984         prop= RNA_struct_find_property(ptr, propname);
1985         if (!prop) {
1986                 RNA_warning("layers property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1987                 return;
1988         }
1989         
1990         /* the number of layers determines the way we group them 
1991          *      - we want 2 rows only (for now)
1992          *      - the number of columns (cols) is the total number of buttons per row
1993          *        the 'remainder' is added to this, as it will be ok to have first row slightly wider if need be
1994          *      - for now, only split into groups if group will have at least 5 items
1995          */
1996         layers= RNA_property_array_length(ptr, prop);
1997         cols= (layers / 2) + (layers % 2);
1998         groups= ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group);
1999
2000         if(used_ptr && used_propname) {
2001                 used_prop= RNA_struct_find_property(used_ptr, used_propname);
2002                 if (!used_prop) {
2003                         RNA_warning("used layers property not found: %s.%s", RNA_struct_identifier(ptr->type), used_propname);
2004                         return;
2005                 }
2006
2007                 if(RNA_property_array_length(used_ptr, used_prop) < layers)
2008                         used_prop = NULL;
2009         }
2010         
2011         /* layers are laid out going across rows, with the columns being divided into groups */
2012         
2013         for (group= 0; group < groups; group++) {
2014                 uCol= uiLayoutColumn(layout, 1);
2015                 
2016                 for (row= 0; row < 2; row++) {
2017                         uiBlock *block;
2018                         uiBut *but;
2019
2020                         uRow= uiLayoutRow(uCol, 1);
2021                         block= uiLayoutGetBlock(uRow);
2022                         layer= groups*cols_per_group*row + cols_per_group*group;
2023                         
2024                         /* add layers as toggle buts */
2025                         for (col= 0; (col < cols_per_group) && (layer < layers); col++, layer++) {
2026                                 int icon = 0;
2027                                 int butlay = 1 << layer;
2028
2029                                 if(active_layer & butlay)
2030                                         icon = ICON_LAYER_ACTIVE;
2031                                 else if(used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, layer))
2032                                         icon = ICON_LAYER_USED;
2033                                 
2034                                 but= uiDefAutoButR(block, ptr, prop, layer, "", icon, 0, 0, UI_UNIT_X/2, UI_UNIT_Y/2);
2035                                 uiButSetFunc(but, handle_layer_buttons, but, SET_INT_IN_POINTER(layer));
2036                                 but->type= TOG;
2037                         }
2038                 }
2039         }
2040 }
2041
2042
2043 /************************* List Template **************************/
2044
2045 static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon, int big)
2046 {
2047         ID *id= NULL;
2048         int icon;
2049
2050         if(!itemptr->data)
2051                 return rnaicon;
2052
2053         /* try ID, material or texture slot */
2054         if(RNA_struct_is_ID(itemptr->type)) {
2055                 id= itemptr->id.data;
2056         }
2057         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2058                 id= RNA_pointer_get(itemptr, "material").data;
2059         }
2060         else if(RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) {
2061                 id= RNA_pointer_get(itemptr, "texture").data;
2062         }
2063         else if(RNA_struct_is_a(itemptr->type, &RNA_DynamicPaintSurface)) {
2064                 DynamicPaintSurface *surface= (DynamicPaintSurface*)itemptr->data;
2065
2066                 if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) return ICON_TEXTURE_SHADED;
2067                 else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) return ICON_OUTLINER_DATA_MESH;
2068                 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return ICON_FILE_IMAGE;
2069         }
2070
2071         /* get icon from ID */
2072         if(id) {
2073                 icon= ui_id_icon_get(C, id, big);
2074
2075                 if(icon)
2076                         return icon;
2077         }
2078
2079         return rnaicon;
2080 }
2081
2082 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)
2083 {
2084         uiBlock *block= uiLayoutGetBlock(layout);
2085         uiBut *but;
2086         uiLayout *split, *overlap, *sub, *row;
2087         char *namebuf;
2088         const char *name;
2089         int icon;
2090
2091         overlap= uiLayoutOverlap(layout);
2092
2093         /* list item behind label & other buttons */
2094         sub= uiLayoutRow(overlap, 0);
2095
2096         but= uiDefButR_prop(block, LISTROW, 0, "", 0,0, UI_UNIT_X*10,UI_UNIT_Y, activeptr, activeprop, 0, 0, i, 0, 0, "");
2097         uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2098
2099         sub= uiLayoutRow(overlap, 0);
2100
2101         /* retrieve icon and name */
2102         icon= list_item_icon_get(C, itemptr, rnaicon, 0);
2103         if(icon == ICON_NONE || icon == ICON_DOT)
2104                 icon= 0;
2105
2106         namebuf= RNA_struct_name_get_alloc(itemptr, NULL, 0, NULL);
2107         name= (namebuf)? namebuf: "";
2108
2109         /* hardcoded types */
2110         if(itemptr->type == &RNA_MeshTextureFaceLayer || itemptr->type == &RNA_MeshColorLayer) {
2111                 uiItemL(sub, name, icon);
2112                 uiBlockSetEmboss(block, UI_EMBOSSN);
2113                 uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", 0, 0, 0, 0, 0, NULL);
2114                 uiBlockSetEmboss(block, UI_EMBOSS);
2115         }
2116         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) {
2117                 uiItemL(sub, name, icon);
2118                 uiBlockSetEmboss(block, UI_EMBOSS);
2119                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0,  NULL);
2120         }
2121         else if(RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
2122                 uiItemL(sub, name, icon);
2123                 uiBlockSetEmboss(block, UI_EMBOSS);
2124                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0,  NULL);
2125         }
2126         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2127                 /* provision to draw active node name */
2128                 Material *ma, *manode;
2129                 Scene *scene= CTX_data_scene(C);
2130                 Object *ob= (Object*)ptr->id.data;
2131                 int index= (Material**)itemptr->data - ob->mat;
2132                 
2133                 /* default item with material base name */
2134                 uiItemL(sub, name, icon);
2135                 
2136                 ma= give_current_material(ob, index+1);
2137                 if (ma && !scene_use_new_shading_nodes(scene)){
2138                         manode= give_node_material(ma);
2139                         if(manode) {
2140                                 char str[MAX_ID_NAME + 12];
2141                                 BLI_snprintf(str, sizeof(str), "Node %s", manode->id.name+2);
2142                                 uiItemL(sub, str, ui_id_icon_get(C, &manode->id, 1));
2143                         }
2144                         else if(ma->use_nodes) {
2145                                 uiItemL(sub, "Node <none>", ICON_NONE);
2146                         }
2147                 }
2148         }
2149         else if(itemptr->type == &RNA_ShapeKey) {
2150                 Object *ob= (Object*)activeptr->data;
2151                 Key *key= (Key*)itemptr->id.data;
2152
2153                 split= uiLayoutSplit(sub, 0.75f, 0);
2154
2155                 uiItemL(split, name, icon);
2156
2157                 uiBlockSetEmboss(block, UI_EMBOSSN);
2158                 row= uiLayoutRow(split, 1);
2159                 if(i == 0 || (key->type != KEY_RELATIVE)) uiItemL(row, "", ICON_NONE);
2160                 else uiItemR(row, itemptr, "value", 0, "", ICON_NONE);
2161
2162                 if(ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH))
2163                         uiLayoutSetActive(row, 0);
2164                 //uiItemR(row, itemptr, "mute", 0, "", ICON_MUTE_IPO_OFF);
2165                 uiBlockSetEmboss(block, UI_EMBOSS);
2166         }
2167         else if(itemptr->type == &RNA_VertexGroup) {
2168                 bDeformGroup *dg= (bDeformGroup *)itemptr->data;
2169                 uiItemL(sub, name, icon);
2170                 /* RNA does not allow nice lock icons, use lower level buttons */
2171 #if 0
2172                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "lock_weight", 0, 0, 0, 0, 0,  NULL);
2173 #else
2174                 uiBlockSetEmboss(block, UI_EMBOSSN);
2175                 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");
2176                 uiBlockSetEmboss(block, UI_EMBOSS);
2177 #endif
2178         }
2179         else if(itemptr->type == &RNA_KeyingSetPath) {
2180                 KS_Path *ksp = (KS_Path*)itemptr->data;
2181                 
2182                 /* icon needs to be the type of ID which is currently active */
2183                 RNA_enum_icon_from_value(id_type_items, ksp->idtype, &icon);
2184                 
2185                 /* nothing else special to do... */
2186                 uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
2187         }
2188         else if(itemptr->type == &RNA_DynamicPaintSurface) {
2189                 char name_final[96];
2190                 const char *enum_name;
2191                 PropertyRNA *prop = RNA_struct_find_property(itemptr, "surface_type");
2192                 DynamicPaintSurface *surface= (DynamicPaintSurface*)itemptr->data;
2193
2194                 RNA_property_enum_name(C, itemptr, prop, RNA_property_enum_get(itemptr, prop), &enum_name);
2195
2196                 BLI_snprintf(name_final, sizeof(name_final), "%s (%s)",name,enum_name);
2197                 uiItemL(sub, name_final, icon);
2198                 if (dynamicPaint_surfaceHasColorPreview(surface)) {
2199                         uiBlockSetEmboss(block, UI_EMBOSSN);
2200                         uiDefIconButR(block, OPTION, 0, (surface->flags & MOD_DPAINT_PREVIEW) ? ICON_RESTRICT_VIEW_OFF : ICON_RESTRICT_VIEW_ON,
2201                                 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "show_preview", 0, 0, 0, 0, 0, NULL);
2202                         uiBlockSetEmboss(block, UI_EMBOSS);
2203                 }
2204                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "is_active", i, 0, 0, 0, 0,  NULL);
2205         }
2206         else if(itemptr->type == &RNA_MovieTrackingObject) {
2207                 MovieTrackingObject *tracking_object= (MovieTrackingObject*)itemptr->data;
2208
2209                 split= uiLayoutSplit(sub, 0.75f, 0);
2210                 if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
2211                         uiItemL(split, name, ICON_CAMERA_DATA);
2212                 }
2213                 else {
2214                         uiItemL(split, name, ICON_OBJECT_DATA);
2215                 }
2216         }
2217
2218         /* There is a last chance to display custom controls (in addition to the name/label):
2219          * If the given item property group features a string property named as prop_list,
2220          * this tries to add controls for all properties of the item listed in that string property.
2221          * (colon-separated names).
2222          *
2223          * This is especially useful for python. E.g., if you list a collection of this property
2224          * group:
2225          *
2226          * class TestPropertyGroup(bpy.types.PropertyGroup):
2227          *     bool    = BoolProperty(default=False)
2228          *     integer = IntProperty()
2229          *     string  = StringProperty()
2230          * 
2231          *     # A string of all identifiers (colon-separated) which property’s controls should be
2232          *     # displayed in a template_list.
2233          *     template_list_controls = StringProperty(default="integer:bool:string", options={"HIDDEN"})
2234          *
2235          * … you’ll get a numfield for the integer prop, a check box for the bool prop, and a textfield
2236          * for the string prop, after the name of each item of the collection.
2237          */
2238         else if (prop_list_id) {
2239                 row = uiLayoutRow(sub, 1);
2240                 uiItemL(row, name, icon);
2241
2242                 /* XXX: Check, as sometimes we get an itemptr looking like
2243                  *      {id = {data = 0x0}, type = 0x0, data = 0x0}
2244                  *      which would obviously produce a sigsev… */
2245                 if (itemptr->type) {
2246                         /* If the special property is set for the item, and it is a collection… */
2247                         PropertyRNA *prop_list= RNA_struct_find_property(itemptr, prop_list_id);
2248
2249                         if(prop_list && RNA_property_type(prop_list) == PROP_STRING) {
2250                                 int prop_names_len;
2251                                 char *prop_names = RNA_property_string_get_alloc(itemptr, prop_list, NULL, 0, &prop_names_len);
2252                                 char *prop_names_end= prop_names + prop_names_len;
2253                                 char *id= prop_names;
2254                                 char *id_next;
2255                                 while (id < prop_names_end) {
2256                                         if ((id_next= strchr(id, ':'))) *id_next++= '\0';
2257                                         else id_next= prop_names_end;
2258                                         uiItemR(row, itemptr, id, 0, NULL, 0);
2259                                         id= id_next;
2260                                 }
2261                                 MEM_freeN(prop_names);
2262                         }
2263                 }
2264         }
2265
2266         else
2267                 uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
2268
2269         /* free name */
2270         if(namebuf)
2271                 MEM_freeN(namebuf);
2272 }
2273
2274 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)
2275 {
2276         //Scene *scene= CTX_data_scene(C);
2277         PropertyRNA *prop= NULL, *activeprop;
2278         PropertyType type, activetype;
2279         StructRNA *ptype;
2280         uiLayout *box, *row, *col;
2281         uiBlock *block;
2282         uiBut *but;
2283         Panel *pa;
2284         const char *name;
2285         char numstr[32];
2286         int rnaicon=0, icon=0, i= 0, activei= 0, len= 0, items, found, min, max;
2287
2288         /* validate arguments */
2289         block= uiLayoutGetBlock(layout);
2290         pa= block->panel;
2291
2292         if(!pa) {
2293                 RNA_warning("Only works inside a panel");
2294                 return;
2295         }
2296
2297         if(!activeptr->data)
2298                 return;
2299         
2300         if(ptr->data) {
2301                 prop= RNA_struct_find_property(ptr, propname);
2302                 if(!prop) {
2303                         RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2304                         return;
2305                 }
2306         }
2307
2308         activeprop= RNA_struct_find_property(activeptr, activepropname);
2309         if(!activeprop) {
2310                 RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), activepropname);
2311                 return;
2312         }
2313
2314         if(prop) {
2315                 type= RNA_property_type(prop);
2316                 if(type != PROP_COLLECTION) {
2317                         RNA_warning("uiExpected collection property");
2318                         return;
2319                 }
2320         }
2321
2322         activetype= RNA_property_type(activeprop);
2323         if(activetype != PROP_INT) {
2324                 RNA_warning("Expected integer property");
2325                 return;
2326         }
2327
2328         /* get icon */
2329         if(ptr->data && prop) {
2330                 ptype= RNA_property_pointer_type(ptr, prop);
2331                 rnaicon= RNA_struct_ui_icon(ptype);
2332         }
2333
2334         /* get active data */
2335         activei= RNA_property_int_get(activeptr, activeprop);
2336
2337         if(listtype == 'i') {
2338                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2339                 col= uiLayoutColumn(box, 1);
2340                 row= uiLayoutRow(col, 0);
2341
2342                 if(ptr->data && prop) {
2343                         /* create list items */
2344                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2345                                 /* create button */
2346                                 if(!(i % 9))
2347                                         row= uiLayoutRow(col, 0);
2348
2349                                 icon= list_item_icon_get(C, &itemptr, rnaicon, 1);
2350                                 but= uiDefIconButR_prop(block, LISTROW, 0, icon, 0,0,UI_UNIT_X*10,UI_UNIT_Y, activeptr, activeprop, 0, 0, i, 0, 0, "");
2351                                 uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2352                                 
2353
2354                                 i++;
2355                         }
2356                         RNA_PROP_END;
2357                 }
2358         }
2359         else if(listtype == 'c') {
2360                 /* compact layout */
2361
2362                 row= uiLayoutRow(layout, 1);
2363
2364                 if(ptr->data && prop) {
2365                         /* create list items */
2366                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2367                                 found= (activei == i);
2368
2369                                 if(found) {
2370                                         /* create button */
2371                                         name= RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL);
2372                                         icon= list_item_icon_get(C, &itemptr, rnaicon, 0);
2373                                         uiItemL(row, (name)? name: "", icon);
2374
2375                                         if(name)
2376                                                 MEM_freeN((void *)name);
2377                                 }
2378
2379                                 i++;
2380                         }
2381                         RNA_PROP_END;
2382                 }
2383
2384                 /* if not found, add in dummy button */
2385                 if(i == 0)
2386                         uiItemL(row, "", ICON_NONE);
2387
2388                 /* next/prev button */
2389                 BLI_snprintf(numstr, sizeof(numstr), "%d :", i);
2390                 but= uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0,0,UI_UNIT_X*5,UI_UNIT_Y, activeptr, activeprop, 0, 0, 0, 0, 0, "");
2391                 if(i == 0)
2392                         uiButSetFlag(but, UI_BUT_DISABLED);
2393         }
2394         else {
2395                 /* default rows */
2396                 if(rows == 0)
2397                         rows= 5;
2398                 if (maxrows == 0)
2399                         maxrows = 5;
2400                 if(pa->list_grip_size != 0)
2401                         rows= pa->list_grip_size;
2402
2403                 /* layout */
2404                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2405                 row= uiLayoutRow(box, 0);
2406                 col = uiLayoutColumn(row, 1);
2407
2408                 /* init numbers */
2409                 RNA_property_int_range(activeptr, activeprop, &min, &max);
2410
2411                 if(prop)
2412                         len= RNA_property_collection_length(ptr, prop);
2413                 items= CLAMPIS(len, rows, MAX2(rows, maxrows));
2414
2415                 /* if list length changes and active is out of view, scroll to it */
2416                 if(pa->list_last_len != len)
2417                         if((activei < pa->list_scroll || activei >= pa->list_scroll+items))
2418                                 pa->list_scroll= activei;
2419
2420                 pa->list_scroll= MIN2(pa->list_scroll, len-items);
2421                 pa->list_scroll= MAX2(pa->list_scroll, 0);
2422                 pa->list_size= items;
2423                 pa->list_last_len= len;
2424
2425                 if(ptr->data && prop) {
2426                         /* create list items */
2427                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2428                                 if(i >= pa->list_scroll && i<pa->list_scroll+items)
2429                                         list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activeprop, prop_list);
2430
2431                                 i++;
2432                         }
2433                         RNA_PROP_END;
2434                 }
2435
2436                 /* add dummy buttons to fill space */
2437                 while(i < pa->list_scroll+items) {
2438                         if(i >= pa->list_scroll)
2439                                 uiItemL(col, "", ICON_NONE);
2440                         i++;
2441                 }
2442
2443                 /* add scrollbar */
2444                 if(len > items) {
2445                         col= uiLayoutColumn(row, 0);
2446                         uiDefButI(block, SCROLL, 0, "", 0,0,UI_UNIT_X*0.75,UI_UNIT_Y*items, &pa->list_scroll, 0, len-items, items, 0, "");
2447                 }
2448         }
2449 }
2450
2451 /************************* Operator Search Template **************************/
2452
2453 static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
2454 {
2455         wmOperatorType *ot= arg2;
2456         
2457         if(ot)
2458                 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
2459 }
2460
2461 static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
2462 {
2463         GHashIterator *iter= WM_operatortype_iter();
2464
2465         for( ; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
2466                 wmOperatorType *ot= BLI_ghashIterator_getValue(iter);
2467
2468                 if(BLI_strcasestr(ot->name, str)) {
2469                         if(WM_operator_poll((bContext*)C, ot)) {
2470                                 char name[256];
2471                                 int len= strlen(ot->name);
2472                                 
2473                                 /* display name for menu, can hold hotkey */
2474                                 BLI_strncpy(name, ot->name, 256);
2475                                 
2476                                 /* check for hotkey */
2477                                 if(len < 256-6) {
2478                                         if(WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, TRUE, &name[len+1], 256-len-1))
2479                                                 name[len]= '|';
2480                                 }
2481                                 
2482                                 if(0==uiSearchItemAdd(items, name, ot, 0))
2483                                         break;
2484                         }
2485                 }
2486         }
2487         BLI_ghashIterator_free(iter);
2488 }
2489
2490 void uiTemplateOperatorSearch(uiLayout *layout)
2491 {
2492         uiBlock *block;
2493         uiBut *but;
2494         static char search[256]= "";
2495                 
2496         block= uiLayoutGetBlock(layout);
2497         uiBlockSetCurLayout(block, layout);
2498
2499         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, 0, 0, "");
2500         uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
2501 }
2502
2503 /************************* Running Jobs Template **************************/
2504
2505 #define B_STOPRENDER    1
2506 #define B_STOPCAST              2
2507 #define B_STOPANIM              3
2508 #define B_STOPCOMPO             4
2509 #define B_STOPSEQ               5
2510 #define B_STOPCLIP              6
2511
2512 static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
2513 {
2514         switch(event) {
2515                 case B_STOPRENDER:
2516                         G.afbreek= 1;
2517                         break;
2518                 case B_STOPCAST:
2519                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C), NULL);
2520                         break;
2521                 case B_STOPANIM:
2522                         WM_operator_name_call(C, "SCREEN_OT_animation_play", WM_OP_INVOKE_SCREEN, NULL);
2523                         break;
2524                 case B_STOPCOMPO:
2525                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2526                         break;
2527                 case B_STOPSEQ:
2528                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2529                         break;
2530                 case B_STOPCLIP:
2531                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2532                         break;
2533         }
2534 }
2535
2536 void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
2537 {
2538         bScreen *screen= CTX_wm_screen(C);
2539         wmWindowManager *wm= CTX_wm_manager(C);
2540         ScrArea *sa= CTX_wm_area(C);
2541         uiBlock *block;
2542         void *owner= NULL;
2543         int handle_event;
2544         
2545         block= uiLayoutGetBlock(layout);
2546         uiBlockSetCurLayout(block, layout);
2547
2548         uiBlockSetHandleFunc(block, do_running_jobs, NULL);
2549
2550         if(sa->spacetype==SPACE_NODE) {
2551                 if(WM_jobs_test(wm, sa))
2552                    owner = sa;
2553                 handle_event= B_STOPCOMPO;
2554         } else if (sa->spacetype==SPACE_SEQ) {
2555                 if(WM_jobs_test(wm, sa))
2556                         owner = sa;
2557                 handle_event = B_STOPSEQ;
2558         } else if(sa->spacetype==SPACE_CLIP) {
2559                 if(WM_jobs_test(wm, sa))
2560                    owner = sa;
2561                 handle_event= B_STOPCLIP;
2562         } else {
2563                 Scene *scene;
2564                 /* another scene can be rendering too, for example via compositor */
2565                 for(scene= CTX_data_main(C)->scene.first; scene; scene= scene->id.next)
2566                         if(WM_jobs_test(wm, scene))
2567                                 break;
2568                 owner = scene;
2569                 handle_event= B_STOPRENDER;
2570         }
2571
2572         if(owner) {
2573                 uiLayout *ui_abs;
2574                 
2575                 ui_abs= uiLayoutAbsolute(layout, 0);
2576                 (void)ui_abs; // UNUSED
2577                 
2578                 uiDefIconBut(block, BUT, handle_event, ICON_PANEL_CLOSE, 
2579                                 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"));
2580                 uiDefBut(block, PROGRESSBAR, 0, WM_jobs_name(wm, owner), 
2581                                 UI_UNIT_X, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, TIP_("Progress"));
2582                 
2583                 uiLayoutRow(layout, 0);
2584         }
2585         if(WM_jobs_test(wm, screen))
2586                 uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, IFACE_("Capture"), 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
2587                                 TIP_("Stop screencast"));
2588         if(screen->animtimer)
2589                 uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_CANCEL, TIP_("Anim Player"), 0,0,100,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
2590                                 TIP_("Stop animation playback"));
2591 }
2592
2593 /************************* Reports for Last Operator Template **************************/
2594
2595 void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
2596 {
2597         ReportList *reports = CTX_wm_reports(C);
2598         Report *report= BKE_reports_last_displayable(reports);
2599         ReportTimerInfo *rti;
2600         
2601         uiLayout *ui_abs;
2602         uiBlock *block;
2603         uiBut *but;
2604         uiStyle *style= UI_GetStyle();
2605         int width;
2606         int icon=0;
2607         
2608         /* if the report display has timed out, don't show */
2609         if (!reports->reporttimer) return;
2610         
2611         rti= (ReportTimerInfo *)reports->reporttimer->customdata;
2612         
2613         if (!rti || rti->widthfac==0.0f || !report) return;
2614         
2615         ui_abs= uiLayoutAbsolute(layout, 0);
2616         block= uiLayoutGetBlock(ui_abs);
2617         
2618         width = BLF_width(style->widget.uifont_id, report->message);
2619         width = MIN2(rti->widthfac*width, width);
2620         width = MAX2(width, 10);
2621         
2622         /* make a box around the report to make it stand out */
2623         uiBlockBeginAlign(block);
2624         but= uiDefBut(block, ROUNDBOX, 0, "", 0, 0, UI_UNIT_X+10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2625         /* set the report's bg color in but->col - ROUNDBOX feature */
2626         but->col[0]= FTOCHAR(rti->col[0]);
2627         but->col[1]= FTOCHAR(rti->col[1]);
2628         but->col[2]= FTOCHAR(rti->col[2]);
2629         but->col[3]= 255; 
2630
2631         but= uiDefBut(block, ROUNDBOX, 0, "", UI_UNIT_X+10, 0, UI_UNIT_X+width, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2632         but->col[0]= but->col[1]= but->col[2]= FTOCHAR(rti->greyscale);
2633         but->col[3]= 255;
2634
2635         uiBlockEndAlign(block);
2636         
2637         
2638         /* icon and report message on top */
2639         if(report->type & RPT_ERROR_ALL)
2640                 icon = ICON_ERROR;
2641         else if(report->type & RPT_WARNING_ALL)
2642                 icon = ICON_ERROR;
2643         else if(report->type & RPT_INFO_ALL)
2644                 icon = ICON_INFO;
2645         
2646         /* XXX: temporary operator to dump all reports to a text block, but only if more than 1 report 
2647          * to be shown instead of icon when appropriate...
2648          */
2649         uiBlockSetEmboss(block, UI_EMBOSSN);
2650
2651         if (reports->list.first != reports->list.last)
2652                 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'"));
2653         else
2654                 uiDefIconBut(block, LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2655
2656         uiBlockSetEmboss(block, UI_EMBOSS);
2657         
2658         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, "");
2659 }
2660
2661 /********************************* Keymap *************************************/
2662
2663 static void keymap_item_modified(bContext *UNUSED(C), void *kmi_p, void *UNUSED(unused))
2664 {
2665         wmKeyMapItem *kmi= (wmKeyMapItem*)kmi_p;
2666         WM_keyconfig_update_tag(NULL, kmi);
2667 }
2668
2669 static void template_keymap_item_properties(uiLayout *layout, const char *title, PointerRNA *ptr)
2670 {
2671         uiLayout *flow;
2672
2673         uiItemS(layout);
2674
2675         if(title)
2676                 uiItemL(layout, title, ICON_NONE);
2677         
2678         flow= uiLayoutColumnFlow(layout, 2, 0);
2679
2680         RNA_STRUCT_BEGIN(ptr, prop) {
2681                 int flag= RNA_property_flag(prop);
2682
2683                 if(flag & PROP_HIDDEN)
2684                         continue;
2685
2686                 /* recurse for nested properties */
2687                 if(RNA_property_type(prop) == PROP_POINTER) {
2688                         PointerRNA propptr= RNA_property_pointer_get(ptr, prop);
2689                         const char *name= RNA_property_ui_name(prop);
2690
2691                         if(propptr.data && RNA_struct_is_a(propptr.type, &RNA_OperatorProperties)) {
2692                                 template_keymap_item_properties(layout, name, &propptr);
2693                                 continue;
2694                         }
2695                 }
2696
2697                 /* add property */
2698                 uiItemR(flow, ptr, RNA_property_identifier(prop), 0, NULL, ICON_NONE);
2699         }
2700         RNA_STRUCT_END;
2701 }
2702
2703 void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
2704 {
2705         PointerRNA propptr= RNA_pointer_get(ptr, "properties");
2706
2707         if(propptr.data) {
2708                 uiBut *but= uiLayoutGetBlock(layout)->buttons.last;
2709
2710                 template_keymap_item_properties(layout, NULL, &propptr);
2711
2712                 /* attach callbacks to compensate for missing properties update,
2713                    we don't know which keymap (item) is being modified there */
2714                 for(; but; but=but->next)
2715                         uiButSetFunc(but, keymap_item_modified, ptr->data, NULL);
2716         }
2717 }
2718