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