use ICON_NULL define rather then 0, makes UI calls less confusing. (no functional...
[blender.git] / source / blender / editors / interface / interface_templates.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Contributor(s): Blender Foundation 2009.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include <stdlib.h>
26 #include <stddef.h>
27 #include <string.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "DNA_scene_types.h"
32 #include "DNA_userdef_types.h"
33
34 #include "BLI_string.h"
35
36 #include "BKE_animsys.h"
37 #include "BKE_colortools.h"
38 #include "BKE_context.h"
39 #include "BKE_global.h"
40 #include "BKE_library.h"
41 #include "BKE_main.h"
42 #include "BKE_object.h"
43 #include "BKE_material.h"
44 #include "BKE_texture.h"
45 #include "BKE_report.h"
46
47 #include "ED_screen.h"
48 #include "ED_render.h"
49
50 #include "RNA_access.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "UI_interface.h"
56 #include "interface_intern.h"
57
58 #include "BLF_api.h"
59
60 void ui_template_fix_linking(void)
61 {
62 }
63
64 /********************** Header Template *************************/
65
66 void uiTemplateHeader(uiLayout *layout, bContext *C, int menus)
67 {
68         uiBlock *block;
69
70         block= uiLayoutAbsoluteBlock(layout);
71         if(menus) ED_area_header_standardbuttons(C, block, 0);
72         else ED_area_header_switchbutton(C, block, 0);
73 }
74
75 /********************** Search Callbacks *************************/
76
77 typedef struct TemplateID {
78         PointerRNA ptr;
79         PropertyRNA *prop;
80
81         ListBase *idlb;
82         int prv_rows, prv_cols;
83 } TemplateID;
84
85 /* Search browse menu, assign  */
86 static void id_search_call_cb(bContext *C, void *arg_template, void *item)
87 {
88         TemplateID *template= (TemplateID*)arg_template;
89
90         /* ID */
91         if(item) {
92                 PointerRNA idptr;
93
94                 RNA_id_pointer_create(item, &idptr);
95                 RNA_property_pointer_set(&template->ptr, template->prop, idptr);
96                 RNA_property_update(C, &template->ptr, template->prop);
97         }
98 }
99
100 /* ID Search browse menu, do the search */
101 static void id_search_cb(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
102 {
103         TemplateID *template= (TemplateID*)arg_template;
104         ListBase *lb= template->idlb;
105         ID *id, *id_from= template->ptr.id.data;
106         int iconid;
107         int flag= RNA_property_flag(template->prop);
108
109         /* ID listbase */
110         for(id= lb->first; id; id= id->next) {
111                 if(!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
112
113                         /* use filter */
114                         if(RNA_property_type(template->prop)==PROP_POINTER) {
115                                 PointerRNA ptr;
116                                 RNA_id_pointer_create(id, &ptr);
117                                 if(RNA_property_pointer_poll(&template->ptr, template->prop, &ptr)==0)
118                                         continue;
119                         }
120
121                         /* hide dot-datablocks, but only if filter does not force it visible */
122                         if(U.uiflag & USER_HIDE_DOT)
123                                 if ((id->name[2]=='.') && (str[0] != '.'))
124                                         continue;
125
126                         if(BLI_strcasestr(id->name+2, str)) {
127                                 char name_ui[32];
128                                 name_uiprefix_id(name_ui, id);
129
130                                 iconid= ui_id_icon_get((bContext*)C, id, 1);
131
132                                 if(!uiSearchItemAdd(items, name_ui, id, iconid))
133                                         break;
134                         }
135                 }
136         }
137 }
138
139 /* ID Search browse menu, open */
140 static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
141 {
142         static char search[256];
143         static TemplateID template;
144         PointerRNA idptr;
145         wmEvent event;
146         wmWindow *win= CTX_wm_window(C);
147         uiBlock *block;
148         uiBut *but;
149         
150         /* clear initial search string, then all items show */
151         search[0]= 0;
152         /* arg_litem is malloced, can be freed by parent button */
153         template= *((TemplateID*)arg_litem);
154         
155         /* get active id for showing first item */
156         idptr= RNA_property_pointer_get(&template.ptr, template.prop);
157
158         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
159         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
160         
161         /* preview thumbnails */
162         if (template.prv_rows > 0 && template.prv_cols > 0) {
163                 int w = 96 * template.prv_cols;
164                 int h = 96 * template.prv_rows + 20;
165                 
166                 /* fake button, it holds space for search items */
167                 uiDefBut(block, LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
168                 
169                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, w, 19, template.prv_rows, template.prv_cols, "");
170                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
171         }
172         /* list view */
173         else {
174                 /* fake button, it holds space for search items */
175                 uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
176                 
177                 but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, 0, 0, "");
178                 uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
179         }
180                 
181         
182         uiBoundsBlock(block, 6);
183         uiBlockSetDirection(block, UI_DOWN);    
184         uiEndBlock(C, block);
185         
186         event= *(win->eventstate);      /* XXX huh huh? make api call */
187         event.type= EVT_BUT_OPEN;
188         event.val= KM_PRESS;
189         event.customdata= but;
190         event.customdatafree= FALSE;
191         wm_event_add(win, &event);
192         
193         return block;
194 }
195
196 /************************ ID Template ***************************/
197 /* This is for browsing and editing the ID-blocks used */
198
199 /* for new/open operators */
200 void uiIDContextProperty(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
201 {
202         TemplateID *template;
203         ARegion *ar= CTX_wm_region(C);
204         uiBlock *block;
205         uiBut *but;
206
207         memset(ptr, 0, sizeof(*ptr));
208         *prop= NULL;
209
210         if(!ar)
211                 return;
212
213         for(block=ar->uiblocks.first; block; block=block->next) {
214                 for(but=block->buttons.first; but; but= but->next) {
215                         /* find the button before the active one */
216                         if((but->flag & (UI_BUT_LAST_ACTIVE|UI_ACTIVE))) {
217                                 if(but->func_argN) {
218                                         template= but->func_argN;
219                                         *ptr= template->ptr;
220                                         *prop= template->prop;
221                                         return;
222                                 }
223                         }
224                 }
225         }
226 }
227
228
229 static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
230 {
231         TemplateID *template= (TemplateID*)arg_litem;
232         PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
233         ID *id= idptr.data, *newid;
234         int event= GET_INT_FROM_POINTER(arg_event);
235         
236         switch(event) {
237                 case UI_ID_BROWSE:
238                 case UI_ID_PIN:
239                         printf("warning, id event %d shouldnt come here\n", event);
240                         break;
241                 case UI_ID_OPEN:
242                 case UI_ID_ADD_NEW:
243                         /* these call uiIDContextPropertySet */
244                         break;
245                 case UI_ID_DELETE:
246                         memset(&idptr, 0, sizeof(idptr));
247                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
248                         RNA_property_update(C, &template->ptr, template->prop);
249
250                         if(id && CTX_wm_window(C)->eventstate->shift) /* useful hidden functionality, */
251                                 id->us= 0;
252
253                         break;
254                 case UI_ID_FAKE_USER:
255                         if(id) {
256                                 if(id->flag & LIB_FAKEUSER) id_us_plus(id);
257                                 else id_us_min(id);
258                         }
259                         else return;
260                         break;
261                 case UI_ID_LOCAL:
262                         if(id) {
263                                 if(id_make_local(id, 0)) {
264                                         /* reassign to get get proper updates/notifiers */
265                                         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
266                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
267                                         RNA_property_update(C, &template->ptr, template->prop);
268                                 }
269                         }
270                         break;
271                 case UI_ID_ALONE:
272                         if(id) {
273                                 /* make copy */
274                                 if(id_copy(id, &newid, 0) && newid) {
275                                         /* copy animation actions too */
276                                         BKE_copy_animdata_id_action(id);
277                                         /* us is 1 by convention, but RNA_property_pointer_set
278                                            will also incremement it, so set it to zero */
279                                         newid->us= 0;
280
281                                         /* assign copy */
282                                         RNA_id_pointer_create(newid, &idptr);
283                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
284                                         RNA_property_update(C, &template->ptr, template->prop);
285                                 }
286                         }
287                         break;
288 #if 0
289                 case UI_ID_AUTO_NAME:
290                         break;
291 #endif
292         }
293 }
294
295 static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, const char *newop, const char *openop, const char *unlinkop)
296 {
297         uiBut *but;
298         uiBlock *block;
299         PointerRNA idptr;
300         ListBase *lb;
301         ID *id, *idfrom;
302
303         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
304         id= idptr.data;
305         idfrom= template->ptr.id.data;
306         lb= template->idlb;
307
308         block= uiLayoutGetBlock(layout);
309         uiBlockBeginAlign(block);
310
311         if(idptr.type)
312                 type= idptr.type;
313
314         if(flag & UI_ID_PREVIEWS) {
315
316                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, "Browse ID data");
317                 if(type) {
318                         but->icon= RNA_struct_ui_icon(type);
319                         if (id) but->icon = ui_id_icon_get(C, id, 1);
320                         uiButSetFlag(but, UI_HAS_ICON|UI_ICON_PREVIEW);
321                 }
322                 if((idfrom && idfrom->lib))
323                         uiButSetFlag(but, UI_BUT_DISABLED);
324                 
325                 
326                 uiLayoutRow(layout, 1);
327         } else 
328                 
329         if(flag & UI_ID_BROWSE) {
330                 but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*1.6, UI_UNIT_Y, "Browse ID data");
331                 if(type) {
332                         but->icon= RNA_struct_ui_icon(type);
333                         /* default dragging of icon for id browse buttons */
334                         uiButSetDragID(but, id);
335                         uiButSetFlag(but, UI_HAS_ICON|UI_ICON_LEFT);
336                 }
337
338                 if((idfrom && idfrom->lib))
339                         uiButSetFlag(but, UI_BUT_DISABLED);
340         }
341
342         /* text button with name */
343         if(id) {
344                 char name[UI_MAX_NAME_STR];
345                 const short user_alert= (id->us <= 0);
346
347                 //text_idbutton(id, name);
348                 name[0]= '\0';
349                 but= uiDefButR(block, TEX, 0, name, 0, 0, UI_UNIT_X*6, UI_UNIT_Y, &idptr, "name", -1, 0, 0, -1, -1, NULL);
350                 uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
351                 if(user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
352
353                 if(id->lib) {
354                         if(id->flag & LIB_INDIRECT) {
355                                 but= uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_INDIRECT, 0,0,UI_UNIT_X,UI_UNIT_Y, 0, 0, 0, 0, 0,
356                                         "Indirect library datablock, cannot change.");
357                                 uiButSetFlag(but, UI_BUT_DISABLED);
358                         }
359                         else {
360                                 but= uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0,0,UI_UNIT_X,UI_UNIT_Y, 0, 0, 0, 0, 0,
361                                         "Direct linked library datablock, click to make local.");
362                                 if(!id_make_local(id, 1 /* test */) || (idfrom && idfrom->lib))
363                                         uiButSetFlag(but, UI_BUT_DISABLED);
364                         }
365
366                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL));
367                 }
368
369                 if(id->us > 1) {
370                         char str[32];
371
372                         sprintf(str, "%d", id->us);
373
374                         if(id->us<10)
375                                 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.");
376                         else
377                                 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.");
378
379                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
380                         if(!id_copy(id, NULL, 1 /* test only */) || (idfrom && idfrom->lib))
381                                 uiButSetFlag(but, UI_BUT_DISABLED);
382                 }
383         
384                 if(user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
385                 
386                 if(id->lib == NULL && !(ELEM4(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT))) {
387                         uiDefButR(block, TOG, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
388                 }
389         }
390         
391         if(flag & UI_ID_ADD_NEW) {
392                 int w= id?UI_UNIT_X: (flag & UI_ID_OPEN)? UI_UNIT_X*3: UI_UNIT_X*6;
393                 
394                 if(newop) {
395                         but= uiDefIconTextButO(block, BUT, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, (id)? "": "New", 0, 0, w, UI_UNIT_Y, NULL);
396                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
397                 }
398                 else {
399                         but= uiDefIconTextBut(block, BUT, 0, ICON_ZOOMIN, (id)? "": "New", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
400                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
401                 }
402
403                 if((idfrom && idfrom->lib))
404                         uiButSetFlag(but, UI_BUT_DISABLED);
405         }
406
407         if(flag & UI_ID_OPEN) {
408                 int w= id?UI_UNIT_X: (flag & UI_ID_ADD_NEW)? UI_UNIT_X*3: UI_UNIT_X*6;
409                 
410                 if(openop) {
411                         but= uiDefIconTextButO(block, BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id)? "": "Open", 0, 0, w, UI_UNIT_Y, NULL);
412                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
413                 }
414                 else {
415                         but= uiDefIconTextBut(block, BUT, 0, ICON_FILESEL, (id)? "": "Open", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
416                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
417                 }
418
419                 if((idfrom && idfrom->lib))
420                         uiButSetFlag(but, UI_BUT_DISABLED);
421         }
422         
423         /* delete button */
424         if(id && (flag & UI_ID_DELETE)) {
425                 if(unlinkop) {
426                         but= uiDefIconButO(block, BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
427                         /* so we can access the template from operators, font unlinking needs this */
428                         uiButSetNFunc(but, NULL, MEM_dupallocN(template), 0);
429                 }
430                 else {
431                         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");
432                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
433
434                         if(RNA_property_flag(template->prop) & PROP_NEVER_NULL)
435                                 uiButSetFlag(but, UI_BUT_DISABLED);
436                 }
437
438                 if((idfrom && idfrom->lib))
439                         uiButSetFlag(but, UI_BUT_DISABLED);
440         }
441         
442         uiBlockEndAlign(block);
443 }
444
445 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)
446 {
447         TemplateID *template;
448         PropertyRNA *prop;
449         StructRNA *type;
450
451         prop= RNA_struct_find_property(ptr, propname);
452
453         if(!prop || RNA_property_type(prop) != PROP_POINTER) {
454                 printf("uiTemplateID: pointer property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
455                 return;
456         }
457
458         template= MEM_callocN(sizeof(TemplateID), "TemplateID");
459         template->ptr= *ptr;
460         template->prop= prop;
461         template->prv_rows = prv_rows;
462         template->prv_cols = prv_cols;
463
464         if(newop)
465                 flag |= UI_ID_ADD_NEW;
466         if(openop)
467                 flag |= UI_ID_OPEN;
468         
469         type= RNA_property_pointer_type(ptr, prop);
470         template->idlb= which_libbase(CTX_data_main(C), RNA_type_to_ID_code(type));
471         
472         /* create UI elements for this template
473          *      - template_ID makes a copy of the template data and assigns it to the relevant buttons
474          */
475         if(template->idlb) {
476                 uiLayoutRow(layout, 1);
477                 template_ID(C, layout, template, type, flag, newop, openop, unlinkop);
478         }
479
480         MEM_freeN(template);
481 }
482
483 void uiTemplateID(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|UI_ID_DELETE, 0, 0);
486 }
487
488 void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop)
489 {
490         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME, 0, 0);
491 }
492
493 void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int rows, int cols)
494 {
495         ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE|UI_ID_PREVIEWS, rows, cols);
496 }
497
498 /************************ ID Chooser Template ***************************/
499
500 /* This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use 
501  *
502  * - propname: property identifier for property that ID-pointer gets stored to
503  * - proptypename: property identifier for property used to determine the type of ID-pointer that can be used
504  */
505 void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename, const char *text)
506 {
507         PropertyRNA *propID, *propType;
508         uiLayout *row;
509         
510         /* get properties... */
511         propID= RNA_struct_find_property(ptr, propname);
512         propType= RNA_struct_find_property(ptr, proptypename);
513
514         if (!propID || RNA_property_type(propID) != PROP_POINTER) {
515                 printf("uiTemplateAnyID: pointer property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
516                 return;
517         }
518         if (!propType || RNA_property_type(propType) != PROP_ENUM) { 
519                 printf("uiTemplateAnyID: pointer-type property not found: %s.%s\n", RNA_struct_identifier(ptr->type), proptypename);
520                 return;
521         }
522         
523         /* Start drawing UI Elements using standard defines */
524         row= uiLayoutRow(layout, 1);
525         
526         /* Label - either use the provided text, or will become "ID-Block:" */
527         if (text)
528                 uiItemL(row, text, ICON_NULL);
529         else
530                 uiItemL(row, "ID-Block:", ICON_NULL);
531         
532         /* ID-Type Selector - just have a menu of icons */
533         // FIXME: the icon-only setting doesn't work when we supply a blank name
534         uiItemFullR(row, ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY, "", ICON_NULL);
535         
536         /* ID-Block Selector - just use pointer widget... */
537         uiItemFullR(row, ptr, propID, 0, 0, 0, "", ICON_NULL);
538 }
539
540 /********************* RNA Path Builder Template ********************/
541
542 /* ---------- */
543
544 /* This is creating/editing RNA-Paths 
545  *
546  * - ptr: struct which holds the path property
547  * - propname: property identifier for property that path gets stored to
548  * - root_ptr: struct that path gets built from
549  */
550 void uiTemplatePathBuilder(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *UNUSED(root_ptr), const char *text)
551 {
552         PropertyRNA *propPath;
553         uiLayout *row;
554         
555         /* check that properties are valid */
556         propPath= RNA_struct_find_property(ptr, propname);
557         if (!propPath || RNA_property_type(propPath) != PROP_STRING) {
558                 printf("uiTemplatePathBuilder: path property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
559                 return;
560         }
561         
562         /* Start drawing UI Elements using standard defines */
563         row= uiLayoutRow(layout, 1);
564         
565         /* Path (existing string) Widget */
566         uiItemR(row, ptr, propname, 0, text, ICON_RNA);
567         
568         // TODO: attach something to this to make allow searching of nested properties to 'build' the path
569 }
570
571 /************************ Modifier Template *************************/
572
573 #define ERROR_LIBDATA_MESSAGE "Can't edit external libdata"
574
575 #include <string.h>
576
577 #include "DNA_object_force.h"
578
579 #include "BKE_depsgraph.h"
580 #include "BKE_modifier.h"
581 #include "BKE_particle.h"
582
583 #include "ED_util.h"
584
585 #include "BLI_math.h"
586 #include "BLI_listbase.h"
587
588 #include "ED_object.h"
589
590 static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v)
591 {
592         Scene *scene = CTX_data_scene(C);
593         Object *ob = ob_v;
594         ModifierData *md= md_v;
595         int i, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 0);
596
597         /* undo button operation */
598         md->mode ^= eModifierMode_OnCage;
599
600         for(i = 0, md=ob->modifiers.first; md; ++i, md=md->next) {
601                 if(md == md_v) {
602                         if(i >= cageIndex)
603                                 md->mode ^= eModifierMode_OnCage;
604                         break;
605                 }
606         }
607
608         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
609         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
610 }
611
612 static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
613 {
614         Object *ob = ob_v;
615         ModifierData *md = md_v;
616         ModifierData *nmd = modifier_new(md->type);
617
618         modifier_copyData(md, nmd);
619         nmd->mode &= ~eModifierMode_Virtual;
620
621         BLI_addhead(&ob->modifiers, nmd);
622         
623         modifier_unique_name(&ob->modifiers, nmd);
624
625         ob->partype = PAROBJECT;
626
627         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
628         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
629
630         ED_undo_push(C, "Modifier convert to real");
631 }
632
633 static int modifier_can_delete(ModifierData *md)
634 {
635         // fluid particle modifier can't be deleted here
636         if(md->type == eModifierType_ParticleSystem)
637                 if(((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID)
638                         return 0;
639
640         return 1;
641 }
642
643 static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob, ModifierData *md, int index, int cageIndex, int lastCageIndex)
644 {
645         ModifierTypeInfo *mti = modifierType_getInfo(md->type);
646         PointerRNA ptr;
647         uiBut *but;
648         uiBlock *block;
649         uiLayout *box, *column, *row;
650         uiLayout *result= NULL;
651         int isVirtual = (md->mode & eModifierMode_Virtual);
652         char str[128];
653
654         /* create RNA pointer */
655         RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr);
656
657         column= uiLayoutColumn(layout, 1);
658         uiLayoutSetContextPointer(column, "modifier", &ptr);
659
660         /* rounded header ------------------------------------------------------------------- */
661         box= uiLayoutBox(column);
662         
663         if (isVirtual) {
664                 row= uiLayoutRow(box, 0);
665                 uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_EXPAND);
666                 block= uiLayoutGetBlock(row);
667                 /* VIRTUAL MODIFIER */
668                 // XXX this is not used now, since these cannot be accessed via RNA
669                 sprintf(str, "%s parent deform", md->name);
670                 uiDefBut(block, LABEL, 0, str, 0, 0, 185, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Modifier name"); 
671                 
672                 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");
673                 uiButSetFunc(but, modifiers_convertToReal, ob, md);
674         }
675         else {
676                 /* REAL MODIFIER */
677                 row = uiLayoutRow(box, 0);
678                 block = uiLayoutGetBlock(row);
679                 
680                 uiBlockSetEmboss(block, UI_EMBOSSN);
681                 /* Open/Close .................................  */
682                 uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NULL);
683                 
684                 /* modifier-type icon */
685                 uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
686                 uiBlockSetEmboss(block, UI_EMBOSS);
687                 
688                 /* modifier name */
689                 uiItemR(row, &ptr, "name", 0, "", ICON_NULL);
690                 
691                 /* mode enabling buttons */
692                 uiBlockBeginAlign(block);
693                 /* Softbody not allowed in this situation, enforce! */
694                 if ( ((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) 
695                         && (md->type!=eModifierType_Surface) ) 
696                 {
697                         uiItemR(row, &ptr, "show_render", 0, "", ICON_NULL);
698                         uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NULL);
699                         
700                         if (mti->flags & eModifierTypeFlag_SupportsEditmode)
701                                 uiItemR(row, &ptr, "show_in_editmode", 0, "", ICON_NULL);
702                 }
703                 if ((ob->type==OB_MESH) && modifier_couldBeCage(scene, md) && (index <= lastCageIndex)) 
704                 {
705                         /* -- convert to rna ? */
706                         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");
707                         if (index < cageIndex)
708                                 uiButSetFlag(but, UI_BUT_DISABLED);
709                         uiButSetFunc(but, modifiers_setOnCage, ob, md);
710                 }
711                 uiBlockEndAlign(block);
712                 
713                 /* Up/Down + Delete ........................... */
714                 uiBlockBeginAlign(block);
715                 uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_modifier_move_up");
716                 uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_modifier_move_down");
717                 uiBlockEndAlign(block);
718                 
719                 uiBlockSetEmboss(block, UI_EMBOSSN);
720                 if (modifier_can_delete(md))
721                         uiItemO(row, "", ICON_X, "OBJECT_OT_modifier_remove");
722                 uiBlockSetEmboss(block, UI_EMBOSS);
723         }
724
725         
726         /* modifier settings (under the header) --------------------------------------------------- */
727         if (!isVirtual && (md->mode & eModifierMode_Expanded)) {
728                 /* apply/convert/copy */
729                 box= uiLayoutBox(column);
730                 row= uiLayoutRow(box, 0);
731                 
732                 if (!ELEM(md->type, eModifierType_Collision, eModifierType_Surface)) {
733                         /* only here obdata, the rest of modifiers is ob level */
734                         uiBlockSetButLock(block, object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
735                         
736                         if (md->type==eModifierType_ParticleSystem) {
737                                 ParticleSystem *psys= ((ParticleSystemModifierData *)md)->psys;
738                                 
739                                 if (!(ob->mode & OB_MODE_PARTICLE_EDIT) && psys->pathcache) {
740                                         if(ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB))
741                                                 uiItemO(row, "Convert", ICON_NULL, "OBJECT_OT_duplicates_make_real");
742                                         else if(psys->part->ren_as == PART_DRAW_PATH)
743                                                 uiItemO(row, "Convert", ICON_NULL, "OBJECT_OT_modifier_convert");
744                                 }
745                         }
746                         else {
747                                 uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
748                                 uiItemEnumO(row, "OBJECT_OT_modifier_apply", "Apply", 0, "apply_as", MODIFIER_APPLY_DATA);
749                                 
750                                 if (modifier_sameTopology(md))
751                                         uiItemEnumO(row, "OBJECT_OT_modifier_apply", "Apply as Shape", 0, "apply_as", MODIFIER_APPLY_SHAPE);
752                         }
753                         
754                         uiBlockClearButLock(block);
755                         uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
756                         
757                         if (!ELEM5(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, eModifierType_Cloth, eModifierType_Smoke))
758                                 uiItemO(row, "Copy", ICON_NULL, "OBJECT_OT_modifier_copy");
759                 }
760                 
761                 /* result is the layout block inside the box, that we return so that modifier settings can be drawn */
762                 result= uiLayoutColumn(box, 0);
763                 block= uiLayoutAbsoluteBlock(box);
764         }
765         
766         /* error messages */
767         if(md->error) {
768                 box = uiLayoutBox(column);
769                 row = uiLayoutRow(box, 0);
770                 uiItemL(row, md->error, ICON_ERROR);
771         }
772         
773         return result;
774 }
775
776 uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
777 {
778         Scene *scene = CTX_data_scene(C);
779         Object *ob;
780         ModifierData *md, *vmd;
781         int i, lastCageIndex, cageIndex;
782
783         /* verify we have valid data */
784         if(!RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
785                 printf("uiTemplateModifier: expected modifier on object.\n");
786                 return NULL;
787         }
788
789         ob= ptr->id.data;
790         md= ptr->data;
791
792         if(!ob || !(GS(ob->id.name) == ID_OB)) {
793                 printf("uiTemplateModifier: expected modifier on object.\n");
794                 return NULL;
795         }
796         
797         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
798         
799         /* find modifier and draw it */
800         cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
801
802         // XXX virtual modifiers are not accesible for python
803         vmd = modifiers_getVirtualModifierList(ob);
804
805         for(i=0; vmd; i++, vmd=vmd->next) {
806                 if(md == vmd)
807                         return draw_modifier(layout, scene, ob, md, i, cageIndex, lastCageIndex);
808                 else if(vmd->mode & eModifierMode_Virtual)
809                         i--;
810         }
811
812         return NULL;
813 }
814
815 /************************ Constraint Template *************************/
816
817 #include "DNA_constraint_types.h"
818
819 #include "BKE_action.h"
820 #include "BKE_constraint.h"
821
822 #define REDRAWIPO                                       1
823 #define REDRAWNLA                                       2
824 #define REDRAWBUTSOBJECT                        3               
825 #define REDRAWACTION                            4
826 #define B_CONSTRAINT_TEST                       5
827 #define B_CONSTRAINT_CHANGETARGET       6
828 #define REMAKEIPO                                       8
829 #define B_DIFF                                          9
830
831 void do_constraint_panels(bContext *C, void *ob_pt, int event)
832 {
833         Main *bmain= CTX_data_main(C);
834         Scene *scene= CTX_data_scene(C);
835         Object *ob= (Object *)ob_pt;
836         
837         switch(event) {
838         case B_CONSTRAINT_TEST:
839                 break;  // no handling
840         case B_CONSTRAINT_CHANGETARGET:
841                 if (ob->pose) ob->pose->flag |= POSE_RECALC;    // checks & sorts pose channels
842                 DAG_scene_sort(bmain, scene);
843                 break;
844         default:
845                 break;
846         }
847
848         // note: RNA updates now call this, commenting else it gets called twice.
849         // if there are problems because of this, then rna needs changed update functions.
850         // 
851         // object_test_constraints(ob);
852         // if(ob->pose) update_pose_constraint_flags(ob->pose);
853         
854         if(ob->type==OB_ARMATURE) DAG_id_tag_update(&ob->id, OB_RECALC_DATA|OB_RECALC_OB);
855         else DAG_id_tag_update(&ob->id, OB_RECALC_OB);
856
857         WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob);
858 }
859
860 static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
861 {
862         ED_object_constraint_set_active(ob_v, con_v);
863 }
864
865 /* draw panel showing settings for a constraint */
866 static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
867 {
868         bPoseChannel *pchan= get_active_posechannel(ob);
869         bConstraintTypeInfo *cti;
870         uiBlock *block;
871         uiLayout *result= NULL, *col, *box, *row;
872         PointerRNA ptr;
873         char typestr[32];
874         short proxy_protected, xco=0, yco=0;
875         int rb_col;
876
877         /* get constraint typeinfo */
878         cti= constraint_get_typeinfo(con);
879         if (cti == NULL) {
880                 /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
881                 if (con->type == CONSTRAINT_TYPE_NULL)
882                         strcpy(typestr, "Null");
883                 else
884                         strcpy(typestr, "Unknown");
885         }
886         else
887                 strcpy(typestr, cti->name);
888                 
889         /* determine whether constraint is proxy protected or not */
890         if (proxylocked_constraints_owner(ob, pchan))
891                 proxy_protected= (con->flag & CONSTRAINT_PROXY_LOCAL)==0;
892         else
893                 proxy_protected= 0;
894
895         /* unless button has own callback, it adds this callback to button */
896         block= uiLayoutGetBlock(layout);
897         uiBlockSetHandleFunc(block, do_constraint_panels, ob);
898         uiBlockSetFunc(block, constraint_active_func, ob, con);
899
900         RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
901
902         col= uiLayoutColumn(layout, 1);
903         uiLayoutSetContextPointer(col, "constraint", &ptr);
904
905         box= uiLayoutBox(col);
906         row = uiLayoutRow(box, 0);
907         block= uiLayoutGetBlock(box);
908
909         /* Draw constraint header */
910         
911         /* rounded header */
912         rb_col= (con->flag & CONSTRAINT_ACTIVE)?50:20;
913
914         /* open/close */
915         uiBlockSetEmboss(block, UI_EMBOSSN);
916         uiItemR(row, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NULL);
917         uiBlockSetEmboss(block, UI_EMBOSS);
918         
919         /* name */
920         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco+10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
921
922         if (con->flag & CONSTRAINT_DISABLE)
923                 uiLayoutSetRedAlert(row, 1);
924         
925         if(proxy_protected == 0) {
926                 uiItemR(row, &ptr, "name", 0, "", ICON_NULL);
927         }
928         else
929                 uiItemL(row, con->name, ICON_NULL);
930         
931         uiLayoutSetRedAlert(row, 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, "", ICON_NULL);
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, ICON_NULL);
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", ICON_NULL);
1253                 uiItemR(row, &ptr, "color", 0, "", ICON_NULL);
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, "", ICON_NULL);
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, ICON_NULL);
1757                 uiItemR(uiLayoutColumn(split, 0), ptr, "white_level", UI_ITEM_R_EXPAND, NULL, ICON_NULL);
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_NULL || 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)) {
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**)itemptr->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>", ICON_NULL);
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, "", ICON_NULL);
2037                 else uiItemR(row, itemptr, "value", 0, "", ICON_NULL);
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, "", ICON_NULL);
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, "", ICON_NULL);
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= NULL;
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                 if(WM_jobs_test(wm, sa))
2321                    owner = sa;
2322                 handle_event= B_STOPCOMPO;
2323         } 
2324         else {
2325                 /* another scene can be rendering too, for example via compositor */
2326                 for(scene= CTX_data_main(C)->scene.first; scene; scene= scene->id.next)
2327                         if(WM_jobs_test(wm, scene))
2328                                 break;
2329                 owner = scene;
2330                 handle_event= B_STOPRENDER;
2331         }
2332
2333         if(owner) {
2334                 uiLayout *ui_abs;
2335                 
2336                 ui_abs= uiLayoutAbsolute(layout, 0);
2337                 
2338                 uiDefIconBut(block, BUT, handle_event, ICON_PANEL_CLOSE, 
2339                                 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");
2340                 uiDefBut(block, PROGRESSBAR, 0, WM_jobs_name(wm, owner), 
2341                                 UI_UNIT_X, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, "Progress");
2342                 
2343                 uiLayoutRow(layout, 0);
2344         }
2345         if(WM_jobs_test(wm, screen))
2346                 uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, "Capture", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop screencast");
2347         if(screen->animtimer)
2348                 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");
2349 }
2350
2351 /************************* Reports for Last Operator Template **************************/
2352
2353 void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
2354 {
2355         ReportList *reports = CTX_wm_reports(C);
2356         Report *report= BKE_reports_last_displayable(reports);
2357         ReportTimerInfo *rti;
2358         
2359         uiLayout *ui_abs;
2360         uiBlock *block;
2361         uiBut *but;
2362         uiStyle *style= U.uistyles.first;
2363         int width;
2364         int icon=0;
2365         
2366         /* if the report display has timed out, don't show */
2367         if (!reports->reporttimer) return;
2368         
2369         rti= (ReportTimerInfo *)reports->reporttimer->customdata;
2370         
2371         if (!rti || rti->widthfac==0.0 || !report) return;
2372         
2373         ui_abs= uiLayoutAbsolute(layout, 0);
2374         block= uiLayoutGetBlock(ui_abs);
2375         
2376         width = BLF_width(style->widget.uifont_id, report->message);
2377         width = MIN2(rti->widthfac*width, width);
2378         width = MAX2(width, 10);
2379         
2380         /* make a box around the report to make it stand out */
2381         uiBlockBeginAlign(block);
2382         but= uiDefBut(block, ROUNDBOX, 0, "", 0, 0, UI_UNIT_X+10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2383         /* set the report's bg color in but->col - ROUNDBOX feature */
2384         but->col[0]= FTOCHAR(rti->col[0]);
2385         but->col[1]= FTOCHAR(rti->col[1]);
2386         but->col[2]= FTOCHAR(rti->col[2]);
2387         but->col[3]= 255; 
2388
2389         but= uiDefBut(block, ROUNDBOX, 0, "", UI_UNIT_X+10, 0, UI_UNIT_X+width, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2390         but->col[0]= but->col[1]= but->col[2]= FTOCHAR(rti->greyscale);
2391         but->col[3]= 255;
2392
2393         uiBlockEndAlign(block);
2394         
2395         
2396         /* icon and report message on top */
2397         if(report->type & RPT_ERROR_ALL)
2398                 icon = ICON_ERROR;
2399         else if(report->type & RPT_WARNING_ALL)
2400                 icon = ICON_ERROR;
2401         else if(report->type & RPT_INFO_ALL)
2402                 icon = ICON_INFO;
2403         
2404         /* XXX: temporary operator to dump all reports to a text block, but only if more than 1 report 
2405          * to be shown instead of icon when appropriate...
2406          */
2407         uiBlockSetEmboss(block, UI_EMBOSSN);
2408
2409         if (reports->list.first != reports->list.last)
2410                 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'");
2411         else
2412                 uiDefIconBut(block, LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
2413
2414         uiBlockSetEmboss(block, UI_EMBOSS);
2415         
2416         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, "");
2417 }
2418