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