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