2.50:
[blender-staging.git] / source / blender / editors / interface / interface_templates.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * Contributor(s): Blender Foundation 2009.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "BLI_string.h"
31
32 #include "BKE_context.h"
33 #include "BKE_library.h"
34 #include "BKE_utildefines.h"
35
36 #include "ED_screen.h"
37 #include "ED_previewrender.h"
38
39 #include "RNA_access.h"
40
41 #include "WM_api.h"
42 #include "WM_types.h"
43
44 #include "UI_interface.h"
45 #include "UI_resources.h"
46
47 void ui_template_fix_linking()
48 {
49 }
50
51 /********************** Header Template *************************/
52
53 void uiTemplateHeader(uiLayout *layout, bContext *C)
54 {
55         uiBlock *block;
56         
57         block= uiLayoutFreeBlock(layout);
58         ED_area_header_standardbuttons(C, block, 0);
59 }
60
61 /******************* Header ID Template ************************/
62
63 typedef struct TemplateID {
64         PointerRNA ptr;
65         PropertyRNA *prop;
66
67         int flag;
68         short browse;
69
70         char newop[256];
71         char openop[256];
72         char unlinkop[256];
73         
74         short idtype;
75 } TemplateID;
76
77 static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
78 {
79         TemplateID *template= (TemplateID*)arg_litem;
80         PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
81         ID *idtest, *id= idptr.data;
82         ListBase *lb= wich_libbase(CTX_data_main(C), template->idtype);
83         int nr, event= GET_INT_FROM_POINTER(arg_event);
84         
85         if(event == UI_ID_BROWSE && template->browse == 32767)
86                 event= UI_ID_ADD_NEW;
87         else if(event == UI_ID_BROWSE && template->browse == 32766)
88                 event= UI_ID_OPEN;
89
90         switch(event) {
91                 case UI_ID_BROWSE: {
92                         if(template->browse== -2) {
93                                 /* XXX implement or find a replacement
94                                  * activate_databrowse((ID *)G.buts->lockpoin, GS(id->name), 0, B_MESHBROWSE, &template->browse, do_global_buttons); */
95                                 return;
96                         }
97                         if(template->browse < 0)
98                                 return;
99
100                         for(idtest=lb->first, nr=1; idtest; idtest=idtest->next, nr++) {
101                                 if(nr==template->browse) {
102                                         if(id == idtest)
103                                                 return;
104
105                                         id= idtest;
106                                         RNA_id_pointer_create(id, &idptr);
107                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
108                                         RNA_property_update(C, &template->ptr, template->prop);
109                                         /* XXX */
110
111                                         break;
112                                 }
113                         }
114                         break;
115                 }
116                 case UI_ID_DELETE:
117                         memset(&idptr, 0, sizeof(idptr));
118                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
119                         RNA_property_update(C, &template->ptr, template->prop);
120                         break;
121                 case UI_ID_FAKE_USER:
122                         if(id) {
123                                 if(id->flag & LIB_FAKEUSER) id->us++;
124                                 else id->us--;
125                         }
126                         else return;
127                         break;
128                 case UI_ID_PIN:
129                         break;
130                 case UI_ID_ADD_NEW:
131                         WM_operator_name_call(C, template->newop, WM_OP_INVOKE_REGION_WIN, NULL);
132                         break;
133                 case UI_ID_OPEN:
134                         WM_operator_name_call(C, template->openop, WM_OP_INVOKE_REGION_WIN, NULL);
135                         break;
136 #if 0
137                 case UI_ID_ALONE:
138                         if(!id || id->us < 1)
139                                 return;
140                         break;
141                 case UI_ID_LOCAL:
142                         if(!id || id->us < 1)
143                                 return;
144                         break;
145                 case UI_ID_AUTO_NAME:
146                         break;
147 #endif
148         }
149 }
150
151 static void template_header_ID(bContext *C, uiBlock *block, TemplateID *template, StructRNA *type)
152 {
153         uiBut *but;
154         TemplateID *duptemplate;
155         PointerRNA idptr;
156         ListBase *lb;
157
158         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
159         lb= wich_libbase(CTX_data_main(C), template->idtype);
160
161         if(idptr.type)
162                 type= idptr.type;
163         if(type)
164                 uiDefIconBut(block, LABEL, 0, RNA_struct_ui_icon(type), 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
165
166         uiBlockBeginAlign(block);
167         if(template->flag & UI_ID_BROWSE) {
168                 char *extrastr, *str;
169                 
170                 if((template->flag & UI_ID_ADD_NEW) && (template->flag & UI_ID_OPEN))
171                         extrastr= "OPEN NEW %x 32766 |ADD NEW %x 32767";
172                 else if(template->flag & UI_ID_ADD_NEW)
173                         extrastr= "ADD NEW %x 32767";
174                 else if(template->flag & UI_ID_OPEN)
175                         extrastr= "OPEN NEW %x 32766";
176                 else
177                         extrastr= NULL;
178
179                 duptemplate= MEM_dupallocN(template);
180                 IDnames_to_pupstring(&str, NULL, extrastr, lb, idptr.data, &duptemplate->browse);
181
182                 but= uiDefButS(block, MENU, 0, str, 0, 0, UI_UNIT_X, UI_UNIT_Y, &duptemplate->browse, 0, 0, 0, 0, "Browse existing choices, or add new");
183                 uiButSetNFunc(but, template_id_cb, duptemplate, SET_INT_IN_POINTER(UI_ID_BROWSE));
184         
185                 MEM_freeN(str);
186         }
187
188         /* text button with name */
189         if(idptr.data) {
190                 char name[64];
191
192                 //text_idbutton(idptr.data, name);
193                 name[0]= '\0';
194                 but= uiDefButR(block, TEX, 0, name, 0, 0, UI_UNIT_X*6, UI_UNIT_Y, &idptr, "name", -1, 0, 0, -1, -1, NULL);
195                 uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
196
197                 /* delete button */
198                 if(template->flag & UI_ID_DELETE) {
199                         if(template->unlinkop[0]) {
200                                 but= uiDefIconButO(block, BUT, template->unlinkop, WM_OP_EXEC_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
201                         }
202                         else {
203                                 but= uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
204                                 uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
205                         }
206                 }
207         }
208         uiBlockEndAlign(block);
209 }
210
211 void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
212 {
213         TemplateID *template;
214         uiBlock *block;
215         PropertyRNA *prop;
216         StructRNA *type;
217
218         if(!ptr->data)
219                 return;
220
221         prop= RNA_struct_find_property(ptr, propname);
222
223         if(!prop || RNA_property_type(prop) != PROP_POINTER) {
224                 printf("uiTemplateID: pointer property not found: %s\n", propname);
225                 return;
226         }
227
228         template= MEM_callocN(sizeof(TemplateID), "TemplateID");
229         template->ptr= *ptr;
230         template->prop= prop;
231         template->flag= UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE;
232
233         if(newop) {
234                 template->flag |= UI_ID_ADD_NEW;
235                 BLI_strncpy(template->newop, newop, sizeof(template->newop));
236         }
237         if(openop) {
238                 template->flag |= UI_ID_OPEN;
239                 BLI_strncpy(template->openop, openop, sizeof(template->openop));
240         }
241         if(unlinkop)
242                 BLI_strncpy(template->unlinkop, unlinkop, sizeof(template->unlinkop));
243
244         type= RNA_property_pointer_type(ptr, prop);
245         template->idtype = RNA_type_to_ID_code(type);
246
247         if(template->idtype) {
248                 uiLayoutRow(layout, 1);
249                 block= uiLayoutGetBlock(layout);
250                 template_header_ID(C, block, template, type);
251         }
252
253         MEM_freeN(template);
254 }
255
256 /************************ Modifier Template *************************/
257
258 #define ERROR_LIBDATA_MESSAGE "Can't edit external libdata"
259
260 #include <string.h>
261
262 #include "DNA_object_force.h"
263 #include "DNA_object_types.h"
264 #include "DNA_modifier_types.h"
265 #include "DNA_scene_types.h"
266
267 #include "BKE_depsgraph.h"
268 #include "BKE_DerivedMesh.h"
269 #include "BKE_global.h"
270 #include "BKE_modifier.h"
271 #include "BKE_object.h"
272 #include "BKE_particle.h"
273 #include "BKE_report.h"
274
275 #include "UI_resources.h"
276 #include "ED_util.h"
277
278 #include "BLI_arithb.h"
279 #include "BLI_listbase.h"
280
281 #include "ED_object.h"
282
283 static void modifiers_del(bContext *C, void *ob_v, void *md_v)
284 {
285         Scene *scene= CTX_data_scene(C);
286         Object *ob= ob_v;
287         ReportList reports;
288
289         BKE_reports_init(&reports, RPT_STORE);
290
291         if(ED_object_modifier_delete(&reports, ob_v, md_v)) {
292                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
293                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
294
295                 ED_undo_push(C, "Delete modifier");
296         }
297         else
298                 uiPupMenuReports(C, &reports);
299
300         BKE_reports_clear(&reports);
301 }
302
303 static void modifiers_moveUp(bContext *C, void *ob_v, void *md_v)
304 {
305         Scene *scene= CTX_data_scene(C);
306         Object *ob= ob_v;
307         ReportList reports;
308
309         BKE_reports_init(&reports, RPT_STORE);
310
311         if(ED_object_modifier_move_up(&reports, ob_v, md_v)) {
312                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
313                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
314
315                 ED_undo_push(C, "Move modifier");
316         }
317         else
318                 uiPupMenuReports(C, &reports);
319
320         BKE_reports_clear(&reports);
321 }
322
323 static void modifiers_moveDown(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_move_down(&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, "Move modifier");
336         }
337         else
338                 uiPupMenuReports(C, &reports);
339
340         BKE_reports_clear(&reports);
341 }
342
343 static void modifiers_convertParticles(bContext *C, void *obv, void *mdv)
344 {
345         Scene *scene= CTX_data_scene(C);
346         Object *ob= obv;
347         ReportList reports;
348
349         BKE_reports_init(&reports, RPT_STORE);
350
351         if(ED_object_modifier_convert(&reports, scene, obv, mdv)) {
352                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
353                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
354
355                 ED_undo_push(C, "Convert particles to mesh object(s).");
356         }
357         else
358                 uiPupMenuReports(C, &reports);
359
360         BKE_reports_clear(&reports);
361 }
362
363 static void modifiers_applyModifier(bContext *C, void *obv, void *mdv)
364 {
365         Scene *scene= CTX_data_scene(C);
366         Object *ob= obv;
367         ReportList reports;
368
369         BKE_reports_init(&reports, RPT_STORE);
370
371         if(ED_object_modifier_apply(&reports, scene, obv, mdv)) {
372                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
373                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
374
375                 ED_undo_push(C, "Apply modifier");
376         }
377         else
378                 uiPupMenuReports(C, &reports);
379
380         BKE_reports_clear(&reports);
381 }
382
383 static void modifiers_copyModifier(bContext *C, void *ob_v, void *md_v)
384 {
385         Scene *scene= CTX_data_scene(C);
386         Object *ob= ob_v;
387         ReportList reports;
388
389         BKE_reports_init(&reports, RPT_STORE);
390
391         if(ED_object_modifier_copy(&reports, ob_v, md_v)) {
392                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
393                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
394                 ED_undo_push(C, "Copy modifier");
395         }
396         else
397                 uiPupMenuReports(C, &reports);
398
399         BKE_reports_clear(&reports);
400 }
401
402 static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v)
403 {
404         Scene *scene= CTX_data_scene(C);
405         Object *ob = ob_v;
406         ModifierData *md;
407         
408         int i, cageIndex = modifiers_getCageIndex(ob, NULL );
409
410         for(i = 0, md=ob->modifiers.first; md; ++i, md=md->next) {
411                 if(md == md_v) {
412                         if(i >= cageIndex)
413                                 md->mode ^= eModifierMode_OnCage;
414                         break;
415                 }
416         }
417
418         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
419         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
420 }
421
422 static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
423 {
424         Scene *scene= CTX_data_scene(C);
425         Object *ob = ob_v;
426         ModifierData *md = md_v;
427         ModifierData *nmd = modifier_new(md->type);
428
429         modifier_copyData(md, nmd);
430         nmd->mode &= ~eModifierMode_Virtual;
431
432         BLI_addhead(&ob->modifiers, nmd);
433
434         ob->partype = PAROBJECT;
435
436         WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
437         DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
438
439         ED_undo_push(C, "Modifier convert to real");
440 }
441
442 static int modifier_can_delete(ModifierData *md)
443 {
444         // deletion over the deflection panel
445         // fluid particle modifier can't be deleted here
446
447         if(md->type==eModifierType_Fluidsim)
448                 return 0;
449         if(md->type==eModifierType_Collision)
450                 return 0;
451         if(md->type==eModifierType_Surface)
452                 return 0;
453         if(md->type == eModifierType_ParticleSystem)
454                 if(((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID)
455                         return 0;
456
457         return 1;
458 }
459
460 static uiLayout *draw_modifier(uiLayout *layout, Object *ob, ModifierData *md, int index, int cageIndex, int lastCageIndex)
461 {
462         ModifierTypeInfo *mti = modifierType_getInfo(md->type);
463         PointerRNA ptr;
464         uiBut *but;
465         uiBlock *block;
466         uiLayout *column, *row, *subrow, *result= NULL;
467         int isVirtual = md->mode&eModifierMode_Virtual;
468         // XXX short color = md->error?TH_REDALERT:TH_BUT_NEUTRAL;
469         short width = 295, buttonWidth = width-120-10;
470         char str[128];
471
472         RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr);
473
474         column= uiLayoutColumn(layout, 1);
475         uiLayoutSetContextPointer(column, "modifier", &ptr);
476
477         /* rounded header */
478         /* XXX uiBlockSetCol(block, color); */
479                 /* roundbox 4 free variables: corner-rounding, nop, roundbox type, shade */
480
481         row= uiLayoutRow(uiLayoutBox(column), 0);
482         block= uiLayoutGetBlock(row);
483
484         subrow= uiLayoutRow(row, 0);
485         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT);
486
487         //uiDefBut(block, ROUNDBOX, 0, "", x-10, y-4, width, 25, NULL, 7.0, 0.0, 
488         //               (!isVirtual && (md->mode&eModifierMode_Expanded))?3:15, 20, ""); 
489         /* XXX uiBlockSetCol(block, TH_AUTO); */
490         
491         /* open/close icon */
492         if (!isVirtual) {
493                 uiBlockSetEmboss(block, UI_EMBOSSN);
494                 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");
495         }
496
497         uiBlockSetEmboss(block, UI_EMBOSS);
498         
499         if (isVirtual) {
500                 sprintf(str, "%s parent deform", md->name);
501                 uiDefBut(block, LABEL, 0, str, 0, 0, 185, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Modifier name"); 
502
503                 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");
504                 uiButSetFunc(but, modifiers_convertToReal, ob, md);
505         } else {
506                 uiBlockBeginAlign(block);
507                 uiDefBut(block, TEX, 0, "", 0, 0, buttonWidth-60, UI_UNIT_Y, md->name, 0.0, sizeof(md->name)-1, 0.0, 0.0, "Modifier name"); 
508
509                 /* Softbody not allowed in this situation, enforce! */
510                 if (((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) && (md->type!=eModifierType_Surface)) {
511                         uiDefIconButBitI(block, TOG, eModifierMode_Render, 0, ICON_SCENE, 0, 0, 19, UI_UNIT_Y,&md->mode, 0, 0, 1, 0, "Enable modifier during rendering");
512                         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");
513                         if (mti->flags&eModifierTypeFlag_SupportsEditmode) {
514                                 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)");
515                         }
516                 }
517                 uiBlockEndAlign(block);
518
519                 /* XXX uiBlockSetEmboss(block, UI_EMBOSSR); */
520
521                 if (ob->type==OB_MESH && modifier_couldBeCage(md) && index<=lastCageIndex) {
522                         int icon; //, color;
523
524                         if (index==cageIndex) {
525                                 // XXX color = TH_BUT_SETTING;
526                                 icon = VICON_EDITMODE_HLT;
527                         } else if (index<cageIndex) {
528                                 // XXX color = TH_BUT_NEUTRAL;
529                                 icon = VICON_EDITMODE_DEHLT;
530                         } else {
531                                 // XXX color = TH_BUT_NEUTRAL;
532                                 icon = ICON_BLANK1;
533                         }
534                         /* XXX uiBlockSetCol(block, color); */
535                         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");
536                         uiButSetFunc(but, modifiers_setOnCage, ob, md);
537                         /* XXX uiBlockSetCol(block, TH_AUTO); */
538                 }
539         }
540
541         subrow= uiLayoutRow(row, 0);
542         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT);
543
544         if(!isVirtual) {
545                 /* XXX uiBlockSetCol(block, TH_BUT_ACTION); */
546
547                 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");
548                 uiButSetFunc(but, modifiers_moveUp, ob, md);
549
550                 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");
551                 uiButSetFunc(but, modifiers_moveDown, ob, md);
552                 
553                 uiBlockSetEmboss(block, UI_EMBOSSN);
554                 
555                 if(modifier_can_delete(md)) {
556                         but = uiDefIconBut(block, BUT, 0, VICON_X, 0, 0, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Delete modifier");
557                         uiButSetFunc(but, modifiers_del, ob, md);
558                 }
559                 /* XXX uiBlockSetCol(block, TH_AUTO); */
560         }
561
562         uiBlockSetEmboss(block, UI_EMBOSS);
563
564         if(!isVirtual && (md->mode&eModifierMode_Expanded)) {
565                 uiLayout *box;
566
567                 box= uiLayoutBox(column);
568                 row= uiLayoutRow(box, 1);
569
570                 if (!isVirtual && (md->type!=eModifierType_Collision) && (md->type!=eModifierType_Surface)) {
571                         uiBlockSetButLock(block, object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE); /* only here obdata, the rest of modifiers is ob level */
572
573                                                 if (md->type==eModifierType_ParticleSystem) {
574                         ParticleSystem *psys= ((ParticleSystemModifierData *)md)->psys;
575
576                         if(!(G.f & G_PARTICLEEDIT)) {
577                                         if(ELEM3(psys->part->draw_as, PART_DRAW_PATH, PART_DRAW_GR, PART_DRAW_OB) && psys->pathcache) {
578                                                 but = uiDefBut(block, BUT, 0, "Convert",        0,0,60,19, 0, 0, 0, 0, 0, "Convert the current particles to a mesh object");
579                                                 uiButSetFunc(but, modifiers_convertParticles, ob, md);
580                                         }
581                                 }
582                         }
583                         else{
584                                 but = uiDefBut(block, BUT, 0, "Apply",  0,0,60,19, 0, 0, 0, 0, 0, "Apply the current modifier and remove from the stack");
585                                 uiButSetFunc(but, modifiers_applyModifier, ob, md);
586                         }
587                         
588                         uiBlockClearButLock(block);
589                         uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
590
591                         if (md->type!=eModifierType_Fluidsim && md->type!=eModifierType_Softbody && md->type!=eModifierType_ParticleSystem && (md->type!=eModifierType_Cloth)) {
592                                 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");
593                                 uiButSetFunc(but, modifiers_copyModifier, ob, md);
594                         }
595                 }
596
597                 result= uiLayoutColumn(box, 0);
598                 block= uiLayoutFreeBlock(box);
599         }
600
601         if (md->error) {
602                 row = uiLayoutRow(uiLayoutBox(column), 0);
603
604                 /* XXX uiBlockSetCol(block, color); */
605                 uiItemL(row, md->error, ICON_ERROR);
606                 /* XXX uiBlockSetCol(block, TH_AUTO); */
607         }
608
609         return result;
610 }
611
612 uiLayout *uiTemplateModifier(uiLayout *layout, PointerRNA *ptr)
613 {
614         Object *ob;
615         ModifierData *md, *vmd;
616         int i, lastCageIndex, cageIndex;
617
618         /* verify we have valid data */
619         if(!RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
620                 printf("uiTemplateModifier: expected modifier on object.\n");
621                 return NULL;
622         }
623
624         ob= ptr->id.data;
625         md= ptr->data;
626
627         if(!ob || !(GS(ob->id.name) == ID_OB)) {
628                 printf("uiTemplateModifier: expected modifier on object.\n");
629                 return NULL;
630         }
631         
632         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
633         
634         /* find modifier and draw it */
635         cageIndex = modifiers_getCageIndex(ob, &lastCageIndex);
636
637         // XXX virtual modifiers are not accesible for python
638         vmd = modifiers_getVirtualModifierList(ob);
639
640         for(i=0; vmd; i++, vmd=vmd->next) {
641                 if(md == vmd)
642                         return draw_modifier(layout, ob, md, i, cageIndex, lastCageIndex);
643                 else if(vmd->mode&eModifierMode_Virtual)
644                         i--;
645         }
646
647         return NULL;
648 }
649
650 /************************ Constraint Template *************************/
651
652 #include "DNA_action_types.h"
653 #include "DNA_constraint_types.h"
654
655 #include "BKE_action.h"
656 #include "BKE_constraint.h"
657
658 #define REDRAWIPO                                       1
659 #define REDRAWNLA                                       2
660 #define REDRAWBUTSOBJECT                        3               
661 #define REDRAWACTION                            4
662 #define B_CONSTRAINT_TEST                       5
663 #define B_CONSTRAINT_CHANGETARGET       6
664 #define B_CONSTRAINT_INF                        7
665 #define REMAKEIPO                                       8
666 #define B_DIFF                                          9
667
668 void do_constraint_panels(bContext *C, void *arg, int event)
669 {
670         Scene *scene= CTX_data_scene(C);
671         Object *ob= CTX_data_active_object(C);
672         
673         switch(event) {
674         case B_CONSTRAINT_TEST:
675                 // XXX allqueue(REDRAWVIEW3D, 0);
676                 // XXX allqueue(REDRAWBUTSOBJECT, 0);
677                 // XXX allqueue(REDRAWBUTSEDIT, 0);
678                 break;  // no handling
679         case B_CONSTRAINT_INF:
680                 /* influence; do not execute actions for 1 dag_flush */
681                 if (ob->pose)
682                         ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
683                 break;
684         case B_CONSTRAINT_CHANGETARGET:
685                 if (ob->pose) ob->pose->flag |= POSE_RECALC;    // checks & sorts pose channels
686                 DAG_scene_sort(scene);
687                 break;
688         default:
689                 break;
690         }
691
692         object_test_constraints(ob);
693         
694         if(ob->pose) update_pose_constraint_flags(ob->pose);
695         
696         if(ob->type==OB_ARMATURE) DAG_object_flush_update(scene, ob, OB_RECALC_DATA|OB_RECALC_OB);
697         else DAG_object_flush_update(scene, ob, OB_RECALC_OB);
698         
699         // XXX allqueue(REDRAWVIEW3D, 0);
700         // XXX allqueue(REDRAWBUTSOBJECT, 0);
701         // XXX allqueue(REDRAWBUTSEDIT, 0);
702 }
703
704 static void constraint_active_func(bContext *C, void *ob_v, void *con_v)
705 {
706         ED_object_constraint_set_active(ob_v, con_v);
707 }
708
709 static void del_constraint_func (bContext *C, void *ob_v, void *con_v)
710 {
711         if(ED_object_constraint_delete(NULL, ob_v, con_v))
712                 ED_undo_push(C, "Delete Constraint");
713 }
714
715 static void verify_constraint_name_func (bContext *C, void *con_v, void *name_v)
716 {
717         Object *ob= CTX_data_active_object(C);
718         bConstraint *con= con_v;
719         char oldname[32];       
720         
721         if (!con)
722                 return;
723         
724         /* put on the stack */
725         BLI_strncpy(oldname, (char *)name_v, 32);
726         
727         ED_object_constraint_rename(ob, con, oldname);
728         ED_object_constraint_set_active(ob, con);
729         // XXX allqueue(REDRAWACTION, 0); 
730 }
731
732 static void constraint_moveUp(bContext *C, void *ob_v, void *con_v)
733 {
734         if(ED_object_constraint_move_up(NULL, ob_v, con_v))
735                 ED_undo_push(C, "Move Constraint");
736 }
737
738 static void constraint_moveDown(bContext *C, void *ob_v, void *con_v)
739 {
740         if(ED_object_constraint_move_down(NULL, ob_v, con_v))
741                 ED_undo_push(C, "Move Constraint");
742 }
743
744 /* some commonly used macros in the constraints drawing code */
745 #define is_armature_target(target) (target && target->type==OB_ARMATURE)
746 #define is_armature_owner(ob) ((ob->type == OB_ARMATURE) && (ob->flag & OB_POSEMODE))
747 #define is_geom_target(target) (target && (ELEM(target->type, OB_MESH, OB_LATTICE)) )
748
749 /* Helper function for draw constraint - draws constraint space stuff 
750  * This function should not be called if no menus are required 
751  * owner/target: -1 = don't draw menu; 0= not posemode, 1 = posemode 
752  */
753 static void draw_constraint_spaceselect (uiBlock *block, bConstraint *con, short xco, short yco, short owner, short target)
754 {
755         short tarx, ownx, iconx;
756         short bwidth;
757         short iconwidth = 20;
758         
759         /* calculate sizes and placement of menus */
760         if (owner == -1) {
761                 bwidth = 125;
762                 tarx = 120;
763                 ownx = 0;
764         }
765         else if (target == -1) {
766                 bwidth = 125;
767                 tarx = 0;
768                 ownx = 120;
769         }
770         else {
771                 bwidth = 100;
772                 tarx = 85;
773                 iconx = tarx + bwidth + 5;
774                 ownx = tarx + bwidth + iconwidth + 10;
775         }
776         
777         
778         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Convert:", xco, yco, 80,18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
779
780         /* Target-Space */
781         if (target == 1) {
782                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x2|Local with Parent %x3|Local Space %x1", 
783                                                                                                 tarx, yco, bwidth, 18, &con->tarspace, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
784         }
785         else if (target == 0) {
786                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Local (Without Parent) Space %x1", 
787                                                                                 tarx, yco, bwidth, 18, &con->tarspace, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
788         }
789         
790         if ((target != -1) && (owner != -1))
791                 uiDefIconBut(block, LABEL, 0, ICON_ARROW_LEFTRIGHT,
792                         iconx, yco, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "");
793         
794         /* Owner-Space */
795         if (owner == 1) {
796                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Pose Space %x2|Local with Parent %x3|Local Space %x1", 
797                                                                                                 ownx, yco, bwidth, 18, &con->ownspace, 0, 0, 0, 0, "Choose space that owner is evaluated in");  
798         }
799         else if (owner == 0) {
800                 uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Local (Without Parent) Space %x1", 
801                                                                                 ownx, yco, bwidth, 18, &con->ownspace, 0, 0, 0, 0, "Choose space that owner is evaluated in");  
802         }
803 }
804
805 /* draw panel showing settings for a constraint */
806 static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
807 {
808         bPoseChannel *pchan= get_active_posechannel(ob);
809         bConstraintTypeInfo *cti;
810         uiBlock *block;
811         uiLayout *result= NULL, *col, *box, *row, *subrow;
812         uiBut *but;
813         PointerRNA ptr;
814         char typestr[32];
815         short width = 265;
816         short proxy_protected, xco=0, yco=0;
817         int rb_col;
818
819         /* get constraint typeinfo */
820         cti= constraint_get_typeinfo(con);
821         if (cti == NULL) {
822                 /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
823                 if (con->type == CONSTRAINT_TYPE_NULL)
824                         strcpy(typestr, "Null");
825                 else
826                         strcpy(typestr, "Unknown");
827         }
828         else
829                 strcpy(typestr, cti->name);
830                 
831         /* determine whether constraint is proxy protected or not */
832         if (proxylocked_constraints_owner(ob, pchan))
833                 proxy_protected= (con->flag & CONSTRAINT_PROXY_LOCAL)==0;
834         else
835                 proxy_protected= 0;
836
837         /* unless button has own callback, it adds this callback to button */
838         block= uiLayoutGetBlock(layout);
839         uiBlockSetHandleFunc(block, do_constraint_panels, NULL);
840         uiBlockSetFunc(block, constraint_active_func, ob, con);
841
842         RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
843
844         col= uiLayoutColumn(layout, 1);
845         uiLayoutSetContextPointer(col, "constraint", &ptr);
846
847         box= uiLayoutBox(col);
848         row= uiLayoutRow(box, 0);
849
850         block= uiLayoutFreeBlock(box);
851
852         subrow= uiLayoutRow(row, 0);
853         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT);
854
855         /* Draw constraint header */
856         uiBlockSetEmboss(block, UI_EMBOSSN);
857         
858         /* rounded header */
859         rb_col= (con->flag & CONSTRAINT_ACTIVE)?50:20;
860         
861         /* open/close */
862         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");
863         
864         /* name */      
865         if ((con->flag & CONSTRAINT_EXPAND) && (proxy_protected==0)) {
866                 /* XXX if (con->flag & CONSTRAINT_DISABLE)
867                         uiBlockSetCol(block, TH_REDALERT);*/
868                 
869                 uiBlockSetEmboss(block, UI_EMBOSS);
870                 
871                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco+10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
872                 
873                 but = uiDefBut(block, TEX, B_CONSTRAINT_TEST, "", xco+120, yco, 85, 18, con->name, 0.0, 29.0, 0.0, 0.0, "Constraint name"); 
874                 uiButSetFunc(but, verify_constraint_name_func, con, NULL);
875         }       
876         else {
877                 uiBlockSetEmboss(block, UI_EMBOSSN);
878                 
879                 /* XXX if (con->flag & CONSTRAINT_DISABLE)
880                         uiBlockSetCol(block, TH_REDALERT);*/
881                 
882                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco+10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
883                 
884                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, con->name, xco+120, yco-1, 135, 19, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
885         }
886
887         // XXX uiBlockSetCol(block, TH_AUTO);   
888
889         subrow= uiLayoutRow(row, 0);
890         uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT);
891         
892         /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
893         if (proxy_protected) {
894                 uiBlockSetEmboss(block, UI_EMBOSSN);
895                 
896                 /* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
897                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_GHOST, xco+244, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
898                 uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_LOCKED, xco+262, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Proxy Protected");
899                 
900                 uiBlockSetEmboss(block, UI_EMBOSS);
901         }
902         else {
903                 short prev_proxylock, show_upbut, show_downbut;
904                 
905                 /* Up/Down buttons: 
906                  *      Proxy-constraints are not allowed to occur after local (non-proxy) constraints
907                  *      as that poses problems when restoring them, so disable the "up" button where
908                  *      it may cause this situation. 
909                  *
910                  *      Up/Down buttons should only be shown (or not greyed - todo) if they serve some purpose. 
911                  */
912                 if (proxylocked_constraints_owner(ob, pchan)) {
913                         if (con->prev) {
914                                 prev_proxylock= (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
915                         }
916                         else
917                                 prev_proxylock= 0;
918                 }
919                 else
920                         prev_proxylock= 0;
921                         
922                 show_upbut= ((prev_proxylock == 0) && (con->prev));
923                 show_downbut= (con->next) ? 1 : 0;
924                 
925                 if (show_upbut || show_downbut) {
926                         uiBlockBeginAlign(block);
927                                 uiBlockSetEmboss(block, UI_EMBOSS);
928                                 
929                                 if (show_upbut) {
930                                         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");
931                                         uiButSetFunc(but, constraint_moveUp, ob, con);
932                                 }
933                                 
934                                 if (show_downbut) {
935                                         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");
936                                         uiButSetFunc(but, constraint_moveDown, ob, con);
937                                 }
938                         uiBlockEndAlign(block);
939                 }
940                 
941                 
942                 /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
943                 uiBlockSetEmboss(block, UI_EMBOSSN);
944                 
945                 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");
946                 uiButSetFunc(but, del_constraint_func, ob, con);
947                 
948                 uiBlockSetEmboss(block, UI_EMBOSS);
949         }
950         
951         /* Set but-locks for protected settings (magic numbers are used here!) */
952         if (proxy_protected)
953                 uiBlockSetButLock(block, 1, "Cannot edit Proxy-Protected Constraint");
954         
955         /* Draw constraint data */
956         if ((con->flag & CONSTRAINT_EXPAND) == 0) {
957                 (yco) -= 21;
958         }
959         else {
960                 box= uiLayoutBox(col);
961                 block= uiLayoutFreeBlock(box);
962
963                 switch (con->type) {
964 #ifndef DISABLE_PYTHON
965                 case CONSTRAINT_TYPE_PYTHON:
966                         {
967                                 bPythonConstraint *data = con->data;
968                                 bConstraintTarget *ct;
969                                 // uiBut *but2;
970                                 int tarnum, theight;
971                                 // static int pyconindex=0;
972                                 // char *menustr;
973                                 
974                                 theight = (data->tarnum)? (data->tarnum * 38) : (38);
975                                 
976                                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Script:", xco+60, yco-24, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
977                                 
978                                 /* do the scripts menu */
979                                 /* XXX menustr = buildmenu_pyconstraints(data->text, &pyconindex);
980                                 but2 = uiDefButI(block, MENU, B_CONSTRAINT_TEST, menustr,
981                                       xco+120, yco-24, 150, 20, &pyconindex,
982                                       0, 0, 0, 0, "Set the Script Constraint to use");
983                                 uiButSetFunc(but2, validate_pyconstraint_cb, data, &pyconindex);
984                                 MEM_freeN(menustr);      */
985                                 
986                                 /* draw target(s) */
987                                 if (data->flag & PYCON_USETARGETS) {
988                                         /* Draw target parameters */ 
989                                         for (ct=data->targets.first, tarnum=1; ct; ct=ct->next, tarnum++) {
990                                                 char tarstr[32];
991                                                 short yoffset= ((tarnum-1) * 38);
992         
993                                                 /* target label */
994                                                 sprintf(tarstr, "Target %d:", tarnum);
995                                                 uiDefBut(block, LABEL, B_CONSTRAINT_TEST, tarstr, xco+45, yco-(48+yoffset), 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
996                                                 
997                                                 /* target space-selector - per target */
998                                                 if (is_armature_target(ct->tar)) {
999                                                         uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x3|Local with Parent %x4|Local Space %x1", 
1000                                                                                                                         xco+10, yco-(66+yoffset), 100, 18, &ct->space, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
1001                                                 }
1002                                                 else {
1003                                                         uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Local (Without Parent) Space %x1", 
1004                                                                                                                         xco+10, yco-(66+yoffset), 100, 18, &ct->space, 0, 0, 0, 0, "Choose space that target is evaluated in"); 
1005                                                 }
1006                                                 
1007                                                 uiBlockBeginAlign(block);
1008                                                         /* target object */
1009                                                         uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", xco+120, yco-(48+yoffset), 150, 18, &ct->tar, "Target Object"); 
1010                                                         
1011                                                         /* subtarget */
1012                                                         if (is_armature_target(ct->tar)) {
1013                                                                 but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", xco+120, yco-(66+yoffset),150,18, &ct->subtarget, 0, 24, 0, 0, "Subtarget Bone");
1014                                                                 uiButSetCompleteFunc(but, autocomplete_bone, (void *)ct->tar);
1015                                                         }
1016                                                         else if (is_geom_target(ct->tar)) {
1017                                                                 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");
1018                                                                 uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ct->tar);
1019                                                         }
1020                                                         else {
1021                                                                 strcpy(ct->subtarget, "");
1022                                                         }
1023                                                 uiBlockEndAlign(block);
1024                                         }
1025                                 }
1026                                 else {
1027                                         /* Draw indication that no target needed */
1028                                         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", xco+60, yco-48, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1029                                         uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Not Applicable", xco+120, yco-48, 150, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
1030                                 }
1031                                 
1032                                 /* settings */
1033                                 uiBlockBeginAlign(block);
1034                                         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.");
1035                                         // XXX uiButSetFunc(but, BPY_pyconstraint_settings, data, NULL);
1036                                         
1037                                         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");
1038                                 uiBlockEndAlign(block);
1039                                 
1040                                 /* constraint space settings */
1041                                 draw_constraint_spaceselect(block, con, xco, yco-(73+theight), is_armature_owner(ob), -1);
1042                         }
1043                         break;
1044 #endif /* DISABLE_PYTHON */
1045                 /*case CONSTRAINT_TYPE_CHILDOF:
1046                         {
1047                                 // Inverse options 
1048                                 uiBlockBeginAlign(block);
1049                                         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)");
1050                                         // XXX uiButSetFunc(but, childof_const_setinv, con, NULL);
1051                                         
1052                                         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)");
1053                                         // XXX uiButSetFunc(but, childof_const_clearinv, con, NULL);
1054                                 uiBlockEndAlign(block);
1055                         }
1056                         break; 
1057                 */
1058                 
1059                 /*case CONSTRAINT_TYPE_RIGIDBODYJOINT:
1060                         {
1061                                 if (data->type==CONSTRAINT_RB_GENERIC6DOF) {
1062                                         // Draw Pairs of LimitToggle+LimitValue 
1063                                         uiBlockBeginAlign(block); 
1064                                                 uiDefButBitS(block, TOG, 1, B_CONSTRAINT_TEST, "LinMinX", xco, yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x limit"); 
1065                                                 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"); 
1066                                         uiBlockEndAlign(block);
1067                                         
1068                                         uiBlockBeginAlign(block); 
1069                                                 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"); 
1070                                                 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"); 
1071                                         uiBlockEndAlign(block);
1072                                         
1073                                         offsetY += 20;
1074                                         uiBlockBeginAlign(block); 
1075                                                 uiDefButBitS(block, TOG, 2, B_CONSTRAINT_TEST, "LinMinY", xco, yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y limit"); 
1076                                                 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"); 
1077                                         uiBlockEndAlign(block);
1078                                         
1079                                         uiBlockBeginAlign(block); 
1080                                                 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"); 
1081                                                 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"); 
1082                                         uiBlockEndAlign(block);
1083                                         
1084                                         offsetY += 20;
1085                                         uiBlockBeginAlign(block); 
1086                                                 uiDefButBitS(block, TOG, 4, B_CONSTRAINT_TEST, "LinMinZ", xco, yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z limit"); 
1087                                                 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"); 
1088                                         uiBlockEndAlign(block);
1089                                         
1090                                         uiBlockBeginAlign(block); 
1091                                                 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"); 
1092                                                 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"); 
1093                                         uiBlockEndAlign(block);
1094                                         offsetY += 20;
1095                                 }
1096                                 if ((data->type==CONSTRAINT_RB_GENERIC6DOF) || (data->type==CONSTRAINT_RB_CONETWIST)) {
1097                                         // Draw Pairs of LimitToggle+LimitValue /
1098                                         uiBlockBeginAlign(block); 
1099                                                 uiDefButBitS(block, TOG, 8, B_CONSTRAINT_TEST, "AngMinX", xco, yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x limit"); 
1100                                                 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"); 
1101                                         uiBlockEndAlign(block);
1102                                         uiBlockBeginAlign(block); 
1103                                                 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"); 
1104                                                 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"); 
1105                                         uiBlockEndAlign(block);
1106                                         
1107                                         offsetY += 20;
1108                                         uiBlockBeginAlign(block); 
1109                                                 uiDefButBitS(block, TOG, 16, B_CONSTRAINT_TEST, "AngMinY", xco, yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y limit"); 
1110                                                 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"); 
1111                                         uiBlockEndAlign(block);
1112                                         
1113                                         uiBlockBeginAlign(block); 
1114                                                 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"); 
1115                                                 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"); 
1116                                         uiBlockEndAlign(block);
1117                                         
1118                                         offsetY += 20;
1119                                         uiBlockBeginAlign(block); 
1120                                                 uiDefButBitS(block, TOG, 32, B_CONSTRAINT_TEST, "AngMinZ", xco, yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z limit"); 
1121                                                 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"); 
1122                                         uiBlockEndAlign(block);
1123                                         
1124                                         uiBlockBeginAlign(block); 
1125                                                 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"); 
1126                                                 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"); 
1127                                         uiBlockEndAlign(block);
1128                                 }
1129                                 
1130                         }
1131                         break;
1132                         */
1133
1134                 case CONSTRAINT_TYPE_NULL:
1135                         {
1136                                 uiItemL(box, "", 0);
1137                         }
1138                         break;
1139                 default:
1140                         result= box;
1141                         break;
1142                 }
1143         }
1144         
1145         /* clear any locks set up for proxies/lib-linking */
1146         uiBlockClearButLock(block);
1147
1148         return result;
1149 }
1150
1151 uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
1152 {
1153         Object *ob;
1154         bConstraint *con;
1155
1156         /* verify we have valid data */
1157         if(!RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
1158                 printf("uiTemplateConstraint: expected constraint on object.\n");
1159                 return NULL;
1160         }
1161
1162         ob= ptr->id.data;
1163         con= ptr->data;
1164
1165         if(!ob || !(GS(ob->id.name) == ID_OB)) {
1166                 printf("uiTemplateConstraint: expected constraint on object.\n");
1167                 return NULL;
1168         }
1169         
1170         uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
1171
1172         /* hrms, the temporal constraint should not draw! */
1173         if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
1174                 bKinematicConstraint *data= con->data;
1175                 if(data->flag & CONSTRAINT_IK_TEMP)
1176                         return NULL;
1177         }
1178
1179         return draw_constraint(layout, ob, con);
1180 }
1181
1182 /************************* Group Template ***************************/
1183
1184 #if 0
1185 static void do_add_groupmenu(void *arg, int event)
1186 {
1187         Object *ob= OBACT;
1188         
1189         if(ob) {
1190                 
1191                 if(event== -1) {
1192                         Group *group= add_group( "Group" );
1193                         add_to_group(group, ob);
1194                 }
1195                 else
1196                         add_to_group(BLI_findlink(&G.main->group, event), ob);
1197                         
1198                 ob->flag |= OB_FROMGROUP;
1199                 BASACT->flag |= OB_FROMGROUP;
1200                 allqueue(REDRAWBUTSOBJECT, 0);
1201                 allqueue(REDRAWVIEW3D, 0);
1202         }               
1203 }
1204
1205 static uiBlock *add_groupmenu(void *arg_unused)
1206 {
1207         uiBlock *block;
1208         Group *group;
1209         short xco=0, yco= 0, index=0;
1210         char str[32];
1211         
1212         block= uiNewBlock(&curarea->uiblocks, "add_constraintmenu", UI_EMBOSSP, UI_HELV, curarea->win);
1213         uiBlockSetButmFunc(block, do_add_groupmenu, NULL);
1214
1215         uiDefBut(block, BUTM, B_NOP, "ADD NEW",         0, 20, 160, 19, NULL, 0.0, 0.0, 1, -1, "");
1216         for(group= G.main->group.first; group; group= group->id.next, index++) {
1217                 
1218                 /*if(group->id.lib) strcpy(str, "L  ");*/ /* we cant allow adding objects inside linked groups, it wont be saved anyway */
1219                 if(group->id.lib==0) {
1220                         strcpy(str, "   ");
1221                         strcat(str, group->id.name+2);
1222                         uiDefBut(block, BUTM, B_NOP, str,       xco*160, -20*yco, 160, 19, NULL, 0.0, 0.0, 1, index, "");
1223                         
1224                         yco++;
1225                         if(yco>24) {
1226                                 yco= 0;
1227                                 xco++;
1228                         }
1229                 }
1230         }
1231         
1232         uiTextBoundsBlock(block, 50);
1233         uiBlockSetDirection(block, UI_DOWN);    
1234         
1235         return block;
1236 }
1237
1238 static void group_ob_rem(void *gr_v, void *ob_v)
1239 {
1240         Object *ob= OBACT;
1241         
1242         if(rem_from_group(gr_v, ob) && find_group(ob, NULL)==NULL) {
1243                 ob->flag &= ~OB_FROMGROUP;
1244                 BASACT->flag &= ~OB_FROMGROUP;
1245         }
1246         allqueue(REDRAWBUTSOBJECT, 0);
1247         allqueue(REDRAWVIEW3D, 0);
1248
1249 }
1250
1251 static void group_local(void *gr_v, void *unused)
1252 {
1253         Group *group= gr_v;
1254         
1255         group->id.lib= NULL;
1256         
1257         allqueue(REDRAWBUTSOBJECT, 0);
1258         allqueue(REDRAWVIEW3D, 0);
1259         
1260 }
1261
1262 uiLayout *uiTemplateGroup(uiLayout *layout, Object *ob, Group *group)
1263 {
1264         uiSetButLock(1, NULL);
1265         uiDefBlockBut(block, add_groupmenu, NULL, "Add to Group", 10,150,150,20, "Add Object to a new Group");
1266
1267         /* all groups */
1268         if(group->id.lib) {
1269                 uiLayoutRow()
1270                 uiBlockBeginAlign(block);
1271                 uiSetButLock(GET_INT_FROM_POINTER(group->id.lib), ERROR_LIBDATA_MESSAGE); /* We cant actually use this button */
1272                 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.");
1273                 uiClearButLock();
1274                 
1275                 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");
1276                 uiButSetFunc(but, group_local, group, NULL);
1277                 uiBlockEndAlign(block);
1278         } else {
1279                 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.");
1280                 uiButSetFunc(but, test_idbutton_cb, group->id.name, NULL);
1281         }
1282         
1283         xco = 290;
1284         if(group->id.lib==0) { /* cant remove objects from linked groups */
1285                 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");
1286                 uiButSetFunc(but, group_ob_rem, group, ob);
1287         }
1288 }
1289 #endif
1290
1291 /************************* Preview Template ***************************/
1292
1293 #include "DNA_material_types.h"
1294
1295 #define B_MATPRV 1
1296
1297
1298 static void do_preview_buttons(bContext *C, void *arg, int event)
1299 {
1300         switch(event) {
1301                 case B_MATPRV:
1302                         WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, arg);
1303                         break;
1304         }
1305 }
1306
1307 void uiTemplatePreview(uiLayout *layout, ID *id)
1308 {
1309         uiLayout *row, *col;
1310         uiBlock *block;
1311         Material *ma;
1312
1313         if(!id || !ELEM4(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA)) {
1314                 printf("uiTemplatePreview: expected ID of type material, texture, lamp or world.\n");
1315                 return;
1316         }
1317
1318         block= uiLayoutGetBlock(layout);
1319
1320         row= uiLayoutRow(layout, 0);
1321
1322         col= uiLayoutColumn(row, 0);
1323         uiLayoutSetKeepAspect(col, 1);
1324         
1325         uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, id, 0.0, 0.0, 0, 0, "");
1326         uiBlockSetDrawExtraFunc(block, ED_preview_draw);
1327         
1328         uiBlockSetHandleFunc(block, do_preview_buttons, NULL);
1329         
1330         if(id) {
1331                 if(GS(id->name) == ID_MA) {
1332                         ma= (Material*)id;
1333
1334                         uiLayoutColumn(row, 1);
1335
1336                         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");
1337                         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");
1338                         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");
1339                         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");
1340                         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");
1341                         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");
1342                 }
1343         }
1344 }
1345
1346 /********************** ColorRamp Template **************************/
1347
1348 void uiTemplateColorRamp(uiLayout *layout, ColorBand *coba, int expand)
1349 {
1350         uiBlock *block;
1351         rctf rect;
1352
1353         if(coba) {
1354                 rect.xmin= 0; rect.xmax= 200;
1355                 rect.ymin= 0; rect.ymax= 190;
1356                 
1357                 block= uiLayoutFreeBlock(layout);
1358                 colorband_buttons(block, coba, &rect, !expand);
1359         }
1360 }
1361
1362 /********************* CurveMapping Template ************************/
1363
1364 #include "DNA_color_types.h"
1365
1366 void uiTemplateCurveMapping(uiLayout *layout, CurveMapping *cumap, int type)
1367 {
1368         uiBlock *block;
1369         rctf rect;
1370
1371         if(cumap) {
1372                 rect.xmin= 0; rect.xmax= 200;
1373                 rect.ymin= 0; rect.ymax= 190;
1374                 
1375                 block= uiLayoutFreeBlock(layout);
1376                 curvemap_buttons(block, cumap, type, 0, 0, &rect);
1377         }
1378 }
1379