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