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