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