2.5 Buttons Modifier:
[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
37 #include "RNA_access.h"
38
39 #include "WM_api.h"
40 #include "WM_types.h"
41
42 #include "UI_interface.h"
43 #include "UI_resources.h"
44
45 void ui_template_fix_linking()
46 {
47 }
48
49 /********************** Header Template *************************/
50
51 void uiTemplateHeader(uiLayout *layout, bContext *C)
52 {
53         uiBlock *block;
54         
55         block= uiLayoutFreeBlock(layout);
56         ED_area_header_standardbuttons(C, block, 0);
57 }
58
59 /******************* Header ID Template ************************/
60
61 typedef struct TemplateHeaderID {
62         PointerRNA ptr;
63         PropertyRNA *prop;
64
65         int flag;
66         short browse;
67
68         char newop[256];
69         char openop[256];
70         char unlinkop[256];
71 } TemplateHeaderID;
72
73 static void template_header_id_cb(bContext *C, void *arg_litem, void *arg_event)
74 {
75         TemplateHeaderID *template= (TemplateHeaderID*)arg_litem;
76         PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
77         ID *idtest, *id= idptr.data;
78         ListBase *lb= wich_libbase(CTX_data_main(C), ID_TXT);
79         int nr, event= GET_INT_FROM_POINTER(arg_event);
80         
81         if(event == UI_ID_BROWSE && template->browse == 32767)
82                 event= UI_ID_ADD_NEW;
83         else if(event == UI_ID_BROWSE && template->browse == 32766)
84                 event= UI_ID_OPEN;
85
86         switch(event) {
87                 case UI_ID_BROWSE: {
88                         if(template->browse== -2) {
89                                 /* XXX implement or find a replacement
90                                  * activate_databrowse((ID *)G.buts->lockpoin, GS(id->name), 0, B_MESHBROWSE, &template->browse, do_global_buttons); */
91                                 return;
92                         }
93                         if(template->browse < 0)
94                                 return;
95
96                         for(idtest=lb->first, nr=1; idtest; idtest=idtest->next, nr++) {
97                                 if(nr==template->browse) {
98                                         if(id == idtest)
99                                                 return;
100
101                                         id= idtest;
102                                         RNA_id_pointer_create(id, &idptr);
103                                         RNA_property_pointer_set(&template->ptr, template->prop, idptr);
104                                         RNA_property_update(C, &template->ptr, template->prop);
105                                         /* XXX */
106
107                                         break;
108                                 }
109                         }
110                         break;
111                 }
112 #if 0
113                 case UI_ID_DELETE:
114                         id= NULL;
115                         break;
116                 case UI_ID_FAKE_USER:
117                         if(id) {
118                                 if(id->flag & LIB_FAKEUSER) id->us++;
119                                 else id->us--;
120                         }
121                         else return;
122                         break;
123 #endif
124                 case UI_ID_PIN:
125                         break;
126                 case UI_ID_ADD_NEW:
127                         WM_operator_name_call(C, template->newop, WM_OP_INVOKE_REGION_WIN, NULL);
128                         break;
129                 case UI_ID_OPEN:
130                         WM_operator_name_call(C, template->openop, WM_OP_INVOKE_REGION_WIN, NULL);
131                         break;
132 #if 0
133                 case UI_ID_ALONE:
134                         if(!id || id->us < 1)
135                                 return;
136                         break;
137                 case UI_ID_LOCAL:
138                         if(!id || id->us < 1)
139                                 return;
140                         break;
141                 case UI_ID_AUTO_NAME:
142                         break;
143 #endif
144         }
145 }
146
147 static void template_header_ID(bContext *C, uiBlock *block, TemplateHeaderID *template)
148 {
149         uiBut *but;
150         TemplateHeaderID *duptemplate;
151         PointerRNA idptr;
152         ListBase *lb;
153         int x= 0, y= 0;
154
155         idptr= RNA_property_pointer_get(&template->ptr, template->prop);
156         lb= wich_libbase(CTX_data_main(C), ID_TXT);
157
158         uiBlockBeginAlign(block);
159         if(template->flag & UI_ID_BROWSE) {
160                 char *extrastr, *str;
161                 
162                 if((template->flag & UI_ID_ADD_NEW) && (template->flag && UI_ID_OPEN))
163                         extrastr= "OPEN NEW %x 32766 |ADD NEW %x 32767";
164                 else if(template->flag & UI_ID_ADD_NEW)
165                         extrastr= "ADD NEW %x 32767";
166                 else if(template->flag & UI_ID_OPEN)
167                         extrastr= "OPEN NEW %x 32766";
168                 else
169                         extrastr= NULL;
170
171                 duptemplate= MEM_dupallocN(template);
172                 IDnames_to_pupstring(&str, NULL, extrastr, lb, idptr.data, &duptemplate->browse);
173
174                 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");
175                 uiButSetNFunc(but, template_header_id_cb, duptemplate, SET_INT_IN_POINTER(UI_ID_BROWSE));
176                 x+= UI_UNIT_X;
177         
178                 MEM_freeN(str);
179         }
180
181         /* text button with name */
182         if(idptr.data) {
183                 char name[64];
184
185                 text_idbutton(idptr.data, name);
186                 but= uiDefButR(block, TEX, 0, name, x, y, UI_UNIT_X*6, UI_UNIT_Y, &idptr, "name", -1, 0, 0, -1, -1, NULL);
187                 uiButSetNFunc(but, template_header_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
188                 x += UI_UNIT_X*6;
189
190                 /* delete button */
191                 if(template->flag & UI_ID_DELETE) {
192                         but= uiDefIconButO(block, BUT, template->unlinkop, WM_OP_EXEC_REGION_WIN, ICON_X, x, y, UI_UNIT_X, UI_UNIT_Y, NULL);
193                         x += UI_UNIT_X;
194                 }
195         }
196         uiBlockEndAlign(block);
197 }
198
199 void uiTemplateHeaderID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
200 {
201         TemplateHeaderID *template;
202         uiBlock *block;
203         PropertyRNA *prop;
204
205         if(!ptr->data)
206                 return;
207
208         prop= RNA_struct_find_property(ptr, propname);
209
210         if(!prop) {
211                 printf("uiTemplateHeaderID: property not found: %s\n", propname);
212                 return;
213         }
214
215         template= MEM_callocN(sizeof(TemplateHeaderID), "TemplateHeaderID");
216         template->ptr= *ptr;
217         template->prop= prop;
218         template->flag= UI_ID_BROWSE|UI_ID_RENAME;
219
220         if(newop) {
221                 template->flag |= UI_ID_ADD_NEW;
222                 BLI_strncpy(template->newop, newop, sizeof(template->newop));
223         }
224         if(openop) {
225                 template->flag |= UI_ID_OPEN;
226                 BLI_strncpy(template->openop, openop, sizeof(template->openop));
227         }
228         if(unlinkop) {
229                 template->flag |= UI_ID_DELETE;
230                 BLI_strncpy(template->unlinkop, unlinkop, sizeof(template->unlinkop));
231         }
232
233         block= uiLayoutFreeBlock(layout);
234         template_header_ID(C, block, template);
235
236         MEM_freeN(template);
237 }
238
239 /************************ Modifier Template *************************/
240
241 #define ERROR_LIBDATA_MESSAGE "Can't edit external libdata"
242
243 #define B_NOP                           0
244 #define B_MODIFIER_RECALC       1
245 #define B_MODIFIER_REDRAW       2
246 #define B_CHANGEDEP                     3
247 #define B_ARM_RECALCDATA        4
248
249 #include <string.h>
250
251 #include "DNA_armature_types.h"
252 #include "DNA_curve_types.h"
253 #include "DNA_object_force.h"
254 #include "DNA_object_types.h"
255 #include "DNA_mesh_types.h"
256 #include "DNA_meshdata_types.h"
257 #include "DNA_modifier_types.h"
258 #include "DNA_particle_types.h"
259 #include "DNA_scene_types.h"
260
261 #include "BKE_bmesh.h"
262 #include "BKE_curve.h"
263 #include "BKE_depsgraph.h"
264 #include "BKE_DerivedMesh.h"
265 #include "BKE_displist.h"
266 #include "BKE_global.h"
267 #include "BKE_lattice.h"
268 #include "BKE_main.h"
269 #include "BKE_mesh.h"
270 #include "BKE_modifier.h"
271 #include "BKE_object.h"
272 #include "BKE_particle.h"
273 #include "BKE_report.h"
274
275 #include "UI_resources.h"
276 #include "ED_util.h"
277
278 #include "BLI_arithb.h"
279 #include "BLI_listbase.h"
280
281 #include "ED_object.h"
282
283 void do_modifier_panels(bContext *C, void *arg, int event)
284 {
285         Scene *scene= CTX_data_scene(C);
286         Object *ob = CTX_data_active_object(C);
287
288         switch(event) {
289         case B_MODIFIER_REDRAW:
290                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
291                 break;
292
293         case B_MODIFIER_RECALC:
294                 WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
295                 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
296                 object_handle_update(scene, ob);
297                 // XXX countall();
298                 break;
299         }
300 }
301
302 static void modifiers_del(bContext *C, void *ob_v, void *md_v)
303 {
304         ReportList reports;
305
306         BKE_reports_init(&reports, RPT_STORE);
307
308         if(ED_object_modifier_delete(&reports, ob_v, md_v))
309                 ED_undo_push(C, "Delete modifier");
310         else
311                 uiPupMenuReports(C, &reports);
312
313         BKE_reports_clear(&reports);
314 }
315
316 static void modifiers_moveUp(bContext *C, void *ob_v, void *md_v)
317 {
318         ReportList reports;
319
320         BKE_reports_init(&reports, RPT_STORE);
321
322         if(ED_object_modifier_move_up(&reports, ob_v, md_v))
323                 ED_undo_push(C, "Move modifier");
324         else
325                 uiPupMenuReports(C, &reports);
326
327         BKE_reports_clear(&reports);
328 }
329
330 static void modifiers_moveDown(bContext *C, void *ob_v, void *md_v)
331 {
332         ReportList reports;
333
334         BKE_reports_init(&reports, RPT_STORE);
335
336         if(ED_object_modifier_move_down(&reports, ob_v, md_v))
337                 ED_undo_push(C, "Move modifier");
338         else
339                 uiPupMenuReports(C, &reports);
340
341         BKE_reports_clear(&reports);
342 }
343
344 static void modifier_testLatticeObj(bContext *C, char *name, ID **idpp)
345 {
346         Main *bmain= CTX_data_main(C);
347         ID *id;
348
349         for (id= bmain->object.first; id; id= id->next) {
350                 if( strcmp(name, id->name+2)==0 ) {
351                         if (((Object *)id)->type != OB_LATTICE) {
352                                 uiPupMenuError(C, "Lattice deform object must be a lattice");
353                                 break;
354                         } 
355                         *idpp= id;
356                         return;
357                 }
358         }
359         *idpp= 0;
360 }
361
362 static void modifier_testCurveObj(bContext *C, char *name, ID **idpp)
363 {
364         Main *bmain= CTX_data_main(C);
365         ID *id;
366
367         for (id= bmain->object.first; id; id= id->next) {
368                 if( strcmp(name, id->name+2)==0 ) {
369                         if (((Object *)id)->type != OB_CURVE) {
370                                 uiPupMenuError(C, "Curve deform object must be a curve");
371                                 break;
372                         } 
373                         *idpp= id;
374                         return;
375                 }
376         }
377         *idpp= 0;
378 }
379
380 static void modifier_testMeshObj(bContext *C, char *name, ID **idpp)
381 {
382         Main *bmain= CTX_data_main(C);
383         Object *obact= CTX_data_active_object(C);
384         ID *id;
385
386         for (id= bmain->object.first; id; id= id->next) {
387                 /* no boolean on its own object */
388                 if(id != (ID *)obact) {
389                         if( strcmp(name, id->name+2)==0 ) {
390                                 if (((Object *)id)->type != OB_MESH) {
391                                         uiPupMenuError(C, "Boolean modifier object must be a mesh");
392                                         break;
393                                 } 
394                                 *idpp= id;
395                                 return;
396                         }
397                 }
398         }
399         *idpp= NULL;
400 }
401
402 static void modifier_testArmatureObj(bContext *C, char *name, ID **idpp)
403 {
404         Main *bmain= CTX_data_main(C);
405         ID *id;
406
407         for (id= bmain->object.first; id; id= id->next) {
408                 if( strcmp(name, id->name+2)==0 ) {
409                         if (((Object *)id)->type != OB_ARMATURE) {
410                                 uiPupMenuError(C, "Armature deform object must be an armature");
411                                 break;
412                         } 
413                         *idpp= id;
414                         return;
415                 }
416         }
417         *idpp= 0;
418 }
419
420 static void modifier_testTexture(bContext *C, char *name, ID **idpp)
421 {
422         Main *bmain= CTX_data_main(C);
423         ID *id;
424
425         for(id = bmain->tex.first; id; id = id->next) {
426                 if(strcmp(name, id->name + 2) == 0) {
427                         *idpp = id;
428                         /* texture gets user, objects not: delete object = clear modifier */
429                         id_us_plus(id);
430                         return;
431                 }
432         }
433         *idpp = 0;
434 }
435
436 #if 0 /* this is currently unused, but could be useful in the future */
437 static void modifier_testMaterial(bContext *C, char *name, ID **idpp)
438 {
439         Main *bmain= CTX_data_main(C);
440         ID *id;
441
442         for(id = bmain->mat.first; id; id = id->next) {
443                 if(strcmp(name, id->name + 2) == 0) {
444                         *idpp = id;
445                         return;
446                 }
447         }
448         *idpp = 0;
449 }
450 #endif
451
452 static void modifier_testImage(bContext *C, char *name, ID **idpp)
453 {
454         Main *bmain= CTX_data_main(C);
455         ID *id;
456
457         for(id = bmain->image.first; id; id = id->next) {
458                 if(strcmp(name, id->name + 2) == 0) {
459                         *idpp = id;
460                         return;
461                 }
462         }
463         *idpp = 0;
464 }
465
466 /* autocomplete callback for ID buttons */
467 void autocomplete_image(bContext *C, char *str, void *arg_v)
468 {
469         Main *bmain= CTX_data_main(C);
470
471         /* search if str matches the beginning of an ID struct */
472         if(str[0]) {
473                 AutoComplete *autocpl = autocomplete_begin(str, 22);
474                 ID *id;
475
476                 for(id = bmain->image.first; id; id = id->next)
477                         autocomplete_do_name(autocpl, id->name+2);
478
479                 autocomplete_end(autocpl, str);
480         }
481 }
482
483 /* autocomplete callback for ID buttons */
484 void autocomplete_meshob(bContext *C, char *str, void *arg_v)
485 {
486         Main *bmain= CTX_data_main(C);
487
488         /* search if str matches the beginning of an ID struct */
489         if(str[0]) {
490                 AutoComplete *autocpl = autocomplete_begin(str, 22);
491                 ID *id;
492
493                 for(id = bmain->object.first; id; id = id->next)
494                         if(((Object *)id)->type == OB_MESH)
495                                 autocomplete_do_name(autocpl, id->name+2);
496
497                 autocomplete_end(autocpl, str);
498         }
499 }
500
501 static void modifiers_convertParticles(bContext *C, void *obv, void *mdv)
502 {
503         Scene *scene= CTX_data_scene(C);
504         ReportList reports;
505
506         BKE_reports_init(&reports, RPT_STORE);
507
508         if(ED_object_modifier_convert(&reports, scene, obv, mdv))
509                 ED_undo_push(C, "Convert particles to mesh object(s).");
510         else
511                 uiPupMenuReports(C, &reports);
512
513         BKE_reports_clear(&reports);
514 }
515
516 static void modifiers_applyModifier(bContext *C, void *obv, void *mdv)
517 {
518         Scene *scene= CTX_data_scene(C);
519         ReportList reports;
520
521         BKE_reports_init(&reports, RPT_STORE);
522
523         if(ED_object_modifier_apply(&reports, scene, obv, mdv))
524                 ED_undo_push(C, "Apply modifier");
525         else
526                 uiPupMenuReports(C, &reports);
527
528         BKE_reports_clear(&reports);
529 }
530
531 static void modifiers_copyModifier(bContext *C, void *ob_v, void *md_v)
532 {
533         ReportList reports;
534
535         BKE_reports_init(&reports, RPT_STORE);
536
537         if(ED_object_modifier_copy(&reports, ob_v, md_v))
538                 ED_undo_push(C, "Copy modifier");
539         else
540                 uiPupMenuReports(C, &reports);
541
542         BKE_reports_clear(&reports);
543 }
544
545 static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v)
546 {
547         Object *ob = ob_v;
548         ModifierData *md;
549         
550         int i, cageIndex = modifiers_getCageIndex(ob, NULL );
551
552         for( i = 0, md=ob->modifiers.first; md; ++i, md=md->next )
553                 if( md == md_v ) {
554                         if( i >= cageIndex )
555                                 md->mode ^= eModifierMode_OnCage;
556                         break;
557                 }
558 }
559
560 static void modifiers_clearHookOffset(bContext *C, void *ob_v, void *md_v)
561 {
562         Object *ob = ob_v;
563         ModifierData *md = md_v;
564         HookModifierData *hmd = (HookModifierData*) md;
565         
566         if (hmd->object) {
567                 Mat4Invert(hmd->object->imat, hmd->object->obmat);
568                 Mat4MulSerie(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
569                 ED_undo_push(C, "Clear hook offset");
570         }
571 }
572
573 static void modifiers_cursorHookCenter(bContext *C, void *ob_v, void *md_v)
574 {
575         /* XXX 
576         Object *ob = ob_v;
577         ModifierData *md = md_v;
578         HookModifierData *hmd = (HookModifierData*) md;
579
580         if(G.vd) {
581                 float *curs = give_cursor();
582                 float bmat[3][3], imat[3][3];
583
584                 where_is_object(ob);
585         
586                 Mat3CpyMat4(bmat, ob->obmat);
587                 Mat3Inv(imat, bmat);
588
589                 curs= give_cursor();
590                 hmd->cent[0]= curs[0]-ob->obmat[3][0];
591                 hmd->cent[1]= curs[1]-ob->obmat[3][1];
592                 hmd->cent[2]= curs[2]-ob->obmat[3][2];
593                 Mat3MulVecfl(imat, hmd->cent);
594
595                 ED_undo_push(C, "Hook cursor center");
596         }*/
597 }
598
599 static void modifiers_selectHook(bContext *C, void *ob_v, void *md_v)
600 {
601         /* XXX ModifierData *md = md_v;
602         HookModifierData *hmd = (HookModifierData*) md;
603
604         hook_select(hmd);*/
605 }
606
607 static void modifiers_reassignHook(bContext *C, void *ob_v, void *md_v)
608 {
609         /* XXX ModifierData *md = md_v;
610         HookModifierData *hmd = (HookModifierData*) md;
611         float cent[3];
612         int *indexar, tot, ok;
613         char name[32];
614                 
615         ok= hook_getIndexArray(&tot, &indexar, name, cent);
616
617         if (!ok) {
618                 uiPupMenuError(C, "Requires selected vertices or active Vertex Group");
619         } else {
620                 if (hmd->indexar) {
621                         MEM_freeN(hmd->indexar);
622                 }
623
624                 VECCOPY(hmd->cent, cent);
625                 hmd->indexar = indexar;
626                 hmd->totindex = tot;
627         }*/
628 }
629
630 static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
631 {
632         Object *ob = ob_v;
633         ModifierData *md = md_v;
634         ModifierData *nmd = modifier_new(md->type);
635
636         modifier_copyData(md, nmd);
637         nmd->mode &= ~eModifierMode_Virtual;
638
639         BLI_addhead(&ob->modifiers, nmd);
640
641         ob->partype = PAROBJECT;
642
643         ED_undo_push(C, "Modifier convert to real");
644 }
645
646 static void build_uvlayer_menu_vars(CustomData *data, char **menu_string,
647                                     int *uvlayer_tmp, char *uvlayer_name)
648 {
649         char strtmp[38];
650         int totuv, i;
651         CustomDataLayer *layer
652                     = &data->layers[CustomData_get_layer_index(data, CD_MTFACE)];
653
654         *uvlayer_tmp = -1;
655
656         totuv = CustomData_number_of_layers(data, CD_MTFACE);
657
658         *menu_string = MEM_callocN(sizeof(**menu_string) * (totuv * 38 + 10),
659                                    "menu_string");
660         sprintf(*menu_string, "UV Layer%%t");
661         for(i = 0; i < totuv; i++) {
662                 /* assign first layer as uvlayer_name if uvlayer_name is null. */
663                 if(strcmp(layer->name, uvlayer_name) == 0) *uvlayer_tmp = i + 1;
664                 sprintf(strtmp, "|%s%%x%d", layer->name, i + 1);
665                 strcat(*menu_string, strtmp);
666                 layer++;
667         }
668
669         /* there is no uvlayer defined, or else it was deleted. Assign active
670          * layer, then recalc modifiers.
671          */
672         if(*uvlayer_tmp == -1) {
673                 if(CustomData_get_active_layer_index(data, CD_MTFACE) != -1) {
674                         *uvlayer_tmp = 1;
675                         layer = data->layers;
676                         for(i = 0; i < CustomData_get_active_layer_index(data, CD_MTFACE);
677                             i++, layer++) {
678                                 if(layer->type == CD_MTFACE) (*uvlayer_tmp)++;
679                         }
680                         strcpy(uvlayer_name, layer->name);
681
682                         /* update the modifiers */
683                         /* XXX do_modifier_panels(B_MODIFIER_RECALC);*/
684                 } else {
685                         /* ok we have no uv layers, so make sure menu button knows that.*/
686                         *uvlayer_tmp = 0;
687                 }
688         }
689 }
690
691 void set_wave_uvlayer(bContext *C, void *arg1, void *arg2)
692 {
693         WaveModifierData *wmd=arg1;
694         CustomDataLayer *layer = arg2;
695
696         /*check we have UV layers*/
697         if (wmd->uvlayer_tmp < 1) return;
698         layer = layer + (wmd->uvlayer_tmp-1);
699         
700         strcpy(wmd->uvlayer_name, layer->name);
701 }
702
703 void set_displace_uvlayer(bContext *C, void *arg1, void *arg2)
704 {
705         DisplaceModifierData *dmd=arg1;
706         CustomDataLayer *layer = arg2;
707
708         /*check we have UV layers*/
709         if (dmd->uvlayer_tmp < 1) return;
710         layer = layer + (dmd->uvlayer_tmp-1);
711         
712         strcpy(dmd->uvlayer_name, layer->name);
713 }
714
715 void set_uvproject_uvlayer(bContext *C, void *arg1, void *arg2)
716 {
717         UVProjectModifierData *umd=arg1;
718         CustomDataLayer *layer = arg2;
719
720         /*check we have UV layers*/
721         if (umd->uvlayer_tmp < 1) return;
722         layer = layer + (umd->uvlayer_tmp-1);
723         
724         strcpy(umd->uvlayer_name, layer->name);
725 }
726
727 static void modifiers_bindMeshDeform(bContext *C, void *ob_v, void *md_v)
728 {
729         Scene *scene= CTX_data_scene(C);
730         MeshDeformModifierData *mmd = (MeshDeformModifierData*) md_v;
731         Object *ob = (Object*)ob_v;
732
733         if(mmd->bindcos) {
734                 if(mmd->bindweights) MEM_freeN(mmd->bindweights);
735                 if(mmd->bindcos) MEM_freeN(mmd->bindcos);
736                 if(mmd->dyngrid) MEM_freeN(mmd->dyngrid);
737                 if(mmd->dyninfluences) MEM_freeN(mmd->dyninfluences);
738                 if(mmd->dynverts) MEM_freeN(mmd->dynverts);
739                 mmd->bindweights= NULL;
740                 mmd->bindcos= NULL;
741                 mmd->dyngrid= NULL;
742                 mmd->dyninfluences= NULL;
743                 mmd->dynverts= NULL;
744                 mmd->totvert= 0;
745                 mmd->totcagevert= 0;
746                 mmd->totinfluence= 0;
747         }
748         else {
749                 DerivedMesh *dm;
750                 int mode= mmd->modifier.mode;
751
752                 /* force modifier to run, it will call binding routine */
753                 mmd->needbind= 1;
754                 mmd->modifier.mode |= eModifierMode_Realtime;
755
756                 if(ob->type == OB_MESH) {
757                         dm= mesh_create_derived_view(scene, ob, 0);
758                         dm->release(dm);
759                 }
760                 else if(ob->type == OB_LATTICE) {
761                         lattice_calc_modifiers(scene, ob);
762                 }
763                 else if(ob->type==OB_MBALL) {
764                         makeDispListMBall(scene, ob);
765                 }
766                 else if(ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
767                         makeDispListCurveTypes(scene, ob, 0);
768                 }
769
770                 mmd->needbind= 0;
771                 mmd->modifier.mode= mode;
772         }
773 }
774
775 void modifiers_explodeFacepa(bContext *C, void *arg1, void *arg2)
776 {
777         ExplodeModifierData *emd=arg1;
778
779         emd->flag |= eExplodeFlag_CalcFaces;
780 }
781
782 void modifiers_explodeDelVg(bContext *C, void *arg1, void *arg2)
783 {
784         ExplodeModifierData *emd=arg1;
785         emd->vgroup = 0;
786 }
787
788 static int modifier_is_fluid_particles(ModifierData *md)
789 {
790         if(md->type == eModifierType_ParticleSystem) {
791                 if(((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID)
792                         return 1;
793         }
794         return 0;
795 }
796
797 static uiLayout *draw_modifier(bContext *C, uiLayout *layout, Object *ob, ModifierData *md, int index, int cageIndex, int lastCageIndex)
798 {
799         Object *obedit= CTX_data_edit_object(C);
800         ModifierTypeInfo *mti = modifierType_getInfo(md->type);
801         uiBut *but;
802         uiBlock *block;
803         uiLayout *column, *row, *result= NULL;
804         int isVirtual = md->mode&eModifierMode_Virtual;
805         int x = 0, y = 0; // XXX , color = md->error?TH_REDALERT:TH_BUT_NEUTRAL;
806         int editing = (obedit==ob);
807         short width = 295, buttonWidth = width-120-10;
808         char str[128];
809
810         column= uiLayoutColumn(layout, 1);
811
812         /* rounded header */
813         /* XXX uiBlockSetCol(block, color); */
814                 /* roundbox 4 free variables: corner-rounding, nop, roundbox type, shade */
815         block= uiLayoutFreeBlock(uiLayoutBox(column));
816         uiBlockSetHandleFunc(block, do_modifier_panels, NULL);
817
818         //uiDefBut(block, ROUNDBOX, 0, "", x-10, y-4, width, 25, NULL, 7.0, 0.0, 
819         //               (!isVirtual && (md->mode&eModifierMode_Expanded))?3:15, 20, ""); 
820         /* XXX uiBlockSetCol(block, TH_AUTO); */
821         
822         /* open/close icon */
823         if (!isVirtual) {
824                 uiBlockSetEmboss(block, UI_EMBOSSN);
825                 uiDefIconButBitI(block, ICONTOG, eModifierMode_Expanded, B_MODIFIER_REDRAW, VICON_DISCLOSURE_TRI_RIGHT, x-10, y-2, 20, 20, &md->mode, 0.0, 0.0, 0.0, 0.0, "Collapse/Expand Modifier");
826         }
827
828         uiBlockSetEmboss(block, UI_EMBOSS);
829         
830         if (isVirtual) {
831                 sprintf(str, "%s parent deform", md->name);
832                 uiDefBut(block, LABEL, 0, str, x+10, y-1, width-110, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Modifier name"); 
833
834                 but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Make Real", x+width-100, y, 80, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Convert virtual modifier to a real modifier");
835                 uiButSetFunc(but, modifiers_convertToReal, ob, md);
836         } else {
837                 uiBlockBeginAlign(block);
838                 uiDefBut(block, TEX, B_MODIFIER_REDRAW, "", x+10, y-1, buttonWidth-60, 19, md->name, 0.0, sizeof(md->name)-1, 0.0, 0.0, "Modifier name"); 
839
840                 /* Softbody not allowed in this situation, enforce! */
841                 if (((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) && (md->type!=eModifierType_Surface)) {
842                         uiDefIconButBitI(block, TOG, eModifierMode_Render, B_MODIFIER_RECALC, ICON_SCENE, x+10+buttonWidth-60, y-1, 19, 19,&md->mode, 0, 0, 1, 0, "Enable modifier during rendering");
843                         but= uiDefIconButBitI(block, TOG, eModifierMode_Realtime, B_MODIFIER_RECALC, VICON_VIEW3D, x+10+buttonWidth-40, y-1, 19, 19,&md->mode, 0, 0, 1, 0, "Enable modifier during interactive display");
844                         if (mti->flags&eModifierTypeFlag_SupportsEditmode) {
845                                 uiDefIconButBitI(block, TOG, eModifierMode_Editmode, B_MODIFIER_RECALC, VICON_EDIT, x+10+buttonWidth-20, y-1, 19, 19,&md->mode, 0, 0, 1, 0, "Enable modifier during Editmode (only if enabled for display)");
846                         }
847                 }
848                 uiBlockEndAlign(block);
849
850                 /* XXX uiBlockSetEmboss(block, UI_EMBOSSR); */
851
852                 if (ob->type==OB_MESH && modifier_couldBeCage(md) && index<=lastCageIndex) {
853                         int icon; //, color;
854
855                         if (index==cageIndex) {
856                                 // XXX color = TH_BUT_SETTING;
857                                 icon = VICON_EDITMODE_HLT;
858                         } else if (index<cageIndex) {
859                                 // XXX color = TH_BUT_NEUTRAL;
860                                 icon = VICON_EDITMODE_DEHLT;
861                         } else {
862                                 // XXX color = TH_BUT_NEUTRAL;
863                                 icon = ICON_BLANK1;
864                         }
865                         /* XXX uiBlockSetCol(block, color); */
866                         but = uiDefIconBut(block, BUT, B_MODIFIER_RECALC, icon, x+width-105, y, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Apply modifier to editing cage during Editmode");
867                         uiButSetFunc(but, modifiers_setOnCage, ob, md);
868                         /* XXX uiBlockSetCol(block, TH_AUTO); */
869                 }
870
871                 /* XXX uiBlockSetCol(block, TH_BUT_ACTION); */
872
873                 but = uiDefIconBut(block, BUT, B_MODIFIER_RECALC, VICON_MOVE_UP, x+width-75, y, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Move modifier up in stack");
874                 uiButSetFunc(but, modifiers_moveUp, ob, md);
875
876                 but = uiDefIconBut(block, BUT, B_MODIFIER_RECALC, VICON_MOVE_DOWN, x+width-75+20, y, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Move modifier down in stack");
877                 uiButSetFunc(but, modifiers_moveDown, ob, md);
878                 
879                 uiBlockSetEmboss(block, UI_EMBOSSN);
880                 
881                 // deletion over the deflection panel
882                 // fluid particle modifier can't be deleted here
883                 if(md->type!=eModifierType_Fluidsim && md->type!=eModifierType_Collision && md->type!=eModifierType_Surface && !modifier_is_fluid_particles(md))
884                 {
885                         but = uiDefIconBut(block, BUT, B_MODIFIER_RECALC, VICON_X, x+width-70+40, y, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Delete modifier");
886                         uiButSetFunc(but, modifiers_del, ob, md);
887                 }
888                 /* XXX uiBlockSetCol(block, TH_AUTO); */
889         }
890
891         uiBlockSetEmboss(block, UI_EMBOSS);
892
893         if(!isVirtual && (md->mode&eModifierMode_Expanded)) {
894                 int cy = y - 8;
895                 int lx = x + width - 60 - 15;
896                 uiLayout *box;
897
898                 box= uiLayoutBox(column);
899                 row= uiLayoutRow(box, 1);
900
901                 y -= 18;
902
903                 if (!isVirtual && (md->type!=eModifierType_Collision) && (md->type!=eModifierType_Surface)) {
904                         uiBlockSetButLock(block, object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE); /* only here obdata, the rest of modifiers is ob level */
905
906                         uiBlockBeginAlign(block);
907                         if (md->type==eModifierType_ParticleSystem) {
908                         ParticleSystem *psys= ((ParticleSystemModifierData *)md)->psys;
909
910                         if(!(G.f & G_PARTICLEEDIT)) {
911                                         if(ELEM3(psys->part->draw_as, PART_DRAW_PATH, PART_DRAW_GR, PART_DRAW_OB) && psys->pathcache) {
912                                                 but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Convert",        lx,(cy-=19),60,19, 0, 0, 0, 0, 0, "Convert the current particles to a mesh object");
913                                                 uiButSetFunc(but, modifiers_convertParticles, ob, md);
914                                         }
915                                 }
916                         }
917                         else{
918                                 but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Apply",  lx,(cy-=19),60,19, 0, 0, 0, 0, 0, "Apply the current modifier and remove from the stack");
919                                 uiButSetFunc(but, modifiers_applyModifier, ob, md);
920                         }
921                         
922                         uiBlockClearButLock(block);
923                         uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
924
925                         if (md->type!=eModifierType_Fluidsim && md->type!=eModifierType_Softbody && md->type!=eModifierType_ParticleSystem && (md->type!=eModifierType_Cloth)) {
926                                 but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Copy",   lx,(cy-=19),60,19, 0, 0, 0, 0, 0, "Duplicate the current modifier at the same position in the stack");
927                                 uiButSetFunc(but, modifiers_copyModifier, ob, md);
928                         }
929                         uiBlockEndAlign(block);
930                 }
931
932                 result= uiLayoutColumn(box, 0);
933                 block= uiLayoutFreeBlock(box);
934
935                 lx = x + 10;
936                 cy = y + 10 - 1;
937                 // else if (md->type==eModifierType_Surface) {
938                 //      uiDefBut(block, LABEL, 1, "See Fields panel.",  lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, "");
939         }
940
941         if (md->error) {
942
943                 row = uiLayoutRow(uiLayoutBox(column), 0);
944
945                 /* XXX uiBlockSetCol(block, color); */
946                 uiItemL(row, md->error, ICON_ERROR);
947                 /* XXX uiBlockSetCol(block, TH_AUTO); */
948         }
949
950         return result;
951 }
952
953 uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
954 {
955         Object *ob;
956         ModifierData *md, *vmd;
957         int i, lastCageIndex, cageIndex;
958
959         /* verify we have valid data */
960         if(!RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
961                 printf("uiTemplateModifier: expected modifier on object.\n");
962                 return NULL;
963         }
964
965         ob= ptr->id.data;
966         md= ptr->data;
967
968         if(!ob || !(GS(ob->id.name) == ID_OB)) {
969                 printf("uiTemplateModifier: expected modifier on object.\n");
970                 return NULL;
971         }
972         
973         uiBlockSetButLock(uiLayoutBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
974         
975         /* find modifier and draw it */
976         cageIndex = modifiers_getCageIndex(ob, &lastCageIndex);
977
978         // XXX virtual modifiers are not accesible for python
979         vmd = modifiers_getVirtualModifierList(ob);
980
981         for(i=0; vmd; i++, vmd=vmd->next) {
982                 if(md == vmd)
983                         return draw_modifier(C, layout, ob, md, i, cageIndex, lastCageIndex);
984                 else if(vmd->mode&eModifierMode_Virtual)
985                         i--;
986         }
987
988         return NULL;
989 }
990