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