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