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