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