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