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