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