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