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