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