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