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