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