Merging r38733 through r38779 from trunk into soc-2011-tomato
[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_key_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_userdef_types.h"
39
40 #include "BLI_string.h"
41 #include "BLI_utildefines.h"
42
43 #include "BKE_animsys.h"
44 #include "BKE_colortools.h"
45 #include "BKE_context.h"
46 #include "BKE_global.h"
47 #include "BKE_library.h"
48 #include "BKE_main.h"
49 #include "BKE_object.h"
50 #include "BKE_material.h"
51 #include "BKE_texture.h"
52 #include "BKE_report.h"
53 #include "BKE_displist.h"
54
55 #include "ED_screen.h"
56 #include "ED_render.h"
57
58 #include "RNA_access.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62
63 #include "UI_interface.h"
64 #include "interface_intern.h"
65
66 #include "BLF_api.h"
67
68 void UI_template_fix_linking(void)
69 {
70 }
71
72 /********************** Header Template *************************/
73
74 void uiTemplateHeader(uiLayout *layout, bContext *C, int menus)
75 {
76         uiBlock *block;
77
78         block= uiLayoutAbsoluteBlock(layout);
79         if(menus) ED_area_header_standardbuttons(C, block, 0);
80         else ED_area_header_switchbutton(C, block, 0);
81 }
82
83 /********************** Search Callbacks *************************/
84
85 typedef struct TemplateID {
86         PointerRNA ptr;
87         PropertyRNA *prop;
88
89         ListBase *idlb;
90         int prv_rows, prv_cols;
91 } TemplateID;
92
93 /* Search browse menu, assign  */
94 static void id_search_call_cb(bContext *C, void *arg_template, void *item)
95 {
96         TemplateID *template= (TemplateID*)arg_template;
97
98         /* ID */
99         if(item) {
100                 PointerRNA idptr;
101
102                 RNA_id_pointer_create(item, &idptr);
103                 RNA_property_pointer_set(&template->ptr, template->prop, idptr);
104                 RNA_property_update(C, &template->ptr, template->prop);
105         }
106 }
107
108 /* ID Search browse menu, do the search */
109 static void id_search_cb(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
110 {
111         TemplateID *template= (TemplateID*)arg_template;
112         ListBase *lb= template->idlb;
113         ID *id, *id_from= template->ptr.id.data;
114         int iconid;
115         int flag= RNA_property_flag(template->prop);
116
117         /* ID listbase */
118         for(id= lb->first; id; id= id->next) {
119                 if(!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
120
121                         /* use filter */
122                         if(RNA_property_type(template->prop)==PROP_POINTER) {
123                                 PointerRNA ptr;
124                                 RNA_id_pointer_create(id, &ptr);
125                                 if(RNA_property_pointer_poll(&template->ptr, template->prop, &ptr)==0)
126                                         continue;
127                         }
128
129                         /* hide dot-datablocks, but only if filter does not force it visible */
130                         if(U.uiflag & USER_HIDE_DOT)
131                                 if ((id->name[2]=='.') && (str[0] != '.'))
132                                         continue;
133
134                         if(BLI_strcasestr(id->name+2, str)) {
135                                 char name_ui[32];
136                                 name_uiprefix_id(name_ui, id);
137
138                                 iconid= ui_id_icon_get((bContext*)C, id, 1);
139
140                                 if(!uiSearchItemAdd(items, name_ui, id, iconid))
141                                         break;
142                         }
143                 }
144         }
145 }
146
147 /* ID Search browse menu, open */
148 static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
149 {
150         static char search[256];
151         static TemplateID template;
152         PointerRNA idptr;
153         wmWindow *win= CTX_wm_window(C);
154         uiBlock *block;
155         uiBut *but;
156         
157         /* clear initial search string, then all items show */
158         search[0]= 0;
159         /* arg_litem is malloced, can be freed by parent button */
160         template= *((TemplateID*)arg_litem);
161         
162         /* get active id for showing first item */
163         idptr= RNA_property_pointer_get(&template.ptr, template.prop);
164
165         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
166         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
167         
168         /* preview thumbnails */
169         if (template.prv_rows > 0 && template.prv_cols > 0) {
170                 int w = 96 * template.prv_cols;
171                 int h = 96 * template.prv_rows + 20;
172                 
173                 /* fake button, it holds space for search items */
174                 uiDefBut(block, LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
175                 
176                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, w, 19, template.prv_rows, template.prv_cols, "");
177                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
178         }
179         /* list view */
180         else {
181                 /* fake button, it holds space for search items */
182                 uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
183                 
184                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, 0, 0, "");
185                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
186         }
187                 
188         
189         uiBoundsBlock(block, 6);
190         uiBlockSetDirection(block, UI_DOWN);    
191         uiEndBlock(C, block);
192         
193         /* give search-field focus */
194         uiButSetFocusOnEnter(win, but);
195         /* this type of search menu requires undo */
196         but->flag |= UI_BUT_UNDO;
197         
198         return block;
199 }
200
201 /************************ ID Template ***************************/
202 /* This is for browsing and editing the ID-blocks used */
203
204 /* for new/open operators */
205 void uiIDContextProperty(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
206 {
207         TemplateID *template;
208         ARegion *ar= CTX_wm_region(C);
209         uiBlock *block;
210         uiBut *but;
211
212         memset(ptr, 0, sizeof(*ptr));
213         *prop= NULL;
214
215         if(!ar)
216                 return;
217
218         for(block=ar->uiblocks.first; block; block=block->next) {
219                 for(but=block->buttons.first; but; but= but->next) {
220                         /* find the button before the active one */
221                         if((but->flag & (UI_BUT_LAST_ACTIVE|UI_ACTIVE))) {
222                                 if(but->func_argN) {
223                                         template= but->func_argN;
224                                         *ptr= template->ptr;
225                                         *prop= template->prop;
226                                         return;
227                                 }
228                         }
229                 }
230         }
231 }
232
233
234 static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
235 {
236         TemplateID *template= (TemplateID*)arg_litem;
237         PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
238         ID *id= idptr.data, *newid;
239         int event= GET_INT_FROM_POINTER(arg_event);
240         
241         switch(event) {
242                 case UI_ID_BROWSE:
243                 case UI_ID_PIN:
244                         RNA_warning("warning, id event %d shouldnt come here\n", event);
245                         break;
246                 case UI_ID_OPEN:
247                 case UI_ID_ADD_NEW:
248                         /* these call uiIDContextPropertySet */
249                         break;
250                 case UI_ID_DELETE:
251                         memset(&idptr, 0, sizeof(idptr));
252                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
253                         RNA_property_update(C, &template->ptr, template->prop);
254
255                         if(id && CTX_wm_window(C)->eventstate->shift) /* useful hidden functionality, */
256                                 id->us= 0;
257
258                         break;
259                 case UI_ID_FAKE_USER:
260                         if(id) {
261                                 if(id->flag & LIB_FAKEUSER) id_us_plus(id);
262                                 else id_us_min(id);
263                         }
264                         else return;
265                         break;
266                 case UI_ID_LOCAL:
267                         if(id) {
268                                 if(id_make_local(id, 0)) {
269                                         /* reassign to get get proper updates/notifiers */
270                                         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
271                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
272                                         RNA_property_update(C, &template->ptr, template->prop);
273                                 }
274                         }
275                         break;
276                 case UI_ID_ALONE:
277                         if(id) {
278                                 /* make copy */
279                                 if(id_copy(id, &newid, 0) && newid) {
280                                         /* copy animation actions too */
281                                         BKE_copy_animdata_id_action(id);
282                                         /* us is 1 by convention, but RNA_property_pointer_set
283                                            will also incremement it, so set it to zero */
284                                         newid->us= 0;
285
286                                         /* assign copy */
287                                         RNA_id_pointer_create(newid, &idptr);
288                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
289                                         RNA_property_update(C, &template->ptr, template->prop);
290                                 }
291                         }
292                         break;
293 #if 0
294                 case UI_ID_AUTO_NAME:
295                         break;
296 #endif
297         }
298 }
299
300 static const char *template_id_browse_tip(StructRNA *type)
301 {
302         if(type) {
303                 switch(RNA_type_to_ID_code(type)) {
304                         case ID_SCE: return "Browse Scene to be linked";
305                         case ID_OB: return "Browse Object to be linked";
306                         case ID_ME: return "Browse Mesh Data to be linked";
307                         case ID_CU: return "Browse Curve Data to be linked";
308                         case ID_MB: return "Browse MetaBall Data to be linked";
309                         case ID_MA: return "Browse Material to be linked";
310                         case ID_TE: return "Browse Texture to be linked";
311                         case ID_IM: return "Browse Image to be linked";
312                         case ID_LA: return "Browse Lattice Data to be linked";
313                         case ID_CA: return "Browse Camera Data to be linked";
314                         case ID_WO: return "Browse World Settings to be linked";
315                         case ID_SCR: return "Choose Screen lay-out";
316                         case ID_TXT: return "Browse Text to be linked";
317                         case ID_SO: return "Browse Sound to be linked";
318                         case ID_AR: return "Browse Armature data to be linked";
319                         case ID_AC: return "Browse Action to be linked";
320                         case ID_NT: return "Browse Node Tree to be linked";
321                         case ID_BR: return "Browse Brush to be linked";
322                         case ID_PA: return "Browse Particle System to be linked";
323                         case ID_GD: return "Browse Grease Pencil Data to be linked";
324                 }
325         }
326         return "Browse ID data to be linked";
327 }
328
329 static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, const char *newop, const char *openop, const char *unlinkop)
330 {
331         uiBut *but;
332         uiBlock *block;
333         PointerRNA idptr;
334         // ListBase *lb; // UNUSED
335         ID *id, *idfrom;
336         int editable= RNA_property_editable(&template->ptr, template->prop);
337
338         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
339         id= idptr.data;
340         idfrom= template->ptr.id.data;
341         // lb= template->idlb;
342
343         block= uiLayoutGetBlock(layout);
344         uiBlockBeginAlign(block);
345
346         if(idptr.type)
347                 type= idptr.type;
348
349         if(flag & UI_ID_PREVIEWS) {
350
351                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, template_id_browse_tip(type));
352                 if(type) {
353                         but->icon= RNA_struct_ui_icon(type);
354                         if (id) but->icon = ui_id_icon_get(C, id, 1);
355                         uiButSetFlag(but, UI_HAS_ICON|UI_ICON_PREVIEW);
356                 }
357                 if((idfrom && idfrom->lib) || !editable)
358                         uiButSetFlag(but, UI_BUT_DISABLED);
359                 
360                 uiLayoutRow(layout, 1);
361         }
362         else if(flag & UI_ID_BROWSE) {
363                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*1.6, UI_UNIT_Y, template_id_browse_tip(type));
364                 if(type) {
365                         but->icon= RNA_struct_ui_icon(type);
366                         /* default dragging of icon for id browse buttons */
367                         uiButSetDragID(but, id);
368                         uiButSetFlag(but, UI_HAS_ICON|UI_ICON_LEFT);
369                 }
370
371                 if((idfrom && idfrom->lib) || !editable)
372                         uiButSetFlag(but, UI_BUT_DISABLED);
373         }
374
375         /* text button with name */
376         if(id) {
377                 char name[UI_MAX_NAME_STR];
378                 const short user_alert= (id->us <= 0);
379
380                 //text_idbutton(id, name);
381                 name[0]= '\0';
382                 but= uiDefButR(block, TEX, 0, name, 0, 0, UI_UNIT_X*6, UI_UNIT_Y, &idptr, "name", -1, 0, 0, -1, -1, NULL);
383                 uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
384                 if(user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
385
386                 if(id->lib) {
387                         if(id->flag & LIB_INDIRECT) {
388                                 but= uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_INDIRECT, 0,0,UI_UNIT_X,UI_UNIT_Y, NULL, 0, 0, 0, 0,
389                                         "Indirect library datablock, cannot change.");
390                                 uiButSetFlag(but, UI_BUT_DISABLED);
391                         }
392                         else {
393                                 but= uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0,0,UI_UNIT_X,UI_UNIT_Y, NULL, 0, 0, 0, 0,
394                                         "Direct linked library datablock, click to make local.");
395                                 if(!id_make_local(id, 1 /* test */) || (idfrom && idfrom->lib))
396                                         uiButSetFlag(but, UI_BUT_DISABLED);
397                         }
398
399                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL));
400                 }
401
402                 if(id->us > 1) {
403                         char str[32];
404
405                         sprintf(str, "%d", id->us);
406
407                         if(id->us<10)
408                                 but= uiDefBut(block, BUT, 0, str, 0,0,UI_UNIT_X,UI_UNIT_Y, NULL, 0, 0, 0, 0, "Displays number of users of this data. Click to make a single-user copy.");
409                         else
410                                 but= uiDefBut(block, BUT, 0, str, 0,0,UI_UNIT_X+10,UI_UNIT_Y, NULL, 0, 0, 0, 0, "Displays number of users of this data. Click to make a single-user copy.");
411
412                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
413                         if(!id_copy(id, NULL, 1 /* test only */) || (idfrom && idfrom->lib) || !editable)
414                                 uiButSetFlag(but, UI_BUT_DISABLED);
415                 }
416         
417                 if(user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
418                 
419                 if(id->lib == NULL && !(ELEM5(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
420                         uiDefButR(block, TOG, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
421                 }
422         }
423         
424         if(flag & UI_ID_ADD_NEW) {
425                 int w= id?UI_UNIT_X: (flag & UI_ID_OPEN)? UI_UNIT_X*3: UI_UNIT_X*6;
426                 
427                 if(newop) {
428                         but= uiDefIconTextButO(block, BUT, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, (id)? "": "New", 0, 0, w, UI_UNIT_Y, NULL);
429                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
430                 }
431                 else {
432                         but= uiDefIconTextBut(block, BUT, 0, ICON_ZOOMIN, (id)? "": "New", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
433                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
434                 }
435
436                 if((idfrom && idfrom->lib) || !editable)
437                         uiButSetFlag(but, UI_BUT_DISABLED);
438         }
439
440         if(flag & UI_ID_OPEN) {
441                 int w= id?UI_UNIT_X: (flag & UI_ID_ADD_NEW)? UI_UNIT_X*3: UI_UNIT_X*6;
442                 
443                 if(openop) {
444                         but= uiDefIconTextButO(block, BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id)? "": "Open", 0, 0, w, UI_UNIT_Y, NULL);
445                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
446                 }
447                 else {
448                         but= uiDefIconTextBut(block, BUT, 0, ICON_FILESEL, (id)? "": "Open", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
449                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
450                 }
451
452                 if((idfrom && idfrom->lib) || !editable)
453                         uiButSetFlag(but, UI_BUT_DISABLED);
454         }
455         
456         /* delete button */
457         if(id && (flag & UI_ID_DELETE) && (RNA_property_flag(template->prop) & PROP_NEVER_UNLINK)==0) {
458                 if(unlinkop) {
459                         but= uiDefIconButO(block, BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
460                         /* so we can access the template from operators, font unlinking needs this */
461                         uiButSetNFunc(but, NULL, MEM_dupallocN(template), NULL);
462                 }
463                 else {
464                         but= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Unlink datablock. Shift + Click to set users to zero, data will then not be saved");
465                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
466
467                         if(RNA_property_flag(template->prop) & PROP_NEVER_NULL)
468                                 uiButSetFlag(but, UI_BUT_DISABLED);
469                 }
470
471                 if((idfrom && idfrom->lib) || !editable)
472                         uiButSetFlag(but, UI_BUT_DISABLED);
473         }
474         
475         uiBlockEndAlign(block);
476 }
477
478 static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int flag, int prv_rows, int prv_cols)
479 {
480         TemplateID *template;
481         PropertyRNA *prop;
482         StructRNA *type;
483
484         prop= RNA_struct_find_property(ptr, propname);
485
486         if(!prop || RNA_property_type(prop) != PROP_POINTER) {
487                 RNA_warning("uiTemplateID: pointer property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
488                 return;
489         }
490
491         template= MEM_callocN(sizeof(TemplateID), "TemplateID");
492         template->ptr= *ptr;
493         template->prop= prop;
494         template->prv_rows = prv_rows;
495         template->prv_cols = prv_cols;
496
497         if(newop)
498                 flag |= UI_ID_ADD_NEW;
499         if(openop)
500                 flag |= UI_ID_OPEN;
501
502         type= RNA_property_pointer_type(ptr, prop);
503         template->idlb= which_libbase(CTX_data_main(C), RNA_type_to_ID_code(type));
504         
505         /* create UI elements for this template
506          *      - template_ID makes a copy of the template data and assigns it to the relevant buttons
507          */
508         if(template->idlb) {
509                 uiLayoutRow(layout, 1);
510                 template_ID(C, layout, template, type, flag, newop, openop, unlinkop);
511         }
512
513         MEM_freeN(template);
514 }
515
516 void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop)
517 {
518         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE, 0, 0);
519 }
520
521 void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop)
522 {
523         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME, 0, 0);
524 }
525
526 void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int rows, int cols)
527 {
528         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE|UI_ID_PREVIEWS, rows, cols);
529 }
530
531 /************************ ID Chooser Template ***************************/
532
533 /* This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use 
534  *
535  * - propname: property identifier for property that ID-pointer gets stored to
536  * - proptypename: property identifier for property used to determine the type of ID-pointer that can be used
537  */
538 void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename, const char *text)
539 {
540         PropertyRNA *propID, *propType;
541         uiLayout *row;
542         
543         /* get properties... */
544         propID= RNA_struct_find_property(ptr, propname);
545         propType= RNA_struct_find_property(ptr, proptypename);
546
547         if (!propID || RNA_property_type(propID) != PROP_POINTER) {
548                 RNA_warning("uiTemplateAnyID: pointer property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
549                 return;
550         }
551         if (!propType || RNA_property_type(propType) != PROP_ENUM) { 
552                 RNA_warning("uiTemplateAnyID: pointer-type property not found: %s.%s\n", RNA_struct_identifier(ptr->type), proptypename);
553                 return;
554         }
555         
556         /* Start drawing UI Elements using standard defines */
557         row= uiLayoutRow(layout, 1);
558         
559         /* Label - either use the provided text, or will become "ID-Block:" */
560         if (text)
561                 uiItemL(row, text, ICON_NONE);
562         else
563                 uiItemL(row, "ID-Block:", ICON_NONE);
564         
565         /* ID-Type Selector - just have a menu of icons */
566         // FIXME: the icon-only setting doesn't work when we supply a blank name
567         uiItemFullR(row, ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
568         
569         /* ID-Block Selector - just use pointer widget... */
570         uiItemFullR(row, ptr, propID, 0, 0, 0, "", ICON_NONE);
571 }
572
573 /********************* RNA Path Builder Template ********************/
574
575 /* ---------- */
576
577 /* This is creating/editing RNA-Paths 
578  *
579  * - ptr: struct which holds the path property
580  * - propname: property identifier for property that path gets stored to
581  * - root_ptr: struct that path gets built from
582  */
583 void uiTemplatePathBuilder(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *UNUSED(root_ptr), const char *text)
584 {
585         PropertyRNA *propPath;
586         uiLayout *row;
587         
588         /* check that properties are valid */
589         propPath= RNA_struct_find_property(ptr, propname);
590         if (!propPath || RNA_property_type(propPath) != PROP_STRING) {
591                 RNA_warning("uiTemplatePathBuilder: path property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
592                 return;
593         }
594         
595         /* Start drawing UI Elements using standard defines */
596         row= uiLayoutRow(layout, 1);
597         
598         /* Path (existing string) Widget */
599         uiItemR(row, ptr, propname, 0, text, ICON_RNA);
600         
601         // TODO: attach something to this to make allow searching of nested properties to 'build' the path
602 }
603
604 /************************ Modifier Template *************************/
605
606 #define ERROR_LIBDATA_MESSAGE "Can't edit external libdata"
607
608 #include <string.h>
609
610 #include "DNA_object_force.h"
611
612 #include "BKE_depsgraph.h"
613 #include "BKE_modifier.h"
614 #include "BKE_particle.h"
615
616 #include "ED_util.h"
617
618 #include "BLI_math.h"
619 #include "BLI_listbase.h"
620
621 #include "ED_object.h"
622
623 static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v)
624 {
625         Scene *scene = CTX_data_scene(C);
626         Object *ob = ob_v;
627         ModifierData *md= md_v;
628         int i, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 0);
629
630         /* undo button operation */
631         md->mode ^= eModifierMode_OnCage;
632
633         for(i = 0, md=ob->modifiers.first; md; ++i, md=md->next) {
634                 if(md == md_v) {
635                         if(i >= cageIndex)
636                                 md->mode ^= eModifierMode_OnCage;
637                         break;
638                 }
639         }
640
641         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
642         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
643 }
644
645 static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
646 {
647         Object *ob = ob_v;
648         ModifierData *md = md_v;
649         ModifierData *nmd = modifier_new(md->type);
650
651         modifier_copyData(md, nmd);
652         nmd->mode &= ~eModifierMode_Virtual;
653
654         BLI_addhead(&ob->modifiers, nmd);
655         
656         modifier_unique_name(&ob->modifiers, nmd);
657
658         ob->partype = PAROBJECT;
659
660         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
661         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
662
663         ED_undo_push(C, "Modifier convert to real");
664 }
665
666 static int modifier_can_delete(ModifierData *md)
667 {
668         // fluid particle modifier can't be deleted here
669         if(md->type == eModifierType_ParticleSystem)
670                 if(((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID)
671                         return 0;
672
673         return 1;
674 }
675
676 // Check wheter Modifier is a simulation or not, this is used for switching to the physics/particles context tab
677 static int modifier_is_simulation(ModifierData *md)
678 {
679         // Physic Tab
680         if(ELEM6(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke, eModifierType_Softbody, eModifierType_Surface)) {
681                 return 1;
682         }
683         // Particle Tab
684         else if (md->type == eModifierType_ParticleSystem) {
685                 return 2;
686         }
687         else {
688                 return 0;
689         }
690 }
691
692 static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob, ModifierData *md, int index, int cageIndex, int lastCageIndex)
693 {
694         ModifierTypeInfo *mti = modifierType_getInfo(md->type);
695         PointerRNA ptr;
696         uiBut *but;
697         uiBlock *block;
698         uiLayout *box, *column, *row;
699         uiLayout *result= NULL;
700         int isVirtual = (md->mode & eModifierMode_Virtual);
701         char str[128];
702
703         /* create RNA pointer */
704         RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr);
705
706         column= uiLayoutColumn(layout, 1);
707         uiLayoutSetContextPointer(column, "modifier", &ptr);
708
709         /* rounded header ------------------------------------------------------------------- */
710         box= uiLayoutBox(column);
711         
712         if (isVirtual) {
713                 row= uiLayoutRow(box, 0);
714                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_EXPAND);
715                 block= uiLayoutGetBlock(row);
716                 /* VIRTUAL MODIFIER */
717                 // XXX this is not used now, since these cannot be accessed via RNA
718                 sprintf(str, "%s parent deform", md->name);
719                 uiDefBut(block, LABEL, 0, str, 0, 0, 185, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Modifier name"); 
720                 
721                 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");
722                 uiButSetFunc(but, modifiers_convertToReal, ob, md);
723         }
724         else {
725                 /* REAL MODIFIER */
726                 row = uiLayoutRow(box, 0);
727                 block = uiLayoutGetBlock(row);
728                 
729                 uiBlockSetEmboss(block, UI_EMBOSSN);
730                 /* Open/Close .................................  */
731                 uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE);
732                 
733                 /* modifier-type icon */
734                 uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
735                 uiBlockSetEmboss(block, UI_EMBOSS);
736                 
737                 /* modifier name */
738                 uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
739                 
740                 /* mode enabling buttons */
741                 uiBlockBeginAlign(block);
742                 /* Softbody not allowed in this situation, enforce! */
743                 if ( ((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) 
744                         && (md->type!=eModifierType_Surface) ) 
745                 {
746                         uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
747                         uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE);
748                         
749                         if (mti->flags & eModifierTypeFlag_SupportsEditmode)
750                                 uiItemR(row, &ptr, "show_in_editmode", 0, "", ICON_NONE);
751                 }
752                 if ((ob->type==OB_MESH) && modifier_couldBeCage(scene, md) && (index <= lastCageIndex)) 
753                 {
754                         /* -- convert to rna ? */
755                         but = uiDefIconButBitI(block, TOG, eModifierMode_OnCage, 0, ICON_MESH_DATA, 0, 0, UI_UNIT_X-2, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0, "Apply modifier to editing cage during Editmode");
756                         if (index < cageIndex)
757                                 uiButSetFlag(but, UI_BUT_DISABLED);
758                         uiButSetFunc(but, modifiers_setOnCage, ob, md);
759                 }
760
761                 /* tesselation point for curve-typed objects */
762                 if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
763                         /* some modifiers could work with pre-tesselated curves only */
764                         if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
765                                 /* add disabled pre-tesselated button, so users could have
766                                    message for this modifiers */
767                                 but = uiDefIconButBitI(block, TOG, eModifierMode_ApplyOnSpline, 0, ICON_SURFACE_DATA, 0, 0, UI_UNIT_X-2, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0, "This modifier could be applied on splines' points only");
768                                 uiButSetFlag(but, UI_BUT_DISABLED);
769                         } else if (mti->type != eModifierTypeType_Constructive) {
770                                 /* constructive modifiers tesselates curve before applying */
771                                 uiItemR(row, &ptr, "use_apply_on_spline", 0, "", ICON_NONE);
772                         }
773                 }
774
775                 uiBlockEndAlign(block);
776                 
777                 /* Up/Down + Delete ........................... */
778                 uiBlockBeginAlign(block);
779                 uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_modifier_move_up");
780                 uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_modifier_move_down");
781                 uiBlockEndAlign(block);
782                 
783                 uiBlockSetEmboss(block, UI_EMBOSSN);
784                 // When Modifier is a simulation, show button to switch to context rather than the delete button. 
785                 if (modifier_can_delete(md) && !modifier_is_simulation(md))
786                         uiItemO(row, "", ICON_X, "OBJECT_OT_modifier_remove");
787                 if (modifier_is_simulation(md) == 1)
788                         uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PHYSICS");
789                 else if (modifier_is_simulation(md) == 2)
790                         uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PARTICLES");
791                 uiBlockSetEmboss(block, UI_EMBOSS);
792         }
793
794         
795         /* modifier settings (under the header) --------------------------------------------------- */
796         if (!isVirtual && (md->mode & eModifierMode_Expanded)) {
797                 /* apply/convert/copy */
798                 box= uiLayoutBox(column);
799                 row= uiLayoutRow(box, 0);
800                 
801                 if (!ELEM(md->type, eModifierType_Collision, eModifierType_Surface)) {
802                         /* only here obdata, the rest of modifiers is ob level */
803                         uiBlockSetButLock(block, object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
804                         
805                         if (md->type==eModifierType_ParticleSystem) {
806                                 ParticleSystem *psys= ((ParticleSystemModifierData *)md)->psys;
807                                 
808                                 if (!(ob->mode & OB_MODE_PARTICLE_EDIT) && psys->pathcache) {
809                                         if(ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB))
810                                                 uiItemO(row, "Convert", ICON_NONE, "OBJECT_OT_duplicates_make_real");
811                                         else if(psys->part->ren_as == PART_DRAW_PATH)
812                                                 uiItemO(row, "Convert", ICON_NONE, "OBJECT_OT_modifier_convert");
813                                 }
814                         }
815                         else {
816                                 uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
817                                 uiItemEnumO(row, "OBJECT_OT_modifier_apply", "Apply", 0, "apply_as", MODIFIER_APPLY_DATA);
818                                 
819                                 if (modifier_sameTopology(md))
820                                         uiItemEnumO(row, "OBJECT_OT_modifier_apply", "Apply as Shape", 0, "apply_as", MODIFIER_APPLY_SHAPE);
821                         }
822                         
823                         uiBlockClearButLock(block);
824                         uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
825                         
826                         if (!ELEM5(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, eModifierType_Cloth, eModifierType_Smoke))
827                                 uiItemO(row, "Copy", ICON_NONE, "OBJECT_OT_modifier_copy");
828                 }
829                 
830                 /* result is the layout block inside the box, that we return so that modifier settings can be drawn */
831                 result= uiLayoutColumn(box, 0);
832                 block= uiLayoutAbsoluteBlock(box);
833         }
834         
835         /* error messages */
836         if(md->error) {
837                 box = uiLayoutBox(column);
838                 row = uiLayoutRow(box, 0);
839                 uiItemL(row, md->error, ICON_ERROR);
840         }
841         
842         return result;
843 }
844
845 uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
846 {
847         Scene *scene = CTX_data_scene(C);
848         Object *ob;
849         ModifierData *md, *vmd;
850         int i, lastCageIndex, cageIndex;
851
852         /* verify we have valid data */
853         if(!RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
854                 RNA_warning("uiTemplateModifier: Expected modifier on object.\n");
855                 return NULL;
856         }
857
858         ob= ptr->id.data;
859         md= ptr->data;
860
861         if(!ob || !(GS(ob->id.name) == ID_OB)) {
862                 RNA_warning("uiTemplateModifier: Expected modifier on object.\n");
863                 return NULL;
864         }
865         
866         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
867         
868         /* find modifier and draw it */
869         cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
870
871         // XXX virtual modifiers are not accesible for python
872         vmd = modifiers_getVirtualModifierList(ob);
873
874         for(i=0; vmd; i++, vmd=vmd->next) {
875                 if(md == vmd)
876                         return draw_modifier(layout, scene, ob, md, i, cageIndex, lastCageIndex);
877                 else if(vmd->mode & eModifierMode_Virtual)
878                         i--;
879         }
880
881         return NULL;
882 }
883
884 /************************ Constraint Template *************************/
885
886 #include "DNA_constraint_types.h"
887
888 #include "BKE_action.h"
889 #include "BKE_constraint.h"
890
891 #define REDRAWIPO                                       1
892 #define REDRAWNLA                                       2
893 #define REDRAWBUTSOBJECT                        3               
894 #define REDRAWACTION                            4
895 #define B_CONSTRAINT_TEST                       5
896 #define B_CONSTRAINT_CHANGETARGET       6
897 #define REMAKEIPO                                       8
898 #define B_DIFF                                          9
899
900 static void do_constraint_panels(bContext *C, void *ob_pt, int event)
901 {
902         Main *bmain= CTX_data_main(C);
903         Scene *scene= CTX_data_scene(C);
904         Object *ob= (Object *)ob_pt;
905         
906         switch(event) {
907         case B_CONSTRAINT_TEST:
908                 break;  // no handling
909         case B_CONSTRAINT_CHANGETARGET:
910                 if (ob->pose) ob->pose->flag |= POSE_RECALC;    // checks & sorts pose channels
911                 DAG_scene_sort(bmain, scene);
912                 break;
913         default:
914                 break;
915         }
916
917         // note: RNA updates now call this, commenting else it gets called twice.
918         // if there are problems because of this, then rna needs changed update functions.
919         // 
920         // object_test_constraints(ob);
921         // if(ob->pose) update_pose_constraint_flags(ob->pose);
922         
923         if(ob->type==OB_ARMATURE) DAG_id_tag_update(&ob->id, OB_RECALC_DATA|OB_RECALC_OB);
924         else DAG_id_tag_update(&ob->id, OB_RECALC_OB);
925
926         WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
927 }
928
929 static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
930 {
931         ED_object_constraint_set_active(ob_v, con_v);
932 }
933
934 /* draw panel showing settings for a constraint */
935 static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
936 {
937         bPoseChannel *pchan= get_active_posechannel(ob);
938         bConstraintTypeInfo *cti;
939         uiBlock *block;
940         uiLayout *result= NULL, *col, *box, *row;
941         PointerRNA ptr;
942         char typestr[32];
943         short proxy_protected, xco=0, yco=0;
944         // int rb_col; // UNUSED
945
946         /* get constraint typeinfo */
947         cti= constraint_get_typeinfo(con);
948         if (cti == NULL) {
949                 /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
950                 if (con->type == CONSTRAINT_TYPE_NULL)
951                         strcpy(typestr, "Null");
952                 else
953                         strcpy(typestr, "Unknown");
954         }
955         else
956                 strcpy(typestr, cti->name);
957                 
958         /* determine whether constraint is proxy protected or not */
959         if (proxylocked_constraints_owner(ob, pchan))
960                 proxy_protected= (con->flag & CONSTRAINT_PROXY_LOCAL)==0;
961         else
962                 proxy_protected= 0;
963
964         /* unless button has own callback, it adds this callback to button */
965         block= uiLayoutGetBlock(layout);
966         uiBlockSetHandleFunc(block, do_constraint_panels, ob);
967         uiBlockSetFunc(block, constraint_active_func, ob, con);
968
969         RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
970
971         col= uiLayoutColumn(layout, 1);
972         uiLayoutSetContextPointer(col, "constraint", &ptr);
973
974         box= uiLayoutBox(col);
975         row = uiLayoutRow(box, 0);
976         block= uiLayoutGetBlock(box);
977
978         /* Draw constraint header */
979
980         /* open/close */
981         uiBlockSetEmboss(block, UI_EMBOSSN);
982         uiItemR(row, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
983         uiBlockSetEmboss(block, UI_EMBOSS);
984         
985         /* name */
986         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco+10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
987
988         if (con->flag & CONSTRAINT_DISABLE)
989                 uiLayoutSetRedAlert(row, 1);
990         
991         if(proxy_protected == 0) {
992                 uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
993         }
994         else
995                 uiItemL(row, con->name, ICON_NONE);
996         
997         uiLayoutSetRedAlert(row, 0);
998         
999         /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
1000         if (proxy_protected) {
1001                 uiBlockSetEmboss(block, UI_EMBOSSN);
1002                 
1003                 /* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
1004                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_GHOST, xco+244, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
1005                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_LOCKED, xco+262, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
1006                 
1007                 uiBlockSetEmboss(block, UI_EMBOSS);
1008         }
1009         else {
1010                 short prev_proxylock, show_upbut, show_downbut;
1011                 
1012                 /* Up/Down buttons: 
1013                  *      Proxy-constraints are not allowed to occur after local (non-proxy) constraints
1014                  *      as that poses problems when restoring them, so disable the "up" button where
1015                  *      it may cause this situation. 
1016                  *
1017                  *      Up/Down buttons should only be shown (or not greyed - todo) if they serve some purpose. 
1018                  */
1019                 if (proxylocked_constraints_owner(ob, pchan)) {
1020                         if (con->prev) {
1021                                 prev_proxylock= (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
1022                         }
1023                         else
1024                                 prev_proxylock= 0;
1025                 }
1026                 else
1027                         prev_proxylock= 0;
1028                         
1029                 show_upbut= ((prev_proxylock == 0) && (con->prev));
1030                 show_downbut= (con->next) ? 1 : 0;
1031                 
1032                 /* enabled */
1033                 uiBlockSetEmboss(block, UI_EMBOSSN);
1034                 uiItemR(row, &ptr, "mute", 0, "", (con->flag & CONSTRAINT_OFF) ? ICON_MUTE_IPO_ON : ICON_MUTE_IPO_OFF);
1035                 uiBlockSetEmboss(block, UI_EMBOSS);
1036                 
1037                 uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
1038                 
1039                 /* up/down */
1040                 if (show_upbut || show_downbut) {
1041                         uiBlockBeginAlign(block);
1042                         if (show_upbut)
1043                                 uiItemO(row, "", ICON_TRIA_UP, "CONSTRAINT_OT_move_up");
1044                                 
1045                         if (show_downbut)
1046                                 uiItemO(row, "", ICON_TRIA_DOWN, "CONSTRAINT_OT_move_down");
1047                         uiBlockEndAlign(block);
1048                 }
1049                 
1050                 /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
1051                 uiBlockSetEmboss(block, UI_EMBOSSN);
1052                 uiItemO(row, "", ICON_X, "CONSTRAINT_OT_delete");
1053                 uiBlockSetEmboss(block, UI_EMBOSS);
1054         }
1055
1056         /* Set but-locks for protected settings (magic numbers are used here!) */
1057         if (proxy_protected)
1058                 uiBlockSetButLock(block, 1, "Cannot edit Proxy-Protected Constraint");
1059
1060         /* Draw constraint data */
1061         if ((con->flag & CONSTRAINT_EXPAND) == 0) {
1062                 (yco) -= 21;
1063         }
1064         else {
1065                 box= uiLayoutBox(col);
1066                 block= uiLayoutAbsoluteBlock(box);
1067                 result= box;
1068         }
1069
1070         /* clear any locks set up for proxies/lib-linking */
1071         uiBlockClearButLock(block);
1072
1073         return result;
1074 }
1075
1076 uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
1077 {
1078         Object *ob;
1079         bConstraint *con;
1080
1081         /* verify we have valid data */
1082         if(!RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
1083                 RNA_warning("uiTemplateConstraint: Expected constraint on object.\n");
1084                 return NULL;
1085         }
1086
1087         ob= ptr->id.data;
1088         con= ptr->data;
1089
1090         if(!ob || !(GS(ob->id.name) == ID_OB)) {
1091                 RNA_warning("uiTemplateConstraint: Expected constraint on object.\n");
1092                 return NULL;
1093         }
1094         
1095         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
1096
1097         /* hrms, the temporal constraint should not draw! */
1098         if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
1099                 bKinematicConstraint *data= con->data;
1100                 if(data->flag & CONSTRAINT_IK_TEMP)
1101                         return NULL;
1102         }
1103
1104         return draw_constraint(layout, ob, con);
1105 }
1106
1107
1108 /************************* Preview Template ***************************/
1109
1110 #include "DNA_lamp_types.h"
1111 #include "DNA_material_types.h"
1112 #include "DNA_world_types.h"
1113
1114 #define B_MATPRV 1
1115
1116 static void do_preview_buttons(bContext *C, void *arg, int event)
1117 {
1118         switch(event) {
1119                 case B_MATPRV:
1120                         WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, arg);
1121                         break;
1122         }
1123 }
1124
1125 void uiTemplatePreview(uiLayout *layout, ID *id, int show_buttons, ID *parent, MTex *slot)
1126 {
1127         uiLayout *row, *col;
1128         uiBlock *block;
1129         Material *ma= NULL;
1130         Tex *tex = (Tex*)id;
1131         ID *pid, *pparent;
1132         short *pr_texture= NULL;
1133         PointerRNA material_ptr;
1134         PointerRNA texture_ptr;
1135
1136         if(id && !ELEM4(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA)) {
1137                 RNA_warning("uiTemplatePreview: Expected ID of type material, texture, lamp or world.\n");
1138                 return;
1139         }
1140
1141         /* decide what to render */
1142         pid= id;
1143         pparent= NULL;
1144
1145         if(id && (GS(id->name) == ID_TE)) {
1146                 if(parent && (GS(parent->name) == ID_MA))
1147                         pr_texture= &((Material*)parent)->pr_texture;
1148                 else if(parent && (GS(parent->name) == ID_WO))
1149                         pr_texture= &((World*)parent)->pr_texture;
1150                 else if(parent && (GS(parent->name) == ID_LA))
1151                         pr_texture= &((Lamp*)parent)->pr_texture;
1152
1153                 if(pr_texture) {
1154                         if(*pr_texture == TEX_PR_OTHER)
1155                                 pid= parent;
1156                         else if(*pr_texture == TEX_PR_BOTH)
1157                                 pparent= parent;
1158                 }
1159         }
1160
1161         /* layout */
1162         block= uiLayoutGetBlock(layout);
1163         row= uiLayoutRow(layout, 0);
1164         col= uiLayoutColumn(row, 0);
1165         uiLayoutSetKeepAspect(col, 1);
1166         
1167         /* add preview */
1168         uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, pid, 0.0, 0.0, 0, 0, "");
1169         uiBlockSetDrawExtraFunc(block, ED_preview_draw, pparent, slot);
1170         uiBlockSetHandleFunc(block, do_preview_buttons, NULL);
1171         
1172         /* add buttons */
1173         if (pid && show_buttons) {
1174                 if(GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) {
1175                         if(GS(pid->name) == ID_MA) ma= (Material*)pid;
1176                         else ma= (Material*)pparent;
1177                         
1178                         /* Create RNA Pointer */
1179                         RNA_pointer_create(id, &RNA_Material, ma, &material_ptr);
1180
1181                         col = uiLayoutColumn(row, 1);
1182                         uiLayoutSetScaleX(col, 1.5);
1183                         uiItemR(col, &material_ptr, "preview_render_type", UI_ITEM_R_EXPAND, "", ICON_NONE);
1184                 }
1185
1186                 if(pr_texture) {
1187                         /* Create RNA Pointer */
1188                         RNA_pointer_create(id, &RNA_Texture, tex, &texture_ptr);
1189                         
1190                         uiLayoutRow(layout, 1);
1191                         uiDefButS(block, ROW, B_MATPRV, "Texture",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_TEXTURE, 0, 0, "");
1192                         if(GS(parent->name) == ID_MA)
1193                                 uiDefButS(block, ROW, B_MATPRV, "Material",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1194                         else if(GS(parent->name) == ID_LA)
1195                                 uiDefButS(block, ROW, B_MATPRV, "Lamp",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1196                         else if(GS(parent->name) == ID_WO)
1197                                 uiDefButS(block, ROW, B_MATPRV, "World",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1198                         uiDefButS(block, ROW, B_MATPRV, "Both",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_BOTH, 0, 0, "");
1199                         
1200                         /* Alpha buton for texture preview */
1201                         if(*pr_texture!=TEX_PR_OTHER) {
1202                                 row = uiLayoutRow(layout, 0);
1203                                 uiItemR(row, &texture_ptr, "use_preview_alpha", 0, NULL, ICON_NONE);
1204                         }
1205                 }
1206         }
1207 }
1208
1209 /********************** ColorRamp Template **************************/
1210
1211
1212 typedef struct RNAUpdateCb {
1213         PointerRNA ptr;
1214         PropertyRNA *prop;
1215 } RNAUpdateCb;
1216
1217 static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
1218 {
1219         RNAUpdateCb *cb= (RNAUpdateCb*)arg_cb;
1220
1221         /* we call update here on the pointer property, this way the
1222            owner of the curve mapping can still define it's own update
1223            and notifier, even if the CurveMapping struct is shared. */
1224         RNA_property_update(C, &cb->ptr, cb->prop);
1225 }
1226
1227 #define B_BANDCOL 1
1228
1229 static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
1230 {
1231         ColorBand *coba= coba_v;
1232         float pos= 0.5f;
1233
1234         if(coba->tot > 1) {
1235                 if(coba->cur > 0)       pos= (coba->data[coba->cur-1].pos + coba->data[coba->cur].pos) * 0.5f;
1236                 else                            pos= (coba->data[coba->cur+1].pos + coba->data[coba->cur].pos) * 0.5f;
1237         }
1238
1239         if(colorband_element_add(coba, pos)) {
1240                 rna_update_cb(C, cb_v, NULL);
1241                 ED_undo_push(C, "Add colorband");       
1242         }
1243 }
1244
1245 static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v)
1246 {
1247         ColorBand *coba= coba_v;
1248
1249         if(colorband_element_remove(coba, coba->cur)) {
1250                 ED_undo_push(C, "Delete colorband");
1251                 rna_update_cb(C, cb_v, NULL);
1252         }
1253 }
1254
1255 static void colorband_flip_cb(bContext *C, void *cb_v, void *coba_v)
1256 {
1257         CBData data_tmp[MAXCOLORBAND];
1258
1259         ColorBand *coba= coba_v;
1260         int a;
1261
1262         for(a=0; a<coba->tot; a++) {
1263                 data_tmp[a]= coba->data[coba->tot - (a + 1)];
1264         }
1265         for(a=0; a<coba->tot; a++) {
1266                 data_tmp[a].pos = 1.0f - data_tmp[a].pos;
1267                 coba->data[a]= data_tmp[a];
1268         }
1269
1270         /* may as well flip the cur*/
1271         coba->cur= coba->tot - (coba->cur + 1);
1272
1273         ED_undo_push(C, "Flip colorband");
1274
1275         rna_update_cb(C, cb_v, NULL);
1276 }
1277
1278
1279 /* offset aligns from bottom, standard width 300, height 115 */
1280 static void colorband_buttons_large(uiLayout *layout, uiBlock *block, ColorBand *coba, int xoffs, int yoffs, RNAUpdateCb *cb)
1281 {
1282         uiBut *bt;
1283         uiLayout *row;
1284         const int line1_y= yoffs + 65 + UI_UNIT_Y + 2; /* 2 for some space between the buttons */
1285         const int line2_y= yoffs + 65;
1286
1287         if(coba==NULL) return;
1288
1289         bt= uiDefBut(block, BUT, 0,     "Add",                  0+xoffs,line1_y,40,UI_UNIT_Y, NULL, 0, 0, 0, 0, "Add a new color stop to the colorband");
1290         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1291
1292         bt= uiDefBut(block, BUT, 0,     "Delete",               45+xoffs,line1_y,45,UI_UNIT_Y, NULL, 0, 0, 0, 0, "Delete the active position");
1293         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1294
1295
1296         /* XXX, todo for later - convert to operator - campbell */
1297         bt= uiDefBut(block, BUT, 0,     "F",            95+xoffs,line1_y,20,UI_UNIT_Y, NULL, 0, 0, 0, 0, "Flip colorband");
1298         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1299
1300         uiDefButS(block, NUM, 0,                "",                             120+xoffs,line1_y,80, UI_UNIT_Y, &coba->cur, 0.0, (float)(MAX2(0, coba->tot-1)), 0, 0, "Choose active color stop");
1301
1302         bt= uiDefButS(block, MENU, 0,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
1303                         210+xoffs, line1_y, 90, UI_UNIT_Y,              &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
1304         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1305         uiBlockEndAlign(block);
1306
1307         bt= uiDefBut(block, BUT_COLORBAND, 0, "",       xoffs,line2_y,300,UI_UNIT_Y, coba, 0, 0, 0, 0, "");
1308         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1309
1310
1311
1312         if(coba->tot) {
1313                 CBData *cbd= coba->data + coba->cur;
1314
1315                 /* better to use rna so we can animate them */
1316                 PointerRNA ptr;
1317                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1318                 row= uiLayoutRow(layout, 0);
1319                 uiItemR(row, &ptr, "position", 0, "Pos", ICON_NONE);
1320                 uiItemR(row, &ptr, "color", 0, "", ICON_NONE);
1321         }
1322
1323 }
1324
1325 static void colorband_buttons_small(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb)
1326 {
1327         uiBut *bt;
1328         float unit= (butr->xmax-butr->xmin)/14.0f;
1329         float xs= butr->xmin;
1330
1331         uiBlockBeginAlign(block);
1332         bt= uiDefBut(block, BUT, 0,     "Add",                  xs,butr->ymin+UI_UNIT_Y,2.0f*unit,UI_UNIT_Y,    NULL, 0, 0, 0, 0, "Add a new color stop to the colorband");
1333         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1334         bt= uiDefBut(block, BUT, 0,     "Delete",               xs+2.0f*unit,butr->ymin+UI_UNIT_Y,1.5f*unit,UI_UNIT_Y,  NULL, 0, 0, 0, 0, "Delete the active position");
1335         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1336         bt= uiDefBut(block, BUT, 0,     "F",            xs+3.5f*unit,butr->ymin+UI_UNIT_Y,0.5f*unit,UI_UNIT_Y,  NULL, 0, 0, 0, 0, "Flip the color ramp");
1337         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1338         uiBlockEndAlign(block);
1339
1340         if(coba->tot) {
1341                 CBData *cbd= coba->data + coba->cur;
1342                 PointerRNA ptr;
1343                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1344                 uiItemR(layout, &ptr, "color", 0, "", ICON_NONE);
1345         }
1346
1347         bt= uiDefButS(block, MENU, 0,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
1348                         xs+10.0f*unit, butr->ymin+UI_UNIT_Y, unit*4, UI_UNIT_Y,         &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
1349         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1350
1351         bt= uiDefBut(block, BUT_COLORBAND, 0, "",               xs,butr->ymin,butr->xmax-butr->xmin,UI_UNIT_Y, coba, 0, 0, 0, 0, "");
1352         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1353
1354         uiBlockEndAlign(block);
1355 }
1356
1357 static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, int small, RNAUpdateCb *cb)
1358 {
1359         if(small)
1360                 colorband_buttons_small(layout, block, coba, butr, cb);
1361         else
1362                 colorband_buttons_large(layout, block, coba, 0, 0, cb);
1363 }
1364
1365 void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, int expand)
1366 {
1367         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1368         PointerRNA cptr;
1369         RNAUpdateCb *cb;
1370         uiBlock *block;
1371         rctf rect;
1372
1373         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1374                 return;
1375
1376         cptr= RNA_property_pointer_get(ptr, prop);
1377         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp))
1378                 return;
1379
1380         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1381         cb->ptr= *ptr;
1382         cb->prop= prop;
1383
1384         rect.xmin= 0; rect.xmax= 200;
1385         rect.ymin= 0; rect.ymax= 190;
1386
1387         block= uiLayoutAbsoluteBlock(layout);
1388         colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1389
1390         MEM_freeN(cb);
1391 }
1392
1393 /********************* Histogram Template ************************/
1394
1395 void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
1396 {
1397         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1398         PointerRNA cptr;
1399         RNAUpdateCb *cb;
1400         uiBlock *block;
1401         uiBut *bt;
1402         Histogram *hist;
1403         rctf rect;
1404         
1405         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1406                 return;
1407         
1408         cptr= RNA_property_pointer_get(ptr, prop);
1409         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Histogram))
1410                 return;
1411         
1412         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1413         cb->ptr= *ptr;
1414         cb->prop= prop;
1415         
1416         rect.xmin= 0; rect.xmax= 200;
1417         rect.ymin= 0; rect.ymax= 190;
1418         
1419         block= uiLayoutAbsoluteBlock(layout);
1420         //colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1421
1422         hist = (Histogram *)cptr.data;
1423
1424         hist->height= (hist->height<=UI_UNIT_Y)?UI_UNIT_Y:hist->height;
1425
1426         bt= uiDefBut(block, HISTOGRAM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, hist->height, hist, 0, 0, 0, 0, "");
1427         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1428
1429         MEM_freeN(cb);
1430 }
1431
1432 /********************* Waveform Template ************************/
1433
1434 void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
1435 {
1436         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1437         PointerRNA cptr;
1438         RNAUpdateCb *cb;
1439         uiBlock *block;
1440         uiBut *bt;
1441         Scopes *scopes;
1442         rctf rect;
1443         
1444         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1445                 return;
1446         
1447         cptr= RNA_property_pointer_get(ptr, prop);
1448         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1449                 return;
1450         scopes = (Scopes *)cptr.data;
1451         
1452         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1453         cb->ptr= *ptr;
1454         cb->prop= prop;
1455         
1456         rect.xmin= 0; rect.xmax= 200;
1457         rect.ymin= 0; rect.ymax= 190;
1458         
1459         block= uiLayoutAbsoluteBlock(layout);
1460         
1461         scopes->wavefrm_height= (scopes->wavefrm_height<=UI_UNIT_Y)?UI_UNIT_Y:scopes->wavefrm_height;
1462
1463         bt= uiDefBut(block, WAVEFORM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->wavefrm_height, scopes, 0, 0, 0, 0, "");
1464         (void)bt; // UNUSED
1465         
1466         MEM_freeN(cb);
1467 }
1468
1469 /********************* Vectorscope Template ************************/
1470
1471 void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
1472 {
1473         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1474         PointerRNA cptr;
1475         RNAUpdateCb *cb;
1476         uiBlock *block;
1477         uiBut *bt;
1478         Scopes *scopes;
1479         rctf rect;
1480         
1481         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1482                 return;
1483         
1484         cptr= RNA_property_pointer_get(ptr, prop);
1485         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1486                 return;
1487         scopes = (Scopes *)cptr.data;
1488
1489         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1490         cb->ptr= *ptr;
1491         cb->prop= prop;
1492         
1493         rect.xmin= 0; rect.xmax= 200;
1494         rect.ymin= 0; rect.ymax= 190;
1495         
1496         block= uiLayoutAbsoluteBlock(layout);
1497
1498         scopes->vecscope_height= (scopes->vecscope_height<=UI_UNIT_Y)?UI_UNIT_Y:scopes->vecscope_height;
1499         
1500         bt= uiDefBut(block, VECTORSCOPE, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->vecscope_height, scopes, 0, 0, 0, 0, "");
1501         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1502         
1503         MEM_freeN(cb);
1504 }
1505
1506 /********************* CurveMapping Template ************************/
1507
1508
1509 static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *UNUSED(arg))
1510 {
1511         CurveMapping *cumap = cumap_v;
1512         float d;
1513
1514         /* we allow 20 times zoom */
1515         if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1516                 d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin);
1517                 cumap->curr.xmin+= d;
1518                 cumap->curr.xmax-= d;
1519                 d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin);
1520                 cumap->curr.ymin+= d;
1521                 cumap->curr.ymax-= d;
1522         }
1523
1524         ED_region_tag_redraw(CTX_wm_region(C));
1525 }
1526
1527 static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *UNUSED(unused))
1528 {
1529         CurveMapping *cumap = cumap_v;
1530         float d, d1;
1531
1532         /* we allow 20 times zoom, but dont view outside clip */
1533         if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1534                 d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin);
1535
1536                 if(cumap->flag & CUMA_DO_CLIP) 
1537                         if(cumap->curr.xmin-d < cumap->clipr.xmin)
1538                                 d1= cumap->curr.xmin - cumap->clipr.xmin;
1539                 cumap->curr.xmin-= d1;
1540
1541                 d1= d;
1542                 if(cumap->flag & CUMA_DO_CLIP) 
1543                         if(cumap->curr.xmax+d > cumap->clipr.xmax)
1544                                 d1= -cumap->curr.xmax + cumap->clipr.xmax;
1545                 cumap->curr.xmax+= d1;
1546
1547                 d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin);
1548
1549                 if(cumap->flag & CUMA_DO_CLIP) 
1550                         if(cumap->curr.ymin-d < cumap->clipr.ymin)
1551                                 d1= cumap->curr.ymin - cumap->clipr.ymin;
1552                 cumap->curr.ymin-= d1;
1553
1554                 d1= d;
1555                 if(cumap->flag & CUMA_DO_CLIP) 
1556                         if(cumap->curr.ymax+d > cumap->clipr.ymax)
1557                                 d1= -cumap->curr.ymax + cumap->clipr.ymax;
1558                 cumap->curr.ymax+= d1;
1559         }
1560
1561         ED_region_tag_redraw(CTX_wm_region(C));
1562 }
1563
1564 static void curvemap_buttons_setclip(bContext *UNUSED(C), void *cumap_v, void *UNUSED(arg))
1565 {
1566         CurveMapping *cumap = cumap_v;
1567
1568         curvemapping_changed(cumap, 0);
1569 }       
1570
1571 static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v)
1572 {
1573         CurveMapping *cumap = cumap_v;
1574
1575         curvemap_remove(cumap->cm+cumap->cur, SELECT);
1576         curvemapping_changed(cumap, 0);
1577
1578         rna_update_cb(C, cb_v, NULL);
1579 }
1580
1581 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
1582 static uiBlock *curvemap_clipping_func(bContext *C, struct ARegion *ar, void *cumap_v)
1583 {
1584         CurveMapping *cumap = cumap_v;
1585         uiBlock *block;
1586         uiBut *bt;
1587         float width= 8*UI_UNIT_X;
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, width+8, 6*UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
1593
1594         bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",    
1595                         0,5*UI_UNIT_Y,width,UI_UNIT_Y, &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,4*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 0, "");
1600         uiDefButF(block, NUM, 0, "Min Y ",       0,3*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 0, "");
1601         uiDefButF(block, NUM, 0, "Max X ",       0,2*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 0, "");
1602         uiDefButF(block, NUM, 0, "Max Y ",       0,UI_UNIT_Y,width,UI_UNIT_Y, &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=10*UI_UNIT_X;
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-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 1, "");
1652         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 2, "");
1653         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 3, "");
1654         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Horizontal",              0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 4, "");
1655         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Extrapolated",    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 5, "");
1656         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, 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=10*UI_UNIT_X;
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-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 1, "");
1674         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 2, "");
1675         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 3, "");
1676         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, 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, dx, &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, dx, &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, dx, &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, dx, &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, dx, &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, dx, &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, dx, &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, dx, &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, dx, &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, dx, &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, dx, 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, dx, 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, dx, "Tools");
1801         else
1802                 bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, "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, dx, "Clipping Options");
1808         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1809
1810         bt= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, dx, 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, UI_UNIT_X/2, UI_UNIT_Y/2);
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                 Key *key= (Key*)itemptr->data;
2106
2107                 split= uiLayoutSplit(sub, 0.75f, 0);
2108
2109                 uiItemL(split, name, icon);
2110
2111                 uiBlockSetEmboss(block, UI_EMBOSSN);
2112                 row= uiLayoutRow(split, 1);
2113                 if(i == 0 || (key->type != KEY_RELATIVE)) uiItemL(row, "", ICON_NONE);
2114                 else uiItemR(row, itemptr, "value", 0, "", ICON_NONE);
2115
2116                 if(ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH))
2117                         uiLayoutSetActive(row, 0);
2118                 //uiItemR(row, itemptr, "mute", 0, "", ICON_MUTE_IPO_OFF);
2119                 uiBlockSetEmboss(block, UI_EMBOSS);
2120         }
2121         else
2122                 uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
2123
2124         /* free name */
2125         if(namebuf)
2126                 MEM_freeN(namebuf);
2127 }
2128
2129 void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *activeptr, const char *activepropname, int rows, int maxrows, int listtype)
2130 {
2131         //Scene *scene= CTX_data_scene(C);
2132         PropertyRNA *prop= NULL, *activeprop;
2133         PropertyType type, activetype;
2134         StructRNA *ptype;
2135         uiLayout *box, *row, *col;
2136         uiBlock *block;
2137         uiBut *but;
2138         Panel *pa;
2139         char *name, str[32];
2140         int rnaicon=0, icon=0, i= 0, activei= 0, len= 0, items, found, min, max;
2141
2142         /* validate arguments */
2143         block= uiLayoutGetBlock(layout);
2144         pa= block->panel;
2145
2146         if(!pa) {
2147                 RNA_warning("uiTemplateList: only works inside a panel.\n");
2148                 return;
2149         }
2150
2151         if(!activeptr->data)
2152                 return;
2153         
2154         if(ptr->data) {
2155                 prop= RNA_struct_find_property(ptr, propname);
2156                 if(!prop) {
2157                         RNA_warning("uiTemplateList: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
2158                         return;
2159                 }
2160         }
2161
2162         activeprop= RNA_struct_find_property(activeptr, activepropname);
2163         if(!activeprop) {
2164                 RNA_warning("uiTemplateList: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), activepropname);
2165                 return;
2166         }
2167
2168         if(prop) {
2169                 type= RNA_property_type(prop);
2170                 if(type != PROP_COLLECTION) {
2171                         RNA_warning("uiTemplateList: Expected collection property.\n");
2172                         return;
2173                 }
2174         }
2175
2176         activetype= RNA_property_type(activeprop);
2177         if(activetype != PROP_INT) {
2178                 RNA_warning("uiTemplateList: Expected integer property.\n");
2179                 return;
2180         }
2181
2182         /* get icon */
2183         if(ptr->data && prop) {
2184                 ptype= RNA_property_pointer_type(ptr, prop);
2185                 rnaicon= RNA_struct_ui_icon(ptype);
2186         }
2187
2188         /* get active data */
2189         activei= RNA_property_int_get(activeptr, activeprop);
2190
2191         if(listtype == 'i') {
2192                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2193                 col= uiLayoutColumn(box, 1);
2194                 row= uiLayoutRow(col, 0);
2195
2196                 if(ptr->data && prop) {
2197                         /* create list items */
2198                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2199                                 /* create button */
2200                                 if(!(i % 9))
2201                                         row= uiLayoutRow(col, 0);
2202
2203                                 icon= list_item_icon_get(C, &itemptr, rnaicon, 1);
2204                                 but= uiDefIconButR(block, LISTROW, 0, icon, 0,0,UI_UNIT_X*10,UI_UNIT_Y, activeptr, activepropname, 0, 0, i, 0, 0, "");
2205                                 uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2206                                 
2207
2208                                 i++;
2209                         }
2210                         RNA_PROP_END;
2211                 }
2212         }
2213         else if(listtype == 'c') {
2214                 /* compact layout */
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 #define B_STOPCLIP              5
2362
2363 static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
2364 {
2365         switch(event) {
2366                 case B_STOPRENDER:
2367                         G.afbreek= 1;
2368                         break;
2369                 case B_STOPCAST:
2370                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C), NULL);
2371                         break;
2372                 case B_STOPANIM:
2373                         WM_operator_name_call(C, "SCREEN_OT_animation_play", WM_OP_INVOKE_SCREEN, NULL);
2374                         break;
2375                 case B_STOPCOMPO:
2376                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2377                         break;
2378                 case B_STOPCLIP:
2379                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2380                         break;
2381         }
2382 }
2383
2384 void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
2385 {
2386         bScreen *screen= CTX_wm_screen(C);
2387         wmWindowManager *wm= CTX_wm_manager(C);
2388         ScrArea *sa= CTX_wm_area(C);
2389         uiBlock *block;
2390         void *owner= NULL;
2391         int handle_event;
2392         
2393         block= uiLayoutGetBlock(layout);
2394         uiBlockSetCurLayout(block, layout);
2395
2396         uiBlockSetHandleFunc(block, do_running_jobs, NULL);
2397
2398         if(sa->spacetype==SPACE_NODE) {
2399                 if(WM_jobs_test(wm, sa))
2400                    owner = sa;
2401                 handle_event= B_STOPCOMPO;
2402         } 
2403         if(sa->spacetype==SPACE_CLIP) {
2404                 if(WM_jobs_test(wm, sa))
2405                    owner = sa;
2406                 handle_event= B_STOPCLIP;
2407         }
2408         else {
2409                 Scene *scene;
2410                 /* another scene can be rendering too, for example via compositor */
2411                 for(scene= CTX_data_main(C)->scene.first; scene; scene= scene->id.next)
2412                         if(WM_jobs_test(wm, scene))
2413                                 break;
2414                 owner = scene;
2415                 handle_event= B_STOPRENDER;
2416         }
2417
2418         if(owner) {
2419                 uiLayout *ui_abs;
2420                 
2421                 ui_abs= uiLayoutAbsolute(layout, 0);
2422                 (void)ui_abs; // UNUSED
2423                 
2424                 uiDefIconBut(block, BUT, handle_event, ICON_PANEL_CLOSE, 
2425                                 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");
2426                 uiDefBut(block, PROGRESSBAR, 0, WM_jobs_name(wm, owner), 
2427                                 UI_UNIT_X, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, "Progress");
2428                 
2429                 uiLayoutRow(layout, 0);
2430         }
2431         if(WM_jobs_test(wm, screen))
2432                 uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, "Capture", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop screencast");
2433         if(screen->animtimer)
2434                 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");
2435 }
2436
2437 /************************* Reports for Last Operator Template **************************/
2438
2439 void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
2440 {
2441         ReportList *reports = CTX_wm_reports(C);
2442         Report *report= BKE_reports_last_displayable(reports);
2443         ReportTimerInfo *rti;
2444         
2445         uiLayout *ui_abs;
2446         uiBlock *block;
2447         uiBut *but;
2448         uiStyle *style= U.uistyles.first;
2449         int width;
2450         int icon=0;
2451         
2452         /* if the report display has timed out, don't show */
2453         if (!reports->reporttimer) return;
2454         
2455         rti= (ReportTimerInfo *)reports->reporttimer->customdata;
2456         
2457         if (!rti || rti->widthfac==0.0f || !report) return;
2458         
2459         ui_abs= uiLayoutAbsolute(layout, 0);
2460         block= uiLayoutGetBlock(ui_abs);
2461         
2462         width = BLF_width(style->widget.uifont_id, report->message);
2463         width = MIN2(rti->widthfac*width, width);
2464         width = MAX2(width, 10);
2465         
2466         /* make a box around the report to make it stand out */
2467         uiBlockBeginAlign(block);
2468         but= uiDefBut(block, ROUNDBOX, 0, "", 0, 0, UI_UNIT_X+10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2469         /* set the report's bg color in but->col - ROUNDBOX feature */
2470         but->col[0]= FTOCHAR(rti->col[0]);
2471         but->col[1]= FTOCHAR(rti->col[1]);
2472         but->col[2]= FTOCHAR(rti->col[2]);
2473         but->col[3]= 255; 
2474
2475         but= uiDefBut(block, ROUNDBOX, 0, "", UI_UNIT_X+10, 0, UI_UNIT_X+width, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2476         but->col[0]= but->col[1]= but->col[2]= FTOCHAR(rti->greyscale);
2477         but->col[3]= 255;
2478
2479         uiBlockEndAlign(block);
2480         
2481         
2482         /* icon and report message on top */
2483         if(report->type & RPT_ERROR_ALL)
2484                 icon = ICON_ERROR;
2485         else if(report->type & RPT_WARNING_ALL)
2486                 icon = ICON_ERROR;
2487         else if(report->type & RPT_INFO_ALL)
2488                 icon = ICON_INFO;
2489         
2490         /* XXX: temporary operator to dump all reports to a text block, but only if more than 1 report 
2491          * to be shown instead of icon when appropriate...
2492          */
2493         uiBlockSetEmboss(block, UI_EMBOSSN);
2494
2495         if (reports->list.first != reports->list.last)
2496                 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'");
2497         else
2498                 uiDefIconBut(block, LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2499
2500         uiBlockSetEmboss(block, UI_EMBOSS);
2501         
2502         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, "");
2503 }
2504