NLA SoC: Merge from 2.5
[blender.git] / source / blender / editors / interface / interface_templates.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * Contributor(s): Blender Foundation 2009.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "DNA_scene_types.h"
31 #include "DNA_screen_types.h"
32
33 #include "BLI_string.h"
34
35 #include "BKE_context.h"
36 #include "BKE_icons.h"
37 #include "BKE_global.h"
38 #include "BKE_library.h"
39 #include "BKE_utildefines.h"
40
41 #include "ED_screen.h"
42 #include "ED_previewrender.h"
43
44 #include "RNA_access.h"
45
46 #include "WM_api.h"
47 #include "WM_types.h"
48
49 #include "UI_interface.h"
50 #include "UI_resources.h"
51 #include "interface_intern.h"
52
53 void ui_template_fix_linking()
54 {
55 }
56
57 /********************** Header Template *************************/
58
59 void uiTemplateHeader(uiLayout *layout, bContext *C)
60 {
61         uiBlock *block;
62         
63         block= uiLayoutFreeBlock(layout);
64         ED_area_header_standardbuttons(C, block, 0);
65 }
66
67 /********************** Search Callbacks *************************/
68
69 typedef struct TemplateID {
70         PointerRNA ptr;
71         PropertyRNA *prop;
72
73         ListBase *idlb;
74 } TemplateID;
75
76 /* Search browse menu, assign  */
77 static void id_search_call_cb(struct bContext *C, void *arg_template, void *item)
78 {
79         TemplateID *template= (TemplateID*)arg_template;
80
81         /* ID */
82         if(item) {
83                 PointerRNA idptr;
84
85                 RNA_id_pointer_create(item, &idptr);
86                 RNA_property_pointer_set(&template->ptr, template->prop, idptr);
87                 RNA_property_update(C, &template->ptr, template->prop);
88         }
89 }
90
91 /* ID Search browse menu, do the search */
92 static void id_search_cb(const struct bContext *C, void *arg_template, char *str, uiSearchItems *items)
93 {
94         TemplateID *template= (TemplateID*)arg_template;
95         Scene *scene= CTX_data_scene(C);
96         ListBase *lb= template->idlb;
97         ID *id;
98         int iconid;
99
100         /* ID listbase */
101         for(id= lb->first; id; id= id->next) {
102                 iconid= ui_id_icon_get(scene, id);
103
104                 if(BLI_strcasestr(id->name+2, str))
105                         if(!uiSearchItemAdd(items, id->name+2, id, iconid))
106                                 break;
107         }
108 }
109
110 /* ID Search browse menu, open */
111 static uiBlock *search_menu(bContext *C, ARegion *ar, void *arg_litem)
112 {
113         static char search[256];
114         static TemplateID template;
115         PointerRNA idptr;
116         wmEvent event;
117         wmWindow *win= CTX_wm_window(C);
118         uiBlock *block;
119         uiBut *but;
120         
121         /* clear initial search string, then all items show */
122         search[0]= 0;
123         /* arg_litem is malloced, can be freed by parent button */
124         template= *((TemplateID*)arg_litem);
125         
126         /* get active id for showing first item */
127         idptr= RNA_property_pointer_get(&template.ptr, template.prop);
128
129         block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
130         uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
131         
132         /* fake button, it holds space for search items */
133         uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
134         
135         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, "");
136         uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
137         
138         uiBoundsBlock(block, 6);
139         uiBlockSetDirection(block, UI_DOWN);    
140         uiEndBlock(C, block);
141         
142         event= *(win->eventstate);      /* XXX huh huh? make api call */
143         event.type= EVT_BUT_OPEN;
144         event.val= KM_PRESS;
145         event.customdata= but;
146         event.customdatafree= FALSE;
147         wm_event_add(win, &event);
148         
149         return block;
150 }
151
152 /************************ ID Template ***************************/
153
154 static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
155 {
156         TemplateID *template= (TemplateID*)arg_litem;
157         PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
158         ID *id= idptr.data;
159         int event= GET_INT_FROM_POINTER(arg_event);
160         
161         switch(event) {
162                 case UI_ID_BROWSE:
163                 case UI_ID_PIN:
164                         printf("warning, id event %d shouldnt come here\n", event);
165                         break;
166                 case UI_ID_OPEN:
167                 case UI_ID_ADD_NEW:
168                         if(template->idlb->last) {
169                                 RNA_id_pointer_create(template->idlb->last, &idptr);
170                                 RNA_property_pointer_set(&template->ptr, template->prop, idptr);
171                                 RNA_property_update(C, &template->ptr, template->prop);
172                         }
173                         break;
174                 case UI_ID_DELETE:
175                         memset(&idptr, 0, sizeof(idptr));
176                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
177                         RNA_property_update(C, &template->ptr, template->prop);
178                         break;
179                 case UI_ID_FAKE_USER:
180                         if(id) {
181                                 if(id->flag & LIB_FAKEUSER) id->us++;
182                                 else id->us--;
183                         }
184                         else return;
185                         break;
186 #if 0
187                 case UI_ID_ALONE:
188                         if(!id || id->us < 1)
189                                 return;
190                         break;
191                 case UI_ID_LOCAL:
192                         if(!id || id->us < 1)
193                                 return;
194                         break;
195                 case UI_ID_AUTO_NAME:
196                         break;
197 #endif
198         }
199 }
200
201 static void template_ID(bContext *C, uiBlock *block, TemplateID *template, StructRNA *type, int flag, char *newop, char *unlinkop)
202 {
203         uiBut *but;
204         PointerRNA idptr;
205         ListBase *lb;
206
207         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
208         lb= template->idlb;
209
210         uiBlockBeginAlign(block);
211
212         if(idptr.type)
213                 type= idptr.type;
214         if(type)
215                 uiDefIconBut(block, LABEL, 0, RNA_struct_ui_icon(type), 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
216
217         if(flag & UI_ID_BROWSE)
218                 uiDefBlockButN(block, search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X, UI_UNIT_Y, "Browse ID data");
219
220         /* text button with name */
221         if(idptr.data) {
222                 char name[64];
223
224                 //text_idbutton(idptr.data, name);
225                 name[0]= '\0';
226                 but= uiDefButR(block, TEX, 0, name, 0, 0, UI_UNIT_X*6, UI_UNIT_Y, &idptr, "name", -1, 0, 0, -1, -1, NULL);
227                 uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
228         }
229         
230         if(flag & UI_ID_ADD_NEW) {
231                 int w= idptr.data?UI_UNIT_X:UI_UNIT_X*6;
232                 
233                 if(newop) {
234                         but= uiDefIconTextButO(block, BUT, newop, WM_OP_EXEC_REGION_WIN, ICON_ZOOMIN, "Add New", 0, 0, w, UI_UNIT_Y, NULL);
235                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
236                 }
237                 else {
238                         but= uiDefIconTextBut(block, BUT, 0, ICON_ZOOMIN, "Add New", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
239                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
240                 }
241         }
242         
243         /* delete button */
244         if(idptr.data && (flag & UI_ID_DELETE)) {
245                 if(unlinkop) {
246                         but= uiDefIconButO(block, BUT, unlinkop, WM_OP_EXEC_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
247                 }
248                 else {
249                         but= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
250                         uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
251                 }
252         }
253         
254         uiBlockEndAlign(block);
255 }
256
257 void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *unlinkop)
258 {
259         TemplateID *template;
260         uiBlock *block;
261         PropertyRNA *prop;
262         StructRNA *type;
263         int flag;
264
265         if(!ptr->data)
266                 return;
267
268         prop= RNA_struct_find_property(ptr, propname);
269
270         if(!prop || RNA_property_type(prop) != PROP_POINTER) {
271                 printf("uiTemplateID: pointer property not found: %s\n", propname);
272                 return;
273         }
274
275         template= MEM_callocN(sizeof(TemplateID), "TemplateID");
276         template->ptr= *ptr;
277         template->prop= prop;
278
279         flag= UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE;
280
281         if(newop)
282                 flag |= UI_ID_ADD_NEW;
283
284         type= RNA_property_pointer_type(ptr, prop);
285         template->idlb= wich_libbase(CTX_data_main(C), RNA_type_to_ID_code(type));
286
287         if(template->idlb) {
288                 uiLayoutRow(layout, 1);
289                 block= uiLayoutGetBlock(layout);
290                 template_ID(C, block, template, type, flag, newop, unlinkop);
291         }
292
293         MEM_freeN(template);
294 }
295
296 /************************ Modifier Template *************************/
297
298 #define ERROR_LIBDATA_MESSAGE "Can't edit external libdata"
299
300 #include <string.h>
301
302 #include "DNA_object_force.h"
303 #include "DNA_object_types.h"
304 #include "DNA_modifier_types.h"
305 #include "DNA_scene_types.h"
306
307 #include "BKE_depsgraph.h"
308 #include "BKE_DerivedMesh.h"
309 #include "BKE_global.h"
310 #include "BKE_modifier.h"
311 #include "BKE_object.h"
312 #include "BKE_particle.h"
313 #include "BKE_report.h"
314
315 #include "UI_resources.h"
316 #include "ED_util.h"
317
318 #include "BLI_arithb.h"
319 #include "BLI_listbase.h"
320
321 #include "ED_object.h"
322
323 static void modifiers_del(bContext *C, void *ob_v, void *md_v)
324 {
325         Scene *scene= CTX_data_scene(C);
326         Object *ob= ob_v;
327         ReportList reports;
328
329         BKE_reports_init(&reports, RPT_STORE);
330
331         if(ED_object_modifier_delete(&reports, ob_v, md_v)) {
332                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
333                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
334
335                 ED_undo_push(C, "Delete modifier");
336         }
337         else
338                 uiPupMenuReports(C, &reports);
339
340         BKE_reports_clear(&reports);
341 }
342
343 static void modifiers_activate(bContext *C, void *ob_v, void *md_v)
344 {
345         Scene *scene= CTX_data_scene(C);
346         Object *ob= ob_v;
347
348         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
349         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
350 }
351
352 static void modifiers_moveUp(bContext *C, void *ob_v, void *md_v)
353 {
354         Scene *scene= CTX_data_scene(C);
355         Object *ob= ob_v;
356         ReportList reports;
357
358         BKE_reports_init(&reports, RPT_STORE);
359
360         if(ED_object_modifier_move_up(&reports, ob_v, md_v)) {
361                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
362                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
363
364                 ED_undo_push(C, "Move modifier");
365         }
366         else
367                 uiPupMenuReports(C, &reports);
368
369         BKE_reports_clear(&reports);
370 }
371
372 static void modifiers_moveDown(bContext *C, void *ob_v, void *md_v)
373 {
374         Scene *scene= CTX_data_scene(C);
375         Object *ob= ob_v;
376         ReportList reports;
377
378         BKE_reports_init(&reports, RPT_STORE);
379
380         if(ED_object_modifier_move_down(&reports, ob_v, md_v)) {
381                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
382                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
383
384                 ED_undo_push(C, "Move modifier");
385         }
386         else
387                 uiPupMenuReports(C, &reports);
388
389         BKE_reports_clear(&reports);
390 }
391
392 static void modifiers_convertParticles(bContext *C, void *obv, void *mdv)
393 {
394         Scene *scene= CTX_data_scene(C);
395         Object *ob= obv;
396         ReportList reports;
397
398         BKE_reports_init(&reports, RPT_STORE);
399
400         if(ED_object_modifier_convert(&reports, scene, obv, mdv)) {
401                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
402                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
403
404                 ED_undo_push(C, "Convert particles to mesh object(s).");
405         }
406         else
407                 uiPupMenuReports(C, &reports);
408
409         BKE_reports_clear(&reports);
410 }
411
412 static void modifiers_applyModifier(bContext *C, void *obv, void *mdv)
413 {
414         Scene *scene= CTX_data_scene(C);
415         Object *ob= obv;
416         ReportList reports;
417
418         BKE_reports_init(&reports, RPT_STORE);
419
420         if(ED_object_modifier_apply(&reports, scene, obv, mdv)) {
421                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
422                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
423
424                 ED_undo_push(C, "Apply modifier");
425         }
426         else
427                 uiPupMenuReports(C, &reports);
428
429         BKE_reports_clear(&reports);
430 }
431
432 static void modifiers_copyModifier(bContext *C, void *ob_v, void *md_v)
433 {
434         Scene *scene= CTX_data_scene(C);
435         Object *ob= ob_v;
436         ReportList reports;
437
438         BKE_reports_init(&reports, RPT_STORE);
439
440         if(ED_object_modifier_copy(&reports, ob_v, md_v)) {
441                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
442                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
443                 ED_undo_push(C, "Copy modifier");
444         }
445         else
446                 uiPupMenuReports(C, &reports);
447
448         BKE_reports_clear(&reports);
449 }
450
451 static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v)
452 {
453         Scene *scene= CTX_data_scene(C);
454         Object *ob = ob_v;
455         ModifierData *md;
456         
457         int i, cageIndex = modifiers_getCageIndex(ob, NULL );
458
459         for(i = 0, md=ob->modifiers.first; md; ++i, md=md->next) {
460                 if(md == md_v) {
461                         if(i >= cageIndex)
462                                 md->mode ^= eModifierMode_OnCage;
463                         break;
464                 }
465         }
466
467         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
468         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
469 }
470
471 static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
472 {
473         Scene *scene= CTX_data_scene(C);
474         Object *ob = ob_v;
475         ModifierData *md = md_v;
476         ModifierData *nmd = modifier_new(md->type);
477
478         modifier_copyData(md, nmd);
479         nmd->mode &= ~eModifierMode_Virtual;
480
481         BLI_addhead(&ob->modifiers, nmd);
482
483         ob->partype = PAROBJECT;
484
485         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
486         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
487
488         ED_undo_push(C, "Modifier convert to real");
489 }
490
491 static int modifier_can_delete(ModifierData *md)
492 {
493         // deletion over the deflection panel
494         // fluid particle modifier can't be deleted here
495
496         if(md->type==eModifierType_Fluidsim)
497                 return 0;
498         if(md->type==eModifierType_Collision)
499                 return 0;
500         if(md->type==eModifierType_Surface)
501                 return 0;
502         if(md->type == eModifierType_ParticleSystem)
503                 if(((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID)
504                         return 0;
505
506         return 1;
507 }
508
509 static uiLayout *draw_modifier(uiLayout *layout, Object *ob, ModifierData *md, int index, int cageIndex, int lastCageIndex)
510 {
511         ModifierTypeInfo *mti = modifierType_getInfo(md->type);
512         PointerRNA ptr;
513         uiBut *but;
514         uiBlock *block;
515         uiLayout *column, *row, *subrow, *result= NULL;
516         int isVirtual = md->mode&eModifierMode_Virtual;
517         // XXX short color = md->error?TH_REDALERT:TH_BUT_NEUTRAL;
518         short width = 295, buttonWidth = width-120-10;
519         char str[128];
520
521         RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr);
522
523         column= uiLayoutColumn(layout, 1);
524         uiLayoutSetContextPointer(column, "modifier", &ptr);
525
526         /* rounded header */
527         /* XXX uiBlockSetCol(block, color); */
528                 /* roundbox 4 free variables: corner-rounding, nop, roundbox type, shade */
529
530         row= uiLayoutRow(uiLayoutBox(column), 0);
531         block= uiLayoutGetBlock(row);
532
533         subrow= uiLayoutRow(row, 0);
534         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT);
535
536         //uiDefBut(block, ROUNDBOX, 0, "", x-10, y-4, width, 25, NULL, 7.0, 0.0, 
537         //               (!isVirtual && (md->mode&eModifierMode_Expanded))?3:15, 20, ""); 
538         /* XXX uiBlockSetCol(block, TH_AUTO); */
539         
540         /* open/close icon */
541         if (!isVirtual) {
542                 uiBlockSetEmboss(block, UI_EMBOSSN);
543                 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");
544         }
545         
546         /* modifier-type icon */
547         uiDefIconBut(block, BUT, 0, RNA_struct_ui_icon(ptr.type), 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Current Modifier Type");
548         
549         uiBlockSetEmboss(block, UI_EMBOSS);
550         
551         if (isVirtual) {
552                 sprintf(str, "%s parent deform", md->name);
553                 uiDefBut(block, LABEL, 0, str, 0, 0, 185, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Modifier name"); 
554
555                 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");
556                 uiButSetFunc(but, modifiers_convertToReal, ob, md);
557         } else {
558                 uiBlockBeginAlign(block);
559                 uiDefBut(block, TEX, 0, "", 0, 0, buttonWidth-40, UI_UNIT_Y, md->name, 0.0, sizeof(md->name)-1, 0.0, 0.0, "Modifier name"); 
560
561                 /* Softbody not allowed in this situation, enforce! */
562                 if (((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) && (md->type!=eModifierType_Surface)) {
563                         uiDefIconButBitI(block, TOG, eModifierMode_Render, 0, ICON_SCENE, 0, 0, 19, UI_UNIT_Y,&md->mode, 0, 0, 1, 0, "Enable modifier during rendering");
564                         but= uiDefIconButBitI(block, TOG, eModifierMode_Realtime, 0, ICON_VIEW3D, 0, 0, 19, UI_UNIT_Y,&md->mode, 0, 0, 1, 0, "Enable modifier during interactive display");
565                         uiButSetFunc(but, modifiers_activate, ob, md);
566                         if (mti->flags&eModifierTypeFlag_SupportsEditmode) {
567                                 but= uiDefIconButBitI(block, TOG, eModifierMode_Editmode, 0, ICON_EDITMODE_HLT, 0, 0, 19, UI_UNIT_Y,&md->mode, 0, 0, 1, 0, "Enable modifier during Editmode (only if enabled for display)");
568                                 uiButSetFunc(but, modifiers_activate, ob, md);
569                         }
570                 }
571                 uiBlockEndAlign(block);
572
573                 /* XXX uiBlockSetEmboss(block, UI_EMBOSSR); */
574
575                 if (ob->type==OB_MESH && modifier_couldBeCage(md) && index<=lastCageIndex) {
576                         int icon; //, color;
577
578                         if (index==cageIndex) {
579                                 // XXX color = TH_BUT_SETTING;
580                                 icon = VICON_EDITMODE_HLT;
581                         } else if (index<cageIndex) {
582                                 // XXX color = TH_BUT_NEUTRAL;
583                                 icon = VICON_EDITMODE_DEHLT;
584                         } else {
585                                 // XXX color = TH_BUT_NEUTRAL;
586                                 icon = ICON_BLANK1;
587                         }
588                         /* XXX uiBlockSetCol(block, color); */
589                         but = uiDefIconBut(block, BUT, 0, icon, 0, 0, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Apply modifier to editing cage during Editmode");
590                         uiButSetFunc(but, modifiers_setOnCage, ob, md);
591                         /* XXX uiBlockSetCol(block, TH_AUTO); */
592                 }
593         }
594
595         subrow= uiLayoutRow(row, 0);
596         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT);
597
598         if(!isVirtual) {
599                 /* XXX uiBlockSetCol(block, TH_BUT_ACTION); */
600
601                 but = uiDefIconBut(block, BUT, 0, VICON_MOVE_UP, 0, 0, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Move modifier up in stack");
602                 uiButSetFunc(but, modifiers_moveUp, ob, md);
603
604                 but = uiDefIconBut(block, BUT, 0, VICON_MOVE_DOWN, 0, 0, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Move modifier down in stack");
605                 uiButSetFunc(but, modifiers_moveDown, ob, md);
606                 
607                 uiBlockSetEmboss(block, UI_EMBOSSN);
608                 
609                 if(modifier_can_delete(md)) {
610                         but = uiDefIconBut(block, BUT, 0, VICON_X, 0, 0, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Delete modifier");
611                         uiButSetFunc(but, modifiers_del, ob, md);
612                 }
613                 /* XXX uiBlockSetCol(block, TH_AUTO); */
614         }
615
616         uiBlockSetEmboss(block, UI_EMBOSS);
617
618         if(!isVirtual && (md->mode&eModifierMode_Expanded)) {
619                 uiLayout *box;
620
621                 box= uiLayoutBox(column);
622                 row= uiLayoutRow(box, 1);
623
624                 if (!isVirtual && (md->type!=eModifierType_Collision) && (md->type!=eModifierType_Surface)) {
625                         uiBlockSetButLock(block, object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE); /* only here obdata, the rest of modifiers is ob level */
626
627                                                 if (md->type==eModifierType_ParticleSystem) {
628                         ParticleSystem *psys= ((ParticleSystemModifierData *)md)->psys;
629
630                         if(!(G.f & G_PARTICLEEDIT)) {
631                                         if(ELEM3(psys->part->draw_as, PART_DRAW_PATH, PART_DRAW_GR, PART_DRAW_OB) && psys->pathcache) {
632                                                 but = uiDefBut(block, BUT, 0, "Convert",        0,0,60,19, 0, 0, 0, 0, 0, "Convert the current particles to a mesh object");
633                                                 uiButSetFunc(but, modifiers_convertParticles, ob, md);
634                                         }
635                                 }
636                         }
637                         else{
638                                 but = uiDefBut(block, BUT, 0, "Apply",  0,0,60,19, 0, 0, 0, 0, 0, "Apply the current modifier and remove from the stack");
639                                 uiButSetFunc(but, modifiers_applyModifier, ob, md);
640                         }
641                         
642                         uiBlockClearButLock(block);
643                         uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
644
645                         if (md->type!=eModifierType_Fluidsim && md->type!=eModifierType_Softbody && md->type!=eModifierType_ParticleSystem && (md->type!=eModifierType_Cloth)) {
646                                 but = uiDefBut(block, BUT, 0, "Copy",   0,0,60,19, 0, 0, 0, 0, 0, "Duplicate the current modifier at the same position in the stack");
647                                 uiButSetFunc(but, modifiers_copyModifier, ob, md);
648                         }
649                 }
650
651                 result= uiLayoutColumn(box, 0);
652                 block= uiLayoutFreeBlock(box);
653         }
654
655         if (md->error) {
656                 row = uiLayoutRow(uiLayoutBox(column), 0);
657
658                 /* XXX uiBlockSetCol(block, color); */
659                 uiItemL(row, md->error, ICON_ERROR);
660                 /* XXX uiBlockSetCol(block, TH_AUTO); */
661         }
662
663         return result;
664 }
665
666 uiLayout *uiTemplateModifier(uiLayout *layout, PointerRNA *ptr)
667 {
668         Object *ob;
669         ModifierData *md, *vmd;
670         int i, lastCageIndex, cageIndex;
671
672         /* verify we have valid data */
673         if(!RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
674                 printf("uiTemplateModifier: expected modifier on object.\n");
675                 return NULL;
676         }
677
678         ob= ptr->id.data;
679         md= ptr->data;
680
681         if(!ob || !(GS(ob->id.name) == ID_OB)) {
682                 printf("uiTemplateModifier: expected modifier on object.\n");
683                 return NULL;
684         }
685         
686         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
687         
688         /* find modifier and draw it */
689         cageIndex = modifiers_getCageIndex(ob, &lastCageIndex);
690
691         // XXX virtual modifiers are not accesible for python
692         vmd = modifiers_getVirtualModifierList(ob);
693
694         for(i=0; vmd; i++, vmd=vmd->next) {
695                 if(md == vmd)
696                         return draw_modifier(layout, ob, md, i, cageIndex, lastCageIndex);
697                 else if(vmd->mode&eModifierMode_Virtual)
698                         i--;
699         }
700
701         return NULL;
702 }
703
704 /************************ Constraint Template *************************/
705
706 #include "DNA_action_types.h"
707 #include "DNA_constraint_types.h"
708
709 #include "BKE_action.h"
710 #include "BKE_constraint.h"
711
712 #define REDRAWIPO                                       1
713 #define REDRAWNLA                                       2
714 #define REDRAWBUTSOBJECT                        3               
715 #define REDRAWACTION                            4
716 #define B_CONSTRAINT_TEST                       5
717 #define B_CONSTRAINT_CHANGETARGET       6
718 #define B_CONSTRAINT_INF                        7
719 #define REMAKEIPO                                       8
720 #define B_DIFF                                          9
721
722 void do_constraint_panels(bContext *C, void *arg, int event)
723 {
724         Scene *scene= CTX_data_scene(C);
725         Object *ob= CTX_data_active_object(C);
726         
727         switch(event) {
728         case B_CONSTRAINT_TEST:
729                 // XXX allqueue(REDRAWVIEW3D, 0);
730                 // XXX allqueue(REDRAWBUTSOBJECT, 0);
731                 // XXX allqueue(REDRAWBUTSEDIT, 0);
732                 break;  // no handling
733         case B_CONSTRAINT_INF:
734                 /* influence; do not execute actions for 1 dag_flush */
735                 if (ob->pose)
736                         ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
737                 break;
738         case B_CONSTRAINT_CHANGETARGET:
739                 if (ob->pose) ob->pose->flag |= POSE_RECALC;    // checks & sorts pose channels
740                 DAG_scene_sort(scene);
741                 break;
742         default:
743                 break;
744         }
745
746         object_test_constraints(ob);
747         
748         if(ob->pose) update_pose_constraint_flags(ob->pose);
749         
750         if(ob->type==OB_ARMATURE) DAG_object_flush_update(scene, ob, OB_RECALC_DATA|OB_RECALC_OB);
751         else DAG_object_flush_update(scene, ob, OB_RECALC_OB);
752         
753         // XXX allqueue(REDRAWVIEW3D, 0);
754         // XXX allqueue(REDRAWBUTSOBJECT, 0);
755         // XXX allqueue(REDRAWBUTSEDIT, 0);
756 }
757
758 static void constraint_active_func(bContext *C, void *ob_v, void *con_v)
759 {
760         ED_object_constraint_set_active(ob_v, con_v);
761 }
762
763 static void del_constraint_func (bContext *C, void *ob_v, void *con_v)
764 {
765         if(ED_object_constraint_delete(NULL, ob_v, con_v))
766                 ED_undo_push(C, "Delete Constraint");
767 }
768
769 static void verify_constraint_name_func (bContext *C, void *con_v, void *name_v)
770 {
771         Object *ob= CTX_data_active_object(C);
772         bConstraint *con= con_v;
773         char oldname[32];       
774         
775         if (!con)
776                 return;
777         
778         /* put on the stack */
779         BLI_strncpy(oldname, (char *)name_v, 32);
780         
781         ED_object_constraint_rename(ob, con, oldname);
782         ED_object_constraint_set_active(ob, con);
783         // XXX allqueue(REDRAWACTION, 0); 
784 }
785
786 static void constraint_moveUp(bContext *C, void *ob_v, void *con_v)
787 {
788         if(ED_object_constraint_move_up(NULL, ob_v, con_v))
789                 ED_undo_push(C, "Move Constraint");
790 }
791
792 static void constraint_moveDown(bContext *C, void *ob_v, void *con_v)
793 {
794         if(ED_object_constraint_move_down(NULL, ob_v, con_v))
795                 ED_undo_push(C, "Move Constraint");
796 }
797
798 /* some commonly used macros in the constraints drawing code */
799 #define is_armature_target(target) (target && target->type==OB_ARMATURE)
800 #define is_armature_owner(ob) ((ob->type == OB_ARMATURE) && (ob->flag & OB_POSEMODE))
801 #define is_geom_target(target) (target && (ELEM(target->type, OB_MESH, OB_LATTICE)) )
802
803 /* Helper function for draw constraint - draws constraint space stuff 
804  * This function should not be called if no menus are required 
805  * owner/target: -1 = don't draw menu; 0= not posemode, 1 = posemode 
806  */
807 static void draw_constraint_spaceselect (uiBlock *block, bConstraint *con, short xco, short yco, short owner, short target)
808 {
809         short tarx, ownx, iconx;
810         short bwidth;
811         short iconwidth = 20;
812         
813         /* calculate sizes and placement of menus */
814         if (owner == -1) {
815                 bwidth = 125;
816                 tarx = 120;
817                 ownx = 0;
818         }
819         else if (target == -1) {
820                 bwidth = 125;
821                 tarx = 0;
822                 ownx = 120;
823         }
824         else {
825                 bwidth = 100;
826                 tarx = 85;
827                 iconx = tarx + bwidth + 5;
828                 ownx = tarx + bwidth + iconwidth + 10;
829         }
830         
831         
832         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Convert:", xco, yco, 80,18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
833
834         /* Target-Space */
835         if (target == 1) {
836                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x2|Local with Parent %x3|Local Space %x1", 
837                                                                                                 tarx, yco, bwidth, 18, &con->tarspace, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
838         }
839         else if (target == 0) {
840                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Local (Without Parent) Space %x1", 
841                                                                                 tarx, yco, bwidth, 18, &con->tarspace, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
842         }
843         
844         if ((target != -1) && (owner != -1))
845                 uiDefIconBut(block, LABEL, 0, ICON_ARROW_LEFTRIGHT,
846                         iconx, yco, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "");
847         
848         /* Owner-Space */
849         if (owner == 1) {
850                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Pose Space %x2|Local with Parent %x3|Local Space %x1", 
851                                                                                                 ownx, yco, bwidth, 18, &con->ownspace, 0, 0, 0, 0, "Choose space that owner is evaluated in");  
852         }
853         else if (owner == 0) {
854                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Local (Without Parent) Space %x1", 
855                                                                                 ownx, yco, bwidth, 18, &con->ownspace, 0, 0, 0, 0, "Choose space that owner is evaluated in");  
856         }
857 }
858
859 /* draw panel showing settings for a constraint */
860 static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
861 {
862         bPoseChannel *pchan= get_active_posechannel(ob);
863         bConstraintTypeInfo *cti;
864         uiBlock *block;
865         uiLayout *result= NULL, *col, *box, *row, *subrow;
866         uiBut *but;
867         PointerRNA ptr;
868         char typestr[32];
869         short width = 265;
870         short proxy_protected, xco=0, yco=0;
871         int rb_col;
872
873         /* get constraint typeinfo */
874         cti= constraint_get_typeinfo(con);
875         if (cti == NULL) {
876                 /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
877                 if (con->type == CONSTRAINT_TYPE_NULL)
878                         strcpy(typestr, "Null");
879                 else
880                         strcpy(typestr, "Unknown");
881         }
882         else
883                 strcpy(typestr, cti->name);
884                 
885         /* determine whether constraint is proxy protected or not */
886         if (proxylocked_constraints_owner(ob, pchan))
887                 proxy_protected= (con->flag & CONSTRAINT_PROXY_LOCAL)==0;
888         else
889                 proxy_protected= 0;
890
891         /* unless button has own callback, it adds this callback to button */
892         block= uiLayoutGetBlock(layout);
893         uiBlockSetHandleFunc(block, do_constraint_panels, NULL);
894         uiBlockSetFunc(block, constraint_active_func, ob, con);
895
896         RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
897
898         col= uiLayoutColumn(layout, 1);
899         uiLayoutSetContextPointer(col, "constraint", &ptr);
900
901         box= uiLayoutBox(col);
902         row= uiLayoutRow(box, 0);
903
904         block= uiLayoutFreeBlock(box);
905
906         subrow= uiLayoutRow(row, 0);
907         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT);
908
909         /* Draw constraint header */
910         uiBlockSetEmboss(block, UI_EMBOSSN);
911         
912         /* rounded header */
913         rb_col= (con->flag & CONSTRAINT_ACTIVE)?50:20;
914         
915         /* open/close */
916         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");
917         
918         /* name */      
919         if ((con->flag & CONSTRAINT_EXPAND) && (proxy_protected==0)) {
920                 /* XXX if (con->flag & CONSTRAINT_DISABLE)
921                         uiBlockSetCol(block, TH_REDALERT);*/
922                 
923                 uiBlockSetEmboss(block, UI_EMBOSS);
924                 
925                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco+10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
926                 
927                 but = uiDefBut(block, TEX, B_CONSTRAINT_TEST, "", xco+120, yco, 85, 18, con->name, 0.0, 29.0, 0.0, 0.0, "Constraint name"); 
928                 uiButSetFunc(but, verify_constraint_name_func, con, NULL);
929         }       
930         else {
931                 uiBlockSetEmboss(block, UI_EMBOSSN);
932                 
933                 /* XXX if (con->flag & CONSTRAINT_DISABLE)
934                         uiBlockSetCol(block, TH_REDALERT);*/
935                 
936                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco+10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
937                 
938                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, con->name, xco+120, yco-1, 135, 19, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
939         }
940
941         // XXX uiBlockSetCol(block, TH_AUTO);   
942
943         subrow= uiLayoutRow(row, 0);
944         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT);
945         
946         /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
947         if (proxy_protected) {
948                 uiBlockSetEmboss(block, UI_EMBOSSN);
949                 
950                 /* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
951                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_GHOST, xco+244, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
952                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_LOCKED, xco+262, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
953                 
954                 uiBlockSetEmboss(block, UI_EMBOSS);
955         }
956         else {
957                 short prev_proxylock, show_upbut, show_downbut;
958                 
959                 /* Up/Down buttons: 
960                  *      Proxy-constraints are not allowed to occur after local (non-proxy) constraints
961                  *      as that poses problems when restoring them, so disable the "up" button where
962                  *      it may cause this situation. 
963                  *
964                  *      Up/Down buttons should only be shown (or not greyed - todo) if they serve some purpose. 
965                  */
966                 if (proxylocked_constraints_owner(ob, pchan)) {
967                         if (con->prev) {
968                                 prev_proxylock= (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
969                         }
970                         else
971                                 prev_proxylock= 0;
972                 }
973                 else
974                         prev_proxylock= 0;
975                         
976                 show_upbut= ((prev_proxylock == 0) && (con->prev));
977                 show_downbut= (con->next) ? 1 : 0;
978                 
979                 if (show_upbut || show_downbut) {
980                         uiBlockBeginAlign(block);
981                                 uiBlockSetEmboss(block, UI_EMBOSS);
982                                 
983                                 if (show_upbut) {
984                                         but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_UP, xco+width-50, yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint up in constraint stack");
985                                         uiButSetFunc(but, constraint_moveUp, ob, con);
986                                 }
987                                 
988                                 if (show_downbut) {
989                                         but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_DOWN, xco+width-50+18, yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint down in constraint stack");
990                                         uiButSetFunc(but, constraint_moveDown, ob, con);
991                                 }
992                         uiBlockEndAlign(block);
993                 }
994                 
995                 
996                 /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
997                 uiBlockSetEmboss(block, UI_EMBOSSN);
998                 
999                 but = uiDefIconBut(block, BUT, B_CONSTRAINT_CHANGETARGET, ICON_X, xco+262, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Delete constraint");
1000                 uiButSetFunc(but, del_constraint_func, ob, con);
1001                 
1002                 uiBlockSetEmboss(block, UI_EMBOSS);
1003         }
1004         
1005         /* Set but-locks for protected settings (magic numbers are used here!) */
1006         if (proxy_protected)
1007                 uiBlockSetButLock(block, 1, "Cannot edit Proxy-Protected Constraint");
1008         
1009         /* Draw constraint data */
1010         if ((con->flag & CONSTRAINT_EXPAND) == 0) {
1011                 (yco) -= 21;
1012         }
1013         else {
1014                 box= uiLayoutBox(col);
1015                 block= uiLayoutFreeBlock(box);
1016
1017                 switch (con->type) {
1018 #ifndef DISABLE_PYTHON
1019                 case CONSTRAINT_TYPE_PYTHON:
1020                         {
1021                                 bPythonConstraint *data = con->data;
1022                                 bConstraintTarget *ct;
1023                                 // uiBut *but2;
1024                                 int tarnum, theight;
1025                                 // static int pyconindex=0;
1026                                 // char *menustr;
1027                                 
1028                                 theight = (data->tarnum)? (data->tarnum * 38) : (38);
1029                                 
1030                                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Script:", xco+60, yco-24, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1031                                 
1032                                 /* do the scripts menu */
1033                                 /* XXX menustr = buildmenu_pyconstraints(data->text, &pyconindex);
1034                                 but2 = uiDefButI(block, MENU, B_CONSTRAINT_TEST, menustr,
1035                                       xco+120, yco-24, 150, 20, &pyconindex,
1036                                       0, 0, 0, 0, "Set the Script Constraint to use");
1037                                 uiButSetFunc(but2, validate_pyconstraint_cb, data, &pyconindex);
1038                                 MEM_freeN(menustr);      */
1039                                 
1040                                 /* draw target(s) */
1041                                 if (data->flag & PYCON_USETARGETS) {
1042                                         /* Draw target parameters */ 
1043                                         for (ct=data->targets.first, tarnum=1; ct; ct=ct->next, tarnum++) {
1044                                                 char tarstr[32];
1045                                                 short yoffset= ((tarnum-1) * 38);
1046         
1047                                                 /* target label */
1048                                                 sprintf(tarstr, "Target %d:", tarnum);
1049                                                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, tarstr, xco+45, yco-(48+yoffset), 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1050                                                 
1051                                                 /* target space-selector - per target */
1052                                                 if (is_armature_target(ct->tar)) {
1053                                                         uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x3|Local with Parent %x4|Local Space %x1", 
1054                                                                                                                         xco+10, yco-(66+yoffset), 100, 18, &ct->space, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
1055                                                 }
1056                                                 else {
1057                                                         uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Local (Without Parent) Space %x1", 
1058                                                                                                                         xco+10, yco-(66+yoffset), 100, 18, &ct->space, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
1059                                                 }
1060                                                 
1061                                                 uiBlockBeginAlign(block);
1062                                                         /* target object */
1063                                                         uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", xco+120, yco-(48+yoffset), 150, 18, &ct->tar, "Target Object"); 
1064                                                         
1065                                                         /* subtarget */
1066                                                         if (is_armature_target(ct->tar)) {
1067                                                                 but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", xco+120, yco-(66+yoffset),150,18, &ct->subtarget, 0, 24, 0, 0, "Subtarget Bone");
1068                                                                 uiButSetCompleteFunc(but, autocomplete_bone, (void *)ct->tar);
1069                                                         }
1070                                                         else if (is_geom_target(ct->tar)) {
1071                                                                 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");
1072                                                                 uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ct->tar);
1073                                                         }
1074                                                         else {
1075                                                                 strcpy(ct->subtarget, "");
1076                                                         }
1077                                                 uiBlockEndAlign(block);
1078                                         }
1079                                 }
1080                                 else {
1081                                         /* Draw indication that no target needed */
1082                                         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", xco+60, yco-48, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1083                                         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Not Applicable", xco+120, yco-48, 150, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1084                                 }
1085                                 
1086                                 /* settings */
1087                                 uiBlockBeginAlign(block);
1088                                         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.");
1089                                         // XXX uiButSetFunc(but, BPY_pyconstraint_settings, data, NULL);
1090                                         
1091                                         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");
1092                                 uiBlockEndAlign(block);
1093                                 
1094                                 /* constraint space settings */
1095                                 draw_constraint_spaceselect(block, con, xco, yco-(73+theight), is_armature_owner(ob), -1);
1096                         }
1097                         break;
1098 #endif /* DISABLE_PYTHON */
1099                 /*case CONSTRAINT_TYPE_CHILDOF:
1100                         {
1101                                 // Inverse options 
1102                                 uiBlockBeginAlign(block);
1103                                         but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Set Offset", xco, yco-151, (width/2),18, NULL, 0, 24, 0, 0, "Calculate current Parent-Inverse Matrix (i.e. restore offset from parent)");
1104                                         // XXX uiButSetFunc(but, childof_const_setinv, con, NULL);
1105                                         
1106                                         but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Clear Offset", xco+((width/2)+10), yco-151, (width/2),18, NULL, 0, 24, 0, 0, "Clear Parent-Inverse Matrix (i.e. clear offset from parent)");
1107                                         // XXX uiButSetFunc(but, childof_const_clearinv, con, NULL);
1108                                 uiBlockEndAlign(block);
1109                         }
1110                         break; 
1111                 */
1112                 
1113                 /*case CONSTRAINT_TYPE_RIGIDBODYJOINT:
1114                         {
1115                                 if (data->type==CONSTRAINT_RB_GENERIC6DOF) {
1116                                         // Draw Pairs of LimitToggle+LimitValue 
1117                                         uiBlockBeginAlign(block); 
1118                                                 uiDefButBitS(block, TOG, 1, B_CONSTRAINT_TEST, "LinMinX", xco, yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x limit"); 
1119                                                 uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", xco+togButWidth, yco-offsetY, (textButWidth-5), 18, &(data->minLimit[0]), -extremeLin, extremeLin, 0.1,0.5,"min x limit"); 
1120                                         uiBlockEndAlign(block);
1121                                         
1122                                         uiBlockBeginAlign(block); 
1123                                                 uiDefButBitS(block, TOG, 1, B_CONSTRAINT_TEST, "LinMaxX", xco+(width-(textButWidth-5)-togButWidth), yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum x limit"); 
1124                                                 uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", xco+(width-textButWidth-5), yco-offsetY, (textButWidth), 18, &(data->maxLimit[0]), -extremeLin, extremeLin, 0.1,0.5,"max x limit"); 
1125                                         uiBlockEndAlign(block);
1126                                         
1127                                         offsetY += 20;
1128                                         uiBlockBeginAlign(block); 
1129                                                 uiDefButBitS(block, TOG, 2, B_CONSTRAINT_TEST, "LinMinY", xco, yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y limit"); 
1130                                                 uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", xco+togButWidth, yco-offsetY, (textButWidth-5), 18, &(data->minLimit[1]), -extremeLin, extremeLin, 0.1,0.5,"min y limit"); 
1131                                         uiBlockEndAlign(block);
1132                                         
1133                                         uiBlockBeginAlign(block); 
1134                                                 uiDefButBitS(block, TOG, 2, B_CONSTRAINT_TEST, "LinMaxY", xco+(width-(textButWidth-5)-togButWidth), yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum y limit"); 
1135                                                 uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", xco+(width-textButWidth-5), yco-offsetY, (textButWidth), 18, &(data->maxLimit[1]), -extremeLin, extremeLin, 0.1,0.5,"max y limit"); 
1136                                         uiBlockEndAlign(block);
1137                                         
1138                                         offsetY += 20;
1139                                         uiBlockBeginAlign(block); 
1140                                                 uiDefButBitS(block, TOG, 4, B_CONSTRAINT_TEST, "LinMinZ", xco, yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z limit"); 
1141                                                 uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", xco+togButWidth, yco-offsetY, (textButWidth-5), 18, &(data->minLimit[2]), -extremeLin, extremeLin, 0.1,0.5,"min z limit"); 
1142                                         uiBlockEndAlign(block);
1143                                         
1144                                         uiBlockBeginAlign(block); 
1145                                                 uiDefButBitS(block, TOG, 4, B_CONSTRAINT_TEST, "LinMaxZ", xco+(width-(textButWidth-5)-togButWidth), yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum z limit"); 
1146                                                 uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", xco+(width-textButWidth-5), yco-offsetY, (textButWidth), 18, &(data->maxLimit[2]), -extremeLin, extremeLin, 0.1,0.5,"max z limit"); 
1147                                         uiBlockEndAlign(block);
1148                                         offsetY += 20;
1149                                 }
1150                                 if ((data->type==CONSTRAINT_RB_GENERIC6DOF) || (data->type==CONSTRAINT_RB_CONETWIST)) {
1151                                         // Draw Pairs of LimitToggle+LimitValue /
1152                                         uiBlockBeginAlign(block); 
1153                                                 uiDefButBitS(block, TOG, 8, B_CONSTRAINT_TEST, "AngMinX", xco, yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x limit"); 
1154                                                 uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", xco+togButWidth, yco-offsetY, (textButWidth-5), 18, &(data->minLimit[3]), -extremeAngX, extremeAngX, 0.1,0.5,"min x limit"); 
1155                                         uiBlockEndAlign(block);
1156                                         uiBlockBeginAlign(block); 
1157                                                 uiDefButBitS(block, TOG, 8, B_CONSTRAINT_TEST, "AngMaxX", xco+(width-(textButWidth-5)-togButWidth), yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum x limit"); 
1158                                                 uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", xco+(width-textButWidth-5), yco-offsetY, (textButWidth), 18, &(data->maxLimit[3]), -extremeAngX, extremeAngX, 0.1,0.5,"max x limit"); 
1159                                         uiBlockEndAlign(block);
1160                                         
1161                                         offsetY += 20;
1162                                         uiBlockBeginAlign(block); 
1163                                                 uiDefButBitS(block, TOG, 16, B_CONSTRAINT_TEST, "AngMinY", xco, yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y limit"); 
1164                                                 uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", xco+togButWidth, yco-offsetY, (textButWidth-5), 18, &(data->minLimit[4]), -extremeAngY, extremeAngY, 0.1,0.5,"min y limit"); 
1165                                         uiBlockEndAlign(block);
1166                                         
1167                                         uiBlockBeginAlign(block); 
1168                                                 uiDefButBitS(block, TOG, 16, B_CONSTRAINT_TEST, "AngMaxY", xco+(width-(textButWidth-5)-togButWidth), yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum y limit"); 
1169                                                 uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", xco+(width-textButWidth-5), yco-offsetY, (textButWidth), 18, &(data->maxLimit[4]), -extremeAngY, extremeAngY, 0.1,0.5,"max y limit"); 
1170                                         uiBlockEndAlign(block);
1171                                         
1172                                         offsetY += 20;
1173                                         uiBlockBeginAlign(block); 
1174                                                 uiDefButBitS(block, TOG, 32, B_CONSTRAINT_TEST, "AngMinZ", xco, yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z limit"); 
1175                                                 uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", xco+togButWidth, yco-offsetY, (textButWidth-5), 18, &(data->minLimit[5]), -extremeAngZ, extremeAngZ, 0.1,0.5,"min z limit"); 
1176                                         uiBlockEndAlign(block);
1177                                         
1178                                         uiBlockBeginAlign(block); 
1179                                                 uiDefButBitS(block, TOG, 32, B_CONSTRAINT_TEST, "AngMaxZ", xco+(width-(textButWidth-5)-togButWidth), yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum z limit"); 
1180                                                 uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", xco+(width-textButWidth-5), yco-offsetY, (textButWidth), 18, &(data->maxLimit[5]), -extremeAngZ, extremeAngZ, 0.1,0.5,"max z limit"); 
1181                                         uiBlockEndAlign(block);
1182                                 }
1183                                 
1184                         }
1185                         break;
1186                         */
1187
1188                 case CONSTRAINT_TYPE_NULL:
1189                         {
1190                                 uiItemL(box, "", 0);
1191                         }
1192                         break;
1193                 default:
1194                         result= box;
1195                         break;
1196                 }
1197         }
1198         
1199         /* clear any locks set up for proxies/lib-linking */
1200         uiBlockClearButLock(block);
1201
1202         return result;
1203 }
1204
1205 uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
1206 {
1207         Object *ob;
1208         bConstraint *con;
1209
1210         /* verify we have valid data */
1211         if(!RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
1212                 printf("uiTemplateConstraint: expected constraint on object.\n");
1213                 return NULL;
1214         }
1215
1216         ob= ptr->id.data;
1217         con= ptr->data;
1218
1219         if(!ob || !(GS(ob->id.name) == ID_OB)) {
1220                 printf("uiTemplateConstraint: expected constraint on object.\n");
1221                 return NULL;
1222         }
1223         
1224         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
1225
1226         /* hrms, the temporal constraint should not draw! */
1227         if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
1228                 bKinematicConstraint *data= con->data;
1229                 if(data->flag & CONSTRAINT_IK_TEMP)
1230                         return NULL;
1231         }
1232
1233         return draw_constraint(layout, ob, con);
1234 }
1235
1236 /************************* Group Template ***************************/
1237
1238 #if 0
1239 static void do_add_groupmenu(void *arg, int event)
1240 {
1241         Object *ob= OBACT;
1242         
1243         if(ob) {
1244                 
1245                 if(event== -1) {
1246                         Group *group= add_group( "Group" );
1247                         add_to_group(group, ob);
1248                 }
1249                 else
1250                         add_to_group(BLI_findlink(&G.main->group, event), ob);
1251                         
1252                 ob->flag |= OB_FROMGROUP;
1253                 BASACT->flag |= OB_FROMGROUP;
1254                 allqueue(REDRAWBUTSOBJECT, 0);
1255                 allqueue(REDRAWVIEW3D, 0);
1256         }               
1257 }
1258
1259 static uiBlock *add_groupmenu(void *arg_unused)
1260 {
1261         uiBlock *block;
1262         Group *group;
1263         short xco=0, yco= 0, index=0;
1264         char str[32];
1265         
1266         block= uiNewBlock(&curarea->uiblocks, "add_constraintmenu", UI_EMBOSSP, UI_HELV, curarea->win);
1267         uiBlockSetButmFunc(block, do_add_groupmenu, NULL);
1268
1269         uiDefBut(block, BUTM, B_NOP, "ADD NEW",         0, 20, 160, 19, NULL, 0.0, 0.0, 1, -1, "");
1270         for(group= G.main->group.first; group; group= group->id.next, index++) {
1271                 
1272                 /*if(group->id.lib) strcpy(str, "L  ");*/ /* we cant allow adding objects inside linked groups, it wont be saved anyway */
1273                 if(group->id.lib==0) {
1274                         strcpy(str, "   ");
1275                         strcat(str, group->id.name+2);
1276                         uiDefBut(block, BUTM, B_NOP, str,       xco*160, -20*yco, 160, 19, NULL, 0.0, 0.0, 1, index, "");
1277                         
1278                         yco++;
1279                         if(yco>24) {
1280                                 yco= 0;
1281                                 xco++;
1282                         }
1283                 }
1284         }
1285         
1286         uiTextBoundsBlock(block, 50);
1287         uiBlockSetDirection(block, UI_DOWN);    
1288         
1289         return block;
1290 }
1291
1292 static void group_ob_rem(void *gr_v, void *ob_v)
1293 {
1294         Object *ob= OBACT;
1295         
1296         if(rem_from_group(gr_v, ob) && find_group(ob, NULL)==NULL) {
1297                 ob->flag &= ~OB_FROMGROUP;
1298                 BASACT->flag &= ~OB_FROMGROUP;
1299         }
1300         allqueue(REDRAWBUTSOBJECT, 0);
1301         allqueue(REDRAWVIEW3D, 0);
1302
1303 }
1304
1305 static void group_local(void *gr_v, void *unused)
1306 {
1307         Group *group= gr_v;
1308         
1309         group->id.lib= NULL;
1310         
1311         allqueue(REDRAWBUTSOBJECT, 0);
1312         allqueue(REDRAWVIEW3D, 0);
1313         
1314 }
1315
1316 uiLayout *uiTemplateGroup(uiLayout *layout, Object *ob, Group *group)
1317 {
1318         uiSetButLock(1, NULL);
1319         uiDefBlockBut(block, add_groupmenu, NULL, "Add to Group", 10,150,150,20, "Add Object to a new Group");
1320
1321         /* all groups */
1322         if(group->id.lib) {
1323                 uiLayoutRow()
1324                 uiBlockBeginAlign(block);
1325                 uiSetButLock(GET_INT_FROM_POINTER(group->id.lib), ERROR_LIBDATA_MESSAGE); /* We cant actually use this button */
1326                 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.");
1327                 uiClearButLock();
1328                 
1329                 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");
1330                 uiButSetFunc(but, group_local, group, NULL);
1331                 uiBlockEndAlign(block);
1332         } else {
1333                 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.");
1334                 uiButSetFunc(but, test_idbutton_cb, group->id.name, NULL);
1335         }
1336         
1337         xco = 290;
1338         if(group->id.lib==0) { /* cant remove objects from linked groups */
1339                 but = uiDefIconBut(block, BUT, B_NOP, VICON_X, xco, 120-yco, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Remove Group membership");
1340                 uiButSetFunc(but, group_ob_rem, group, ob);
1341         }
1342 }
1343 #endif
1344
1345 /************************* Preview Template ***************************/
1346
1347 #include "DNA_material_types.h"
1348
1349 #define B_MATPRV 1
1350
1351
1352 static void do_preview_buttons(bContext *C, void *arg, int event)
1353 {
1354         switch(event) {
1355                 case B_MATPRV:
1356                         WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, arg);
1357                         break;
1358         }
1359 }
1360
1361 void uiTemplatePreview(uiLayout *layout, ID *id)
1362 {
1363         uiLayout *row, *col;
1364         uiBlock *block;
1365         Material *ma;
1366
1367         if(id && !ELEM4(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA)) {
1368                 printf("uiTemplatePreview: expected ID of type material, texture, lamp or world.\n");
1369                 return;
1370         }
1371
1372         block= uiLayoutGetBlock(layout);
1373
1374         row= uiLayoutRow(layout, 0);
1375
1376         col= uiLayoutColumn(row, 0);
1377         uiLayoutSetKeepAspect(col, 1);
1378         
1379         uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, id, 0.0, 0.0, 0, 0, "");
1380         uiBlockSetDrawExtraFunc(block, ED_preview_draw);
1381         
1382         uiBlockSetHandleFunc(block, do_preview_buttons, NULL);
1383         
1384         if(id) {
1385                 if(GS(id->name) == ID_MA) {
1386                         ma= (Material*)id;
1387
1388                         uiLayoutColumn(row, 1);
1389
1390                         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");
1391                         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");
1392                         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");
1393                         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");
1394                         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");
1395                         uiDefIconButC(block, ROW, B_MATPRV, ICON_MATSPHERE, 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");
1396                 }
1397         }
1398 }
1399
1400 /********************** ColorRamp Template **************************/
1401
1402 void uiTemplateColorRamp(uiLayout *layout, ColorBand *coba, int expand)
1403 {
1404         uiBlock *block;
1405         rctf rect;
1406
1407         if(coba) {
1408                 rect.xmin= 0; rect.xmax= 200;
1409                 rect.ymin= 0; rect.ymax= 190;
1410                 
1411                 block= uiLayoutFreeBlock(layout);
1412                 colorband_buttons(block, coba, &rect, !expand);
1413         }
1414 }
1415
1416 /********************* CurveMapping Template ************************/
1417
1418 #include "DNA_color_types.h"
1419
1420 void uiTemplateCurveMapping(uiLayout *layout, CurveMapping *cumap, int type)
1421 {
1422         uiBlock *block;
1423         rctf rect;
1424
1425         if(cumap) {
1426                 rect.xmin= 0; rect.xmax= 200;
1427                 rect.ymin= 0; rect.ymax= 190;
1428                 
1429                 block= uiLayoutFreeBlock(layout);
1430                 curvemap_buttons(block, cumap, type, 0, 0, &rect);
1431         }
1432 }
1433
1434 /********************* Layer Buttons Template ************************/
1435
1436 // TODO:
1437 //      - option for showing extra info like whether layer has contents?
1438 //      - for now, grouping of layers is determined by dividing up the length of 
1439 //        the array of layer bitflags
1440
1441 void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, char *propname)
1442 {
1443         uiLayout *uRow, *uSplit, *uCol;
1444         PropertyRNA *prop;
1445         int groups, cols, layers;
1446         int group, col, layer, row;
1447         
1448         if (!ptr->data)
1449                 return;
1450         
1451         prop= RNA_struct_find_property(ptr, propname);
1452         if (!prop) {
1453                 printf("uiTemplateLayer: layers property not found: %s\n", propname);
1454                 return;
1455         }
1456         
1457         /* the number of layers determines the way we group them 
1458          *      - we want 2 rows only (for now)
1459          *      - the number of columns (cols) is the total number of buttons per row
1460          *        the 'remainder' is added to this, as it will be ok to have first row slightly wider if need be
1461          *      - for now, only split into groups if if group will have at least 5 items
1462          */
1463         layers= RNA_property_array_length(prop);
1464         cols= (layers / 2) + (layers % 2);
1465         groups= ((cols / 2) < 5) ? (1) : (cols / 2);
1466         
1467         /* layers are laid out going across rows, with the columns being divided into groups */
1468         uSplit= uiLayoutSplit(layout, (1.0f/(float)groups));
1469         
1470         for (group= 0; group < groups; group++) {
1471                 uCol= uiLayoutColumn(uSplit, 1);
1472                 
1473                 for (row= 0; row < 2; row++) {
1474                         uRow= uiLayoutRow(uCol, 1);
1475                         layer= groups*cols*row + cols*group;
1476                         
1477                         /* add layers as toggle buts */
1478                         for (col= 0; (col < cols) && (layer < layers); col++, layer++) {
1479                                 int icon=0; // XXX - add some way of setting this...
1480                                 uiItemFullR(uRow, "", icon, ptr, prop, layer, 0, 0, 0, 1);
1481                         }
1482                 }
1483         }
1484 }
1485
1486
1487 /************************* List Template **************************/
1488
1489 ListBase uiTemplateList(uiLayout *layout, PointerRNA *ptr, char *propname, PointerRNA *activeptr, char *activepropname, int rows, int columns, int compact)
1490 {
1491         CollectionPointerLink *link;
1492         PropertyRNA *prop= NULL, *activeprop;
1493         PropertyType type, activetype;
1494         uiLayout *box, *row, *col;
1495         uiBlock *block;
1496         uiBut *but;
1497         Panel *pa;
1498         ListBase lb;
1499         char *name, str[32];
1500         int i= 0, activei= 0, len, items, found, min, max;
1501
1502         lb.first= lb.last= NULL;
1503         
1504         /* validate arguments */
1505         block= uiLayoutGetBlock(layout);
1506         pa= block->panel;
1507
1508         if(!pa) {
1509                 printf("uiTemplateList: only works inside a panel.\n");
1510                 return lb;
1511         }
1512
1513         if(!activeptr->data)
1514                 return lb;
1515         
1516         if(ptr->data) {
1517                 prop= RNA_struct_find_property(ptr, propname);
1518                 if(!prop) {
1519                         printf("uiTemplateList: property not found: %s\n", propname);
1520                         return lb;
1521                 }
1522         }
1523
1524         activeprop= RNA_struct_find_property(activeptr, activepropname);
1525         if(!activeprop) {
1526                 printf("uiTemplateList: property not found: %s\n", activepropname);
1527                 return lb;
1528         }
1529
1530         if(prop) {
1531                 type= RNA_property_type(prop);
1532                 if(type != PROP_COLLECTION) {
1533                         printf("uiTemplateList: expected collection property.\n");
1534                         return lb;
1535                 }
1536         }
1537
1538         activetype= RNA_property_type(activeprop);
1539         if(activetype != PROP_INT) {
1540                 printf("uiTemplateList: expected integer property.\n");
1541                 return lb;
1542         }
1543
1544         /* get active data */
1545         activei= RNA_property_int_get(activeptr, activeprop);
1546
1547         if(compact) {
1548                 /* compact layout */
1549                 found= 0;
1550
1551                 row= uiLayoutRow(layout, 1);
1552
1553                 if(ptr->data && prop) {
1554                         /* create list items */
1555                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
1556                                 found= (activei == i);
1557
1558                                 if(found) {
1559                                         /* create button */
1560                                         name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
1561                                         if(name) {
1562                                                 uiItemL(row, name, RNA_struct_ui_icon(itemptr.type));
1563                                                 MEM_freeN(name);
1564                                         }
1565
1566                                         /* add to list to return */
1567                                         link= MEM_callocN(sizeof(CollectionPointerLink), "uiTemplateList return");
1568                                         link->ptr= itemptr;
1569                                         BLI_addtail(&lb, link);
1570                                 }
1571
1572                                 i++;
1573                         }
1574                         RNA_PROP_END;
1575                 }
1576
1577                 /* if not found, add in dummy button */
1578                 if(i == 0)
1579                         uiItemL(row, "", 0);
1580
1581                 /* next/prev button */
1582                 sprintf(str, "%d :", i);
1583                 but= uiDefIconTextButR(block, NUM, 0, 0, str, 0,0,UI_UNIT_X*5,UI_UNIT_Y, activeptr, activepropname, 0, 0, 0, 0, 0, "");
1584                 if(i == 0)
1585                         uiButSetFlag(but, UI_BUT_DISABLED);
1586         }
1587         else {
1588                 /* default rows/columns */
1589                 if(rows == 0)
1590                         rows= 5;
1591                 if(columns == 0)
1592                         columns= 1;
1593
1594                 /* layout */
1595                 box= uiLayoutBox(layout);
1596                 row= uiLayoutRow(box, 0);
1597                 col = uiLayoutColumn(row, 1);
1598
1599                 uiBlockSetEmboss(block, UI_EMBOSSN);
1600
1601                 /* init numbers */
1602                 RNA_property_int_range(activeptr, activeprop, &min, &max);
1603
1604                 len= max - min + 1;
1605                 items= rows*columns;
1606
1607                 pa->list_scroll= MIN2(pa->list_scroll, len-items);
1608                 pa->list_scroll= MAX2(pa->list_scroll, 0);
1609
1610                 if(ptr->data && prop) {
1611                         /* create list items */
1612                         RNA_PROP_BEGIN(ptr, itemptr, prop) {
1613                                 if(i >= pa->list_scroll && i<pa->list_scroll+items) {
1614                                         name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
1615
1616                                         if(name) {
1617                                                 /* create button */
1618                                                 but= uiDefIconTextButR(block, ROW, 0, RNA_struct_ui_icon(itemptr.type), name, 0,0,UI_UNIT_X*10,UI_UNIT_Y, activeptr, activepropname, 0, 0, i, 0, 0, "");
1619                                                 uiButSetFlag(but, UI_ICON_LEFT|UI_TEXT_LEFT);
1620
1621                                                 MEM_freeN(name);
1622                                         }
1623
1624                                         /* add to list to return */
1625                                         link= MEM_callocN(sizeof(CollectionPointerLink), "uiTemplateList return");
1626                                         link->ptr= itemptr;
1627                                         BLI_addtail(&lb, link);
1628                                 }
1629
1630                                 i++;
1631                         }
1632                         RNA_PROP_END;
1633                 }
1634
1635                 /* add dummy buttons to fill space */
1636                 while(i < pa->list_scroll+items) {
1637                         if(i >= pa->list_scroll)
1638                                 uiItemL(col, "", 0);
1639                         i++;
1640                 }
1641
1642                 uiBlockSetEmboss(block, UI_EMBOSS);
1643
1644                 /* add scrollbar */
1645                 if(len > items) {
1646                         col= uiLayoutColumn(row, 0);
1647                         uiDefButI(block, SCROLL, 0, "", 0,0,UI_UNIT_X*0.75,UI_UNIT_Y*items, &pa->list_scroll, 0, len-items, items, 0, "");
1648                 }
1649         }
1650
1651         /* return items in list */
1652         return lb;
1653 }
1654
1655 /************************* Operator Search Template **************************/
1656
1657 static void operator_call_cb(struct bContext *C, void *arg1, void *arg2)
1658 {
1659         wmOperatorType *ot= arg2;
1660         
1661         if(ot)
1662                 WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
1663 }
1664
1665 static void operator_search_cb(const struct bContext *C, void *arg, char *str, uiSearchItems *items)
1666 {
1667         wmOperatorType *ot = WM_operatortype_first();
1668         
1669         for(; ot; ot= ot->next) {
1670                 
1671                 if(BLI_strcasestr(ot->name, str)) {
1672                         if(ot->poll==NULL || ot->poll((bContext *)C)) {
1673                                 char name[256];
1674                                 int len= strlen(ot->name);
1675                                 
1676                                 /* display name for menu, can hold hotkey */
1677                                 BLI_strncpy(name, ot->name, 256);
1678                                 
1679                                 /* check for hotkey */
1680                                 if(len < 256-6) {
1681                                         if(WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, &name[len+1], 256-len-1))
1682                                                 name[len]= '|';
1683                                 }
1684                                 
1685                                 if(0==uiSearchItemAdd(items, name, ot, 0))
1686                                         break;
1687                         }
1688                 }
1689         }
1690 }
1691
1692 void uiTemplateOperatorSearch(uiLayout *layout)
1693 {
1694         uiBlock *block;
1695         uiBut *but;
1696         static char search[256]= "";
1697                 
1698         block= uiLayoutGetBlock(layout);
1699         uiBlockSetCurLayout(block, layout);
1700
1701         but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, "");
1702         uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
1703 }
1704
1705 /************************* Running Jobs Template **************************/
1706
1707 #define B_STOPRENDER    1
1708 #define B_STOPCAST              2
1709 #define B_STOPANIM              3
1710
1711 static void do_running_jobs(bContext *C, void *arg, int event)
1712 {
1713         switch(event) {
1714                 case B_STOPRENDER:
1715                         G.afbreek= 1;
1716                         break;
1717                 case B_STOPCAST:
1718                         WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C));
1719                         break;
1720                 case B_STOPANIM:
1721                         ED_screen_animation_timer(C, 0, 0);
1722                         break;
1723         }
1724 }
1725
1726 void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
1727 {
1728         bScreen *screen= CTX_wm_screen(C);
1729         Scene *scene= CTX_data_scene(C);
1730         wmWindowManager *wm= CTX_wm_manager(C);
1731         uiBlock *block;
1732
1733         block= uiLayoutGetBlock(layout);
1734         uiBlockSetCurLayout(block, layout);
1735
1736         uiBlockSetHandleFunc(block, do_running_jobs, NULL);
1737
1738         if(WM_jobs_test(wm, scene))
1739                 uiDefIconTextBut(block, BUT, B_STOPRENDER, ICON_REC, "Render", 0,0,75,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop rendering");
1740         if(WM_jobs_test(wm, screen))
1741                 uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_REC, "Capture", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop screencast");
1742         if(screen->animtimer)
1743                 uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_REC, "Anim Player", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop animation playback");
1744 }
1745