code cleanup: remove unused macros, commet some which may be useful later - or good...
[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 B_CONSTRAINT_TEST           5
941 // #define B_CONSTRAINT_CHANGETARGET   6
942
943 static void do_constraint_panels(bContext *C, void *ob_pt, int event)
944 {
945         Object *ob = (Object *)ob_pt;
946
947         switch (event) {
948                 case B_CONSTRAINT_TEST:
949                         break; /* no handling */
950 #if 0   /* UNUSED */
951                 case B_CONSTRAINT_CHANGETARGET:
952                 {
953                         Main *bmain = CTX_data_main(C);
954                         Scene *scene = CTX_data_scene(C);
955                         if (ob->pose) ob->pose->flag |= POSE_RECALC;  /* checks & sorts pose channels */
956                         DAG_scene_sort(bmain, scene);
957                         break;
958                 }
959 #endif
960                 default:
961                         break;
962         }
963
964         /* note: RNA updates now call this, commenting else it gets called twice.
965          * if there are problems because of this, then rna needs changed update functions.
966          *
967          * object_test_constraints(ob);
968          * if (ob->pose) BKE_pose_update_constraint_flags(ob->pose); */
969         
970         if (ob->type == OB_ARMATURE) DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
971         else DAG_id_tag_update(&ob->id, OB_RECALC_OB);
972
973         WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
974 }
975
976 static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
977 {
978         ED_object_constraint_set_active(ob_v, con_v);
979 }
980
981 /* draw panel showing settings for a constraint */
982 static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
983 {
984         bPoseChannel *pchan = BKE_pose_channel_active(ob);
985         bConstraintTypeInfo *cti;
986         uiBlock *block;
987         uiLayout *result = NULL, *col, *box, *row;
988         PointerRNA ptr;
989         char typestr[32];
990         short proxy_protected, xco = 0, yco = 0;
991         // int rb_col; // UNUSED
992
993         /* get constraint typeinfo */
994         cti = constraint_get_typeinfo(con);
995         if (cti == NULL) {
996                 /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
997                 BLI_strncpy(typestr, (con->type == CONSTRAINT_TYPE_NULL) ? "Null" : "Unknown", sizeof(typestr));
998         }
999         else
1000                 BLI_strncpy(typestr, cti->name, sizeof(typestr));
1001                 
1002         /* determine whether constraint is proxy protected or not */
1003         if (proxylocked_constraints_owner(ob, pchan))
1004                 proxy_protected = (con->flag & CONSTRAINT_PROXY_LOCAL) == 0;
1005         else
1006                 proxy_protected = 0;
1007
1008         /* unless button has own callback, it adds this callback to button */
1009         block = uiLayoutGetBlock(layout);
1010         uiBlockSetHandleFunc(block, do_constraint_panels, ob);
1011         uiBlockSetFunc(block, constraint_active_func, ob, con);
1012
1013         RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
1014
1015         col = uiLayoutColumn(layout, TRUE);
1016         uiLayoutSetContextPointer(col, "constraint", &ptr);
1017
1018         box = uiLayoutBox(col);
1019         row = uiLayoutRow(box, FALSE);
1020         block = uiLayoutGetBlock(box);
1021
1022         /* Draw constraint header */
1023
1024         /* open/close */
1025         uiBlockSetEmboss(block, UI_EMBOSSN);
1026         uiItemR(row, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
1027         uiBlockSetEmboss(block, UI_EMBOSS);
1028         
1029         /* name */
1030         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco + 10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
1031
1032         if (con->flag & CONSTRAINT_DISABLE)
1033                 uiLayoutSetRedAlert(row, TRUE);
1034         
1035         if (proxy_protected == 0) {
1036                 uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
1037         }
1038         else
1039                 uiItemL(row, con->name, ICON_NONE);
1040         
1041         uiLayoutSetRedAlert(row, FALSE);
1042         
1043         /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
1044         if (proxy_protected) {
1045                 uiBlockSetEmboss(block, UI_EMBOSSN);
1046                 
1047                 /* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
1048                 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"));
1049                 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"));
1050                 
1051                 uiBlockSetEmboss(block, UI_EMBOSS);
1052         }
1053         else {
1054                 short prev_proxylock, show_upbut, show_downbut;
1055                 
1056                 /* Up/Down buttons: 
1057                  *      Proxy-constraints are not allowed to occur after local (non-proxy) constraints
1058                  *      as that poses problems when restoring them, so disable the "up" button where
1059                  *      it may cause this situation. 
1060                  *
1061                  *  Up/Down buttons should only be shown (or not grayed - todo) if they serve some purpose.
1062                  */
1063                 if (proxylocked_constraints_owner(ob, pchan)) {
1064                         if (con->prev) {
1065                                 prev_proxylock = (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
1066                         }
1067                         else
1068                                 prev_proxylock = 0;
1069                 }
1070                 else
1071                         prev_proxylock = 0;
1072                         
1073                 show_upbut = ((prev_proxylock == 0) && (con->prev));
1074                 show_downbut = (con->next) ? 1 : 0;
1075                 
1076                 /* enabled */
1077                 uiBlockSetEmboss(block, UI_EMBOSSN);
1078                 uiItemR(row, &ptr, "mute", 0, "", (con->flag & CONSTRAINT_OFF) ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF);
1079                 uiBlockSetEmboss(block, UI_EMBOSS);
1080                 
1081                 uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
1082                 
1083                 /* up/down */
1084                 if (show_upbut || show_downbut) {
1085                         uiBlockBeginAlign(block);
1086                         if (show_upbut)
1087                                 uiItemO(row, "", ICON_TRIA_UP, "CONSTRAINT_OT_move_up");
1088                                 
1089                         if (show_downbut)
1090                                 uiItemO(row, "", ICON_TRIA_DOWN, "CONSTRAINT_OT_move_down");
1091                         uiBlockEndAlign(block);
1092                 }
1093                 
1094                 /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
1095                 uiBlockSetEmboss(block, UI_EMBOSSN);
1096                 uiItemO(row, "", ICON_X, "CONSTRAINT_OT_delete");
1097                 uiBlockSetEmboss(block, UI_EMBOSS);
1098         }
1099
1100         /* Set but-locks for protected settings (magic numbers are used here!) */
1101         if (proxy_protected)
1102                 uiBlockSetButLock(block, 1, "Cannot edit Proxy-Protected Constraint");
1103
1104         /* Draw constraint data */
1105         if ((con->flag & CONSTRAINT_EXPAND) == 0) {
1106                 (yco) -= 21;
1107         }
1108         else {
1109                 box = uiLayoutBox(col);
1110                 block = uiLayoutAbsoluteBlock(box);
1111                 result = box;
1112         }
1113
1114         /* clear any locks set up for proxies/lib-linking */
1115         uiBlockClearButLock(block);
1116
1117         return result;
1118 }
1119
1120 uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
1121 {
1122         Object *ob;
1123         bConstraint *con;
1124
1125         /* verify we have valid data */
1126         if (!RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
1127                 RNA_warning("Expected constraint on object");
1128                 return NULL;
1129         }
1130
1131         ob = ptr->id.data;
1132         con = ptr->data;
1133
1134         if (!ob || !(GS(ob->id.name) == ID_OB)) {
1135                 RNA_warning("Expected constraint on object");
1136                 return NULL;
1137         }
1138         
1139         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
1140
1141         /* hrms, the temporal constraint should not draw! */
1142         if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
1143                 bKinematicConstraint *data = con->data;
1144                 if (data->flag & CONSTRAINT_IK_TEMP)
1145                         return NULL;
1146         }
1147
1148         return draw_constraint(layout, ob, con);
1149 }
1150
1151
1152 /************************* Preview Template ***************************/
1153
1154 #include "DNA_lamp_types.h"
1155 #include "DNA_material_types.h"
1156 #include "DNA_world_types.h"
1157
1158 #define B_MATPRV 1
1159
1160 static void do_preview_buttons(bContext *C, void *arg, int event)
1161 {
1162         switch (event) {
1163                 case B_MATPRV:
1164                         WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING, arg);
1165                         break;
1166         }
1167 }
1168
1169 void uiTemplatePreview(uiLayout *layout, ID *id, int show_buttons, ID *parent, MTex *slot)
1170 {
1171         uiLayout *row, *col;
1172         uiBlock *block;
1173         Material *ma = NULL;
1174         Tex *tex = (Tex *)id;
1175         ID *pid, *pparent;
1176         short *pr_texture = NULL;
1177         PointerRNA material_ptr;
1178         PointerRNA texture_ptr;
1179
1180         if (id && !ELEM4(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA)) {
1181                 RNA_warning("Expected ID of type material, texture, lamp or world");
1182                 return;
1183         }
1184
1185         /* decide what to render */
1186         pid = id;
1187         pparent = NULL;
1188
1189         if (id && (GS(id->name) == ID_TE)) {
1190                 if (parent && (GS(parent->name) == ID_MA))
1191                         pr_texture = &((Material *)parent)->pr_texture;
1192                 else if (parent && (GS(parent->name) == ID_WO))
1193                         pr_texture = &((World *)parent)->pr_texture;
1194                 else if (parent && (GS(parent->name) == ID_LA))
1195                         pr_texture = &((Lamp *)parent)->pr_texture;
1196
1197                 if (pr_texture) {
1198                         if (*pr_texture == TEX_PR_OTHER)
1199                                 pid = parent;
1200                         else if (*pr_texture == TEX_PR_BOTH)
1201                                 pparent = parent;
1202                 }
1203         }
1204
1205         /* layout */
1206         block = uiLayoutGetBlock(layout);
1207         row = uiLayoutRow(layout, FALSE);
1208         col = uiLayoutColumn(row, FALSE);
1209         uiLayoutSetKeepAspect(col, TRUE);
1210         
1211         /* add preview */
1212         uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, pid, 0.0, 0.0, 0, 0, "");
1213         uiBlockSetDrawExtraFunc(block, ED_preview_draw, pparent, slot);
1214         uiBlockSetHandleFunc(block, do_preview_buttons, NULL);
1215         
1216         /* add buttons */
1217         if (pid && show_buttons) {
1218                 if (GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) {
1219                         if (GS(pid->name) == ID_MA) ma = (Material *)pid;
1220                         else ma = (Material *)pparent;
1221                         
1222                         /* Create RNA Pointer */
1223                         RNA_pointer_create(id, &RNA_Material, ma, &material_ptr);
1224
1225                         col = uiLayoutColumn(row, TRUE);
1226                         uiLayoutSetScaleX(col, 1.5);
1227                         uiItemR(col, &material_ptr, "preview_render_type", UI_ITEM_R_EXPAND, "", ICON_NONE);
1228                 }
1229
1230                 if (pr_texture) {
1231                         /* Create RNA Pointer */
1232                         RNA_pointer_create(id, &RNA_Texture, tex, &texture_ptr);
1233                         
1234                         uiLayoutRow(layout, TRUE);
1235                         uiDefButS(block, ROW, B_MATPRV, IFACE_("Texture"),  0, 0, UI_UNIT_X * 10, UI_UNIT_Y, pr_texture, 10, TEX_PR_TEXTURE, 0, 0, "");
1236                         if (GS(parent->name) == ID_MA)
1237                                 uiDefButS(block, ROW, B_MATPRV, IFACE_("Material"),  0, 0, UI_UNIT_X * 10, UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1238                         else if (GS(parent->name) == ID_LA)
1239                                 uiDefButS(block, ROW, B_MATPRV, IFACE_("Lamp"),  0, 0, UI_UNIT_X * 10, UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1240                         else if (GS(parent->name) == ID_WO)
1241                                 uiDefButS(block, ROW, B_MATPRV, IFACE_("World"),  0, 0, UI_UNIT_X * 10, UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
1242                         uiDefButS(block, ROW, B_MATPRV, IFACE_("Both"),  0, 0, UI_UNIT_X * 10, UI_UNIT_Y, pr_texture, 10, TEX_PR_BOTH, 0, 0, "");
1243                         
1244                         /* Alpha button for texture preview */
1245                         if (*pr_texture != TEX_PR_OTHER) {
1246                                 row = uiLayoutRow(layout, FALSE);
1247                                 uiItemR(row, &texture_ptr, "use_preview_alpha", 0, NULL, ICON_NONE);
1248                         }
1249                 }
1250         }
1251 }
1252
1253 /********************** ColorRamp Template **************************/
1254
1255
1256 typedef struct RNAUpdateCb {
1257         PointerRNA ptr;
1258         PropertyRNA *prop;
1259 } RNAUpdateCb;
1260
1261 static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
1262 {
1263         RNAUpdateCb *cb = (RNAUpdateCb *)arg_cb;
1264
1265         /* we call update here on the pointer property, this way the
1266          * owner of the curve mapping can still define it's own update
1267          * and notifier, even if the CurveMapping struct is shared. */
1268         RNA_property_update(C, &cb->ptr, cb->prop);
1269 }
1270
1271 static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
1272 {
1273         ColorBand *coba = coba_v;
1274         float pos = 0.5f;
1275
1276         if (coba->tot > 1) {
1277                 if (coba->cur > 0) pos = (coba->data[coba->cur - 1].pos + coba->data[coba->cur].pos) * 0.5f;
1278                 else pos = (coba->data[coba->cur + 1].pos + coba->data[coba->cur].pos) * 0.5f;
1279         }
1280
1281         if (colorband_element_add(coba, pos)) {
1282                 rna_update_cb(C, cb_v, NULL);
1283                 ED_undo_push(C, "Add colorband");       
1284         }
1285 }
1286
1287 static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v)
1288 {
1289         ColorBand *coba = coba_v;
1290
1291         if (colorband_element_remove(coba, coba->cur)) {
1292                 ED_undo_push(C, "Delete colorband");
1293                 rna_update_cb(C, cb_v, NULL);
1294         }
1295 }
1296
1297 static void colorband_flip_cb(bContext *C, void *cb_v, void *coba_v)
1298 {
1299         CBData data_tmp[MAXCOLORBAND];
1300
1301         ColorBand *coba = coba_v;
1302         int a;
1303
1304         for (a = 0; a < coba->tot; a++) {
1305                 data_tmp[a] = coba->data[coba->tot - (a + 1)];
1306         }
1307         for (a = 0; a < coba->tot; a++) {
1308                 data_tmp[a].pos = 1.0f - data_tmp[a].pos;
1309                 coba->data[a] = data_tmp[a];
1310         }
1311
1312         /* may as well flip the cur*/
1313         coba->cur = coba->tot - (coba->cur + 1);
1314
1315         ED_undo_push(C, "Flip colorband");
1316
1317         rna_update_cb(C, cb_v, NULL);
1318 }
1319
1320 static void colorband_update_cb(bContext *UNUSED(C), void *bt_v, void *coba_v)
1321 {
1322         uiBut *bt = bt_v;
1323         ColorBand *coba = coba_v;
1324
1325         /* sneaky update here, we need to sort the colorband points to be in order,
1326          * however the RNA pointer then is wrong, so we update it */
1327         colorband_update_sort(coba);
1328         bt->rnapoin.data = coba->data + coba->cur;
1329 }
1330
1331 /* offset aligns from bottom, standard width 300, height 115 */
1332 static void colorband_buttons_large(uiLayout *layout, uiBlock *block, ColorBand *coba, int xoffs, int yoffs, RNAUpdateCb *cb)
1333 {
1334         uiBut *bt;
1335         uiLayout *row;
1336         const int line1_y = yoffs + 65 + UI_UNIT_Y + 2; /* 2 for some space between the buttons */
1337         const int line2_y = yoffs + 65;
1338
1339         if (coba == NULL) return;
1340
1341         bt = uiDefBut(block, BUT, 0, IFACE_("Add"), 0 + xoffs, line1_y, 40, UI_UNIT_Y, NULL, 0, 0, 0, 0,
1342                       TIP_("Add a new color stop to the colorband"));
1343         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1344
1345         bt = uiDefBut(block, BUT, 0, IFACE_("Delete"), 45 + xoffs, line1_y, 45, UI_UNIT_Y, NULL, 0, 0, 0, 0,
1346                       TIP_("Delete the active position"));
1347         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1348
1349
1350         /* XXX, todo for later - convert to operator - campbell */
1351         bt = uiDefBut(block, BUT, 0, "F",        95 + xoffs, line1_y, 20, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Flip colorband"));
1352         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1353
1354         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"));
1355
1356         bt = uiDefButS(block, MENU, 0,       IFACE_("Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4"),
1357                        210 + xoffs, line1_y, 90, UI_UNIT_Y,      &coba->ipotype, 0.0, 0.0, 0, 0, TIP_("Set interpolation between color stops"));
1358         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1359         uiBlockEndAlign(block);
1360
1361         bt = uiDefBut(block, BUT_COLORBAND, 0, "",   xoffs, line2_y, 300, UI_UNIT_Y, coba, 0, 0, 0, 0, "");
1362         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1363
1364
1365
1366         if (coba->tot) {
1367                 CBData *cbd = coba->data + coba->cur;
1368
1369                 /* better to use rna so we can animate them */
1370                 PointerRNA ptr;
1371                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1372                 row = uiLayoutRow(layout, FALSE);
1373
1374                 uiItemR(row, &ptr, "position", 0, "Pos", ICON_NONE);
1375                 bt = block->buttons.last;
1376                 uiButSetFunc(bt, colorband_update_cb, bt, coba);
1377
1378                 uiItemR(row, &ptr, "color", 0, "", ICON_NONE);
1379         }
1380
1381 }
1382
1383 static void colorband_buttons_small(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb)
1384 {
1385         uiBut *bt;
1386         float unit = BLI_rctf_size_x(butr) / 14.0f;
1387         float xs = butr->xmin;
1388
1389         uiBlockBeginAlign(block);
1390         bt = uiDefBut(block, BUT, 0, IFACE_("Add"), xs, butr->ymin + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y, NULL, 0, 0, 0, 0,
1391                       TIP_("Add a new color stop to the colorband"));
1392         uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
1393         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,
1394                       TIP_("Delete the active position"));
1395         uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
1396         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"));
1397         uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
1398         uiBlockEndAlign(block);
1399
1400         if (coba->tot) {
1401                 CBData *cbd = coba->data + coba->cur;
1402                 PointerRNA ptr;
1403                 RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
1404                 uiItemR(layout, &ptr, "color", 0, "", ICON_NONE);
1405         }
1406
1407         bt = uiDefButS(block, MENU, 0, TIP_("Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4"),
1408                        xs + 10.0f * unit, butr->ymin + UI_UNIT_Y, unit * 4, UI_UNIT_Y,     &coba->ipotype, 0.0, 0.0, 0, 0,
1409                        TIP_("Set interpolation between color stops"));
1410         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1411
1412         bt = uiDefBut(block, BUT_COLORBAND, 0, "", xs, butr->ymin, BLI_rctf_size_x(butr), UI_UNIT_Y, coba, 0, 0, 0, 0, "");
1413         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1414
1415         uiBlockEndAlign(block);
1416 }
1417
1418 static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, int small, RNAUpdateCb *cb)
1419 {
1420         if (small)
1421                 colorband_buttons_small(layout, block, coba, butr, cb);
1422         else
1423                 colorband_buttons_large(layout, block, coba, 0, 0, cb);
1424 }
1425
1426 void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, int expand)
1427 {
1428         PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1429         PointerRNA cptr;
1430         RNAUpdateCb *cb;
1431         uiBlock *block;
1432         rctf rect;
1433
1434         if (!prop || RNA_property_type(prop) != PROP_POINTER)
1435                 return;
1436
1437         cptr = RNA_property_pointer_get(ptr, prop);
1438         if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp))
1439                 return;
1440
1441         cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1442         cb->ptr = *ptr;
1443         cb->prop = prop;
1444
1445         rect.xmin = 0; rect.xmax = 200;
1446         rect.ymin = 0; rect.ymax = 190;
1447
1448         block = uiLayoutAbsoluteBlock(layout);
1449         colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1450
1451         MEM_freeN(cb);
1452 }
1453
1454 /********************* Histogram Template ************************/
1455
1456 void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
1457 {
1458         PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1459         PointerRNA cptr;
1460         RNAUpdateCb *cb;
1461         uiBlock *block;
1462         uiBut *bt;
1463         Histogram *hist;
1464         rctf rect;
1465         
1466         if (!prop || RNA_property_type(prop) != PROP_POINTER)
1467                 return;
1468         
1469         cptr = RNA_property_pointer_get(ptr, prop);
1470         if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Histogram))
1471                 return;
1472         
1473         cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1474         cb->ptr = *ptr;
1475         cb->prop = prop;
1476         
1477         rect.xmin = 0; rect.xmax = 200;
1478         rect.ymin = 0; rect.ymax = 190;
1479         
1480         block = uiLayoutAbsoluteBlock(layout);
1481         //colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
1482
1483         hist = (Histogram *)cptr.data;
1484
1485         hist->height = (hist->height <= UI_UNIT_Y) ? UI_UNIT_Y : hist->height;
1486
1487         bt = uiDefBut(block, HISTOGRAM, 0, "", rect.xmin, rect.ymin, BLI_rctf_size_x(&rect), hist->height, hist, 0, 0, 0, 0, "");
1488         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1489
1490         MEM_freeN(cb);
1491 }
1492
1493 /********************* Waveform Template ************************/
1494
1495 void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
1496 {
1497         PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1498         PointerRNA cptr;
1499         RNAUpdateCb *cb;
1500         uiBlock *block;
1501         uiBut *bt;
1502         Scopes *scopes;
1503         rctf rect;
1504         
1505         if (!prop || RNA_property_type(prop) != PROP_POINTER)
1506                 return;
1507         
1508         cptr = RNA_property_pointer_get(ptr, prop);
1509         if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1510                 return;
1511         scopes = (Scopes *)cptr.data;
1512         
1513         cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1514         cb->ptr = *ptr;
1515         cb->prop = prop;
1516         
1517         rect.xmin = 0; rect.xmax = 200;
1518         rect.ymin = 0; rect.ymax = 190;
1519         
1520         block = uiLayoutAbsoluteBlock(layout);
1521         
1522         scopes->wavefrm_height = (scopes->wavefrm_height <= UI_UNIT_Y) ? UI_UNIT_Y : scopes->wavefrm_height;
1523
1524         bt = uiDefBut(block, WAVEFORM, 0, "", rect.xmin, rect.ymin, BLI_rctf_size_x(&rect), scopes->wavefrm_height, scopes, 0, 0, 0, 0, "");
1525         (void)bt;  /* UNUSED */
1526         
1527         MEM_freeN(cb);
1528 }
1529
1530 /********************* Vectorscope Template ************************/
1531
1532 void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
1533 {
1534         PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1535         PointerRNA cptr;
1536         RNAUpdateCb *cb;
1537         uiBlock *block;
1538         uiBut *bt;
1539         Scopes *scopes;
1540         rctf rect;
1541         
1542         if (!prop || RNA_property_type(prop) != PROP_POINTER)
1543                 return;
1544         
1545         cptr = RNA_property_pointer_get(ptr, prop);
1546         if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
1547                 return;
1548         scopes = (Scopes *)cptr.data;
1549
1550         cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1551         cb->ptr = *ptr;
1552         cb->prop = prop;
1553         
1554         rect.xmin = 0; rect.xmax = 200;
1555         rect.ymin = 0; rect.ymax = 190;
1556         
1557         block = uiLayoutAbsoluteBlock(layout);
1558
1559         scopes->vecscope_height = (scopes->vecscope_height <= UI_UNIT_Y) ? UI_UNIT_Y : scopes->vecscope_height;
1560         
1561         bt = uiDefBut(block, VECTORSCOPE, 0, "", rect.xmin, rect.ymin, BLI_rctf_size_x(&rect), scopes->vecscope_height, scopes, 0, 0, 0, 0, "");
1562         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1563         
1564         MEM_freeN(cb);
1565 }
1566
1567 /********************* CurveMapping Template ************************/
1568
1569
1570 static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *UNUSED(arg))
1571 {
1572         CurveMapping *cumap = cumap_v;
1573         float d;
1574
1575         /* we allow 20 times zoom */
1576         if (BLI_rctf_size_x(&cumap->curr) > 0.04f * BLI_rctf_size_x(&cumap->clipr)) {
1577                 d = 0.1154f * BLI_rctf_size_x(&cumap->curr);
1578                 cumap->curr.xmin += d;
1579                 cumap->curr.xmax -= d;
1580                 d = 0.1154f * BLI_rctf_size_y(&cumap->curr);
1581                 cumap->curr.ymin += d;
1582                 cumap->curr.ymax -= d;
1583         }
1584
1585         ED_region_tag_redraw(CTX_wm_region(C));
1586 }
1587
1588 static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *UNUSED(unused))
1589 {
1590         CurveMapping *cumap = cumap_v;
1591         float d, d1;
1592
1593         /* we allow 20 times zoom, but don't view outside clip */
1594         if (BLI_rctf_size_x(&cumap->curr) < 20.0f * BLI_rctf_size_x(&cumap->clipr)) {
1595                 d = d1 = 0.15f * BLI_rctf_size_x(&cumap->curr);
1596
1597                 if (cumap->flag & CUMA_DO_CLIP) 
1598                         if (cumap->curr.xmin - d < cumap->clipr.xmin)
1599                                 d1 = cumap->curr.xmin - cumap->clipr.xmin;
1600                 cumap->curr.xmin -= d1;
1601
1602                 d1 = d;
1603                 if (cumap->flag & CUMA_DO_CLIP) 
1604                         if (cumap->curr.xmax + d > cumap->clipr.xmax)
1605                                 d1 = -cumap->curr.xmax + cumap->clipr.xmax;
1606                 cumap->curr.xmax += d1;
1607
1608                 d = d1 = 0.15f * BLI_rctf_size_y(&cumap->curr);
1609
1610                 if (cumap->flag & CUMA_DO_CLIP) 
1611                         if (cumap->curr.ymin - d < cumap->clipr.ymin)
1612                                 d1 = cumap->curr.ymin - cumap->clipr.ymin;
1613                 cumap->curr.ymin -= d1;
1614
1615                 d1 = d;
1616                 if (cumap->flag & CUMA_DO_CLIP) 
1617                         if (cumap->curr.ymax + d > cumap->clipr.ymax)
1618                                 d1 = -cumap->curr.ymax + cumap->clipr.ymax;
1619                 cumap->curr.ymax += d1;
1620         }
1621
1622         ED_region_tag_redraw(CTX_wm_region(C));
1623 }
1624
1625 static void curvemap_buttons_setclip(bContext *UNUSED(C), void *cumap_v, void *UNUSED(arg))
1626 {
1627         CurveMapping *cumap = cumap_v;
1628
1629         curvemapping_changed(cumap, FALSE);
1630 }       
1631
1632 static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v)
1633 {
1634         CurveMapping *cumap = cumap_v;
1635
1636         curvemap_remove(cumap->cm + cumap->cur, SELECT);
1637         curvemapping_changed(cumap, FALSE);
1638
1639         rna_update_cb(C, cb_v, NULL);
1640 }
1641
1642 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
1643 static uiBlock *curvemap_clipping_func(bContext *C, ARegion *ar, void *cumap_v)
1644 {
1645         CurveMapping *cumap = cumap_v;
1646         uiBlock *block;
1647         uiBut *bt;
1648         float width = 8 * UI_UNIT_X;
1649
1650         block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
1651
1652         /* use this for a fake extra empy space around the buttons */
1653         uiDefBut(block, LABEL, 0, "",           -4, 16, width + 8, 6 * UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
1654
1655         bt = uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",
1656                           0, 5 * UI_UNIT_Y, width, UI_UNIT_Y, &cumap->flag, 0.0, 0.0, 10, 0, "");
1657         uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
1658
1659         uiBlockBeginAlign(block);
1660         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, "");
1661         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, "");
1662         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, "");
1663         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, "");
1664
1665         uiBlockSetDirection(block, UI_RIGHT);
1666
1667         uiEndBlock(C, block);
1668         return block;
1669 }
1670
1671 static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
1672 {
1673         CurveMapping *cumap = cumap_v;
1674         CurveMap *cuma = cumap->cm + cumap->cur;
1675
1676         switch (event) {
1677                 case 0: /* reset */
1678                         curvemap_reset(cuma, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
1679                         curvemapping_changed(cumap, FALSE);
1680                         break;
1681                 case 1:
1682                         cumap->curr = cumap->clipr;
1683                         break;
1684                 case 2: /* set vector */
1685                         curvemap_sethandle(cuma, 1);
1686                         curvemapping_changed(cumap, FALSE);
1687                         break;
1688                 case 3: /* set auto */
1689                         curvemap_sethandle(cuma, 0);
1690                         curvemapping_changed(cumap, FALSE);
1691                         break;
1692                 case 4: /* extend horiz */
1693                         cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
1694                         curvemapping_changed(cumap, FALSE);
1695                         break;
1696                 case 5: /* extend extrapolate */
1697                         cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
1698                         curvemapping_changed(cumap, FALSE);
1699                         break;
1700         }
1701         ED_region_tag_redraw(CTX_wm_region(C));
1702 }
1703
1704 static uiBlock *curvemap_tools_func(bContext *C, ARegion *ar, void *cumap_v)
1705 {
1706         uiBlock *block;
1707         short yco = 0, menuwidth = 10 * UI_UNIT_X;
1708
1709         block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
1710         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1711
1712         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, "");
1713         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, "");
1714         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, "");
1715         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, "");
1716         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, "");
1717         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, "");
1718
1719         uiBlockSetDirection(block, UI_RIGHT);
1720         uiTextBoundsBlock(block, 50);
1721
1722         uiEndBlock(C, block);
1723         return block;
1724 }
1725
1726 static uiBlock *curvemap_brush_tools_func(bContext *C, ARegion *ar, void *cumap_v)
1727 {
1728         uiBlock *block;
1729         short yco = 0, menuwidth = 10 * UI_UNIT_X;
1730
1731         block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
1732         uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
1733
1734         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, "");
1735         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, "");
1736         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, "");
1737         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, "");
1738
1739         uiBlockSetDirection(block, UI_RIGHT);
1740         uiTextBoundsBlock(block, 50);
1741
1742         uiEndBlock(C, block);
1743         return block;
1744 }
1745
1746 static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
1747 {
1748         ED_region_tag_redraw(CTX_wm_region(C));
1749 }
1750
1751 static void curvemap_buttons_update(bContext *UNUSED(C), void *UNUSED(arg1), void *cumap_v)
1752 {
1753         CurveMapping *cumap = cumap_v;
1754
1755         curvemapping_changed(cumap, TRUE);
1756 }
1757
1758 static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
1759 {
1760         CurveMapping *cumap = cumap_v;
1761         int a;
1762         
1763         cumap->preset = CURVE_PRESET_LINE;
1764         for (a = 0; a < CM_TOT; a++)
1765                 curvemap_reset(cumap->cm + a, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
1766         
1767         cumap->black[0] = cumap->black[1] = cumap->black[2] = 0.0f;
1768         cumap->white[0] = cumap->white[1] = cumap->white[2] = 1.0f;
1769         curvemapping_set_black_white(cumap, NULL, NULL);
1770         
1771         curvemapping_changed(cumap, FALSE);
1772
1773         rna_update_cb(C, cb_v, NULL);
1774 }
1775
1776 /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
1777 static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels, int brush, RNAUpdateCb *cb)
1778 {
1779         CurveMapping *cumap = ptr->data;
1780         CurveMap *cm = &cumap->cm[cumap->cur];
1781         CurveMapPoint *cmp = NULL;
1782         uiLayout *row, *sub, *split;
1783         uiBlock *block;
1784         uiBut *bt;
1785         float dx = UI_UNIT_X;
1786         int icon, size;
1787         int bg = -1, i;
1788
1789         block = uiLayoutGetBlock(layout);
1790
1791         /* curve chooser */
1792         row = uiLayoutRow(layout, FALSE);
1793
1794         if (labeltype == 'v') {
1795                 /* vector */
1796                 sub = uiLayoutRow(row, TRUE);
1797                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1798
1799                 if (cumap->cm[0].curve) {
1800                         bt = uiDefButI(block, ROW, 0, "X", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1801                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1802                 }
1803                 if (cumap->cm[1].curve) {
1804                         bt = uiDefButI(block, ROW, 0, "Y", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1805                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1806                 }
1807                 if (cumap->cm[2].curve) {
1808                         bt = uiDefButI(block, ROW, 0, "Z", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1809                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1810                 }
1811         }
1812         else if (labeltype == 'c') {
1813                 /* color */
1814                 sub = uiLayoutRow(row, TRUE);
1815                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1816
1817                 if (cumap->cm[3].curve) {
1818                         bt = uiDefButI(block, ROW, 0, "C", 0, 0, dx, dx, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
1819                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1820                 }
1821                 if (cumap->cm[0].curve) {
1822                         bt = uiDefButI(block, ROW, 0, "R", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1823                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1824                 }
1825                 if (cumap->cm[1].curve) {
1826                         bt = uiDefButI(block, ROW, 0, "G", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1827                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1828                 }
1829                 if (cumap->cm[2].curve) {
1830                         bt = uiDefButI(block, ROW, 0, "B", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1831                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1832                 }
1833         }
1834         else if (labeltype == 'h') {
1835                 /* HSV */
1836                 sub = uiLayoutRow(row, TRUE);
1837                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
1838                 
1839                 if (cumap->cm[0].curve) {
1840                         bt = uiDefButI(block, ROW, 0, "H", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
1841                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1842                 }
1843                 if (cumap->cm[1].curve) {
1844                         bt = uiDefButI(block, ROW, 0, "S", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
1845                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1846                 }
1847                 if (cumap->cm[2].curve) {
1848                         bt = uiDefButI(block, ROW, 0, "V", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
1849                         uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
1850                 }
1851         }
1852         else
1853                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
1854         
1855         if (labeltype == 'h')
1856                 bg = UI_GRAD_H;
1857
1858         /* operation buttons */
1859         sub = uiLayoutRow(row, TRUE);
1860
1861         uiBlockSetEmboss(block, UI_EMBOSSN);
1862
1863         bt = uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom in"));
1864         uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
1865
1866         bt = uiDefIconBut(block, BUT, 0, ICON_ZOOMOUT, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom out"));
1867         uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
1868
1869         if (brush)
1870                 bt = uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, TIP_("Tools"));
1871         else
1872                 bt = uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, TIP_("Tools"));
1873
1874         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1875
1876         icon = (cumap->flag & CUMA_DO_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
1877         bt = uiDefIconBlockBut(block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
1878         uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
1879
1880         bt = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete points"));
1881         uiButSetNFunc(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
1882
1883         uiBlockSetEmboss(block, UI_EMBOSS);
1884
1885         uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
1886
1887         /* curve itself */
1888         size = uiLayoutGetWidth(layout);
1889         row = uiLayoutRow(layout, FALSE);
1890         uiDefBut(block, BUT_CURVE, 0, "", 0, 0, size, MIN2(size, 200), cumap, 0.0f, 1.0f, bg, 0, "");
1891
1892         /* sliders for selected point */
1893         for (i = 0; i < cm->totpoint; i++) {
1894                 if (cm->curve[i].flag & CUMA_SELECT) {
1895                         cmp = &cm->curve[i];
1896                         break;
1897                 }
1898         }
1899
1900         if (cmp) {
1901                 uiLayoutRow(layout, TRUE);
1902                 uiBlockSetNFunc(block, curvemap_buttons_update, NULL, cumap);
1903                 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, "");
1904                 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, "");
1905         }
1906
1907         /* black/white levels */
1908         if (levels) {
1909                 split = uiLayoutSplit(layout, 0.0f, FALSE);
1910                 uiItemR(uiLayoutColumn(split, FALSE), ptr, "black_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1911                 uiItemR(uiLayoutColumn(split, FALSE), ptr, "white_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1912
1913                 uiLayoutRow(layout, FALSE);
1914                 bt = uiDefBut(block, BUT, 0, IFACE_("Reset"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
1915                               TIP_("Reset Black/White point and curves"));
1916                 uiButSetNFunc(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
1917         }
1918
1919         uiBlockSetNFunc(block, NULL, NULL, NULL);
1920 }
1921
1922 void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, int levels, int brush)
1923 {
1924         RNAUpdateCb *cb;
1925         PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1926         PointerRNA cptr;
1927
1928         if (!prop) {
1929                 RNA_warning("curve property not found: %s.%s",
1930                             RNA_struct_identifier(ptr->type), propname);
1931                 return;
1932         }
1933
1934         if (RNA_property_type(prop) != PROP_POINTER) {
1935                 RNA_warning("curve is not a pointer: %s.%s",
1936                             RNA_struct_identifier(ptr->type), propname);
1937                 return;
1938         }
1939
1940         cptr = RNA_property_pointer_get(ptr, prop);
1941         if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveMapping))
1942                 return;
1943
1944         cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
1945         cb->ptr = *ptr;
1946         cb->prop = prop;
1947
1948         curvemap_buttons_layout(layout, &cptr, type, levels, brush, cb);
1949
1950         MEM_freeN(cb);
1951 }
1952
1953 /********************* ColorWheel Template ************************/
1954
1955 #define WHEEL_SIZE  100
1956
1957 void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic)
1958 {
1959         PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1960         uiBlock *block = uiLayoutGetBlock(layout);
1961         uiLayout *col, *row;
1962         uiBut *but;
1963         float softmin, softmax, step, precision;
1964         
1965         if (!prop) {
1966                 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1967                 return;
1968         }
1969
1970         RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
1971         
1972         col = uiLayoutColumn(layout, FALSE);
1973         row = uiLayoutRow(col, TRUE);
1974         
1975         but = uiDefButR_prop(block, HSVCIRCLE, 0, "",   0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop, -1, 0.0, 0.0, 0, 0, "");
1976
1977         if (lock) {
1978                 but->flag |= UI_BUT_COLOR_LOCK;
1979         }
1980
1981         if (lock_luminosity) {
1982                 float color[4]; /* in case of alpha */
1983                 but->flag |= UI_BUT_VEC_SIZE_LOCK;
1984                 RNA_property_float_get_array(ptr, prop, color);
1985                 but->a2 = len_v3(color);
1986         }
1987
1988         if (cubic)
1989                 but->flag |= UI_BUT_COLOR_CUBIC;
1990
1991         uiItemS(row);
1992         
1993         if (value_slider)
1994                 uiDefButR_prop(block, HSVCUBE, 0, "", WHEEL_SIZE + 6, 0, 14, WHEEL_SIZE, ptr, prop, -1, softmin, softmax, UI_GRAD_V_ALT, 0, "");
1995 }
1996
1997 /********************* Layer Buttons Template ************************/
1998
1999 static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
2000 {
2001         uiBut *but = arg1;
2002         int cur = GET_INT_FROM_POINTER(arg2);
2003         wmWindow *win = CTX_wm_window(C);
2004         int i, tot, shift = win->eventstate->shift;
2005
2006         if (!shift) {
2007                 tot = RNA_property_array_length(&but->rnapoin, but->rnaprop);
2008                 
2009                 /* Normally clicking only selects one layer */
2010                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, TRUE);
2011                 for (i = 0; i < tot; ++i) {
2012                         if (i != cur)
2013                                 RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, FALSE);
2014                 }
2015         }
2016
2017         /* view3d layer change should update depsgraph (invisible object changed maybe) */
2018         /* see view3d_header.c */
2019 }
2020
2021 /* TODO:
2022  * - for now, grouping of layers is determined by dividing up the length of
2023  *   the array of layer bitflags */
2024
2025 void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
2026                       PointerRNA *used_ptr, const char *used_propname, int active_layer)
2027 {
2028         uiLayout *uRow, *uCol;
2029         PropertyRNA *prop, *used_prop = NULL;
2030         int groups, cols, layers;
2031         int group, col, layer, row;
2032         int cols_per_group = 5;
2033
2034         prop = RNA_struct_find_property(ptr, propname);
2035         if (!prop) {
2036                 RNA_warning("layers property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2037                 return;
2038         }
2039         
2040         /* the number of layers determines the way we group them 
2041          *      - we want 2 rows only (for now)
2042          *      - the number of columns (cols) is the total number of buttons per row
2043          *        the 'remainder' is added to this, as it will be ok to have first row slightly wider if need be
2044          *      - for now, only split into groups if group will have at least 5 items
2045          */
2046         layers = RNA_property_array_length(ptr, prop);
2047         cols = (layers / 2) + (layers % 2);
2048         groups = ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group);
2049
2050         if (used_ptr && used_propname) {
2051                 used_prop = RNA_struct_find_property(used_ptr, used_propname);
2052                 if (!used_prop) {
2053                         RNA_warning("used layers property not found: %s.%s", RNA_struct_identifier(ptr->type), used_propname);
2054                         return;
2055                 }
2056
2057                 if (RNA_property_array_length(used_ptr, used_prop) < layers)
2058                         used_prop = NULL;
2059         }
2060         
2061         /* layers are laid out going across rows, with the columns being divided into groups */
2062         
2063         for (group = 0; group < groups; group++) {
2064                 uCol = uiLayoutColumn(layout, TRUE);
2065                 
2066                 for (row = 0; row < 2; row++) {
2067                         uiBlock *block;
2068                         uiBut *but;
2069
2070                         uRow = uiLayoutRow(uCol, TRUE);
2071                         block = uiLayoutGetBlock(uRow);
2072                         layer = groups * cols_per_group * row + cols_per_group * group;
2073                         
2074                         /* add layers as toggle buts */
2075                         for (col = 0; (col < cols_per_group) && (layer < layers); col++, layer++) {
2076                                 int icon = 0;
2077                                 int butlay = 1 << layer;
2078
2079                                 if (active_layer & butlay)
2080                                         icon = ICON_LAYER_ACTIVE;
2081                                 else if (used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, layer))
2082                                         icon = ICON_LAYER_USED;
2083                                 
2084                                 but = uiDefAutoButR(block, ptr, prop, layer, "", icon, 0, 0, UI_UNIT_X / 2, UI_UNIT_Y / 2);
2085                                 uiButSetFunc(but, handle_layer_buttons, but, SET_INT_IN_POINTER(layer));
2086                                 but->type = TOG;
2087                         }
2088                 }
2089         }
2090 }
2091
2092
2093 /************************* List Template **************************/
2094
2095 static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon, int big)
2096 {
2097         ID *id = NULL;
2098         int icon;
2099
2100         if (!itemptr->data)
2101                 return rnaicon;
2102
2103         /* try ID, material or texture slot */
2104         if (RNA_struct_is_ID(itemptr->type)) {
2105                 id = itemptr->id.data;
2106         }
2107         else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2108                 id = RNA_pointer_get(itemptr, "material").data;
2109         }
2110         else if (RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) {
2111                 id = RNA_pointer_get(itemptr, "texture").data;
2112         }
2113         else if (RNA_struct_is_a(itemptr->type, &RNA_DynamicPaintSurface)) {
2114                 DynamicPaintSurface *surface = (DynamicPaintSurface *)itemptr->data;
2115
2116                 if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) return ICON_TEXTURE_SHADED;
2117                 else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) return ICON_OUTLINER_DATA_MESH;
2118                 else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return ICON_FILE_IMAGE;
2119         }
2120
2121         /* get icon from ID */
2122         if (id) {
2123                 icon = ui_id_icon_get(C, id, big);
2124
2125                 if (icon)
2126                         return icon;
2127         }
2128
2129         return rnaicon;
2130 }
2131
2132 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)
2133 {
2134         uiBlock *block = uiLayoutGetBlock(layout);
2135         uiBut *but;
2136         uiLayout *split, *overlap, *sub, *row;
2137         char *namebuf;
2138         const char *name;
2139         int icon;
2140
2141         overlap = uiLayoutOverlap(layout);
2142
2143         /* list item behind label & other buttons */
2144         sub = uiLayoutRow(overlap, FALSE);
2145
2146         but = uiDefButR_prop(block, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, activeptr, activeprop, 0, 0, i, 0, 0, "");
2147         uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2148
2149         sub = uiLayoutRow(overlap, FALSE);
2150
2151         /* retrieve icon and name */
2152         icon = list_item_icon_get(C, itemptr, rnaicon, 0);
2153         if (icon == ICON_NONE || icon == ICON_DOT)
2154                 icon = 0;
2155
2156         namebuf = RNA_struct_name_get_alloc(itemptr, NULL, 0, NULL);
2157         name = (namebuf) ? namebuf : "";
2158
2159         /* hardcoded types */
2160         if (itemptr->type == &RNA_MeshTexturePolyLayer || itemptr->type == &RNA_MeshLoopColorLayer) {
2161                 uiItemL(sub, name, icon);
2162                 uiBlockSetEmboss(block, UI_EMBOSSN);
2163                 uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", 0, 0, 0, 0, 0, NULL);
2164                 uiBlockSetEmboss(block, UI_EMBOSS);
2165         }
2166         else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) {
2167                 uiItemL(sub, name, icon);
2168                 uiBlockSetEmboss(block, UI_EMBOSS);
2169                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0,  NULL);
2170         }
2171         else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
2172                 uiItemL(sub, name, icon);
2173                 uiBlockSetEmboss(block, UI_EMBOSS);
2174                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0,  NULL);
2175         }
2176         else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
2177                 /* provision to draw active node name */
2178                 Material *ma, *manode;
2179                 Scene *scene = CTX_data_scene(C);
2180                 Object *ob = (Object *)ptr->id.data;
2181                 int index = (Material **)itemptr->data - ob->mat;
2182                 
2183                 /* default item with material base name */
2184                 uiItemL(sub, name, icon);
2185                 
2186                 ma = give_current_material(ob, index + 1);
2187                 if (ma && !BKE_scene_use_new_shading_nodes(scene)) {
2188                         manode = give_node_material(ma);
2189                         if (manode) {
2190                                 char str[MAX_ID_NAME + 12];
2191                                 BLI_snprintf(str, sizeof(str), IFACE_("Node %s"), manode->id.name + 2);
2192                                 uiItemL(sub, str, ui_id_icon_get(C, &manode->id, 1));
2193                         }
2194                         else if (ma->use_nodes) {
2195                                 uiItemL(sub, IFACE_("Node <none>"), ICON_NONE);
2196                         }
2197                 }
2198         }
2199         else if (itemptr->type == &RNA_ShapeKey) {
2200                 Object *ob = (Object *)activeptr->data;
2201                 Key *key = (Key *)itemptr->id.data;
2202                 KeyBlock *kb = (KeyBlock *)itemptr->data;
2203
2204                 split = uiLayoutSplit(sub, 0.66f, FALSE);
2205
2206                 uiItemL(split, name, icon);
2207
2208                 uiBlockSetEmboss(block, UI_EMBOSSN);
2209                 row = uiLayoutRow(split, TRUE);
2210                 if (i == 0 || (key->type != KEY_RELATIVE)) uiItemL(row, "", ICON_NONE);
2211                 else uiItemR(row, itemptr, "value", 0, "", ICON_NONE);
2212                 uiItemR(row, itemptr, "mute", 0, "", ICON_NONE);
2213
2214                 if ((kb->flag & KEYBLOCK_MUTE) ||
2215                     (ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH)))
2216                 {
2217                         uiLayoutSetActive(row, FALSE);
2218                 }
2219                 uiBlockSetEmboss(block, UI_EMBOSS);
2220         }
2221         else if (itemptr->type == &RNA_VertexGroup) {
2222                 bDeformGroup *dg = (bDeformGroup *)itemptr->data;
2223                 uiItemL(sub, name, icon);
2224                 /* RNA does not allow nice lock icons, use lower level buttons */
2225 #if 0
2226                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "lock_weight", 0, 0, 0, 0, 0,  NULL);
2227 #else
2228                 uiBlockSetEmboss(block, UI_EMBOSSN);
2229                 uiDefIconButBitC(block, TOG, DG_LOCK_WEIGHT, 0, (dg->flag & DG_LOCK_WEIGHT) ? ICON_LOCKED : ICON_UNLOCKED,
2230                                  0, 0, UI_UNIT_X, UI_UNIT_Y, &dg->flag, 0, 0, 0, 0,
2231                                  TIP_("Maintain relative weights while painting"));
2232                 uiBlockSetEmboss(block, UI_EMBOSS);
2233 #endif
2234         }
2235         else if (itemptr->type == &RNA_KeyingSetPath) {
2236                 KS_Path *ksp = (KS_Path *)itemptr->data;
2237                 
2238                 /* icon needs to be the type of ID which is currently active */
2239                 RNA_enum_icon_from_value(id_type_items, ksp->idtype, &icon);
2240                 
2241                 /* nothing else special to do... */
2242                 uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
2243         }
2244         else if (itemptr->type == &RNA_DynamicPaintSurface) {
2245                 char name_final[96];
2246                 const char *enum_name;
2247                 PropertyRNA *prop = RNA_struct_find_property(itemptr, "surface_type");
2248                 DynamicPaintSurface *surface = (DynamicPaintSurface *)itemptr->data;
2249
2250                 RNA_property_enum_name(C, itemptr, prop, RNA_property_enum_get(itemptr, prop), &enum_name);
2251
2252                 BLI_snprintf(name_final, sizeof(name_final), "%s (%s)", name, enum_name);
2253                 uiItemL(sub, name_final, icon);
2254                 if (dynamicPaint_surfaceHasColorPreview(surface)) {
2255                         uiBlockSetEmboss(block, UI_EMBOSSN);
2256                         uiDefIconButR(block, OPTION, 0, (surface->flags & MOD_DPAINT_PREVIEW) ? ICON_RESTRICT_VIEW_OFF : ICON_RESTRICT_VIEW_ON,
2257                                       0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "show_preview", 0, 0, 0, 0, 0, NULL);
2258                         uiBlockSetEmboss(block, UI_EMBOSS);
2259                 }
2260                 uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "is_active", i, 0, 0, 0, 0,  NULL);
2261         }
2262         else if (itemptr->type == &RNA_MovieTrackingObject) {
2263                 MovieTrackingObject *tracking_object = (MovieTrackingObject *)itemptr->data;
2264
2265                 split = uiLayoutSplit(sub, 0.75f, FALSE);
2266                 if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
2267                         uiItemL(split, name, ICON_CAMERA_DATA);
2268                 }
2269                 else {
2270                         uiItemL(split, name, ICON_OBJECT_DATA);
2271                 }
2272         }
2273         else if (itemptr->type == &RNA_MaskLayer) {
2274                 split = uiLayoutRow(sub, FALSE);
2275
2276                 uiItemL(split, name, icon);
2277
2278                 uiBlockSetEmboss(block, UI_EMBOSSN);
2279                 row = uiLayoutRow(split, TRUE);
2280                 uiItemR(row, itemptr, "alpha", 0, "", ICON_NONE);
2281                 uiItemR(row, itemptr, "hide", 0, "", ICON_NONE);
2282                 uiItemR(row, itemptr, "hide_select", 0, "", ICON_NONE);
2283                 uiItemR(row, itemptr, "hide_render", 0, "", ICON_NONE);
2284
2285                 uiBlockSetEmboss(block, UI_EMBOSS);
2286         }
2287
2288         /* There is a last chance to display custom controls (in addition to the name/label):
2289          * If the given item property group features a string property named as prop_list,
2290          * this tries to add controls for all properties of the item listed in that string property.
2291          * (colon-separated names).
2292          *
2293          * This is especially useful for python. E.g., if you list a collection of this property
2294          * group:
2295          *
2296          * class TestPropertyGroup(bpy.types.PropertyGroup):
2297          *     bool    = BoolProperty(default=False)
2298          *     integer = IntProperty()
2299          *     string  = StringProperty()
2300          * 
2301          *     # A string of all identifiers (colon-separated) which property's controls should be
2302          *     # displayed in a template_list.
2303          *     template_list_controls = StringProperty(default="integer:bool:string", options={"HIDDEN"})
2304          *
2305          * ... you'll get a numfield for the integer prop, a check box for the bool prop, and a textfield
2306          * for the string prop, after the name of each item of the collection.
2307          */
2308         else if (prop_list_id) {
2309                 row = uiLayoutRow(sub, TRUE);
2310                 uiItemL(row, name, icon);
2311
2312                 /* XXX: Check, as sometimes we get an itemptr looking like
2313                  *      {id = {data = 0x0}, type = 0x0, data = 0x0}
2314                  *      which would obviously produce a sigsev... */
2315                 if (itemptr->type) {
2316                         /* If the special property is set for the item, and it is a collection... */
2317                         PropertyRNA *prop_list = RNA_struct_find_property(itemptr, prop_list_id);
2318
2319                         if (prop_list && RNA_property_type(prop_list) == PROP_STRING) {
2320                                 int prop_names_len;
2321                                 char *prop_names = RNA_property_string_get_alloc(itemptr, prop_list, NULL, 0, &prop_names_len);
2322                                 char *prop_names_end = prop_names + prop_names_len;
2323                                 char *id = prop_names;
2324                                 char *id_next;
2325                                 while (id < prop_names_end) {
2326                                         if ((id_next = strchr(id, ':'))) *id_next++ = '\0';
2327                                         else id_next = prop_names_end;
2328                                         uiItemR(row, itemptr, id, 0, NULL, ICON_NONE);
2329                                         id = id_next;
2330                                 }
2331                                 MEM_freeN(prop_names);
2332                         }
2333                 }
2334         }
2335
2336         else
2337                 uiItemL(sub, name, icon);  /* fails, backdrop LISTROW... */
2338
2339         /* free name */
2340         if (namebuf) {
2341                 MEM_freeN(namebuf);
2342         }
2343 }
2344
2345 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)
2346 {
2347         PropertyRNA *prop = NULL, *activeprop;
2348         PropertyType type, activetype;
2349         StructRNA *ptype;
2350         uiLayout *box, *row, *col;
2351         uiBlock *block;
2352         uiBut *but;
2353         Panel *pa;
2354         const char *name;
2355         char numstr[32];
2356         int rnaicon = 0, icon = 0, i = 0, activei = 0, len = 0, items, found, min, max;
2357
2358         /* validate arguments */
2359         block = uiLayoutGetBlock(layout);
2360         pa = block->panel;
2361
2362         if (!pa) {
2363                 RNA_warning("Only works inside a panel");
2364                 return;
2365         }
2366
2367         if (!activeptr->data)
2368                 return;
2369         
2370         if (ptr->data) {
2371                 prop = RNA_struct_find_property(ptr, propname);
2372                 if (!prop) {
2373                         RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2374                         return;
2375                 }
2376         }
2377
2378         activeprop = RNA_struct_find_property(activeptr, activepropname);
2379         if (!activeprop) {
2380                 RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), activepropname);
2381                 return;
2382         }
2383
2384         if (prop) {
2385                 type = RNA_property_type(prop);
2386                 if (type != PROP_COLLECTION) {
2387                         RNA_warning("uiExpected collection property");
2388                         return;
2389                 }
2390         }
2391
2392         activetype = RNA_property_type(activeprop);
2393         if (activetype != PROP_INT) {
2394                 RNA_warning("Expected integer property");
2395                 return;
2396         }
2397
2398         /* get icon */
2399         if (ptr->data && prop) {
2400                 ptype = RNA_property_pointer_type(ptr, prop);
2401                 rnaicon = RNA_struct_ui_icon(ptype);
2402         }
2403
2404         /* get active data */
2405         activei = RNA_property_int_get(activeptr, activeprop);
2406
2407         if (listtype == 'i') {
2408                 box = uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2409                 col = uiLayoutColumn(box, TRUE);
2410                 row = uiLayoutRow(col, FALSE);
2411
2412                 if (ptr->data && prop) {
2413                         /* create list items */
2414                         RNA_PROP_BEGIN (ptr, itemptr, prop)
2415                         {
2416                                 /* create button */
2417                                 if (!(i % 9))
2418                                         row = uiLayoutRow(col, FALSE);
2419
2420                                 icon = list_item_icon_get(C, &itemptr, rnaicon, 1);
2421                                 but = uiDefIconButR_prop(block, LISTROW, 0, icon, 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, activeptr, activeprop, 0, 0, i, 0, 0, "");
2422                                 uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
2423                                 
2424
2425                                 i++;
2426                         }
2427                         RNA_PROP_END;
2428                 }
2429         }
2430         else if (listtype == 'c') {
2431                 /* compact layout */
2432
2433                 row = uiLayoutRow(layout, TRUE);
2434
2435                 if (ptr->data && prop) {
2436                         /* create list items */
2437                         RNA_PROP_BEGIN (ptr, itemptr, prop)
2438                         {
2439                                 found = (activei == i);
2440
2441                                 if (found) {
2442                                         /* create button */
2443                                         name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL);
2444                                         icon = list_item_icon_get(C, &itemptr, rnaicon, 0);
2445                                         uiItemL(row, (name) ? name : "", icon);
2446
2447                                         if (name) {
2448                                                 MEM_freeN((void *)name);
2449                                         }
2450                                 }
2451
2452                                 i++;
2453                         }
2454                         RNA_PROP_END;
2455                 }
2456
2457                 /* if not found, add in dummy button */
2458                 if (i == 0)
2459                         uiItemL(row, "", ICON_NONE);
2460
2461                 /* next/prev button */
2462                 BLI_snprintf(numstr, sizeof(numstr), "%d :", i);
2463                 but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, activeptr, activeprop, 0, 0, 0, 0, 0, "");
2464                 if (i == 0)
2465                         uiButSetFlag(but, UI_BUT_DISABLED);
2466         }
2467         else {
2468                 /* default rows */
2469                 if (rows == 0)
2470                         rows = 5;
2471                 if (maxrows == 0)
2472                         maxrows = 5;
2473                 if (pa->list_grip_size != 0)
2474                         rows = pa->list_grip_size;
2475
2476                 /* layout */
2477                 box = uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
2478                 row = uiLayoutRow(box, FALSE);
2479                 col = uiLayoutColumn(row, TRUE);
2480
2481                 /* init numbers */
2482                 RNA_property_int_range(activeptr, activeprop, &min, &max);
2483
2484                 if (prop)
2485                         len = RNA_property_collection_length(ptr, prop);
2486                 items = CLAMPIS(len, rows, MAX2(rows, maxrows));
2487
2488                 /* if list length changes and active is out of view, scroll to it */
2489                 if (pa->list_last_len != len)
2490                         if ((activei < pa->list_scroll || activei >= pa->list_scroll + items))
2491                                 pa->list_scroll = activei;
2492
2493                 pa->list_scroll = MIN2(pa->list_scroll, len - items);
2494                 pa->list_scroll = MAX2(pa->list_scroll, 0);
2495                 pa->list_size = items;
2496                 pa->list_last_len = len;
2497
2498                 if (ptr->data && prop) {
2499                         /* create list items */
2500                         RNA_PROP_BEGIN (ptr, itemptr, prop)
2501                         {
2502                                 if (i >= pa->list_scroll && i < pa->list_scroll + items)
2503                                         list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activeprop, prop_list);
2504
2505                                 i++;
2506                         }
2507                         RNA_PROP_END;
2508                 }
2509
2510                 /* add dummy buttons to fill space */
2511                 while (i < pa->list_scroll + items) {
2512                         if (i >= pa->list_scroll)
2513                                 uiItemL(col, "", ICON_NONE);
2514                         i++;
2515                 }
2516
2517                 /* add scrollbar */
2518                 if (len > items) {
2519                         col = uiLayoutColumn(row, FALSE);
2520                         uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &pa->list_scroll, 0, len - items, items, 0, "");
2521                 }
2522         }
2523 }
2524
2525 /************************* Operator Search Template **************************/
2526
2527 static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
2528 {
2529         wmOperatorType *ot = arg2;
2530         
2531         if (ot)
2532                 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
2533 }
2534
2535 static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
2536 {
2537         GHashIterator *iter = WM_operatortype_iter();
2538
2539         for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
2540                 wmOperatorType *ot = BLI_ghashIterator_getValue(iter);
2541
2542                 if (BLI_strcasestr(ot->name, str)) {
2543                         if (WM_operator_poll((bContext *)C, ot)) {
2544                                 char name[256];
2545                                 int len = strlen(ot->name);
2546                                 
2547                                 /* display name for menu, can hold hotkey */
2548                                 BLI_strncpy(name, ot->name, sizeof(name));
2549                                 
2550                                 /* check for hotkey */
2551                                 if (len < sizeof(name) - 6) {
2552                                         if (WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, TRUE,
2553                                                                          &name[len + 1], sizeof(name) - len - 1))
2554                                         {
2555                                                 name[len] = '|';
2556                                         }
2557                                 }
2558                                 
2559                                 if (0 == uiSearchItemAdd(items, name, ot, 0))
2560                                         break;
2561                         }
2562                 }
2563         }
2564         BLI_ghashIterator_free(iter);
2565 }
2566
2567 void uiTemplateOperatorSearch(uiLayout *layout)
2568 {
2569         uiBlock *block;
2570         uiBut *but;
2571         static char search[256] = "";
2572                 
2573         block = uiLayoutGetBlock(layout);
2574         uiBlockSetCurLayout(block, layout);
2575
2576         but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, "");
2577         uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
2578 }
2579
2580 /************************* Running Jobs Template **************************/
2581
2582 #define B_STOPRENDER    1
2583 #define B_STOPCAST      2
2584 #define B_STOPANIM      3
2585 #define B_STOPCOMPO     4
2586 #define B_STOPSEQ       5
2587 #define B_STOPCLIP      6
2588 #define B_STOPOTHER     7
2589
2590 static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
2591 {
2592         switch (event) {
2593                 case B_STOPRENDER:
2594                         G.is_break = TRUE;
2595                         break;
2596                 case B_STOPCAST:
2597                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C), NULL);
2598                         break;
2599                 case B_STOPANIM:
2600                         WM_operator_name_call(C, "SCREEN_OT_animation_play", WM_OP_INVOKE_SCREEN, NULL);
2601                         break;
2602                 case B_STOPCOMPO:
2603                         WM_jobs_stop(CTX_wm_manager(C), CTX_data_scene(C), NULL);
2604                         break;
2605                 case B_STOPSEQ:
2606                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2607                         break;
2608                 case B_STOPCLIP:
2609                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
2610                         break;
2611                 case B_STOPOTHER:
2612                         G.is_break = TRUE;
2613                         break;
2614         }
2615 }
2616
2617 void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
2618 {
2619         bScreen *screen = CTX_wm_screen(C);
2620         wmWindowManager *wm = CTX_wm_manager(C);
2621         ScrArea *sa = CTX_wm_area(C);
2622         uiBlock *block;
2623         void *owner = NULL;
2624         int handle_event;
2625         
2626         block = uiLayoutGetBlock(layout);
2627         uiBlockSetCurLayout(block, layout);
2628
2629         uiBlockSetHandleFunc(block, do_running_jobs, NULL);
2630
2631         if (sa->spacetype == SPACE_SEQ) {
2632                 if (WM_jobs_test(wm, sa, WM_JOB_TYPE_ANY))
2633                         owner = sa;
2634                 handle_event = B_STOPSEQ;
2635         }
2636         else if (sa->spacetype == SPACE_CLIP) {
2637                 if (WM_jobs_test(wm, sa, WM_JOB_TYPE_ANY))
2638                         owner = sa;
2639                 handle_event = B_STOPCLIP;
2640         }
2641         else {
2642                 Scene *scene;
2643                 /* another scene can be rendering too, for example via compositor */
2644                 for (scene = CTX_data_main(C)->scene.first; scene; scene = scene->id.next) {
2645                         if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) {
2646                                 handle_event = B_STOPRENDER;
2647                                 break;
2648                         }
2649                         else if (WM_jobs_test(wm, scene, WM_JOB_TYPE_COMPOSITE)) {
2650                                 handle_event = B_STOPCOMPO;
2651                                 break;
2652                         }
2653                         else if (WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY)) {
2654                                 handle_event = B_STOPOTHER;
2655                                 break;
2656                         }
2657                 }
2658                 owner = scene;
2659         }
2660
2661         if (owner) {
2662                 uiLayout *ui_abs;
2663                 
2664                 ui_abs = uiLayoutAbsolute(layout, FALSE);
2665                 (void)ui_abs;  /* UNUSED */
2666                 
2667                 uiDefIconBut(block, BUT, handle_event, ICON_PANEL_CLOSE, 
2668                              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"));
2669                 uiDefBut(block, PROGRESSBAR, 0, WM_jobs_name(wm, owner), 
2670                          UI_UNIT_X, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, TIP_("Progress"));
2671                 
2672                 uiLayoutRow(layout, FALSE);
2673         }
2674         if (WM_jobs_test(wm, screen, WM_JOB_TYPE_SCREENCAST))
2675                 uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, IFACE_("Capture"), 0, 0, 85, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
2676                                  TIP_("Stop screencast"));
2677         if (screen->animtimer)
2678                 uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_CANCEL, TIP_("Anim Player"), 0, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
2679                                  TIP_("Stop animation playback"));
2680 }
2681
2682 /************************* Reports for Last Operator Template **************************/
2683
2684 void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
2685 {
2686         ReportList *reports = CTX_wm_reports(C);
2687         Report *report = BKE_reports_last_displayable(reports);
2688         ReportTimerInfo *rti;
2689         
2690         uiLayout *ui_abs;
2691         uiBlock *block;
2692         uiBut *but;
2693         uiStyle *style = UI_GetStyle();
2694         int width;
2695         int icon = 0;
2696         
2697         /* if the report display has timed out, don't show */
2698         if (!reports->reporttimer) return;
2699         
2700         rti = (ReportTimerInfo *)reports->reporttimer->customdata;
2701         
2702         if (!rti || rti->widthfac == 0.0f || !report) return;
2703         
2704         ui_abs = uiLayoutAbsolute(layout, FALSE);
2705         block = uiLayoutGetBlock(ui_abs);
2706         
2707         width = BLF_width(style->widget.uifont_id, report->message);
2708         width = MIN2(rti->widthfac * width, width);
2709         width = MAX2(width, 10);
2710         
2711         /* make a box around the report to make it stand out */
2712         uiBlockBeginAlign(block);
2713         but = uiDefBut(block, ROUNDBOX, 0, "", 0, 0, UI_UNIT_X + 10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2714         /* set the report's bg color in but->col - ROUNDBOX feature */
2715         rgb_float_to_uchar(but->col, rti->col);
2716         but->col[3] = 255;
2717
2718         but = uiDefBut(block, ROUNDBOX, 0, "", UI_UNIT_X + 10, 0, UI_UNIT_X + width, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2719         but->col[0] = but->col[1] = but->col[2] = FTOCHAR(rti->grayscale);
2720         but->col[3] = 255;
2721
2722         uiBlockEndAlign(block);
2723         
2724         
2725         /* icon and report message on top */
2726         if (report->type & RPT_ERROR_ALL)
2727                 icon = ICON_ERROR;
2728         else if (report->type & RPT_WARNING_ALL)
2729                 icon = ICON_ERROR;
2730         else if (report->type & RPT_INFO_ALL)
2731                 icon = ICON_INFO;
2732         
2733         /* XXX: temporary operator to dump all reports to a text block, but only if more than 1 report 
2734          * to be shown instead of icon when appropriate...
2735          */
2736         uiBlockSetEmboss(block, UI_EMBOSSN);
2737
2738         if (reports->list.first != reports->list.last)
2739                 uiDefIconButO(block, BUT, "UI_OT_reports_to_textblock", WM_OP_INVOKE_REGION_WIN, icon, 2, 0,
2740                               UI_UNIT_X, UI_UNIT_Y, TIP_("Click to see the remaining reports in text block: 'Recent Reports'"));
2741         else
2742                 uiDefIconBut(block, LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2743
2744         uiBlockSetEmboss(block, UI_EMBOSS);
2745         
2746         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, "");
2747 }
2748
2749 /********************************* Keymap *************************************/
2750
2751 static void keymap_item_modified(bContext *UNUSED(C), void *kmi_p, void *UNUSED(unused))
2752 {
2753         wmKeyMapItem *kmi = (wmKeyMapItem *)kmi_p;
2754         WM_keyconfig_update_tag(NULL, kmi);
2755 }
2756
2757 static void template_keymap_item_properties(uiLayout *layout, const char *title, PointerRNA *ptr)
2758 {
2759         uiLayout *flow;
2760
2761         uiItemS(layout);
2762
2763         if (title)
2764                 uiItemL(layout, title, ICON_NONE);
2765         
2766         flow = uiLayoutColumnFlow(layout, 2, FALSE);
2767
2768         RNA_STRUCT_BEGIN (ptr, prop)
2769         {
2770                 int flag = RNA_property_flag(prop);
2771
2772                 if (flag & PROP_HIDDEN)
2773                         continue;
2774
2775                 /* recurse for nested properties */
2776                 if (RNA_property_type(prop) == PROP_POINTER) {
2777                         PointerRNA propptr = RNA_property_pointer_get(ptr, prop);
2778                         const char *name = RNA_property_ui_name(prop);
2779
2780                         if (propptr.data && RNA_struct_is_a(propptr.type, &RNA_OperatorProperties)) {
2781                                 template_keymap_item_properties(layout, name, &propptr);
2782                                 continue;
2783                         }
2784                 }
2785
2786                 /* add property */
2787                 uiItemR(flow, ptr, RNA_property_identifier(prop), 0, NULL, ICON_NONE);
2788         }
2789         RNA_STRUCT_END;
2790 }
2791
2792 void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
2793 {
2794         PointerRNA propptr = RNA_pointer_get(ptr, "properties");
2795
2796         if (propptr.data) {
2797                 uiBut *but = uiLayoutGetBlock(layout)->buttons.last;
2798
2799                 template_keymap_item_properties(layout, NULL, &propptr);
2800
2801                 /* attach callbacks to compensate for missing properties update,
2802                  * we don't know which keymap (item) is being modified there */
2803                 for (; but; but = but->next)
2804                         uiButSetFunc(but, keymap_item_modified, ptr->data, NULL);
2805         }
2806 }
2807
2808 /********************************* Color management *************************************/
2809
2810 void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char *propname)
2811 {
2812         PropertyRNA *prop;
2813         PointerRNA colorspace_settings_ptr;
2814
2815         prop = RNA_struct_find_property(ptr, propname);
2816
2817         if (!prop) {
2818                 printf("%s: property not found: %s.%s\n",
2819                        __func__, RNA_struct_identifier(ptr->type), propname);
2820                 return;
2821         }
2822
2823         colorspace_settings_ptr = RNA_property_pointer_get(ptr, prop);
2824
2825         uiItemL(layout, "Color Space:", ICON_NONE);
2826         uiItemR(layout, &colorspace_settings_ptr, "name", 0, "", ICON_NONE);
2827 }
2828
2829 void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr, const char *propname)
2830 {
2831         PropertyRNA *prop;
2832         PointerRNA view_transform_ptr;
2833         uiLayout *col, *row;
2834         ColorManagedViewSettings *view_settings;
2835
2836         prop = RNA_struct_find_property(ptr, propname);
2837
2838         if (!prop) {
2839                 printf("%s: property not found: %s.%s\n",
2840                        __func__, RNA_struct_identifier(ptr->type), propname);
2841                 return;
2842         }
2843
2844         view_transform_ptr = RNA_property_pointer_get(ptr, prop);
2845         view_settings = view_transform_ptr.data;
2846
2847         col = uiLayoutColumn(layout, FALSE);
2848
2849         row = uiLayoutRow(col, FALSE);
2850         uiItemR(row, &view_transform_ptr, "view_transform", UI_ITEM_R_EXPAND, IFACE_("View"), ICON_NONE);
2851
2852         col = uiLayoutColumn(layout, FALSE);
2853         uiItemR(col, &view_transform_ptr, "exposure", 0, NULL, ICON_NONE);
2854         uiItemR(col, &view_transform_ptr, "gamma", 0, NULL, ICON_NONE);
2855
2856         col = uiLayoutColumn(layout, FALSE);
2857         uiItemR(col, &view_transform_ptr, "use_curve_mapping", 0, NULL, ICON_NONE);
2858         if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES)
2859                 uiTemplateCurveMapping(col, &view_transform_ptr, "curve_mapping", 'c', TRUE, 0);
2860 }