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