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