Merge with trunk r38663
[blender.git] / source / blender / editors / interface / interface_templates.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Contributor(s): Blender Foundation 2009.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/editors/interface/interface_templates.c
26  *  \ingroup edinterface
27  */
28
29
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_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(ELEM7(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke, eModifierType_Softbody, eModifierType_Surface, eModifierType_DynamicPaint)) {
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         /* open/close */
983         uiBlockSetEmboss(block, UI_EMBOSSN);
984         uiItemR(row, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
985         uiBlockSetEmboss(block, UI_EMBOSS);
986         
987         /* name */
988         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco+10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
989
990         if (con->flag & CONSTRAINT_DISABLE)
991                 uiLayoutSetRedAlert(row, 1);
992         
993         if(proxy_protected == 0) {
994                 uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
995         }
996         else
997                 uiItemL(row, con->name, ICON_NONE);
998         
999         uiLayoutSetRedAlert(row, 0);
1000         
1001         /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
1002         if (proxy_protected) {
1003                 uiBlockSetEmboss(block, UI_EMBOSSN);
1004                 
1005                 /* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
1006                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_GHOST, xco+244, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
1007                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_LOCKED, xco+262, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
1008                 
1009                 uiBlockSetEmboss(block, UI_EMBOSS);
1010         }
1011         else {
1012                 short prev_proxylock, show_upbut, show_downbut;
1013                 
1014                 /* Up/Down buttons: 
1015                  *      Proxy-constraints are not allowed to occur after local (non-proxy) constraints
1016                  *      as that poses problems when restoring them, so disable the "up" button where
1017                  *      it may cause this situation. 
1018                  *
1019                  *      Up/Down buttons should only be shown (or not greyed - todo) if they serve some purpose. 
1020                  */
1021                 if (proxylocked_constraints_owner(ob, pchan)) {
1022                         if (con->prev) {
1023                                 prev_proxylock= (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
1024                         }
1025                         else
1026                                 prev_proxylock= 0;
1027                 }
1028                 else
1029                         prev_proxylock= 0;
1030                         
1031                 show_upbut= ((prev_proxylock == 0) && (con->prev));
1032                 show_downbut= (con->next) ? 1 : 0;
1033                 
1034                 /* enabled */
1035                 uiBlockSetEmboss(block, UI_EMBOSSN);
1036                 uiItemR(row, &ptr, "mute", 0, "", (con->flag & CONSTRAINT_OFF) ? ICON_MUTE_IPO_ON : ICON_MUTE_IPO_OFF);
1037                 uiBlockSetEmboss(block, UI_EMBOSS);
1038                 
1039                 uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
1040                 
1041                 /* up/down */
1042                 if (show_upbut || show_downbut) {
1043                         uiBlockBeginAlign(block);
1044                         if (show_upbut)
1045                                 uiItemO(row, "", ICON_TRIA_UP, "CONSTRAINT_OT_move_up");
1046                                 
1047                         if (show_downbut)
1048                                 uiItemO(row, "", ICON_TRIA_DOWN, "CONSTRAINT_OT_move_down");
1049                         uiBlockEndAlign(block);
1050                 }
1051                 
1052                 /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
1053                 uiBlockSetEmboss(block, UI_EMBOSSN);
1054                 uiItemO(row, "", ICON_X, "CONSTRAINT_OT_delete");
1055                 uiBlockSetEmboss(block, UI_EMBOSS);
1056         }
1057
1058         /* Set but-locks for protected settings (magic numbers are used here!) */
1059         if (proxy_protected)
1060                 uiBlockSetButLock(block, 1, "Cannot edit Proxy-Protected Constraint");
1061
1062         /* Draw constraint data */
1063         if ((con->flag & CONSTRAINT_EXPAND) == 0) {
1064                 (yco) -= 21;
1065         }
1066         else {
1067                 box= uiLayoutBox(col);
1068                 block= uiLayoutAbsoluteBlock(box);
1069                 result= box;
1070         }
1071
1072         /* clear any locks set up for proxies/lib-linking */
1073         uiBlockClearButLock(block);
1074
1075         return result;
1076 }
1077
1078 uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
1079 {
1080         Object *ob;
1081         bConstraint *con;
1082
1083         /* verify we have valid data */
1084         if(!RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
1085                 RNA_warning("uiTemplateConstraint: Expected constraint on object.\n");
1086                 return NULL;
1087         }
1088
1089         ob= ptr->id.data;
1090         con= ptr->data;
1091
1092         if(!ob || !(GS(ob->id.name) == ID_OB)) {
1093                 RNA_warning("uiTemplateConstraint: Expected constraint on object.\n");
1094                 return NULL;
1095         }
1096         
1097         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
1098
1099         /* hrms, the temporal constraint should not draw! */
1100         if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
1101                 bKinematicConstraint *data= con->data;
1102                 if(data->flag & CONSTRAINT_IK_TEMP)
1103                         return NULL;
1104         }
1105
1106         return draw_constraint(layout, ob, con);
1107 }
1108
1109
1110 /************************* Preview Template ***************************/
1111
1112 #include "DNA_lamp_types.h"
1113 #include "DNA_material_types.h"
1114 #include "DNA_world_types.h"
1115
1116 #define B_MATPRV 1
1117
1118 static void do_preview_buttons(bContext *C, void *arg, int event)
1119 {
1120         switch(event) {
1121                 case B_MATPRV:
1122                         WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, arg);
1123                         break;
1124         }
1125 }
1126
1127 void uiTemplatePreview(uiLayout *layout, ID *id, int show_buttons, ID *parent, MTex *slot)
1128 {
1129         uiLayout *row, *col;
1130         uiBlock *block;
1131         Material *ma= NULL;
1132         Tex *tex = (Tex*)id;
1133         ID *pid, *pparent;
1134         short *pr_texture= NULL;
1135         PointerRNA material_ptr;
1136         PointerRNA texture_ptr;
1137
1138         if(id && !ELEM4(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA)) {
1139                 RNA_warning("uiTemplatePreview: Expected ID of type material, texture, lamp or world.\n");
1140                 return;
1141         }
1142
1143         /* decide what to render */
1144         pid= id;
1145         pparent= NULL;
1146
1147         if(id && (GS(id->name) == ID_TE)) {
1148                 if(parent && (GS(parent->name) == ID_MA))
1149                         pr_texture= &((Material*)parent)->pr_texture;
1150                 else if(parent && (GS(parent->name) == ID_WO))
1151                         pr_texture= &((World*)parent)->pr_texture;
1152                 else if(parent && (GS(parent->name) == ID_LA))
1153                         pr_texture= &((Lamp*)parent)->pr_texture;
1154
1155                 if(pr_texture) {
1156                         if(*pr_texture == TEX_PR_OTHER)
1157                                 pid= parent;
1158                         else if(*pr_texture == TEX_PR_BOTH)
1159                                 pparent= parent;
1160                 }
1161         }
1162
1163         /* layout */
1164         block= uiLayoutGetBlock(layout);
1165         row= uiLayoutRow(layout, 0);
1166         col= uiLayoutColumn(row, 0);
1167         uiLayoutSetKeepAspect(col, 1);
1168         
1169         /* add preview */
1170         uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, pid, 0.0, 0.0, 0, 0, "");
1171         uiBlockSetDrawExtraFunc(block, ED_preview_draw, pparent, slot);
1172         uiBlockSetHandleFunc(block, do_preview_buttons, NULL);
1173         
1174         /* add buttons */
1175         if (pid && show_buttons) {
1176                 if(GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) {
1177                         if(GS(pid->name) == ID_MA) ma= (Material*)pid;
1178                         else ma= (Material*)pparent;
1179                         
1180                         /* Create RNA Pointer */
1181                         RNA_pointer_create(id, &RNA_Material, ma, &material_ptr);
1182
1183                         col = uiLayoutColumn(row, 1);
1184                         uiLayoutSetScaleX(col, 1.5);
1185                         uiItemR(col, &material_ptr, "preview_render_type", UI_ITEM_R_EXPAND, "", ICON_NONE);
1186                 }
1187
1188                 if(pr_texture) {
1189                         /* Create RNA Pointer */
1190                         RNA_pointer_create(id, &RNA_Texture, tex, &texture_ptr);
1191                         
1192                         uiLayoutRow(layout, 1);
1193                         uiDefButS(block, ROW, B_MATPRV, "Texture",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_TEXTURE, 0, 0, "");
1194                         if(GS(parent->name) == ID_MA)
1195                                 uiDefButS(block, ROW, B_MATPRV, "Material",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1196                         else if(GS(parent->name) == ID_LA)
1197                                 uiDefButS(block, ROW, B_MATPRV, "Lamp",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1198                         else if(GS(parent->name) == ID_WO)
1199                                 uiDefButS(block, ROW, B_MATPRV, "World",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1200                         uiDefButS(block, ROW, B_MATPRV, "Both",  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_BOTH, 0, 0, "");
1201                         
1202                         /* Alpha buton for texture preview */
1203                         if(*pr_texture!=TEX_PR_OTHER) {
1204                                 row = uiLayoutRow(layout, 0);
1205                                 uiItemR(row, &texture_ptr, "use_preview_alpha", 0, NULL, ICON_NONE);
1206                         }
1207                 }
1208         }
1209 }
1210
1211 /********************** ColorRamp Template **************************/
1212
1213
1214 typedef struct RNAUpdateCb {
1215         PointerRNA ptr;
1216         PropertyRNA *prop;
1217 } RNAUpdateCb;
1218
1219 static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
1220 {
1221         RNAUpdateCb *cb= (RNAUpdateCb*)arg_cb;
1222
1223         /* we call update here on the pointer property, this way the
1224            owner of the curve mapping can still define it's own update
1225            and notifier, even if the CurveMapping struct is shared. */
1226         RNA_property_update(C, &cb->ptr, cb->prop);
1227 }
1228
1229 #define B_BANDCOL 1
1230
1231 static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
1232 {
1233         ColorBand *coba= coba_v;
1234         float pos= 0.5f;
1235
1236         if(coba->tot > 1) {
1237                 if(coba->cur > 0)       pos= (coba->data[coba->cur-1].pos + coba->data[coba->cur].pos) * 0.5f;
1238                 else                            pos= (coba->data[coba->cur+1].pos + coba->data[coba->cur].pos) * 0.5f;
1239         }
1240
1241         if(colorband_element_add(coba, pos)) {
1242                 rna_update_cb(C, cb_v, NULL);
1243                 ED_undo_push(C, "Add colorband");       
1244         }
1245 }
1246
1247 static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v)
1248 {
1249         ColorBand *coba= coba_v;
1250
1251         if(colorband_element_remove(coba, coba->cur)) {
1252                 ED_undo_push(C, "Delete colorband");
1253                 rna_update_cb(C, cb_v, NULL);
1254         }
1255 }
1256
1257 static void colorband_flip_cb(bContext *C, void *cb_v, void *coba_v)
1258 {
1259         CBData data_tmp[MAXCOLORBAND];
1260
1261         ColorBand *coba= coba_v;
1262         int a;
1263
1264         for(a=0; a<coba->tot; a++) {
1265                 data_tmp[a]= coba->data[coba->tot - (a + 1)];
1266         }
1267         for(a=0; a<coba->tot; a++) {
1268                 data_tmp[a].pos = 1.0f - data_tmp[a].pos;
1269                 coba->data[a]= data_tmp[a];
1270         }
1271
1272         /* may as well flip the cur*/
1273         coba->cur= coba->tot - (coba->cur + 1);
1274
1275         ED_undo_push(C, "Flip colorband");
1276
1277         rna_update_cb(C, cb_v, NULL);
1278 }
1279
1280
1281 /* offset aligns from bottom, standard width 300, height 115 */
1282 static void colorband_buttons_large(uiLayout *layout, uiBlock *block, ColorBand *coba, int xoffs, int yoffs, RNAUpdateCb *cb)
1283 {
1284         uiBut *bt;
1285         uiLayout *row;
1286         const int line1_y= yoffs + 65 + UI_UNIT_Y + 2; /* 2 for some space between the buttons */
1287         const int line2_y= yoffs + 65;
1288
1289         if(coba==NULL) return;
1290
1291         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");
1292         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1293
1294         bt= uiDefBut(block, BUT, 0,     "Delete",               45+xoffs,line1_y,45,UI_UNIT_Y, NULL, 0, 0, 0, 0, "Delete the active position");
1295         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1296
1297
1298         /* XXX, todo for later - convert to operator - campbell */
1299         bt= uiDefBut(block, BUT, 0,     "F",            95+xoffs,line1_y,20,UI_UNIT_Y, NULL, 0, 0, 0, 0, "Flip colorband");
1300         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1301
1302         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");
1303
1304         bt= uiDefButS(block, MENU, 0,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
1305                         210+xoffs, line1_y, 90, UI_UNIT_Y,              &coba->ipotype, 0.0, 0.0, 0, 0, "Set interpolation between color stops");
1306         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1307         uiBlockEndAlign(block);
1308
1309         bt= uiDefBut(block, BUT_COLORBAND, 0, "",       xoffs,line2_y,300,UI_UNIT_Y, coba, 0, 0, 0, 0, "");
1310         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1311
1312
1313
1314         if(coba->tot) {
1315                 CBData *cbd= coba->data + coba->cur;
1316
1317                 /* better to use rna so we can animate them */
1318                 PointerRNA ptr;
1319                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1320                 row= uiLayoutRow(layout, 0);
1321                 uiItemR(row, &ptr, "position", 0, "Pos", ICON_NONE);
1322                 uiItemR(row, &ptr, "color", 0, "", ICON_NONE);
1323         }
1324
1325 }
1326
1327 static void colorband_buttons_small(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb)
1328 {
1329         uiBut *bt;
1330         float unit= (butr->xmax-butr->xmin)/14.0f;
1331         float xs= butr->xmin;
1332
1333         uiBlockBeginAlign(block);
1334         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");
1335         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1336         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");
1337         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1338         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");
1339         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1340         uiBlockEndAlign(block);
1341
1342         if(coba->tot) {
1343                 CBData *cbd= coba->data + coba->cur;
1344                 PointerRNA ptr;
1345                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1346                 uiItemR(layout, &ptr, "color", 0, "", ICON_NONE);
1347         }
1348
1349         bt= uiDefButS(block, MENU, 0,           "Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4",
1350                         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");
1351         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1352
1353         bt= uiDefBut(block, BUT_COLORBAND, 0, "",               xs,butr->ymin,butr->xmax-butr->xmin,UI_UNIT_Y, coba, 0, 0, 0, 0, "");
1354         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1355
1356         uiBlockEndAlign(block);
1357 }
1358
1359 static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, int small, RNAUpdateCb *cb)
1360 {
1361         if(small)
1362                 colorband_buttons_small(layout, block, coba, butr, cb);
1363         else
1364                 colorband_buttons_large(layout, block, coba, 0, 0, cb);
1365 }
1366
1367 void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, int expand)
1368 {
1369         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1370         PointerRNA cptr;
1371         RNAUpdateCb *cb;
1372         uiBlock *block;
1373         rctf rect;
1374
1375         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1376                 return;
1377
1378         cptr= RNA_property_pointer_get(ptr, prop);
1379         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp))
1380                 return;
1381
1382         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1383         cb->ptr= *ptr;
1384         cb->prop= prop;
1385
1386         rect.xmin= 0; rect.xmax= 200;
1387         rect.ymin= 0; rect.ymax= 190;
1388
1389         block= uiLayoutAbsoluteBlock(layout);
1390         colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1391
1392         MEM_freeN(cb);
1393 }
1394
1395 /********************* Histogram Template ************************/
1396
1397 void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
1398 {
1399         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1400         PointerRNA cptr;
1401         RNAUpdateCb *cb;
1402         uiBlock *block;
1403         uiBut *bt;
1404         Histogram *hist;
1405         rctf rect;
1406         
1407         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1408                 return;
1409         
1410         cptr= RNA_property_pointer_get(ptr, prop);
1411         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Histogram))
1412                 return;
1413         
1414         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1415         cb->ptr= *ptr;
1416         cb->prop= prop;
1417         
1418         rect.xmin= 0; rect.xmax= 200;
1419         rect.ymin= 0; rect.ymax= 190;
1420         
1421         block= uiLayoutAbsoluteBlock(layout);
1422         //colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1423
1424         hist = (Histogram *)cptr.data;
1425
1426         hist->height= (hist->height<=UI_UNIT_Y)?UI_UNIT_Y:hist->height;
1427
1428         bt= uiDefBut(block, HISTOGRAM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, hist->height, hist, 0, 0, 0, 0, "");
1429         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1430
1431         MEM_freeN(cb);
1432 }
1433
1434 /********************* Waveform Template ************************/
1435
1436 void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
1437 {
1438         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1439         PointerRNA cptr;
1440         RNAUpdateCb *cb;
1441         uiBlock *block;
1442         uiBut *bt;
1443         Scopes *scopes;
1444         rctf rect;
1445         
1446         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1447                 return;
1448         
1449         cptr= RNA_property_pointer_get(ptr, prop);
1450         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1451                 return;
1452         scopes = (Scopes *)cptr.data;
1453         
1454         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1455         cb->ptr= *ptr;
1456         cb->prop= prop;
1457         
1458         rect.xmin= 0; rect.xmax= 200;
1459         rect.ymin= 0; rect.ymax= 190;
1460         
1461         block= uiLayoutAbsoluteBlock(layout);
1462         
1463         scopes->wavefrm_height= (scopes->wavefrm_height<=UI_UNIT_Y)?UI_UNIT_Y:scopes->wavefrm_height;
1464
1465         bt= uiDefBut(block, WAVEFORM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->wavefrm_height, scopes, 0, 0, 0, 0, "");
1466         (void)bt; // UNUSED
1467         
1468         MEM_freeN(cb);
1469 }
1470
1471 /********************* Vectorscope Template ************************/
1472
1473 void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
1474 {
1475         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1476         PointerRNA cptr;
1477         RNAUpdateCb *cb;
1478         uiBlock *block;
1479         uiBut *bt;
1480         Scopes *scopes;
1481         rctf rect;
1482         
1483         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1484                 return;
1485         
1486         cptr= RNA_property_pointer_get(ptr, prop);
1487         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1488                 return;
1489         scopes = (Scopes *)cptr.data;
1490
1491         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1492         cb->ptr= *ptr;
1493         cb->prop= prop;
1494         
1495         rect.xmin= 0; rect.xmax= 200;
1496         rect.ymin= 0; rect.ymax= 190;
1497         
1498         block= uiLayoutAbsoluteBlock(layout);
1499
1500         scopes->vecscope_height= (scopes->vecscope_height<=UI_UNIT_Y)?UI_UNIT_Y:scopes->vecscope_height;
1501         
1502         bt= uiDefBut(block, VECTORSCOPE, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->vecscope_height, scopes, 0, 0, 0, 0, "");
1503         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1504         
1505         MEM_freeN(cb);
1506 }
1507
1508 /********************* CurveMapping Template ************************/
1509
1510
1511 static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *UNUSED(arg))
1512 {
1513         CurveMapping *cumap = cumap_v;
1514         float d;
1515
1516         /* we allow 20 times zoom */
1517         if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1518                 d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin);
1519                 cumap->curr.xmin+= d;
1520                 cumap->curr.xmax-= d;
1521                 d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin);
1522                 cumap->curr.ymin+= d;
1523                 cumap->curr.ymax-= d;
1524         }
1525
1526         ED_region_tag_redraw(CTX_wm_region(C));
1527 }
1528
1529 static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *UNUSED(unused))
1530 {
1531         CurveMapping *cumap = cumap_v;
1532         float d, d1;
1533
1534         /* we allow 20 times zoom, but dont view outside clip */
1535         if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1536                 d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin);
1537
1538                 if(cumap->flag & CUMA_DO_CLIP) 
1539                         if(cumap->curr.xmin-d < cumap->clipr.xmin)
1540                                 d1= cumap->curr.xmin - cumap->clipr.xmin;
1541                 cumap->curr.xmin-= d1;
1542
1543                 d1= d;
1544                 if(cumap->flag & CUMA_DO_CLIP) 
1545                         if(cumap->curr.xmax+d > cumap->clipr.xmax)
1546                                 d1= -cumap->curr.xmax + cumap->clipr.xmax;
1547                 cumap->curr.xmax+= d1;
1548
1549                 d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin);
1550
1551                 if(cumap->flag & CUMA_DO_CLIP) 
1552                         if(cumap->curr.ymin-d < cumap->clipr.ymin)
1553                                 d1= cumap->curr.ymin - cumap->clipr.ymin;
1554                 cumap->curr.ymin-= d1;
1555
1556                 d1= d;
1557                 if(cumap->flag & CUMA_DO_CLIP) 
1558                         if(cumap->curr.ymax+d > cumap->clipr.ymax)
1559                                 d1= -cumap->curr.ymax + cumap->clipr.ymax;
1560                 cumap->curr.ymax+= d1;
1561         }
1562
1563         ED_region_tag_redraw(CTX_wm_region(C));
1564 }
1565
1566 static void curvemap_buttons_setclip(bContext *UNUSED(C), void *cumap_v, void *UNUSED(arg))
1567 {
1568         CurveMapping *cumap = cumap_v;
1569
1570         curvemapping_changed(cumap, 0);
1571 }       
1572
1573 static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v)
1574 {
1575         CurveMapping *cumap = cumap_v;
1576
1577         curvemap_remove(cumap->cm+cumap->cur, SELECT);
1578         curvemapping_changed(cumap, 0);
1579
1580         rna_update_cb(C, cb_v, NULL);
1581 }
1582
1583 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
1584 static uiBlock *curvemap_clipping_func(bContext *C, struct ARegion *ar, void *cumap_v)
1585 {
1586         CurveMapping *cumap = cumap_v;
1587         uiBlock *block;
1588         uiBut *bt;
1589         float width= 8*UI_UNIT_X;
1590
1591         block= uiBeginBlock(C, ar, "curvemap_clipping_func", UI_EMBOSS);
1592
1593         /* use this for a fake extra empy space around the buttons */
1594         uiDefBut(block, LABEL, 0, "",                   -4, 16, width+8, 6*UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
1595
1596         bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",    
1597                         0,5*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->flag, 0.0, 0.0, 10, 0, "");
1598         uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
1599
1600         uiBlockBeginAlign(block);
1601         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, "");
1602         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, "");
1603         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, "");
1604         uiDefButF(block, NUM, 0, "Max Y ",       0,UI_UNIT_Y,width,UI_UNIT_Y, &cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 0, "");
1605
1606         uiBlockSetDirection(block, UI_RIGHT);
1607
1608         uiEndBlock(C, block);
1609         return block;
1610 }
1611
1612 static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
1613 {
1614         CurveMapping *cumap = cumap_v;
1615         CurveMap *cuma= cumap->cm+cumap->cur;
1616
1617         switch(event) {
1618                 case 0: /* reset */
1619                         curvemap_reset(cuma, &cumap->clipr,     cumap->preset, CURVEMAP_SLOPE_POSITIVE);
1620                         curvemapping_changed(cumap, 0);
1621                         break;
1622                 case 1:
1623                         cumap->curr= cumap->clipr;
1624                         break;
1625                 case 2: /* set vector */
1626                         curvemap_sethandle(cuma, 1);
1627                         curvemapping_changed(cumap, 0);
1628                         break;
1629                 case 3: /* set auto */
1630                         curvemap_sethandle(cuma, 0);
1631                         curvemapping_changed(cumap, 0);
1632                         break;
1633                 case 4: /* extend horiz */
1634                         cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
1635                         curvemapping_changed(cumap, 0);
1636                         break;
1637                 case 5: /* extend extrapolate */
1638                         cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
1639                         curvemapping_changed(cumap, 0);
1640                         break;
1641         }
1642         ED_region_tag_redraw(CTX_wm_region(C));
1643 }
1644
1645 static uiBlock *curvemap_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1646 {
1647         uiBlock *block;
1648         short yco= 0, menuwidth=10*UI_UNIT_X;
1649
1650         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
1651         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1652
1653         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View",                             0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 1, "");
1654         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 2, "");
1655         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 3, "");
1656         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Horizontal",              0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 4, "");
1657         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Extrapolated",    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 5, "");
1658         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1659
1660         uiBlockSetDirection(block, UI_RIGHT);
1661         uiTextBoundsBlock(block, 50);
1662
1663         uiEndBlock(C, block);
1664         return block;
1665 }
1666
1667 static uiBlock *curvemap_brush_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1668 {
1669         uiBlock *block;
1670         short yco= 0, menuwidth=10*UI_UNIT_X;
1671
1672         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
1673         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1674
1675         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View",                             0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 1, "");
1676         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle",                  0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 2, "");
1677         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle",                    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 3, "");
1678         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve",                    0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1679
1680         uiBlockSetDirection(block, UI_RIGHT);
1681         uiTextBoundsBlock(block, 50);
1682
1683         uiEndBlock(C, block);
1684         return block;
1685 }
1686
1687 static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
1688 {
1689         ED_region_tag_redraw(CTX_wm_region(C));
1690 }
1691
1692 static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
1693 {
1694         CurveMapping *cumap = cumap_v;
1695         int a;
1696         
1697         cumap->preset = CURVE_PRESET_LINE;
1698         for(a=0; a<CM_TOT; a++)
1699                 curvemap_reset(cumap->cm+a, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
1700         
1701         cumap->black[0]=cumap->black[1]=cumap->black[2]= 0.0f;
1702         cumap->white[0]=cumap->white[1]=cumap->white[2]= 1.0f;
1703         curvemapping_set_black_white(cumap, NULL, NULL);
1704         
1705         curvemapping_changed(cumap, 0);
1706
1707         rna_update_cb(C, cb_v, NULL);
1708 }
1709
1710 /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
1711 static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels, int brush, RNAUpdateCb *cb)
1712 {
1713         CurveMapping *cumap= ptr->data;
1714         uiLayout *row, *sub, *split;
1715         uiBlock *block;
1716         uiBut *bt;
1717         float dx= UI_UNIT_X;
1718         int icon, size;
1719         int bg=-1;
1720
1721         block= uiLayoutGetBlock(layout);
1722
1723         /* curve chooser */
1724         row= uiLayoutRow(layout, 0);
1725
1726         if(labeltype=='v') {
1727                 /* vector */
1728                 sub= uiLayoutRow(row, 1);
1729                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1730
1731                 if(cumap->cm[0].curve) {
1732                         bt= uiDefButI(block, ROW, 0, "X", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1733                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1734                 }
1735                 if(cumap->cm[1].curve) {
1736                         bt= uiDefButI(block, ROW, 0, "Y", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1737                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1738                 }
1739                 if(cumap->cm[2].curve) {
1740                         bt= uiDefButI(block, ROW, 0, "Z", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1741                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1742                 }
1743         }
1744         else if(labeltype=='c') {
1745                 /* color */
1746                 sub= uiLayoutRow(row, 1);
1747                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1748
1749                 if(cumap->cm[3].curve) {
1750                         bt= uiDefButI(block, ROW, 0, "C", 0, 0, dx, dx, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
1751                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1752                 }
1753                 if(cumap->cm[0].curve) {
1754                         bt= uiDefButI(block, ROW, 0, "R", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1755                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1756                 }
1757                 if(cumap->cm[1].curve) {
1758                         bt= uiDefButI(block, ROW, 0, "G", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1759                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1760                 }
1761                 if(cumap->cm[2].curve) {
1762                         bt= uiDefButI(block, ROW, 0, "B", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1763                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1764                 }
1765         }
1766         else if (labeltype == 'h') {
1767                 /* HSV */
1768                 sub= uiLayoutRow(row, 1);
1769                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1770                 
1771                 if(cumap->cm[0].curve) {
1772                         bt= uiDefButI(block, ROW, 0, "H", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1773                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1774                 }
1775                 if(cumap->cm[1].curve) {
1776                         bt= uiDefButI(block, ROW, 0, "S", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1777                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1778                 }
1779                 if(cumap->cm[2].curve) {
1780                         bt= uiDefButI(block, ROW, 0, "V", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1781                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1782                 }
1783         }
1784         else
1785                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
1786         
1787         if (labeltype=='h')
1788                 bg = UI_GRAD_H;
1789
1790         /* operation buttons */
1791         sub= uiLayoutRow(row, 1);
1792
1793         uiBlockSetEmboss(block, UI_EMBOSSN);
1794
1795         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom in");
1796         uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
1797
1798         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMOUT, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom out");
1799         uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
1800
1801         if(brush)
1802                 bt= uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, "Tools");
1803         else
1804                 bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, "Tools");
1805
1806         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1807
1808         if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT;
1809         bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, "Clipping Options");
1810         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1811
1812         bt= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, "Delete points");
1813         uiButSetNFunc(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
1814
1815         uiBlockSetEmboss(block, UI_EMBOSS);
1816
1817         uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
1818
1819         /* curve itself */
1820         size= uiLayoutGetWidth(layout);
1821         row= uiLayoutRow(layout, 0);
1822         uiDefBut(block, BUT_CURVE, 0, "", 0, 0, size, MIN2(size, 200), cumap, 0.0f, 1.0f, bg, 0, "");
1823
1824         /* black/white levels */
1825         if(levels) {
1826                 split= uiLayoutSplit(layout, 0, 0);
1827                 uiItemR(uiLayoutColumn(split, 0), ptr, "black_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1828                 uiItemR(uiLayoutColumn(split, 0), ptr, "white_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1829
1830                 uiLayoutRow(layout, 0);
1831                 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");
1832                 uiButSetNFunc(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
1833         }
1834
1835         uiBlockSetNFunc(block, NULL, NULL, NULL);
1836 }
1837
1838 void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, int levels, int brush)
1839 {
1840         RNAUpdateCb *cb;
1841         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1842         PointerRNA cptr;
1843
1844         if(!prop) {
1845                 RNA_warning("uiTemplateCurveMapping: curve property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
1846                 return;
1847         }
1848
1849         if(RNA_property_type(prop) != PROP_POINTER) {
1850                 RNA_warning("uiTemplateCurveMapping: curve is not a pointer: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
1851                 return;
1852         }
1853
1854         cptr= RNA_property_pointer_get(ptr, prop);
1855         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveMapping))
1856                 return;
1857
1858         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1859         cb->ptr= *ptr;
1860         cb->prop= prop;
1861
1862         curvemap_buttons_layout(layout, &cptr, type, levels, brush, cb);
1863
1864         MEM_freeN(cb);
1865 }
1866
1867 /********************* ColorWheel Template ************************/
1868
1869 #define WHEEL_SIZE      100
1870
1871 void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic)
1872 {
1873         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1874         uiBlock *block= uiLayoutGetBlock(layout);
1875         uiLayout *col, *row;
1876         uiBut *but;
1877         float softmin, softmax, step, precision;
1878         
1879         if (!prop) {
1880                 RNA_warning("uiTemplateColorWheel: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
1881                 return;
1882         }
1883
1884         RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
1885         
1886         col = uiLayoutColumn(layout, 0);
1887         row= uiLayoutRow(col, 1);
1888         
1889         but= uiDefButR(block, HSVCIRCLE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, propname, -1, 0.0, 0.0, 0, 0, "");
1890
1891         if(lock) {
1892                 but->flag |= UI_BUT_COLOR_LOCK;
1893         }
1894
1895         if(lock_luminosity) {
1896                 float color[4]; /* incase of alpha */
1897                 but->flag |= UI_BUT_VEC_SIZE_LOCK;
1898                 RNA_property_float_get_array(ptr, prop, color);
1899                 but->a2= len_v3(color);
1900         }
1901
1902         if(cubic)
1903                 but->flag |= UI_BUT_COLOR_CUBIC;
1904
1905         uiItemS(row);
1906         
1907         if (value_slider)
1908                 uiDefButR(block, HSVCUBE, 0, "", WHEEL_SIZE+6, 0, 14, WHEEL_SIZE, ptr, propname, -1, softmin, softmax, UI_GRAD_V_ALT, 0, "");
1909 }
1910
1911 /********************* Layer Buttons Template ************************/
1912
1913 static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
1914 {
1915         uiBut *but = arg1;
1916         int cur = GET_INT_FROM_POINTER(arg2);
1917         wmWindow *win= CTX_wm_window(C);
1918         int i, tot, shift= win->eventstate->shift;
1919
1920         if(!shift) {
1921                 tot= RNA_property_array_length(&but->rnapoin, but->rnaprop);
1922                 
1923                 /* Normally clicking only selects one layer */
1924                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, 1);
1925                 for(i = 0; i < tot; ++i) {
1926                         if(i != cur)
1927                                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, 0);
1928                 }
1929         }
1930         
1931         /* view3d layer change should update depsgraph (invisible object changed maybe) */
1932         /* see view3d_header.c */
1933 }
1934
1935 // TODO:
1936 //      - for now, grouping of layers is determined by dividing up the length of 
1937 //        the array of layer bitflags
1938
1939 void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
1940                           PointerRNA *used_ptr, const char *used_propname, int active_layer)
1941 {
1942         uiLayout *uRow, *uCol;
1943         PropertyRNA *prop, *used_prop= NULL;
1944         int groups, cols, layers;
1945         int group, col, layer, row;
1946         int cols_per_group = 5;
1947
1948         prop= RNA_struct_find_property(ptr, propname);
1949         if (!prop) {
1950                 RNA_warning("uiTemplateLayer: layers property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
1951                 return;
1952         }
1953         
1954         /* the number of layers determines the way we group them 
1955          *      - we want 2 rows only (for now)
1956          *      - the number of columns (cols) is the total number of buttons per row
1957          *        the 'remainder' is added to this, as it will be ok to have first row slightly wider if need be
1958          *      - for now, only split into groups if group will have at least 5 items
1959          */
1960         layers= RNA_property_array_length(ptr, prop);
1961         cols= (layers / 2) + (layers % 2);
1962         groups= ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group);
1963
1964         if(used_ptr && used_propname) {
1965                 used_prop= RNA_struct_find_property(used_ptr, used_propname);
1966                 if (!used_prop) {
1967                         RNA_warning("uiTemplateLayer: used layers property not found: %s.%s\n", RNA_struct_identifier(ptr->type), used_propname);
1968                         return;
1969                 }
1970
1971                 if(RNA_property_array_length(used_ptr, used_prop) < layers)
1972                         used_prop = NULL;
1973         }
1974         
1975         /* layers are laid out going across rows, with the columns being divided into groups */
1976         
1977         for (group= 0; group < groups; group++) {
1978                 uCol= uiLayoutColumn(layout, 1);
1979                 
1980                 for (row= 0; row < 2; row++) {
1981                         uiBlock *block;
1982                         uiBut *but;
1983
1984                         uRow= uiLayoutRow(uCol, 1);
1985                         block= uiLayoutGetBlock(uRow);
1986                         layer= groups*cols_per_group*row + cols_per_group*group;
1987                         
1988                         /* add layers as toggle buts */
1989                         for (col= 0; (col < cols_per_group) && (layer < layers); col++, layer++) {
1990                                 int icon = 0;
1991                                 int butlay = 1 << layer;
1992
1993                                 if(active_layer & butlay)
1994                                         icon = ICON_LAYER_ACTIVE;
1995                                 else if(used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, layer))
1996                                         icon = ICON_LAYER_USED;
1997                                 
1998                                 but= uiDefAutoButR(block, ptr, prop, layer, "", icon, 0, 0, UI_UNIT_X/2, UI_UNIT_Y/2);
1999                                 uiButSetFunc(but, handle_layer_buttons, but, SET_INT_IN_POINTER(layer));
2000                                 but->type= TOG;
2001                         }
2002                 }
2003         }
2004 }
2005
2006
2007 /************************* List Template **************************/
2008
2009 static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon, int big)
2010 {
2011         ID *id= NULL;
2012         int icon;
2013
2014         if(!itemptr->data)
2015                 return rnaicon;
2016
2017         /* try ID, material or texture slot */
2018         if(RNA_struct_is_ID(itemptr->type)) {
2019                 id= itemptr->id.data;
2020         }
2021         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2022                 id= RNA_pointer_get(itemptr, "material").data;
2023         }
2024         else if(RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) {
2025                 id= RNA_pointer_get(itemptr, "texture").data;
2026         }
2027         else if(RNA_struct_is_a(itemptr->type, &RNA_DynamicPaintSurface)) {
2028                 DynamicPaintSurface *surface= (DynamicPaintSurface*)itemptr->data;
2029
2030                 if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) return ICON_TEXTURE_SHADED;
2031                 else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) return ICON_OUTLINER_DATA_MESH;
2032                 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return ICON_FILE_IMAGE;
2033         }
2034
2035         /* get icon from ID */
2036         if(id) {
2037                 icon= ui_id_icon_get(C, id, big);
2038
2039                 if(icon)
2040                         return icon;
2041         }
2042
2043         return rnaicon;
2044 }
2045
2046 static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *itemptr, int i, int rnaicon, PointerRNA *activeptr, const char *activepropname)
2047 {
2048         uiBlock *block= uiLayoutGetBlock(layout);
2049         uiBut *but;
2050         uiLayout *split, *overlap, *sub, *row;
2051         char *namebuf;
2052         const char *name;
2053         int icon;
2054
2055         overlap= uiLayoutOverlap(layout);
2056
2057         /* list item behind label & other buttons */
2058         sub= uiLayoutRow(overlap, 0);
2059
2060         but= uiDefButR(block, LISTROW, 0, "", 0,0, UI_UNIT_X*10,UI_UNIT_Y, activeptr, activepropname, 0, 0, i, 0, 0, "");
2061         uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2062
2063         sub= uiLayoutRow(overlap, 0);
2064
2065         /* retrieve icon and name */
2066         icon= list_item_icon_get(C, itemptr, rnaicon, 0);
2067         if(icon == ICON_NONE || icon == ICON_DOT)
2068                 icon= 0;
2069
2070         namebuf= RNA_struct_name_get_alloc(itemptr, NULL, 0);
2071         name= (namebuf)? namebuf: "";
2072
2073         /* hardcoded types */
2074         if(itemptr->type == &RNA_MeshTextureFaceLayer || itemptr->type == &RNA_MeshColorLayer) {
2075                 uiItemL(sub, name, icon);
2076                 uiBlockSetEmboss(block, UI_EMBOSSN);
2077                 uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", 0, 0, 0, 0, 0, NULL);
2078                 uiBlockSetEmboss(block, UI_EMBOSS);
2079         }
2080         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) {
2081                 uiItemL(sub, name, icon);
2082                 uiBlockSetEmboss(block, UI_EMBOSS);
2083                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0,  NULL);
2084         }
2085         else if(RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
2086                 uiItemL(sub, name, icon);
2087                 uiBlockSetEmboss(block, UI_EMBOSS);
2088                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0,  NULL);
2089         }
2090         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2091                 /* provision to draw active node name */
2092                 Material *ma, *manode;
2093                 Object *ob= (Object*)ptr->id.data;
2094                 int index= (Material**)itemptr->data - ob->mat;
2095                 
2096                 /* default item with material base name */
2097                 uiItemL(sub, name, icon);
2098                 
2099                 ma= give_current_material(ob, index+1);
2100                 if(ma) {
2101                         manode= give_node_material(ma);
2102                         if(manode) {
2103                                 char str[MAX_ID_NAME + 12];
2104                                 sprintf(str, "Node %s", manode->id.name+2);
2105                                 uiItemL(sub, str, ui_id_icon_get(C, &manode->id, 1));
2106                         }
2107                         else if(ma->use_nodes) {
2108                                 uiItemL(sub, "Node <none>", ICON_NONE);
2109                         }
2110                 }
2111         }
2112         else if(itemptr->type == &RNA_ShapeKey) {
2113                 Object *ob= (Object*)activeptr->data;
2114                 Key *key= (Key*)itemptr->data;
2115
2116                 split= uiLayoutSplit(sub, 0.75f, 0);
2117
2118                 uiItemL(split, name, icon);
2119
2120                 uiBlockSetEmboss(block, UI_EMBOSSN);
2121                 row= uiLayoutRow(split, 1);
2122                 if(i == 0 || (key->type != KEY_RELATIVE)) uiItemL(row, "", ICON_NONE);
2123                 else uiItemR(row, itemptr, "value", 0, "", ICON_NONE);
2124
2125                 if(ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH))
2126                         uiLayoutSetActive(row, 0);
2127                 //uiItemR(row, itemptr, "mute", 0, "", ICON_MUTE_IPO_OFF);
2128                 uiBlockSetEmboss(block, UI_EMBOSS);
2129         }
2130         else if(itemptr->type == &RNA_DynamicPaintSurface) {
2131                 char name_final[96];
2132                 const char *enum_name;
2133                 PropertyRNA *prop = RNA_struct_find_property(itemptr, "surface_type");
2134                 DynamicPaintSurface *surface= (DynamicPaintSurface*)itemptr->data;
2135
2136                 RNA_property_enum_name(C, itemptr, prop, RNA_property_enum_get(itemptr, prop), &enum_name);
2137
2138                 sprintf(name_final, "%s (%s)",name,enum_name);
2139                 uiItemL(sub, name_final, icon);
2140                 if (dynamicPaint_surfaceHasColorPreview(surface)) {
2141                         uiBlockSetEmboss(block, UI_EMBOSSN);
2142                         uiDefIconButR(block, OPTION, 0, (surface->flags & MOD_DPAINT_PREVIEW) ? ICON_RESTRICT_VIEW_OFF : ICON_RESTRICT_VIEW_ON,
2143                                 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "show_preview", 0, 0, 0, 0, 0, NULL);
2144                         uiBlockSetEmboss(block, UI_EMBOSS);
2145                 }
2146                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "is_active", i, 0, 0, 0, 0,  NULL);
2147         }
2148         else
2149                 uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
2150
2151         /* free name */
2152         if(namebuf)
2153                 MEM_freeN(namebuf);
2154 }
2155
2156 void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *activeptr, const char *activepropname, int rows, int maxrows, int listtype)
2157 {
2158         //Scene *scene= CTX_data_scene(C);
2159         PropertyRNA *prop= NULL, *activeprop;
2160         PropertyType type, activetype;
2161         StructRNA *ptype;
2162         uiLayout *box, *row, *col;
2163         uiBlock *block;
2164         uiBut *but;
2165         Panel *pa;
2166         char *name, str[32];
2167         int rnaicon=0, icon=0, i= 0, activei= 0, len= 0, items, found, min, max;
2168
2169         /* validate arguments */
2170         block= uiLayoutGetBlock(layout);
2171         pa= block->panel;
2172
2173         if(!pa) {
2174                 RNA_warning("uiTemplateList: only works inside a panel.\n");
2175                 return;
2176         }
2177
2178         if(!activeptr->data)
2179                 return;
2180         
2181         if(ptr->data) {
2182                 prop= RNA_struct_find_property(ptr, propname);
2183                 if(!prop) {
2184                         RNA_warning("uiTemplateList: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
2185                         return;
2186                 }
2187         }
2188
2189         activeprop= RNA_struct_find_property(activeptr, activepropname);
2190         if(!activeprop) {
2191                 RNA_warning("uiTemplateList: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), activepropname);
2192                 return;
2193         }
2194
2195         if(prop) {
2196                 type= RNA_property_type(prop);
2197                 if(type != PROP_COLLECTION) {
2198                         RNA_warning("uiTemplateList: Expected collection property.\n");
2199                         return;
2200                 }
2201         }
2202
2203         activetype= RNA_property_type(activeprop);
2204         if(activetype != PROP_INT) {
2205                 RNA_warning("uiTemplateList: Expected integer property.\n");
2206                 return;
2207         }
2208
2209         /* get icon */
2210         if(ptr->data && prop) {
2211                 ptype= RNA_property_pointer_type(ptr, prop);
2212                 rnaicon= RNA_struct_ui_icon(ptype);
2213         }
2214
2215         /* get active data */
2216         activei= RNA_property_int_get(activeptr, activeprop);
2217
2218         if(listtype == 'i') {
2219                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2220                 col= uiLayoutColumn(box, 1);
2221                 row= uiLayoutRow(col, 0);
2222
2223                 if(ptr->data && prop) {
2224                         /* create list items */
2225                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2226                                 /* create button */
2227                                 if(i == 9)
2228                                         row= uiLayoutRow(col, 0);
2229
2230                                 icon= list_item_icon_get(C, &itemptr, rnaicon, 1);
2231                                 but= uiDefIconButR(block, LISTROW, 0, icon, 0,0,UI_UNIT_X*10,UI_UNIT_Y, activeptr, activepropname, 0, 0, i, 0, 0, "");
2232                                 uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2233                                 
2234
2235                                 i++;
2236                         }
2237                         RNA_PROP_END;
2238                 }
2239         }
2240         else if(listtype == 'c') {
2241                 /* compact layout */
2242                 found= 0;
2243
2244                 row= uiLayoutRow(layout, 1);
2245
2246                 if(ptr->data && prop) {
2247                         /* create list items */
2248                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2249                                 found= (activei == i);
2250
2251                                 if(found) {
2252                                         /* create button */
2253                                         name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
2254                                         icon= list_item_icon_get(C, &itemptr, rnaicon, 0);
2255                                         uiItemL(row, (name)? name: "", icon);
2256
2257                                         if(name)
2258                                                 MEM_freeN(name);
2259                                 }
2260
2261                                 i++;
2262                         }
2263                         RNA_PROP_END;
2264                 }
2265
2266                 /* if not found, add in dummy button */
2267                 if(i == 0)
2268                         uiItemL(row, "", ICON_NONE);
2269
2270                 /* next/prev button */
2271                 sprintf(str, "%d :", i);
2272                 but= uiDefIconTextButR(block, NUM, 0, 0, str, 0,0,UI_UNIT_X*5,UI_UNIT_Y, activeptr, activepropname, 0, 0, 0, 0, 0, "");
2273                 if(i == 0)
2274                         uiButSetFlag(but, UI_BUT_DISABLED);
2275         }
2276         else {
2277                 /* default rows */
2278                 if(rows == 0)
2279                         rows= 5;
2280                 if (maxrows == 0)
2281                         maxrows = 5;
2282                 if(pa->list_grip_size != 0)
2283                         rows= pa->list_grip_size;
2284
2285                 /* layout */
2286                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2287                 row= uiLayoutRow(box, 0);
2288                 col = uiLayoutColumn(row, 1);
2289
2290                 /* init numbers */
2291                 RNA_property_int_range(activeptr, activeprop, &min, &max);
2292
2293                 if(prop)
2294                         len= RNA_property_collection_length(ptr, prop);
2295                 items= CLAMPIS(len, rows, MAX2(rows, maxrows));
2296
2297                 /* if list length changes and active is out of view, scroll to it */
2298                 if(pa->list_last_len != len)
2299                         if((activei < pa->list_scroll || activei >= pa->list_scroll+items))
2300                                 pa->list_scroll= activei;
2301
2302                 pa->list_scroll= MIN2(pa->list_scroll, len-items);
2303                 pa->list_scroll= MAX2(pa->list_scroll, 0);
2304                 pa->list_size= items;
2305                 pa->list_last_len= len;
2306
2307                 if(ptr->data && prop) {
2308                         /* create list items */
2309                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2310                                 if(i >= pa->list_scroll && i<pa->list_scroll+items)
2311                                         list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activepropname);
2312
2313                                 i++;
2314                         }
2315                         RNA_PROP_END;
2316                 }
2317
2318                 /* add dummy buttons to fill space */
2319                 while(i < pa->list_scroll+items) {
2320                         if(i >= pa->list_scroll)
2321                                 uiItemL(col, "", ICON_NONE);
2322                         i++;
2323                 }
2324
2325                 /* add scrollbar */
2326                 if(len > items) {
2327                         col= uiLayoutColumn(row, 0);
2328                         uiDefButI(block, SCROLL, 0, "", 0,0,UI_UNIT_X*0.75,UI_UNIT_Y*items, &pa->list_scroll, 0, len-items, items, 0, "");
2329                 }
2330         }
2331 }
2332
2333 /************************* Operator Search Template **************************/
2334
2335 static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
2336 {
2337         wmOperatorType *ot= arg2;
2338         
2339         if(ot)
2340                 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
2341 }
2342
2343 static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
2344 {
2345         wmOperatorType *ot = WM_operatortype_first();
2346         
2347         for(; ot; ot= ot->next) {
2348                 
2349                 if(BLI_strcasestr(ot->name, str)) {
2350                         if(WM_operator_poll((bContext*)C, ot)) {
2351                                 char name[256];
2352                                 int len= strlen(ot->name);
2353                                 
2354                                 /* display name for menu, can hold hotkey */
2355                                 BLI_strncpy(name, ot->name, 256);
2356                                 
2357                                 /* check for hotkey */
2358                                 if(len < 256-6) {
2359                                         if(WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, &name[len+1], 256-len-1))
2360                                                 name[len]= '|';
2361                                 }
2362                                 
2363                                 if(0==uiSearchItemAdd(items, name, ot, 0))
2364                                         break;
2365                         }
2366                 }
2367         }
2368 }
2369
2370 void uiTemplateOperatorSearch(uiLayout *layout)
2371 {
2372         uiBlock *block;
2373         uiBut *but;
2374         static char search[256]= "";
2375                 
2376         block= uiLayoutGetBlock(layout);
2377         uiBlockSetCurLayout(block, layout);
2378
2379         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, 0, 0, "");
2380         uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
2381 }
2382
2383 /************************* Running Jobs Template **************************/
2384
2385 #define B_STOPRENDER    1
2386 #define B_STOPCAST              2
2387 #define B_STOPANIM              3
2388 #define B_STOPCOMPO             4
2389
2390 static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
2391 {
2392         switch(event) {
2393                 case B_STOPRENDER:
2394                         G.afbreek= 1;
2395                         break;
2396                 case B_STOPCAST:
2397                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C), NULL);
2398                         break;
2399                 case B_STOPANIM:
2400                         WM_operator_name_call(C, "SCREEN_OT_animation_play", WM_OP_INVOKE_SCREEN, NULL);
2401                         break;
2402                 case B_STOPCOMPO:
2403                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2404                         break;
2405         }
2406 }
2407
2408 void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
2409 {
2410         bScreen *screen= CTX_wm_screen(C);
2411         wmWindowManager *wm= CTX_wm_manager(C);
2412         ScrArea *sa= CTX_wm_area(C);
2413         uiBlock *block;
2414         void *owner= NULL;
2415         int handle_event;
2416         
2417         block= uiLayoutGetBlock(layout);
2418         uiBlockSetCurLayout(block, layout);
2419
2420         uiBlockSetHandleFunc(block, do_running_jobs, NULL);
2421
2422         if(sa->spacetype==SPACE_NODE) {
2423                 if(WM_jobs_test(wm, sa))
2424                    owner = sa;
2425                 handle_event= B_STOPCOMPO;
2426         } 
2427         else {
2428                 Scene *scene;
2429                 /* another scene can be rendering too, for example via compositor */
2430                 for(scene= CTX_data_main(C)->scene.first; scene; scene= scene->id.next)
2431                         if(WM_jobs_test(wm, scene))
2432                                 break;
2433                 owner = scene;
2434                 handle_event= B_STOPRENDER;
2435         }
2436
2437         if(owner) {
2438                 uiLayout *ui_abs;
2439                 
2440                 ui_abs= uiLayoutAbsolute(layout, 0);
2441                 (void)ui_abs; // UNUSED
2442                 
2443                 uiDefIconBut(block, BUT, handle_event, ICON_PANEL_CLOSE, 
2444                                 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");
2445                 uiDefBut(block, PROGRESSBAR, 0, WM_jobs_name(wm, owner), 
2446                                 UI_UNIT_X, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, "Progress");
2447                 
2448                 uiLayoutRow(layout, 0);
2449         }
2450         if(WM_jobs_test(wm, screen))
2451                 uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, "Capture", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop screencast");
2452         if(screen->animtimer)
2453                 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");
2454 }
2455
2456 /************************* Reports for Last Operator Template **************************/
2457
2458 void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
2459 {
2460         ReportList *reports = CTX_wm_reports(C);
2461         Report *report= BKE_reports_last_displayable(reports);
2462         ReportTimerInfo *rti;
2463         
2464         uiLayout *ui_abs;
2465         uiBlock *block;
2466         uiBut *but;
2467         uiStyle *style= U.uistyles.first;
2468         int width;
2469         int icon=0;
2470         
2471         /* if the report display has timed out, don't show */
2472         if (!reports->reporttimer) return;
2473         
2474         rti= (ReportTimerInfo *)reports->reporttimer->customdata;
2475         
2476         if (!rti || rti->widthfac==0.0f || !report) return;
2477         
2478         ui_abs= uiLayoutAbsolute(layout, 0);
2479         block= uiLayoutGetBlock(ui_abs);
2480         
2481         width = BLF_width(style->widget.uifont_id, report->message);
2482         width = MIN2(rti->widthfac*width, width);
2483         width = MAX2(width, 10);
2484         
2485         /* make a box around the report to make it stand out */
2486         uiBlockBeginAlign(block);
2487         but= uiDefBut(block, ROUNDBOX, 0, "", 0, 0, UI_UNIT_X+10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2488         /* set the report's bg color in but->col - ROUNDBOX feature */
2489         but->col[0]= FTOCHAR(rti->col[0]);
2490         but->col[1]= FTOCHAR(rti->col[1]);
2491         but->col[2]= FTOCHAR(rti->col[2]);
2492         but->col[3]= 255; 
2493
2494         but= uiDefBut(block, ROUNDBOX, 0, "", UI_UNIT_X+10, 0, UI_UNIT_X+width, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2495         but->col[0]= but->col[1]= but->col[2]= FTOCHAR(rti->greyscale);
2496         but->col[3]= 255;
2497
2498         uiBlockEndAlign(block);
2499         
2500         
2501         /* icon and report message on top */
2502         if(report->type & RPT_ERROR_ALL)
2503                 icon = ICON_ERROR;
2504         else if(report->type & RPT_WARNING_ALL)
2505                 icon = ICON_ERROR;
2506         else if(report->type & RPT_INFO_ALL)
2507                 icon = ICON_INFO;
2508         
2509         /* XXX: temporary operator to dump all reports to a text block, but only if more than 1 report 
2510          * to be shown instead of icon when appropriate...
2511          */
2512         uiBlockSetEmboss(block, UI_EMBOSSN);
2513
2514         if (reports->list.first != reports->list.last)
2515                 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'");
2516         else
2517                 uiDefIconBut(block, LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2518
2519         uiBlockSetEmboss(block, UI_EMBOSS);
2520         
2521         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, "");
2522 }
2523