Merging r40572 through r40597 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_anim_types.h"
37 #include "DNA_key_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_userdef_types.h"
40
41 #include "BLI_string.h"
42 #include "BLI_utildefines.h"
43 #include "BLI_ghash.h"
44
45 #include "BKE_animsys.h"
46 #include "BKE_colortools.h"
47 #include "BKE_context.h"
48 #include "BKE_global.h"
49 #include "BKE_library.h"
50 #include "BKE_main.h"
51 #include "BKE_object.h"
52 #include "BKE_material.h"
53 #include "BKE_texture.h"
54 #include "BKE_report.h"
55 #include "BKE_displist.h"
56
57 #include "ED_screen.h"
58 #include "ED_object.h"
59 #include "ED_render.h"
60
61 #include "RNA_access.h"
62 #include "RNA_enum_types.h"
63
64 #include "WM_api.h"
65 #include "WM_types.h"
66
67 #include "UI_interface.h"
68 #include "interface_intern.h"
69
70 #include "BLF_api.h"
71 #include "BLF_translation.h"
72
73 void UI_template_fix_linking(void)
74 {
75 }
76
77 /********************** Header Template *************************/
78
79 void uiTemplateHeader(uiLayout *layout, bContext *C, int menus)
80 {
81         uiBlock *block;
82
83         block= uiLayoutAbsoluteBlock(layout);
84         if(menus) ED_area_header_standardbuttons(C, block, 0);
85         else ED_area_header_switchbutton(C, block, 0);
86 }
87
88 /********************** Search Callbacks *************************/
89
90 typedef struct TemplateID {
91         PointerRNA ptr;
92         PropertyRNA *prop;
93
94         ListBase *idlb;
95         int prv_rows, prv_cols;
96 } TemplateID;
97
98 /* Search browse menu, assign  */
99 static void id_search_call_cb(bContext *C, void *arg_template, void *item)
100 {
101         TemplateID *template= (TemplateID*)arg_template;
102
103         /* ID */
104         if(item) {
105                 PointerRNA idptr;
106
107                 RNA_id_pointer_create(item, &idptr);
108                 RNA_property_pointer_set(&template->ptr, template->prop, idptr);
109                 RNA_property_update(C, &template->ptr, template->prop);
110         }
111 }
112
113 /* ID Search browse menu, do the search */
114 static void id_search_cb(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
115 {
116         TemplateID *template= (TemplateID*)arg_template;
117         ListBase *lb= template->idlb;
118         ID *id, *id_from= template->ptr.id.data;
119         int iconid;
120         int flag= RNA_property_flag(template->prop);
121
122         /* ID listbase */
123         for(id= lb->first; id; id= id->next) {
124                 if(!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
125
126                         /* use filter */
127                         if(RNA_property_type(template->prop)==PROP_POINTER) {
128                                 PointerRNA ptr;
129                                 RNA_id_pointer_create(id, &ptr);
130                                 if(RNA_property_pointer_poll(&template->ptr, template->prop, &ptr)==0)
131                                         continue;
132                         }
133
134                         /* hide dot-datablocks, but only if filter does not force it visible */
135                         if(U.uiflag & USER_HIDE_DOT)
136                                 if ((id->name[2]=='.') && (str[0] != '.'))
137                                         continue;
138
139                         if(BLI_strcasestr(id->name+2, str)) {
140                                 char name_ui[32];
141                                 name_uiprefix_id(name_ui, id);
142
143                                 iconid= ui_id_icon_get((bContext*)C, id, 1);
144
145                                 if(!uiSearchItemAdd(items, name_ui, id, iconid))
146                                         break;
147                         }
148                 }
149         }
150 }
151
152 /* ID Search browse menu, open */
153 static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
154 {
155         static char search[256];
156         static TemplateID template;
157         PointerRNA idptr;
158         wmWindow *win= CTX_wm_window(C);
159         uiBlock *block;
160         uiBut *but;
161         
162         /* clear initial search string, then all items show */
163         search[0]= 0;
164         /* arg_litem is malloced, can be freed by parent button */
165         template= *((TemplateID*)arg_litem);
166         
167         /* get active id for showing first item */
168         idptr= RNA_property_pointer_get(&template.ptr, template.prop);
169
170         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
171         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
172         
173         /* preview thumbnails */
174         if (template.prv_rows > 0 && template.prv_cols > 0) {
175                 int w = 96 * template.prv_cols;
176                 int h = 96 * template.prv_rows + 20;
177                 
178                 /* fake button, it holds space for search items */
179                 uiDefBut(block, LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
180                 
181                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, w, 19, template.prv_rows, template.prv_cols, "");
182                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
183         }
184         /* list view */
185         else {
186                 /* fake button, it holds space for search items */
187                 uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
188                 
189                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, 0, 0, "");
190                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
191         }
192                 
193         
194         uiBoundsBlock(block, 6);
195         uiBlockSetDirection(block, UI_DOWN);    
196         uiEndBlock(C, block);
197         
198         /* give search-field focus */
199         uiButSetFocusOnEnter(win, but);
200         /* this type of search menu requires undo */
201         but->flag |= UI_BUT_UNDO;
202         
203         return block;
204 }
205
206 /************************ ID Template ***************************/
207 /* This is for browsing and editing the ID-blocks used */
208
209 /* for new/open operators */
210 void uiIDContextProperty(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
211 {
212         TemplateID *template;
213         ARegion *ar= CTX_wm_region(C);
214         uiBlock *block;
215         uiBut *but;
216
217         memset(ptr, 0, sizeof(*ptr));
218         *prop= NULL;
219
220         if(!ar)
221                 return;
222
223         for(block=ar->uiblocks.first; block; block=block->next) {
224                 for(but=block->buttons.first; but; but= but->next) {
225                         /* find the button before the active one */
226                         if((but->flag & (UI_BUT_LAST_ACTIVE|UI_ACTIVE))) {
227                                 if(but->func_argN) {
228                                         template= but->func_argN;
229                                         *ptr= template->ptr;
230                                         *prop= template->prop;
231                                         return;
232                                 }
233                         }
234                 }
235         }
236 }
237
238
239 static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
240 {
241         TemplateID *template= (TemplateID*)arg_litem;
242         PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
243         ID *id= idptr.data;
244         int event= GET_INT_FROM_POINTER(arg_event);
245         
246         switch(event) {
247                 case UI_ID_BROWSE:
248                 case UI_ID_PIN:
249                         RNA_warning("warning, id event %d shouldnt come here", event);
250                         break;
251                 case UI_ID_OPEN:
252                 case UI_ID_ADD_NEW:
253                         /* these call uiIDContextPropertySet */
254                         break;
255                 case UI_ID_DELETE:
256                         memset(&idptr, 0, sizeof(idptr));
257                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
258                         RNA_property_update(C, &template->ptr, template->prop);
259
260                         if(id && CTX_wm_window(C)->eventstate->shift) /* useful hidden functionality, */
261                                 id->us= 0;
262
263                         break;
264                 case UI_ID_FAKE_USER:
265                         if(id) {
266                                 if(id->flag & LIB_FAKEUSER) id_us_plus(id);
267                                 else id_us_min(id);
268                         }
269                         else return;
270                         break;
271                 case UI_ID_LOCAL:
272                         if(id) {
273                                 if(id_make_local(id, 0)) {
274                                         /* reassign to get get proper updates/notifiers */
275                                         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
276                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
277                                         RNA_property_update(C, &template->ptr, template->prop);
278                                 }
279                         }
280                         break;
281                 case UI_ID_ALONE:
282                         if(id) {
283                                 const int do_scene_obj= (GS(id->name) == ID_OB) &&
284                                                         (template->ptr.type == &RNA_SceneObjects);
285
286                                 /* make copy */
287                                 if(do_scene_obj) {
288                                         Scene *scene= CTX_data_scene(C);
289                                         ED_object_single_user(scene, (struct Object *)id);
290                                         WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
291                                 }
292                                 else {
293                                         if(id) {
294                                                 id_single_user(C, id, &template->ptr, template->prop);
295                                         }
296                                 }
297                         }
298                         break;
299 #if 0
300                 case UI_ID_AUTO_NAME:
301                         break;
302 #endif
303         }
304 }
305
306 static const char *template_id_browse_tip(StructRNA *type)
307 {
308         if(type) {
309                 switch(RNA_type_to_ID_code(type)) {
310                         case ID_SCE: return N_("Browse Scene to be linked");
311                         case ID_OB: return N_("Browse Object to be linked");
312                         case ID_ME: return N_("Browse Mesh Data to be linked");
313                         case ID_CU: return N_("Browse Curve Data to be linked");
314                         case ID_MB: return N_("Browse MetaBall Data to be linked");
315                         case ID_MA: return N_("Browse Material to be linked");
316                         case ID_TE: return N_("Browse Texture to be linked");
317                         case ID_IM: return N_("Browse Image to be linked");
318                         case ID_LT: return N_("Browse Lattice Data to be linked");
319                         case ID_LA: return N_("Browse Lamp Data to be linked");
320                         case ID_CA: return N_("Browse Camera Data to be linked");
321                         case ID_WO: return N_("Browse World Settings to be linked");
322                         case ID_SCR: return N_("Choose Screen lay-out");
323                         case ID_TXT: return N_("Browse Text to be linked");
324                         case ID_SPK: return N_("Browse Speaker Data to be linked");
325                         case ID_SO: return N_("Browse Sound to be linked");
326                         case ID_AR: return N_("Browse Armature data to be linked");
327                         case ID_AC: return N_("Browse Action to be linked");
328                         case ID_NT: return N_("Browse Node Tree to be linked");
329                         case ID_BR: return N_("Browse Brush to be linked");
330                         case ID_PA: return N_("Browse Particle System to be linked");
331                         case ID_GD: return N_("Browse Grease Pencil Data to be linked");
332                 }
333         }
334         return N_("Browse ID data to be linked");
335 }
336
337 static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, const char *newop, const char *openop, const char *unlinkop)
338 {
339         uiBut *but;
340         uiBlock *block;
341         PointerRNA idptr;
342         // ListBase *lb; // UNUSED
343         ID *id, *idfrom;
344         int editable= RNA_property_editable(&template->ptr, template->prop);
345
346         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
347         id= idptr.data;
348         idfrom= template->ptr.id.data;
349         // lb= template->idlb;
350
351         block= uiLayoutGetBlock(layout);
352         uiBlockBeginAlign(block);
353
354         if(idptr.type)
355                 type= idptr.type;
356
357         if(flag & UI_ID_PREVIEWS) {
358
359                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6,
360                                 UI_translate_do_tooltip(template_id_browse_tip(type)));
361                 if(type) {
362                         but->icon= RNA_struct_ui_icon(type);
363                         if (id) but->icon = ui_id_icon_get(C, id, 1);
364                         uiButSetFlag(but, UI_HAS_ICON|UI_ICON_PREVIEW);
365                 }
366                 if((idfrom && idfrom->lib) || !editable)
367                         uiButSetFlag(but, UI_BUT_DISABLED);
368                 
369                 uiLayoutRow(layout, 1);
370         }
371         else if(flag & UI_ID_BROWSE) {
372                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*1.6, UI_UNIT_Y,
373                                 UI_translate_do_tooltip(template_id_browse_tip(type)));
374                 if(type) {
375                         but->icon= RNA_struct_ui_icon(type);
376                         /* default dragging of icon for id browse buttons */
377                         uiButSetDragID(but, id);
378                         uiButSetFlag(but, UI_HAS_ICON|UI_ICON_LEFT);
379                 }
380
381                 if((idfrom && idfrom->lib) || !editable)
382                         uiButSetFlag(but, UI_BUT_DISABLED);
383         }
384
385         /* text button with name */
386         if(id) {
387                 char name[UI_MAX_NAME_STR];
388                 const short user_alert= (id->us <= 0);
389
390                 //text_idbutton(id, name);
391                 name[0]= '\0';
392                 but= uiDefButR(block, TEX, 0, name, 0, 0, UI_UNIT_X*6, UI_UNIT_Y, &idptr, "name", -1, 0, 0, -1, -1, NULL);
393                 uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
394                 if(user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
395
396                 if(id->lib) {
397                         if(id->flag & LIB_INDIRECT) {
398                                 but= uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_INDIRECT, 0,0,UI_UNIT_X,UI_UNIT_Y, NULL, 0, 0, 0, 0,
399                                         UI_translate_do_tooltip(N_("Indirect library datablock, cannot change")));
400                                 uiButSetFlag(but, UI_BUT_DISABLED);
401                         }
402                         else {
403                                 but= uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0,0,UI_UNIT_X,UI_UNIT_Y, NULL, 0, 0, 0, 0,
404                                         UI_translate_do_tooltip(N_("Direct linked library datablock, click to make local")));
405                                 if(!id_make_local(id, 1 /* test */) || (idfrom && idfrom->lib))
406                                         uiButSetFlag(but, UI_BUT_DISABLED);
407                         }
408
409                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL));
410                 }
411
412                 if(id->us > 1) {
413                         char str[32];
414
415                         BLI_snprintf(str, sizeof(str), "%d", id->us);
416
417                         but= uiDefBut(block, BUT, 0, str, 0,0,UI_UNIT_X + ((id->us < 10) ? 0:10), UI_UNIT_Y, NULL, 0, 0, 0, 0,
418                                                 UI_translate_do_tooltip(_("Displays number of users of this data. Click to make a single-user copy")));
419
420                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
421                         if(!id_copy(id, NULL, 1 /* test only */) || (idfrom && idfrom->lib) || !editable)
422                                 uiButSetFlag(but, UI_BUT_DISABLED);
423                 }
424         
425                 if(user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
426                 
427                 if(id->lib == NULL && !(ELEM5(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
428                         uiDefButR(block, TOG, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
429                 }
430         }
431         
432         if(flag & UI_ID_ADD_NEW) {
433                 int w= id?UI_UNIT_X: (flag & UI_ID_OPEN)? UI_UNIT_X*3: UI_UNIT_X*6;
434                 
435                 if(newop) {
436                         but= uiDefIconTextButO(block, BUT, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, (id)? "": UI_translate_do_iface(N_("New")), 0, 0, w, UI_UNIT_Y, NULL);
437                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
438                 }
439                 else {
440                         but= uiDefIconTextBut(block, BUT, 0, ICON_ZOOMIN, (id)? "": _("New"), 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
441                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
442                 }
443
444                 if((idfrom && idfrom->lib) || !editable)
445                         uiButSetFlag(but, UI_BUT_DISABLED);
446         }
447
448         if(flag & UI_ID_OPEN) {
449                 int w= id?UI_UNIT_X: (flag & UI_ID_ADD_NEW)? UI_UNIT_X*3: UI_UNIT_X*6;
450                 
451                 if(openop) {
452                         but= uiDefIconTextButO(block, BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id)? "": UI_translate_do_iface(N_("Open")), 0, 0, w, UI_UNIT_Y, NULL);
453                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
454                 }
455                 else {
456                         but= uiDefIconTextBut(block, BUT, 0, ICON_FILESEL, (id)? "": UI_translate_do_iface(N_("Open")), 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
457                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
458                 }
459
460                 if((idfrom && idfrom->lib) || !editable)
461                         uiButSetFlag(but, UI_BUT_DISABLED);
462         }
463         
464         /* delete button */
465         if(id && (flag & UI_ID_DELETE) && (RNA_property_flag(template->prop) & PROP_NEVER_UNLINK)==0) {
466                 if(unlinkop) {
467                         but= uiDefIconButO(block, BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
468                         /* so we can access the template from operators, font unlinking needs this */
469                         uiButSetNFunc(but, NULL, MEM_dupallocN(template), NULL);
470                 }
471                 else {
472                         but= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
473                                         UI_translate_do_tooltip(N_("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("pointer property not found: %s.%s", 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("pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
558                 return;
559         }
560         if (!propType || RNA_property_type(propType) != PROP_ENUM) { 
561                 RNA_warning("pointer-type property not found: %s.%s", 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("path property not found: %s.%s", 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                 BLI_snprintf(str, sizeof(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, UI_translate_do_iface(N_("Make Real")), 0, 0, 80, 16, NULL, 0.0, 0.0, 0.0, 0.0,
731                                         UI_translate_do_tooltip(N_("Convert virtual modifier to a real modifier")));
732                 uiButSetFunc(but, modifiers_convertToReal, ob, md);
733         }
734         else {
735                 /* REAL MODIFIER */
736                 row = uiLayoutRow(box, 0);
737                 block = uiLayoutGetBlock(row);
738                 
739                 uiBlockSetEmboss(block, UI_EMBOSSN);
740                 /* Open/Close .................................  */
741                 uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE);
742                 
743                 /* modifier-type icon */
744                 uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
745                 uiBlockSetEmboss(block, UI_EMBOSS);
746                 
747                 /* modifier name */
748                 uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
749                 
750                 /* mode enabling buttons */
751                 uiBlockBeginAlign(block);
752                 /* Softbody not allowed in this situation, enforce! */
753                 if ( ((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) 
754                         && (md->type!=eModifierType_Surface) ) 
755                 {
756                         uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
757                         uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE);
758                         
759                         if (mti->flags & eModifierTypeFlag_SupportsEditmode)
760                                 uiItemR(row, &ptr, "show_in_editmode", 0, "", ICON_NONE);
761                 }
762                 if ((ob->type==OB_MESH) && modifier_couldBeCage(scene, md) && (index <= lastCageIndex)) 
763                 {
764                         /* -- convert to rna ? */
765                         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,
766                                         UI_translate_do_tooltip(N_("Apply modifier to editing cage during Editmode")));
767                         if (index < cageIndex)
768                                 uiButSetFlag(but, UI_BUT_DISABLED);
769                         uiButSetFunc(but, modifiers_setOnCage, ob, md);
770                 }
771
772                 /* tesselation point for curve-typed objects */
773                 if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
774                         /* some modifiers could work with pre-tesselated curves only */
775                         if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
776                                 /* add disabled pre-tesselated button, so users could have
777                                    message for this modifiers */
778                                 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,
779                                                 UI_translate_do_tooltip(N_("This modifier could be applied on splines' points only")));
780                                 uiButSetFlag(but, UI_BUT_DISABLED);
781                         } else if (mti->type != eModifierTypeType_Constructive) {
782                                 /* constructive modifiers tesselates curve before applying */
783                                 uiItemR(row, &ptr, "use_apply_on_spline", 0, "", ICON_NONE);
784                         }
785                 }
786
787                 uiBlockEndAlign(block);
788                 
789                 /* Up/Down + Delete ........................... */
790                 uiBlockBeginAlign(block);
791                 uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_modifier_move_up");
792                 uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_modifier_move_down");
793                 uiBlockEndAlign(block);
794                 
795                 uiBlockSetEmboss(block, UI_EMBOSSN);
796                 // When Modifier is a simulation, show button to switch to context rather than the delete button. 
797                 if (modifier_can_delete(md) && !modifier_is_simulation(md))
798                         uiItemO(row, "", ICON_X, "OBJECT_OT_modifier_remove");
799                 if (modifier_is_simulation(md) == 1)
800                         uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PHYSICS");
801                 else if (modifier_is_simulation(md) == 2)
802                         uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PARTICLES");
803                 uiBlockSetEmboss(block, UI_EMBOSS);
804         }
805
806         
807         /* modifier settings (under the header) --------------------------------------------------- */
808         if (!isVirtual && (md->mode & eModifierMode_Expanded)) {
809                 /* apply/convert/copy */
810                 box= uiLayoutBox(column);
811                 row= uiLayoutRow(box, 0);
812                 
813                 if (!ELEM(md->type, eModifierType_Collision, eModifierType_Surface)) {
814                         /* only here obdata, the rest of modifiers is ob level */
815                         uiBlockSetButLock(block, object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
816                         
817                         if (md->type==eModifierType_ParticleSystem) {
818                                 ParticleSystem *psys= ((ParticleSystemModifierData *)md)->psys;
819                                 
820                                 if (!(ob->mode & OB_MODE_PARTICLE_EDIT) && psys->pathcache) {
821                                         if(ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB))
822                                                 uiItemO(row, "Convert", ICON_NONE, "OBJECT_OT_duplicates_make_real");
823                                         else if(psys->part->ren_as == PART_DRAW_PATH)
824                                                 uiItemO(row, "Convert", ICON_NONE, "OBJECT_OT_modifier_convert");
825                                 }
826                         }
827                         else {
828                                 uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
829                                 uiItemEnumO(row, "OBJECT_OT_modifier_apply", UI_translate_do_iface(N_("Apply")), 0, "apply_as", MODIFIER_APPLY_DATA);
830                                 
831                                 if (modifier_sameTopology(md))
832                                         uiItemEnumO(row, "OBJECT_OT_modifier_apply", UI_translate_do_iface(N_("Apply as Shape")), 0, "apply_as", MODIFIER_APPLY_SHAPE);
833                         }
834                         
835                         uiBlockClearButLock(block);
836                         uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
837                         
838                         if (!ELEM5(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, eModifierType_Cloth, eModifierType_Smoke))
839                                 uiItemO(row, UI_translate_do_tooltip(N_("Copy")), ICON_NONE, "OBJECT_OT_modifier_copy");
840                 }
841                 
842                 /* result is the layout block inside the box, that we return so that modifier settings can be drawn */
843                 result= uiLayoutColumn(box, 0);
844                 block= uiLayoutAbsoluteBlock(box);
845         }
846         
847         /* error messages */
848         if(md->error) {
849                 box = uiLayoutBox(column);
850                 row = uiLayoutRow(box, 0);
851                 uiItemL(row, md->error, ICON_ERROR);
852         }
853         
854         return result;
855 }
856
857 uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
858 {
859         Scene *scene = CTX_data_scene(C);
860         Object *ob;
861         ModifierData *md, *vmd;
862         int i, lastCageIndex, cageIndex;
863
864         /* verify we have valid data */
865         if(!RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
866                 RNA_warning("Expected modifier on object");
867                 return NULL;
868         }
869
870         ob= ptr->id.data;
871         md= ptr->data;
872
873         if(!ob || !(GS(ob->id.name) == ID_OB)) {
874                 RNA_warning("Expected modifier on object");
875                 return NULL;
876         }
877         
878         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
879         
880         /* find modifier and draw it */
881         cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
882
883         // XXX virtual modifiers are not accesible for python
884         vmd = modifiers_getVirtualModifierList(ob);
885
886         for(i=0; vmd; i++, vmd=vmd->next) {
887                 if(md == vmd)
888                         return draw_modifier(layout, scene, ob, md, i, cageIndex, lastCageIndex);
889                 else if(vmd->mode & eModifierMode_Virtual)
890                         i--;
891         }
892
893         return NULL;
894 }
895
896 /************************ Constraint Template *************************/
897
898 #include "DNA_constraint_types.h"
899
900 #include "BKE_action.h"
901 #include "BKE_constraint.h"
902
903 #define REDRAWIPO                                       1
904 #define REDRAWNLA                                       2
905 #define REDRAWBUTSOBJECT                        3               
906 #define REDRAWACTION                            4
907 #define B_CONSTRAINT_TEST                       5
908 #define B_CONSTRAINT_CHANGETARGET       6
909 #define REMAKEIPO                                       8
910 #define B_DIFF                                          9
911
912 static void do_constraint_panels(bContext *C, void *ob_pt, int event)
913 {
914         Main *bmain= CTX_data_main(C);
915         Scene *scene= CTX_data_scene(C);
916         Object *ob= (Object *)ob_pt;
917         
918         switch(event) {
919         case B_CONSTRAINT_TEST:
920                 break;  // no handling
921         case B_CONSTRAINT_CHANGETARGET:
922                 if (ob->pose) ob->pose->flag |= POSE_RECALC;    // checks & sorts pose channels
923                 DAG_scene_sort(bmain, scene);
924                 break;
925         default:
926                 break;
927         }
928
929         // note: RNA updates now call this, commenting else it gets called twice.
930         // if there are problems because of this, then rna needs changed update functions.
931         // 
932         // object_test_constraints(ob);
933         // if(ob->pose) update_pose_constraint_flags(ob->pose);
934         
935         if(ob->type==OB_ARMATURE) DAG_id_tag_update(&ob->id, OB_RECALC_DATA|OB_RECALC_OB);
936         else DAG_id_tag_update(&ob->id, OB_RECALC_OB);
937
938         WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
939 }
940
941 static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
942 {
943         ED_object_constraint_set_active(ob_v, con_v);
944 }
945
946 /* draw panel showing settings for a constraint */
947 static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
948 {
949         bPoseChannel *pchan= get_active_posechannel(ob);
950         bConstraintTypeInfo *cti;
951         uiBlock *block;
952         uiLayout *result= NULL, *col, *box, *row;
953         PointerRNA ptr;
954         char typestr[32];
955         short proxy_protected, xco=0, yco=0;
956         // int rb_col; // UNUSED
957
958         /* get constraint typeinfo */
959         cti= constraint_get_typeinfo(con);
960         if (cti == NULL) {
961                 /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
962                 BLI_strncpy(typestr, (con->type == CONSTRAINT_TYPE_NULL) ? "Null" : "Unknown", sizeof(typestr));
963         }
964         else
965                 BLI_strncpy(typestr, cti->name, sizeof(typestr));
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, UI_translate_do_tooltip(N_("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, UI_translate_do_tooltip(N_("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("Expected constraint on object");
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("Expected constraint on object");
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("Expected ID of type material, texture, lamp or world");
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, UI_translate_do_iface(N_("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, UI_translate_do_iface(N_("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, UI_translate_do_iface(N_("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, UI_translate_do_iface(N_("World")),  0, 0,UI_UNIT_X*10,UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1207                         uiDefButS(block, ROW, B_MATPRV, UI_translate_do_iface(N_("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,     UI_translate_do_iface(N_("Add")), 0+xoffs,line1_y,40,UI_UNIT_Y, NULL, 0, 0, 0, 0,
1299                         UI_translate_do_tooltip(N_("Add a new color stop to the colorband")));
1300         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1301
1302         bt= uiDefBut(block, BUT, 0,     UI_translate_do_iface(N_("Delete")), 45+xoffs,line1_y,45,UI_UNIT_Y, NULL, 0, 0, 0, 0,
1303                         UI_translate_do_tooltip(N_("Delete the active position")));
1304         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1305
1306
1307         /* XXX, todo for later - convert to operator - campbell */
1308         bt= uiDefBut(block, BUT, 0,     "F",            95+xoffs,line1_y,20,UI_UNIT_Y, NULL, 0, 0, 0, 0, UI_translate_do_tooltip(N_("Flip colorband")));
1309         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1310
1311         uiDefButS(block, NUM, 0,                "",                             120+xoffs,line1_y,80, UI_UNIT_Y, &coba->cur, 0.0, (float)(MAX2(0, coba->tot-1)), 0, 0, UI_translate_do_tooltip(N_("Choose active color stop")));
1312
1313         bt= uiDefButS(block, MENU, 0,           UI_translate_do_iface(N_("Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4")),
1314                         210+xoffs, line1_y, 90, UI_UNIT_Y,              &coba->ipotype, 0.0, 0.0, 0, 0, UI_translate_do_tooltip(N_("Set interpolation between color stops")));
1315         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1316         uiBlockEndAlign(block);
1317
1318         bt= uiDefBut(block, BUT_COLORBAND, 0, "",       xoffs,line2_y,300,UI_UNIT_Y, coba, 0, 0, 0, 0, "");
1319         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1320
1321
1322
1323         if(coba->tot) {
1324                 CBData *cbd= coba->data + coba->cur;
1325
1326                 /* better to use rna so we can animate them */
1327                 PointerRNA ptr;
1328                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1329                 row= uiLayoutRow(layout, 0);
1330                 uiItemR(row, &ptr, "position", 0, "Pos", ICON_NONE);
1331                 uiItemR(row, &ptr, "color", 0, "", ICON_NONE);
1332         }
1333
1334 }
1335
1336 static void colorband_buttons_small(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb)
1337 {
1338         uiBut *bt;
1339         float unit= (butr->xmax-butr->xmin)/14.0f;
1340         float xs= butr->xmin;
1341
1342         uiBlockBeginAlign(block);
1343         bt= uiDefBut(block, BUT, 0,     UI_translate_do_iface(N_("Add")), xs,butr->ymin+UI_UNIT_Y,2.0f*unit,UI_UNIT_Y,  NULL, 0, 0, 0, 0,
1344                         UI_translate_do_tooltip(N_("Add a new color stop to the colorband")));
1345         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1346         bt= uiDefBut(block, BUT, 0,     UI_translate_do_iface(N_("Delete")), xs+2.0f*unit,butr->ymin+UI_UNIT_Y,1.5f*unit,UI_UNIT_Y,     NULL, 0, 0, 0, 0,
1347                      UI_translate_do_tooltip(N_("Delete the active position")));
1348         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1349         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, UI_translate_do_tooltip(N_("Flip the color ramp")));
1350         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1351         uiBlockEndAlign(block);
1352
1353         if(coba->tot) {
1354                 CBData *cbd= coba->data + coba->cur;
1355                 PointerRNA ptr;
1356                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1357                 uiItemR(layout, &ptr, "color", 0, "", ICON_NONE);
1358         }
1359
1360         bt= uiDefButS(block, MENU, 0, UI_translate_do_tooltip(N_("Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4")),
1361                         xs+10.0f*unit, butr->ymin+UI_UNIT_Y, unit*4, UI_UNIT_Y,         &coba->ipotype, 0.0, 0.0, 0, 0,
1362                         UI_translate_do_tooltip(N_("Set interpolation between color stops")));
1363         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1364
1365         bt= uiDefBut(block, BUT_COLORBAND, 0, "",               xs,butr->ymin,butr->xmax-butr->xmin,UI_UNIT_Y, coba, 0, 0, 0, 0, "");
1366         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1367
1368         uiBlockEndAlign(block);
1369 }
1370
1371 static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, int small, RNAUpdateCb *cb)
1372 {
1373         if(small)
1374                 colorband_buttons_small(layout, block, coba, butr, cb);
1375         else
1376                 colorband_buttons_large(layout, block, coba, 0, 0, cb);
1377 }
1378
1379 void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, int expand)
1380 {
1381         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1382         PointerRNA cptr;
1383         RNAUpdateCb *cb;
1384         uiBlock *block;
1385         rctf rect;
1386
1387         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1388                 return;
1389
1390         cptr= RNA_property_pointer_get(ptr, prop);
1391         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp))
1392                 return;
1393
1394         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1395         cb->ptr= *ptr;
1396         cb->prop= prop;
1397
1398         rect.xmin= 0; rect.xmax= 200;
1399         rect.ymin= 0; rect.ymax= 190;
1400
1401         block= uiLayoutAbsoluteBlock(layout);
1402         colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1403
1404         MEM_freeN(cb);
1405 }
1406
1407 /********************* Histogram Template ************************/
1408
1409 void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
1410 {
1411         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1412         PointerRNA cptr;
1413         RNAUpdateCb *cb;
1414         uiBlock *block;
1415         uiBut *bt;
1416         Histogram *hist;
1417         rctf rect;
1418         
1419         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1420                 return;
1421         
1422         cptr= RNA_property_pointer_get(ptr, prop);
1423         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Histogram))
1424                 return;
1425         
1426         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1427         cb->ptr= *ptr;
1428         cb->prop= prop;
1429         
1430         rect.xmin= 0; rect.xmax= 200;
1431         rect.ymin= 0; rect.ymax= 190;
1432         
1433         block= uiLayoutAbsoluteBlock(layout);
1434         //colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1435
1436         hist = (Histogram *)cptr.data;
1437
1438         hist->height= (hist->height<=UI_UNIT_Y)?UI_UNIT_Y:hist->height;
1439
1440         bt= uiDefBut(block, HISTOGRAM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, hist->height, hist, 0, 0, 0, 0, "");
1441         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1442
1443         MEM_freeN(cb);
1444 }
1445
1446 /********************* Waveform Template ************************/
1447
1448 void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
1449 {
1450         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1451         PointerRNA cptr;
1452         RNAUpdateCb *cb;
1453         uiBlock *block;
1454         uiBut *bt;
1455         Scopes *scopes;
1456         rctf rect;
1457         
1458         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1459                 return;
1460         
1461         cptr= RNA_property_pointer_get(ptr, prop);
1462         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1463                 return;
1464         scopes = (Scopes *)cptr.data;
1465         
1466         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1467         cb->ptr= *ptr;
1468         cb->prop= prop;
1469         
1470         rect.xmin= 0; rect.xmax= 200;
1471         rect.ymin= 0; rect.ymax= 190;
1472         
1473         block= uiLayoutAbsoluteBlock(layout);
1474         
1475         scopes->wavefrm_height= (scopes->wavefrm_height<=UI_UNIT_Y)?UI_UNIT_Y:scopes->wavefrm_height;
1476
1477         bt= uiDefBut(block, WAVEFORM, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->wavefrm_height, scopes, 0, 0, 0, 0, "");
1478         (void)bt; // UNUSED
1479         
1480         MEM_freeN(cb);
1481 }
1482
1483 /********************* Vectorscope Template ************************/
1484
1485 void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
1486 {
1487         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1488         PointerRNA cptr;
1489         RNAUpdateCb *cb;
1490         uiBlock *block;
1491         uiBut *bt;
1492         Scopes *scopes;
1493         rctf rect;
1494         
1495         if(!prop || RNA_property_type(prop) != PROP_POINTER)
1496                 return;
1497         
1498         cptr= RNA_property_pointer_get(ptr, prop);
1499         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1500                 return;
1501         scopes = (Scopes *)cptr.data;
1502
1503         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1504         cb->ptr= *ptr;
1505         cb->prop= prop;
1506         
1507         rect.xmin= 0; rect.xmax= 200;
1508         rect.ymin= 0; rect.ymax= 190;
1509         
1510         block= uiLayoutAbsoluteBlock(layout);
1511
1512         scopes->vecscope_height= (scopes->vecscope_height<=UI_UNIT_Y)?UI_UNIT_Y:scopes->vecscope_height;
1513         
1514         bt= uiDefBut(block, VECTORSCOPE, 0, "", rect.xmin, rect.ymin, rect.xmax-rect.xmin, scopes->vecscope_height, scopes, 0, 0, 0, 0, "");
1515         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1516         
1517         MEM_freeN(cb);
1518 }
1519
1520 /********************* CurveMapping Template ************************/
1521
1522
1523 static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *UNUSED(arg))
1524 {
1525         CurveMapping *cumap = cumap_v;
1526         float d;
1527
1528         /* we allow 20 times zoom */
1529         if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1530                 d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin);
1531                 cumap->curr.xmin+= d;
1532                 cumap->curr.xmax-= d;
1533                 d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin);
1534                 cumap->curr.ymin+= d;
1535                 cumap->curr.ymax-= d;
1536         }
1537
1538         ED_region_tag_redraw(CTX_wm_region(C));
1539 }
1540
1541 static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *UNUSED(unused))
1542 {
1543         CurveMapping *cumap = cumap_v;
1544         float d, d1;
1545
1546         /* we allow 20 times zoom, but dont view outside clip */
1547         if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
1548                 d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin);
1549
1550                 if(cumap->flag & CUMA_DO_CLIP) 
1551                         if(cumap->curr.xmin-d < cumap->clipr.xmin)
1552                                 d1= cumap->curr.xmin - cumap->clipr.xmin;
1553                 cumap->curr.xmin-= d1;
1554
1555                 d1= d;
1556                 if(cumap->flag & CUMA_DO_CLIP) 
1557                         if(cumap->curr.xmax+d > cumap->clipr.xmax)
1558                                 d1= -cumap->curr.xmax + cumap->clipr.xmax;
1559                 cumap->curr.xmax+= d1;
1560
1561                 d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin);
1562
1563                 if(cumap->flag & CUMA_DO_CLIP) 
1564                         if(cumap->curr.ymin-d < cumap->clipr.ymin)
1565                                 d1= cumap->curr.ymin - cumap->clipr.ymin;
1566                 cumap->curr.ymin-= d1;
1567
1568                 d1= d;
1569                 if(cumap->flag & CUMA_DO_CLIP) 
1570                         if(cumap->curr.ymax+d > cumap->clipr.ymax)
1571                                 d1= -cumap->curr.ymax + cumap->clipr.ymax;
1572                 cumap->curr.ymax+= d1;
1573         }
1574
1575         ED_region_tag_redraw(CTX_wm_region(C));
1576 }
1577
1578 static void curvemap_buttons_setclip(bContext *UNUSED(C), void *cumap_v, void *UNUSED(arg))
1579 {
1580         CurveMapping *cumap = cumap_v;
1581
1582         curvemapping_changed(cumap, 0);
1583 }       
1584
1585 static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v)
1586 {
1587         CurveMapping *cumap = cumap_v;
1588
1589         curvemap_remove(cumap->cm+cumap->cur, SELECT);
1590         curvemapping_changed(cumap, 0);
1591
1592         rna_update_cb(C, cb_v, NULL);
1593 }
1594
1595 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
1596 static uiBlock *curvemap_clipping_func(bContext *C, struct ARegion *ar, void *cumap_v)
1597 {
1598         CurveMapping *cumap = cumap_v;
1599         uiBlock *block;
1600         uiBut *bt;
1601         float width= 8*UI_UNIT_X;
1602
1603         block= uiBeginBlock(C, ar, "curvemap_clipping_func", UI_EMBOSS);
1604
1605         /* use this for a fake extra empy space around the buttons */
1606         uiDefBut(block, LABEL, 0, "",                   -4, 16, width+8, 6*UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
1607
1608         bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",    
1609                         0,5*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->flag, 0.0, 0.0, 10, 0, "");
1610         uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
1611
1612         uiBlockBeginAlign(block);
1613         uiDefButF(block, NUM, 0, UI_translate_do_iface(N_("Min X ")),    0,4*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 0, "");
1614         uiDefButF(block, NUM, 0, UI_translate_do_iface(N_("Min Y ")),    0,3*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 0, "");
1615         uiDefButF(block, NUM, 0, UI_translate_do_iface(N_("Max X ")),    0,2*UI_UNIT_Y,width,UI_UNIT_Y, &cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 0, "");
1616         uiDefButF(block, NUM, 0, UI_translate_do_iface(N_("Max Y ")),    0,UI_UNIT_Y,width,UI_UNIT_Y, &cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 0, "");
1617
1618         uiBlockSetDirection(block, UI_RIGHT);
1619
1620         uiEndBlock(C, block);
1621         return block;
1622 }
1623
1624 static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
1625 {
1626         CurveMapping *cumap = cumap_v;
1627         CurveMap *cuma= cumap->cm+cumap->cur;
1628
1629         switch(event) {
1630                 case 0: /* reset */
1631                         curvemap_reset(cuma, &cumap->clipr,     cumap->preset, CURVEMAP_SLOPE_POSITIVE);
1632                         curvemapping_changed(cumap, 0);
1633                         break;
1634                 case 1:
1635                         cumap->curr= cumap->clipr;
1636                         break;
1637                 case 2: /* set vector */
1638                         curvemap_sethandle(cuma, 1);
1639                         curvemapping_changed(cumap, 0);
1640                         break;
1641                 case 3: /* set auto */
1642                         curvemap_sethandle(cuma, 0);
1643                         curvemapping_changed(cumap, 0);
1644                         break;
1645                 case 4: /* extend horiz */
1646                         cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
1647                         curvemapping_changed(cumap, 0);
1648                         break;
1649                 case 5: /* extend extrapolate */
1650                         cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
1651                         curvemapping_changed(cumap, 0);
1652                         break;
1653         }
1654         ED_region_tag_redraw(CTX_wm_region(C));
1655 }
1656
1657 static uiBlock *curvemap_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1658 {
1659         uiBlock *block;
1660         short yco= 0, menuwidth=10*UI_UNIT_X;
1661
1662         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
1663         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1664
1665         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, UI_translate_do_iface(N_("Reset View")),                  0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 1, "");
1666         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, UI_translate_do_iface(N_("Vector Handle")),               0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 2, "");
1667         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, UI_translate_do_iface(N_("Auto Handle")),                 0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 3, "");
1668         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, UI_translate_do_iface(N_("Extend Horizontal")),   0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 4, "");
1669         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, UI_translate_do_iface(N_("Extend Extrapolated")), 0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 5, "");
1670         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, UI_translate_do_iface(N_("Reset Curve")),                 0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1671
1672         uiBlockSetDirection(block, UI_RIGHT);
1673         uiTextBoundsBlock(block, 50);
1674
1675         uiEndBlock(C, block);
1676         return block;
1677 }
1678
1679 static uiBlock *curvemap_brush_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
1680 {
1681         uiBlock *block;
1682         short yco= 0, menuwidth=10*UI_UNIT_X;
1683
1684         block= uiBeginBlock(C, ar, "curvemap_tools_func", UI_EMBOSS);
1685         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1686
1687         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, UI_translate_do_iface(N_("Reset View")),          0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 1, "");
1688         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, UI_translate_do_iface(N_("Vector Handle")),       0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 2, "");
1689         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, UI_translate_do_iface(N_("Auto Handle")),         0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 3, "");
1690         uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, UI_translate_do_iface(N_("Reset Curve")),         0, yco-=UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1691
1692         uiBlockSetDirection(block, UI_RIGHT);
1693         uiTextBoundsBlock(block, 50);
1694
1695         uiEndBlock(C, block);
1696         return block;
1697 }
1698
1699 static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
1700 {
1701         ED_region_tag_redraw(CTX_wm_region(C));
1702 }
1703
1704 static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
1705 {
1706         CurveMapping *cumap = cumap_v;
1707         int a;
1708         
1709         cumap->preset = CURVE_PRESET_LINE;
1710         for(a=0; a<CM_TOT; a++)
1711                 curvemap_reset(cumap->cm+a, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
1712         
1713         cumap->black[0]=cumap->black[1]=cumap->black[2]= 0.0f;
1714         cumap->white[0]=cumap->white[1]=cumap->white[2]= 1.0f;
1715         curvemapping_set_black_white(cumap, NULL, NULL);
1716         
1717         curvemapping_changed(cumap, 0);
1718
1719         rna_update_cb(C, cb_v, NULL);
1720 }
1721
1722 /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
1723 static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels, int brush, RNAUpdateCb *cb)
1724 {
1725         CurveMapping *cumap= ptr->data;
1726         uiLayout *row, *sub, *split;
1727         uiBlock *block;
1728         uiBut *bt;
1729         float dx= UI_UNIT_X;
1730         int icon, size;
1731         int bg=-1;
1732
1733         block= uiLayoutGetBlock(layout);
1734
1735         /* curve chooser */
1736         row= uiLayoutRow(layout, 0);
1737
1738         if(labeltype=='v') {
1739                 /* vector */
1740                 sub= uiLayoutRow(row, 1);
1741                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1742
1743                 if(cumap->cm[0].curve) {
1744                         bt= uiDefButI(block, ROW, 0, "X", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1745                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1746                 }
1747                 if(cumap->cm[1].curve) {
1748                         bt= uiDefButI(block, ROW, 0, "Y", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1749                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1750                 }
1751                 if(cumap->cm[2].curve) {
1752                         bt= uiDefButI(block, ROW, 0, "Z", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1753                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1754                 }
1755         }
1756         else if(labeltype=='c') {
1757                 /* color */
1758                 sub= uiLayoutRow(row, 1);
1759                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1760
1761                 if(cumap->cm[3].curve) {
1762                         bt= uiDefButI(block, ROW, 0, "C", 0, 0, dx, dx, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
1763                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1764                 }
1765                 if(cumap->cm[0].curve) {
1766                         bt= uiDefButI(block, ROW, 0, "R", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1767                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1768                 }
1769                 if(cumap->cm[1].curve) {
1770                         bt= uiDefButI(block, ROW, 0, "G", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1771                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1772                 }
1773                 if(cumap->cm[2].curve) {
1774                         bt= uiDefButI(block, ROW, 0, "B", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1775                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1776                 }
1777         }
1778         else if (labeltype == 'h') {
1779                 /* HSV */
1780                 sub= uiLayoutRow(row, 1);
1781                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1782                 
1783                 if(cumap->cm[0].curve) {
1784                         bt= uiDefButI(block, ROW, 0, "H", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1785                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1786                 }
1787                 if(cumap->cm[1].curve) {
1788                         bt= uiDefButI(block, ROW, 0, "S", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1789                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1790                 }
1791                 if(cumap->cm[2].curve) {
1792                         bt= uiDefButI(block, ROW, 0, "V", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1793                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1794                 }
1795         }
1796         else
1797                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
1798         
1799         if (labeltype=='h')
1800                 bg = UI_GRAD_H;
1801
1802         /* operation buttons */
1803         sub= uiLayoutRow(row, 1);
1804
1805         uiBlockSetEmboss(block, UI_EMBOSSN);
1806
1807         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, UI_translate_do_tooltip(N_("Zoom in")));
1808         uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
1809
1810         bt= uiDefIconBut(block, BUT, 0, ICON_ZOOMOUT, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, UI_translate_do_tooltip(N_("Zoom out")));
1811         uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
1812
1813         if(brush)
1814                 bt= uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, UI_translate_do_tooltip(N_("Tools")));
1815         else
1816                 bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, UI_translate_do_tooltip(N_("Tools")));
1817
1818         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1819
1820         if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT;
1821         bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, UI_translate_do_tooltip(N_("Clipping Options")));
1822         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1823
1824         bt= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, UI_translate_do_tooltip(N_("Delete points")));
1825         uiButSetNFunc(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
1826
1827         uiBlockSetEmboss(block, UI_EMBOSS);
1828
1829         uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
1830
1831         /* curve itself */
1832         size= uiLayoutGetWidth(layout);
1833         row= uiLayoutRow(layout, 0);
1834         uiDefBut(block, BUT_CURVE, 0, "", 0, 0, size, MIN2(size, 200), cumap, 0.0f, 1.0f, bg, 0, "");
1835
1836         /* black/white levels */
1837         if(levels) {
1838                 split= uiLayoutSplit(layout, 0, 0);
1839                 uiItemR(uiLayoutColumn(split, 0), ptr, "black_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1840                 uiItemR(uiLayoutColumn(split, 0), ptr, "white_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1841
1842                 uiLayoutRow(layout, 0);
1843                 bt=uiDefBut(block, BUT, 0, UI_translate_do_iface(N_("Reset")),  0, 0, UI_UNIT_X*10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
1844                                 UI_translate_do_tooltip(N_("Reset Black/White point and curves")));
1845                 uiButSetNFunc(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
1846         }
1847
1848         uiBlockSetNFunc(block, NULL, NULL, NULL);
1849 }
1850
1851 void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, int levels, int brush)
1852 {
1853         RNAUpdateCb *cb;
1854         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1855         PointerRNA cptr;
1856
1857         if(!prop) {
1858                 RNA_warning("curve property not found: %s.%s",
1859                             RNA_struct_identifier(ptr->type), propname);
1860                 return;
1861         }
1862
1863         if(RNA_property_type(prop) != PROP_POINTER) {
1864                 RNA_warning("curve is not a pointer: %s.%s",
1865                             RNA_struct_identifier(ptr->type), propname);
1866                 return;
1867         }
1868
1869         cptr= RNA_property_pointer_get(ptr, prop);
1870         if(!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveMapping))
1871                 return;
1872
1873         cb= MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1874         cb->ptr= *ptr;
1875         cb->prop= prop;
1876
1877         curvemap_buttons_layout(layout, &cptr, type, levels, brush, cb);
1878
1879         MEM_freeN(cb);
1880 }
1881
1882 /********************* ColorWheel Template ************************/
1883
1884 #define WHEEL_SIZE      100
1885
1886 void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic)
1887 {
1888         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1889         uiBlock *block= uiLayoutGetBlock(layout);
1890         uiLayout *col, *row;
1891         uiBut *but;
1892         float softmin, softmax, step, precision;
1893         
1894         if (!prop) {
1895                 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1896                 return;
1897         }
1898
1899         RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
1900         
1901         col = uiLayoutColumn(layout, 0);
1902         row= uiLayoutRow(col, 1);
1903         
1904         but= uiDefButR_prop(block, HSVCIRCLE, 0, "",    0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop, -1, 0.0, 0.0, 0, 0, "");
1905
1906         if(lock) {
1907                 but->flag |= UI_BUT_COLOR_LOCK;
1908         }
1909
1910         if(lock_luminosity) {
1911                 float color[4]; /* incase of alpha */
1912                 but->flag |= UI_BUT_VEC_SIZE_LOCK;
1913                 RNA_property_float_get_array(ptr, prop, color);
1914                 but->a2= len_v3(color);
1915         }
1916
1917         if(cubic)
1918                 but->flag |= UI_BUT_COLOR_CUBIC;
1919
1920         uiItemS(row);
1921         
1922         if (value_slider)
1923                 uiDefButR_prop(block, HSVCUBE, 0, "", WHEEL_SIZE+6, 0, 14, WHEEL_SIZE, ptr, prop, -1, softmin, softmax, UI_GRAD_V_ALT, 0, "");
1924 }
1925
1926 /********************* Layer Buttons Template ************************/
1927
1928 static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
1929 {
1930         uiBut *but = arg1;
1931         int cur = GET_INT_FROM_POINTER(arg2);
1932         wmWindow *win= CTX_wm_window(C);
1933         int i, tot, shift= win->eventstate->shift;
1934
1935         if(!shift) {
1936                 tot= RNA_property_array_length(&but->rnapoin, but->rnaprop);
1937                 
1938                 /* Normally clicking only selects one layer */
1939                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, 1);
1940                 for(i = 0; i < tot; ++i) {
1941                         if(i != cur)
1942                                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, 0);
1943                 }
1944         }
1945         
1946         /* view3d layer change should update depsgraph (invisible object changed maybe) */
1947         /* see view3d_header.c */
1948 }
1949
1950 // TODO:
1951 //      - for now, grouping of layers is determined by dividing up the length of 
1952 //        the array of layer bitflags
1953
1954 void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
1955                           PointerRNA *used_ptr, const char *used_propname, int active_layer)
1956 {
1957         uiLayout *uRow, *uCol;
1958         PropertyRNA *prop, *used_prop= NULL;
1959         int groups, cols, layers;
1960         int group, col, layer, row;
1961         int cols_per_group = 5;
1962
1963         prop= RNA_struct_find_property(ptr, propname);
1964         if (!prop) {
1965                 RNA_warning("layers property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1966                 return;
1967         }
1968         
1969         /* the number of layers determines the way we group them 
1970          *      - we want 2 rows only (for now)
1971          *      - the number of columns (cols) is the total number of buttons per row
1972          *        the 'remainder' is added to this, as it will be ok to have first row slightly wider if need be
1973          *      - for now, only split into groups if group will have at least 5 items
1974          */
1975         layers= RNA_property_array_length(ptr, prop);
1976         cols= (layers / 2) + (layers % 2);
1977         groups= ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group);
1978
1979         if(used_ptr && used_propname) {
1980                 used_prop= RNA_struct_find_property(used_ptr, used_propname);
1981                 if (!used_prop) {
1982                         RNA_warning("used layers property not found: %s.%s", RNA_struct_identifier(ptr->type), used_propname);
1983                         return;
1984                 }
1985
1986                 if(RNA_property_array_length(used_ptr, used_prop) < layers)
1987                         used_prop = NULL;
1988         }
1989         
1990         /* layers are laid out going across rows, with the columns being divided into groups */
1991         
1992         for (group= 0; group < groups; group++) {
1993                 uCol= uiLayoutColumn(layout, 1);
1994                 
1995                 for (row= 0; row < 2; row++) {
1996                         uiBlock *block;
1997                         uiBut *but;
1998
1999                         uRow= uiLayoutRow(uCol, 1);
2000                         block= uiLayoutGetBlock(uRow);
2001                         layer= groups*cols_per_group*row + cols_per_group*group;
2002                         
2003                         /* add layers as toggle buts */
2004                         for (col= 0; (col < cols_per_group) && (layer < layers); col++, layer++) {
2005                                 int icon = 0;
2006                                 int butlay = 1 << layer;
2007
2008                                 if(active_layer & butlay)
2009                                         icon = ICON_LAYER_ACTIVE;
2010                                 else if(used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, layer))
2011                                         icon = ICON_LAYER_USED;
2012                                 
2013                                 but= uiDefAutoButR(block, ptr, prop, layer, "", icon, 0, 0, UI_UNIT_X/2, UI_UNIT_Y/2);
2014                                 uiButSetFunc(but, handle_layer_buttons, but, SET_INT_IN_POINTER(layer));
2015                                 but->type= TOG;
2016                         }
2017                 }
2018         }
2019 }
2020
2021
2022 /************************* List Template **************************/
2023
2024 static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon, int big)
2025 {
2026         ID *id= NULL;
2027         int icon;
2028
2029         if(!itemptr->data)
2030                 return rnaicon;
2031
2032         /* try ID, material or texture slot */
2033         if(RNA_struct_is_ID(itemptr->type)) {
2034                 id= itemptr->id.data;
2035         }
2036         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2037                 id= RNA_pointer_get(itemptr, "material").data;
2038         }
2039         else if(RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) {
2040                 id= RNA_pointer_get(itemptr, "texture").data;
2041         }
2042
2043         /* get icon from ID */
2044         if(id) {
2045                 icon= ui_id_icon_get(C, id, big);
2046
2047                 if(icon)
2048                         return icon;
2049         }
2050
2051         return rnaicon;
2052 }
2053
2054 static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *itemptr, int i, int rnaicon, PointerRNA *activeptr, PropertyRNA *activeprop)
2055 {
2056         uiBlock *block= uiLayoutGetBlock(layout);
2057         uiBut *but;
2058         uiLayout *split, *overlap, *sub, *row;
2059         char *namebuf;
2060         const char *name;
2061         int icon;
2062
2063         overlap= uiLayoutOverlap(layout);
2064
2065         /* list item behind label & other buttons */
2066         sub= uiLayoutRow(overlap, 0);
2067
2068         but= uiDefButR_prop(block, LISTROW, 0, "", 0,0, UI_UNIT_X*10,UI_UNIT_Y, activeptr, activeprop, 0, 0, i, 0, 0, "");
2069         uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2070
2071         sub= uiLayoutRow(overlap, 0);
2072
2073         /* retrieve icon and name */
2074         icon= list_item_icon_get(C, itemptr, rnaicon, 0);
2075         if(icon == ICON_NONE || icon == ICON_DOT)
2076                 icon= 0;
2077
2078         namebuf= RNA_struct_name_get_alloc(itemptr, NULL, 0);
2079         name= (namebuf)? namebuf: "";
2080
2081         /* hardcoded types */
2082         if(itemptr->type == &RNA_MeshTextureFaceLayer || itemptr->type == &RNA_MeshColorLayer) {
2083                 uiItemL(sub, name, icon);
2084                 uiBlockSetEmboss(block, UI_EMBOSSN);
2085                 uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", 0, 0, 0, 0, 0, NULL);
2086                 uiBlockSetEmboss(block, UI_EMBOSS);
2087         }
2088         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) {
2089                 uiItemL(sub, name, icon);
2090                 uiBlockSetEmboss(block, UI_EMBOSS);
2091                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0,  NULL);
2092         }
2093         else if(RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
2094                 uiItemL(sub, name, icon);
2095                 uiBlockSetEmboss(block, UI_EMBOSS);
2096                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0,  NULL);
2097         }
2098         else if(RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2099                 /* provision to draw active node name */
2100                 Material *ma, *manode;
2101                 Object *ob= (Object*)ptr->id.data;
2102                 int index= (Material**)itemptr->data - ob->mat;
2103                 
2104                 /* default item with material base name */
2105                 uiItemL(sub, name, icon);
2106                 
2107                 ma= give_current_material(ob, index+1);
2108                 if(ma) {
2109                         manode= give_node_material(ma);
2110                         if(manode) {
2111                                 char str[MAX_ID_NAME + 12];
2112                                 BLI_snprintf(str, sizeof(str), "Node %s", manode->id.name+2);
2113                                 uiItemL(sub, str, ui_id_icon_get(C, &manode->id, 1));
2114                         }
2115                         else if(ma->use_nodes) {
2116                                 uiItemL(sub, "Node <none>", ICON_NONE);
2117                         }
2118                 }
2119         }
2120         else if(itemptr->type == &RNA_ShapeKey) {
2121                 Object *ob= (Object*)activeptr->data;
2122                 Key *key= (Key*)itemptr->id.data;
2123
2124                 split= uiLayoutSplit(sub, 0.75f, 0);
2125
2126                 uiItemL(split, name, icon);
2127
2128                 uiBlockSetEmboss(block, UI_EMBOSSN);
2129                 row= uiLayoutRow(split, 1);
2130                 if(i == 0 || (key->type != KEY_RELATIVE)) uiItemL(row, "", ICON_NONE);
2131                 else uiItemR(row, itemptr, "value", 0, "", ICON_NONE);
2132
2133                 if(ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH))
2134                         uiLayoutSetActive(row, 0);
2135                 //uiItemR(row, itemptr, "mute", 0, "", ICON_MUTE_IPO_OFF);
2136                 uiBlockSetEmboss(block, UI_EMBOSS);
2137         }
2138         else if(itemptr->type == &RNA_VertexGroup) {
2139                 bDeformGroup *dg= (bDeformGroup *)itemptr->data;
2140                 uiItemL(sub, name, icon);
2141                 /* RNA does not allow nice lock icons, use lower level buttons */
2142 #if 0
2143                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "lock_weight", 0, 0, 0, 0, 0,  NULL);
2144 #else
2145                 uiBlockSetEmboss(block, UI_EMBOSSN);
2146                 uiDefIconButBitC(block, TOG, DG_LOCK_WEIGHT, 0, (dg->flag & DG_LOCK_WEIGHT) ? ICON_LOCKED : ICON_UNLOCKED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &dg->flag, 0, 0, 0, 0, "Maintain relative weights while painting");
2147                 uiBlockSetEmboss(block, UI_EMBOSS);
2148 #endif
2149         }
2150         else if(itemptr->type == &RNA_KeyingSetPath) {
2151                 KS_Path *ksp = (KS_Path*)itemptr->data;
2152                 
2153                 /* icon needs to be the type of ID which is currently active */
2154                 RNA_enum_icon_from_value(id_type_items, ksp->idtype, &icon);
2155                 
2156                 /* nothing else special to do... */
2157                 uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
2158         }
2159         else
2160                 uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
2161
2162         /* free name */
2163         if(namebuf)
2164                 MEM_freeN(namebuf);
2165 }
2166
2167 void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *activeptr, const char *activepropname, int rows, int maxrows, int listtype)
2168 {
2169         //Scene *scene= CTX_data_scene(C);
2170         PropertyRNA *prop= NULL, *activeprop;
2171         PropertyType type, activetype;
2172         StructRNA *ptype;
2173         uiLayout *box, *row, *col;
2174         uiBlock *block;
2175         uiBut *but;
2176         Panel *pa;
2177         char *name, str[32];
2178         int rnaicon=0, icon=0, i= 0, activei= 0, len= 0, items, found, min, max;
2179
2180         /* validate arguments */
2181         block= uiLayoutGetBlock(layout);
2182         pa= block->panel;
2183
2184         if(!pa) {
2185                 RNA_warning("Only works inside a panel");
2186                 return;
2187         }
2188
2189         if(!activeptr->data)
2190                 return;
2191         
2192         if(ptr->data) {
2193                 prop= RNA_struct_find_property(ptr, propname);
2194                 if(!prop) {
2195                         RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2196                         return;
2197                 }
2198         }
2199
2200         activeprop= RNA_struct_find_property(activeptr, activepropname);
2201         if(!activeprop) {
2202                 RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), activepropname);
2203                 return;
2204         }
2205
2206         if(prop) {
2207                 type= RNA_property_type(prop);
2208                 if(type != PROP_COLLECTION) {
2209                         RNA_warning("uiExpected collection property");
2210                         return;
2211                 }
2212         }
2213
2214         activetype= RNA_property_type(activeprop);
2215         if(activetype != PROP_INT) {
2216                 RNA_warning("Expected integer property");
2217                 return;
2218         }
2219
2220         /* get icon */
2221         if(ptr->data && prop) {
2222                 ptype= RNA_property_pointer_type(ptr, prop);
2223                 rnaicon= RNA_struct_ui_icon(ptype);
2224         }
2225
2226         /* get active data */
2227         activei= RNA_property_int_get(activeptr, activeprop);
2228
2229         if(listtype == 'i') {
2230                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2231                 col= uiLayoutColumn(box, 1);
2232                 row= uiLayoutRow(col, 0);
2233
2234                 if(ptr->data && prop) {
2235                         /* create list items */
2236                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2237                                 /* create button */
2238                                 if(!(i % 9))
2239                                         row= uiLayoutRow(col, 0);
2240
2241                                 icon= list_item_icon_get(C, &itemptr, rnaicon, 1);
2242                                 but= uiDefIconButR_prop(block, LISTROW, 0, icon, 0,0,UI_UNIT_X*10,UI_UNIT_Y, activeptr, activeprop, 0, 0, i, 0, 0, "");
2243                                 uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2244                                 
2245
2246                                 i++;
2247                         }
2248                         RNA_PROP_END;
2249                 }
2250         }
2251         else if(listtype == 'c') {
2252                 /* compact layout */
2253
2254                 row= uiLayoutRow(layout, 1);
2255
2256                 if(ptr->data && prop) {
2257                         /* create list items */
2258                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2259                                 found= (activei == i);
2260
2261                                 if(found) {
2262                                         /* create button */
2263                                         name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
2264                                         icon= list_item_icon_get(C, &itemptr, rnaicon, 0);
2265                                         uiItemL(row, (name)? name: "", icon);
2266
2267                                         if(name)
2268                                                 MEM_freeN(name);
2269                                 }
2270
2271                                 i++;
2272                         }
2273                         RNA_PROP_END;
2274                 }
2275
2276                 /* if not found, add in dummy button */
2277                 if(i == 0)
2278                         uiItemL(row, "", ICON_NONE);
2279
2280                 /* next/prev button */
2281                 BLI_snprintf(str, sizeof(str), "%d :", i);
2282                 but= uiDefIconTextButR_prop(block, NUM, 0, 0, str, 0,0,UI_UNIT_X*5,UI_UNIT_Y, activeptr, activeprop, 0, 0, 0, 0, 0, "");
2283                 if(i == 0)
2284                         uiButSetFlag(but, UI_BUT_DISABLED);
2285         }
2286         else {
2287                 /* default rows */
2288                 if(rows == 0)
2289                         rows= 5;
2290                 if (maxrows == 0)
2291                         maxrows = 5;
2292                 if(pa->list_grip_size != 0)
2293                         rows= pa->list_grip_size;
2294
2295                 /* layout */
2296                 box= uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2297                 row= uiLayoutRow(box, 0);
2298                 col = uiLayoutColumn(row, 1);
2299
2300                 /* init numbers */
2301                 RNA_property_int_range(activeptr, activeprop, &min, &max);
2302
2303                 if(prop)
2304                         len= RNA_property_collection_length(ptr, prop);
2305                 items= CLAMPIS(len, rows, MAX2(rows, maxrows));
2306
2307                 /* if list length changes and active is out of view, scroll to it */
2308                 if(pa->list_last_len != len)
2309                         if((activei < pa->list_scroll || activei >= pa->list_scroll+items))
2310                                 pa->list_scroll= activei;
2311
2312                 pa->list_scroll= MIN2(pa->list_scroll, len-items);
2313                 pa->list_scroll= MAX2(pa->list_scroll, 0);
2314                 pa->list_size= items;
2315                 pa->list_last_len= len;
2316
2317                 if(ptr->data && prop) {
2318                         /* create list items */
2319                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
2320                                 if(i >= pa->list_scroll && i<pa->list_scroll+items)
2321                                         list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activeprop);
2322
2323                                 i++;
2324                         }
2325                         RNA_PROP_END;
2326                 }
2327
2328                 /* add dummy buttons to fill space */
2329                 while(i < pa->list_scroll+items) {
2330                         if(i >= pa->list_scroll)
2331                                 uiItemL(col, "", ICON_NONE);
2332                         i++;
2333                 }
2334
2335                 /* add scrollbar */
2336                 if(len > items) {
2337                         col= uiLayoutColumn(row, 0);
2338                         uiDefButI(block, SCROLL, 0, "", 0,0,UI_UNIT_X*0.75,UI_UNIT_Y*items, &pa->list_scroll, 0, len-items, items, 0, "");
2339                 }
2340         }
2341 }
2342
2343 /************************* Operator Search Template **************************/
2344
2345 static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
2346 {
2347         wmOperatorType *ot= arg2;
2348         
2349         if(ot)
2350                 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
2351 }
2352
2353 static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
2354 {
2355         GHashIterator *iter= WM_operatortype_iter();
2356
2357         for( ; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
2358                 wmOperatorType *ot= BLI_ghashIterator_getValue(iter);
2359
2360                 if(BLI_strcasestr(ot->name, str)) {
2361                         if(WM_operator_poll((bContext*)C, ot)) {
2362                                 char name[256];
2363                                 int len= strlen(ot->name);
2364                                 
2365                                 /* display name for menu, can hold hotkey */
2366                                 BLI_strncpy(name, ot->name, 256);
2367                                 
2368                                 /* check for hotkey */
2369                                 if(len < 256-6) {
2370                                         if(WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, &name[len+1], 256-len-1))
2371                                                 name[len]= '|';
2372                                 }
2373                                 
2374                                 if(0==uiSearchItemAdd(items, name, ot, 0))
2375                                         break;
2376                         }
2377                 }
2378         }
2379         BLI_ghashIterator_free(iter);
2380 }
2381
2382 void uiTemplateOperatorSearch(uiLayout *layout)
2383 {
2384         uiBlock *block;
2385         uiBut *but;
2386         static char search[256]= "";
2387                 
2388         block= uiLayoutGetBlock(layout);
2389         uiBlockSetCurLayout(block, layout);
2390
2391         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, 0, 0, "");
2392         uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
2393 }
2394
2395 /************************* Running Jobs Template **************************/
2396
2397 #define B_STOPRENDER    1
2398 #define B_STOPCAST              2
2399 #define B_STOPANIM              3
2400 #define B_STOPCOMPO             4
2401 #define B_STOPSEQ               5
2402 #define B_STOPCLIP              6
2403
2404 static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
2405 {
2406         switch(event) {
2407                 case B_STOPRENDER:
2408                         G.afbreek= 1;
2409                         break;
2410                 case B_STOPCAST:
2411                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C), NULL);
2412                         break;
2413                 case B_STOPANIM:
2414                         WM_operator_name_call(C, "SCREEN_OT_animation_play", WM_OP_INVOKE_SCREEN, NULL);
2415                         break;
2416                 case B_STOPCOMPO:
2417                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2418                         break;
2419                 case B_STOPSEQ:
2420                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2421                         break;
2422                 case B_STOPCLIP:
2423                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2424                         break;
2425         }
2426 }
2427
2428 void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
2429 {
2430         bScreen *screen= CTX_wm_screen(C);
2431         wmWindowManager *wm= CTX_wm_manager(C);
2432         ScrArea *sa= CTX_wm_area(C);
2433         uiBlock *block;
2434         void *owner= NULL;
2435         int handle_event;
2436         
2437         block= uiLayoutGetBlock(layout);
2438         uiBlockSetCurLayout(block, layout);
2439
2440         uiBlockSetHandleFunc(block, do_running_jobs, NULL);
2441
2442         if(sa->spacetype==SPACE_NODE) {
2443                 if(WM_jobs_test(wm, sa))
2444                    owner = sa;
2445                 handle_event= B_STOPCOMPO;
2446         } else if (sa->spacetype==SPACE_SEQ) {
2447                 if(WM_jobs_test(wm, sa))
2448                         owner = sa;
2449                 handle_event = B_STOPSEQ;
2450         } else if(sa->spacetype==SPACE_CLIP) {
2451                 if(WM_jobs_test(wm, sa))
2452                    owner = sa;
2453                 handle_event= B_STOPCLIP;
2454         } else {
2455                 Scene *scene;
2456                 /* another scene can be rendering too, for example via compositor */
2457                 for(scene= CTX_data_main(C)->scene.first; scene; scene= scene->id.next)
2458                         if(WM_jobs_test(wm, scene))
2459                                 break;
2460                 owner = scene;
2461                 handle_event= B_STOPRENDER;
2462         }
2463
2464         if(owner) {
2465                 uiLayout *ui_abs;
2466                 
2467                 ui_abs= uiLayoutAbsolute(layout, 0);
2468                 (void)ui_abs; // UNUSED
2469                 
2470                 uiDefIconBut(block, BUT, handle_event, ICON_PANEL_CLOSE, 
2471                                 0, UI_UNIT_Y*0.1, UI_UNIT_X*0.8, UI_UNIT_Y*0.8, NULL, 0.0f, 0.0f, 0, 0, UI_translate_do_tooltip(N_("Stop this job")));
2472                 uiDefBut(block, PROGRESSBAR, 0, WM_jobs_name(wm, owner), 
2473                                 UI_UNIT_X, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, UI_translate_do_tooltip(N_("Progress")));
2474                 
2475                 uiLayoutRow(layout, 0);
2476         }
2477         if(WM_jobs_test(wm, screen))
2478                 uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, UI_translate_do_iface(N_("Capture")), 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
2479                                 UI_translate_do_tooltip(N_("Stop screencast")));
2480         if(screen->animtimer)
2481                 uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_CANCEL, UI_translate_do_tooltip(N_("Anim Player")), 0,0,100,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
2482                                 UI_translate_do_tooltip(N_("Stop animation playback")));
2483 }
2484
2485 /************************* Reports for Last Operator Template **************************/
2486
2487 void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
2488 {
2489         ReportList *reports = CTX_wm_reports(C);
2490         Report *report= BKE_reports_last_displayable(reports);
2491         ReportTimerInfo *rti;
2492         
2493         uiLayout *ui_abs;
2494         uiBlock *block;
2495         uiBut *but;
2496         uiStyle *style= UI_GetStyle();
2497         int width;
2498         int icon=0;
2499         
2500         /* if the report display has timed out, don't show */
2501         if (!reports->reporttimer) return;
2502         
2503         rti= (ReportTimerInfo *)reports->reporttimer->customdata;
2504         
2505         if (!rti || rti->widthfac==0.0f || !report) return;
2506         
2507         ui_abs= uiLayoutAbsolute(layout, 0);
2508         block= uiLayoutGetBlock(ui_abs);
2509         
2510         width = BLF_width(style->widget.uifont_id, report->message);
2511         width = MIN2(rti->widthfac*width, width);
2512         width = MAX2(width, 10);
2513         
2514         /* make a box around the report to make it stand out */
2515         uiBlockBeginAlign(block);
2516         but= uiDefBut(block, ROUNDBOX, 0, "", 0, 0, UI_UNIT_X+10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2517         /* set the report's bg color in but->col - ROUNDBOX feature */
2518         but->col[0]= FTOCHAR(rti->col[0]);
2519         but->col[1]= FTOCHAR(rti->col[1]);
2520         but->col[2]= FTOCHAR(rti->col[2]);
2521         but->col[3]= 255; 
2522
2523         but= uiDefBut(block, ROUNDBOX, 0, "", UI_UNIT_X+10, 0, UI_UNIT_X+width, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2524         but->col[0]= but->col[1]= but->col[2]= FTOCHAR(rti->greyscale);
2525         but->col[3]= 255;
2526
2527         uiBlockEndAlign(block);
2528         
2529         
2530         /* icon and report message on top */
2531         if(report->type & RPT_ERROR_ALL)
2532                 icon = ICON_ERROR;
2533         else if(report->type & RPT_WARNING_ALL)
2534                 icon = ICON_ERROR;
2535         else if(report->type & RPT_INFO_ALL)
2536                 icon = ICON_INFO;
2537         
2538         /* XXX: temporary operator to dump all reports to a text block, but only if more than 1 report 
2539          * to be shown instead of icon when appropriate...
2540          */
2541         uiBlockSetEmboss(block, UI_EMBOSSN);
2542
2543         if (reports->list.first != reports->list.last)
2544                 uiDefIconButO(block, BUT, "UI_OT_reports_to_textblock", WM_OP_INVOKE_REGION_WIN, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, UI_translate_do_tooltip(N_("Click to see rest of reports in textblock: 'Recent Reports'")));
2545         else
2546                 uiDefIconBut(block, LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2547
2548         uiBlockSetEmboss(block, UI_EMBOSS);
2549         
2550         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, "");
2551 }
2552