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