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