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