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