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