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