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