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