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