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