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