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