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