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