32e49ce3f71e5ff9a2bb8239c0a08540618ce90a
[blender.git] / source / blender / editors / object / object_edit.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation, 2002-2008 full recode
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 #include <time.h>
31 #include <float.h>
32 #include <ctype.h>
33 #include <stddef.h> //for offsetof
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_blenlib.h"
38 #include "BLI_math.h"
39 #include "BLI_editVert.h"
40 #include "BLI_ghash.h"
41 #include "BLI_rand.h"
42
43 #include "DNA_armature_types.h"
44 #include "DNA_curve_types.h"
45 #include "DNA_group_types.h"
46 #include "DNA_lattice_types.h"
47 #include "DNA_material_types.h"
48 #include "DNA_meta_types.h"
49 #include "DNA_property_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_object_types.h"
52 #include "DNA_meshdata_types.h"
53 #include "DNA_vfont_types.h"
54
55 #include "IMB_imbuf_types.h"
56
57 #include "BKE_anim.h"
58 #include "BKE_constraint.h"
59 #include "BKE_context.h"
60 #include "BKE_curve.h"
61 #include "BKE_depsgraph.h"
62 #include "BKE_font.h"
63 #include "BKE_image.h"
64 #include "BKE_library.h"
65 #include "BKE_main.h"
66 #include "BKE_material.h"
67 #include "BKE_mball.h"
68 #include "BKE_mesh.h"
69 #include "BKE_object.h"
70 #include "BKE_paint.h"
71 #include "BKE_pointcache.h"
72 #include "BKE_property.h"
73 #include "BKE_sca.h"
74 #include "BKE_softbody.h"
75 #include "BKE_modifier.h"
76
77 #include "ED_armature.h"
78 #include "ED_curve.h"
79 #include "ED_mesh.h"
80 #include "ED_mball.h"
81 #include "ED_lattice.h"
82 #include "ED_object.h"
83 #include "ED_screen.h"
84 #include "ED_util.h"
85
86
87 #include "RNA_access.h"
88 #include "RNA_define.h"
89 #include "RNA_enum_types.h"
90
91 /* for menu/popup icons etc etc*/
92
93 #include "UI_interface.h"
94 #include "WM_api.h"
95 #include "WM_types.h"
96
97 #include "object_intern.h"      // own include
98
99 /* ************* XXX **************** */
100 static void error(const char *UNUSED(arg)) {}
101 static void waitcursor(int UNUSED(val)) {}
102 static int pupmenu(const char *UNUSED(msg)) {return 0;}
103
104 /* port over here */
105 static bContext *C;
106 static void error_libdata() {}
107
108
109 /* find the correct active object per context
110  * note: context can be NULL when called from a enum with PROP_ENUM_NO_CONTEXT */
111 Object *ED_object_active_context(bContext *C)
112 {
113         Object *ob= NULL;
114         if(C) {
115                 ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
116                 if (!ob) ob= CTX_data_active_object(C);
117         }
118         return ob;
119 }
120
121
122 /* ********* clear/set restrict view *********/
123 static int object_hide_view_clear_exec(bContext *C, wmOperator *UNUSED(op))
124 {
125         Main *bmain= CTX_data_main(C);
126         ScrArea *sa= CTX_wm_area(C);
127         View3D *v3d= sa->spacedata.first;
128         Scene *scene= CTX_data_scene(C);
129         Base *base;
130         int changed = 0;
131         
132         /* XXX need a context loop to handle such cases */
133         for(base = FIRSTBASE; base; base=base->next){
134                 if((base->lay & v3d->lay) && base->object->restrictflag & OB_RESTRICT_VIEW) {
135                         base->flag |= SELECT;
136                         base->object->flag = base->flag;
137                         base->object->restrictflag &= ~OB_RESTRICT_VIEW; 
138                         changed = 1;
139                 }
140         }
141         if (changed) {
142                 DAG_scene_sort(bmain, scene);
143                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
144         }
145
146         return OPERATOR_FINISHED;
147 }
148
149 void OBJECT_OT_hide_view_clear(wmOperatorType *ot)
150 {
151         
152         /* identifiers */
153         ot->name= "Clear Restrict View";
154         ot->description = "Reveal the object by setting the hide flag";
155         ot->idname= "OBJECT_OT_hide_view_clear";
156         
157         /* api callbacks */
158         ot->exec= object_hide_view_clear_exec;
159         ot->poll= ED_operator_view3d_active;
160         
161         /* flags */
162         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
163 }
164
165 static int object_hide_view_set_exec(bContext *C, wmOperator *op)
166 {
167         Main *bmain= CTX_data_main(C);
168         Scene *scene= CTX_data_scene(C);
169         short changed = 0;
170         int unselected= RNA_boolean_get(op->ptr, "unselected");
171         
172         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
173                 if(!unselected) {
174                         if (base->flag & SELECT){
175                                 base->flag &= ~SELECT;
176                                 base->object->flag = base->flag;
177                                 base->object->restrictflag |= OB_RESTRICT_VIEW;
178                                 changed = 1;
179                                 if (base==BASACT) {
180                                         ED_base_object_activate(C, NULL);
181                                 }
182                         }
183                 }
184                 else {
185                         if (!(base->flag & SELECT)){
186                                 base->object->restrictflag |= OB_RESTRICT_VIEW;
187                                 changed = 1;
188                         }
189                 }       
190         }
191         CTX_DATA_END;
192
193         if (changed) {
194                 DAG_scene_sort(bmain, scene);
195                 
196                 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C));
197                 
198         }
199
200         return OPERATOR_FINISHED;
201 }
202
203 void OBJECT_OT_hide_view_set(wmOperatorType *ot)
204 {
205         /* identifiers */
206         ot->name= "Set Restrict View";
207         ot->description = "Hide the object by setting the hide flag";
208         ot->idname= "OBJECT_OT_hide_view_set";
209         
210         /* api callbacks */
211         ot->exec= object_hide_view_set_exec;
212         ot->poll= ED_operator_view3d_active;
213         
214         /* flags */
215         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
216         
217         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects.");
218         
219 }
220
221 /* 99% same as above except no need for scene refreshing (TODO, update render preview) */
222 static int object_hide_render_clear_exec(bContext *C, wmOperator *UNUSED(op))
223 {
224         short changed= 0;
225
226         /* XXX need a context loop to handle such cases */
227         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
228                 if(ob->restrictflag & OB_RESTRICT_RENDER) {
229                         ob->restrictflag &= ~OB_RESTRICT_RENDER;
230                         changed= 1;
231                 }
232         }
233         CTX_DATA_END;
234
235         if(changed)
236                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_OUTLINER, NULL);
237
238         return OPERATOR_FINISHED;
239 }
240
241 void OBJECT_OT_hide_render_clear(wmOperatorType *ot)
242 {
243
244         /* identifiers */
245         ot->name= "Clear Restrict Render";
246         ot->description = "Reveal the render object by setting the hide render flag";
247         ot->idname= "OBJECT_OT_hide_render_clear";
248
249         /* api callbacks */
250         ot->exec= object_hide_render_clear_exec;
251         ot->poll= ED_operator_view3d_active;
252
253         /* flags */
254         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
255 }
256
257 static int object_hide_render_set_exec(bContext *C, wmOperator *op)
258 {
259         int unselected= RNA_boolean_get(op->ptr, "unselected");
260
261         CTX_DATA_BEGIN(C, Base*, base, visible_bases) {
262                 if(!unselected) {
263                         if (base->flag & SELECT){
264                                 base->object->restrictflag |= OB_RESTRICT_RENDER;
265                         }
266                 }
267                 else {
268                         if (!(base->flag & SELECT)){
269                                 base->object->restrictflag |= OB_RESTRICT_RENDER;
270                         }
271                 }
272         }
273         CTX_DATA_END;
274         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_OUTLINER, NULL);
275         return OPERATOR_FINISHED;
276 }
277
278 void OBJECT_OT_hide_render_set(wmOperatorType *ot)
279 {
280         /* identifiers */
281         ot->name= "Set Restrict Render";
282         ot->description = "Hide the render object by setting the hide render flag";
283         ot->idname= "OBJECT_OT_hide_render_set";
284
285         /* api callbacks */
286         ot->exec= object_hide_render_set_exec;
287         ot->poll= ED_operator_view3d_active;
288
289         /* flags */
290         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
291
292         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects.");
293 }
294
295 /* ******************* toggle editmode operator  ***************** */
296
297 void ED_object_exit_editmode(bContext *C, int flag)
298 {
299         /* Note! only in exceptional cases should 'EM_DO_UNDO' NOT be in the flag */
300
301         Scene *scene= CTX_data_scene(C);
302         Object *obedit= CTX_data_edit_object(C);
303         int freedata = flag & EM_FREEDATA;
304         
305         if(obedit==NULL) return;
306         
307         if(flag & EM_WAITCURSOR) waitcursor(1);
308         if(obedit->type==OB_MESH) {
309                 Mesh *me= obedit->data;
310                 
311 //              if(EM_texFaceCheck())
312                 
313 //              if(retopo_mesh_paint_check())
314 //                      retopo_end_okee();
315                 
316                 if(me->edit_mesh->totvert>MESH_MAX_VERTS) {
317                         error("Too many vertices");
318                         return;
319                 }
320                 load_editMesh(scene, obedit);
321                 
322                 if(freedata) {
323                         free_editMesh(me->edit_mesh);
324                         MEM_freeN(me->edit_mesh);
325                         me->edit_mesh= NULL;
326                 }
327                 
328                 if(obedit->restore_mode & OB_MODE_WEIGHT_PAINT) {
329                         mesh_octree_table(NULL, NULL, NULL, 'e');
330                         mesh_mirrtopo_table(NULL, 'e');
331                 }
332         }
333         else if (obedit->type==OB_ARMATURE) {   
334                 ED_armature_from_edit(obedit);
335                 if(freedata)
336                         ED_armature_edit_free(obedit);
337         }
338         else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
339                 load_editNurb(obedit);
340                 if(freedata) free_editNurb(obedit);
341         }
342         else if(obedit->type==OB_FONT && freedata) {
343                 load_editText(obedit);
344                 if(freedata) free_editText(obedit);
345         }
346         else if(obedit->type==OB_LATTICE) {
347                 load_editLatt(obedit);
348                 if(freedata) free_editLatt(obedit);
349         }
350         else if(obedit->type==OB_MBALL) {
351                 load_editMball(obedit);
352                 if(freedata) free_editMball(obedit);
353         }
354
355         /* freedata only 0 now on file saves and render */
356         if(freedata) {
357                 ListBase pidlist;
358                 PTCacheID *pid;
359
360                 /* for example; displist make is different in editmode */
361                 scene->obedit= NULL; // XXX for context
362
363                 /* flag object caches as outdated */
364                 BKE_ptcache_ids_from_object(&pidlist, obedit, NULL, 0);
365                 for(pid=pidlist.first; pid; pid=pid->next) {
366                         if(pid->type != PTCACHE_TYPE_PARTICLES) /* particles don't need reset on geometry change */
367                                 pid->cache->flag |= PTCACHE_OUTDATED;
368                 }
369                 BLI_freelistN(&pidlist);
370                 
371                 BKE_ptcache_object_reset(scene, obedit, PTCACHE_RESET_OUTDATED);
372
373                 /* also flush ob recalc, doesn't take much overhead, but used for particles */
374                 DAG_id_flush_update(&obedit->id, OB_RECALC_OB|OB_RECALC_DATA);
375         
376                 if(flag & EM_DO_UNDO)
377                         ED_undo_push(C, "Editmode");
378         
379                 if(flag & EM_WAITCURSOR) waitcursor(0);
380         
381                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, scene);
382
383                 obedit->mode &= ~OB_MODE_EDIT;
384         }
385 }
386
387
388 void ED_object_enter_editmode(bContext *C, int flag)
389 {
390         Scene *scene= CTX_data_scene(C);
391         Base *base= NULL;
392         Object *ob;
393         ScrArea *sa= CTX_wm_area(C);
394         View3D *v3d= NULL;
395         int ok= 0;
396         
397         if(scene->id.lib) return;
398         
399         if(sa && sa->spacetype==SPACE_VIEW3D)
400                 v3d= sa->spacedata.first;
401         
402         if((flag & EM_IGNORE_LAYER)==0) {
403                 base= CTX_data_active_base(C); /* active layer checked here for view3d */
404
405                 if(base==NULL) return;
406                 else if(v3d && (base->lay & v3d->lay)==0) return;
407                 else if(!v3d && (base->lay & scene->lay)==0) return;
408         }
409         else {
410                 base= scene->basact;
411         }
412
413         if (ELEM3(NULL, base, base->object, base->object->data)) return;
414
415         ob = base->object;
416         
417         if (object_data_is_libdata(ob)) {
418                 error_libdata();
419                 return;
420         }
421         
422         if(flag & EM_WAITCURSOR) waitcursor(1);
423
424         ob->restore_mode = ob->mode;
425
426         /* note, when switching scenes the object can have editmode data but
427          * not be scene->obedit: bug 22954, this avoids calling self eternally */
428         if((ob->restore_mode & OB_MODE_EDIT)==0)
429                 ED_object_toggle_modes(C, ob->mode);
430
431         ob->mode= OB_MODE_EDIT;
432         
433         if(ob->type==OB_MESH) {
434                 Mesh *me= ob->data;
435                 
436                 if(me->pv) mesh_pmv_off(me);
437                 ok= 1;
438                 scene->obedit= ob;      // context sees this
439                 
440                 make_editMesh(scene, ob);
441
442                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MESH, scene);
443         }
444         else if (ob->type==OB_ARMATURE){
445                 bArmature *arm= base->object->data;
446                 if (!arm) return;
447                 /*
448                  * The function object_data_is_libdata make a problem here, the
449                  * check for ob->proxy return 0 and let blender enter to edit mode
450                  * this causa a crash when you try leave the edit mode.
451                  * The problem is that i can't remove the ob->proxy check from
452                  * object_data_is_libdata that prevent the bugfix #6614, so
453                  * i add this little hack here.
454                  */
455                 if(arm->id.lib) {
456                         error_libdata();
457                         return;
458                 }
459                 ok=1;
460                 scene->obedit= ob;
461                 ED_armature_to_edit(ob);
462                 /* to ensure all goes in restposition and without striding */
463                 DAG_id_flush_update(&ob->id, OB_RECALC_ALL); // XXX: should this be OB_RECALC_DATA?
464
465                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_ARMATURE, scene);
466         }
467         else if(ob->type==OB_FONT) {
468                 scene->obedit= ob; // XXX for context
469                 ok= 1;
470                  make_editText(ob);
471
472                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_TEXT, scene);
473         }
474         else if(ob->type==OB_MBALL) {
475                 scene->obedit= ob; // XXX for context
476                 ok= 1;
477                 make_editMball(ob);
478
479                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MBALL, scene);
480         }
481         else if(ob->type==OB_LATTICE) {
482                 scene->obedit= ob; // XXX for context
483                 ok= 1;
484                 make_editLatt(ob);
485                 
486                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_LATTICE, scene);
487         }
488         else if(ob->type==OB_SURF || ob->type==OB_CURVE) {
489                 ok= 1;
490                 scene->obedit= ob; // XXX for context
491                 make_editNurb(ob);
492                 
493                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_CURVE, scene);
494         }
495         
496         if(ok) {
497                 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
498         }
499         else {
500                 scene->obedit= NULL; // XXX for context
501                 ob->mode &= ~OB_MODE_EDIT;
502                 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, scene);
503         }
504         
505         if(flag & EM_DO_UNDO) ED_undo_push(C, "Enter Editmode");
506         if(flag & EM_WAITCURSOR) waitcursor(0);
507 }
508
509 static int editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op))
510 {
511         if(!CTX_data_edit_object(C))
512                 ED_object_enter_editmode(C, EM_WAITCURSOR);
513         else
514                 ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO);
515         
516         return OPERATOR_FINISHED;
517 }
518
519 static int editmode_toggle_poll(bContext *C)
520 {
521         Object *ob = CTX_data_active_object(C);
522
523         /* covers proxies too */
524         if(ELEM(NULL, ob, ob->data) || ((ID *)ob->data)->lib)
525                 return 0;
526
527         return ob && (ob->type == OB_MESH || ob->type == OB_ARMATURE ||
528                           ob->type == OB_FONT || ob->type == OB_MBALL ||
529                           ob->type == OB_LATTICE || ob->type == OB_SURF ||
530                           ob->type == OB_CURVE);
531 }
532
533 void OBJECT_OT_editmode_toggle(wmOperatorType *ot)
534 {
535         
536         /* identifiers */
537         ot->name= "Toggle Editmode";
538         ot->description = "Toggle object's editmode";
539         ot->idname= "OBJECT_OT_editmode_toggle";
540         
541         /* api callbacks */
542         ot->exec= editmode_toggle_exec;
543         
544         ot->poll= editmode_toggle_poll;
545         
546         /* flags */
547         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
548 }
549
550 /* *************************** */
551
552 static int posemode_exec(bContext *C, wmOperator *UNUSED(op))
553 {
554         Base *base= CTX_data_active_base(C);
555         
556         if(base->object->type==OB_ARMATURE) {
557                 if(base->object==CTX_data_edit_object(C)) {
558                         ED_object_exit_editmode(C, EM_FREEDATA|EM_DO_UNDO);
559                         ED_armature_enter_posemode(C, base);
560                 }
561                 else if(base->object->mode & OB_MODE_POSE)
562                         ED_armature_exit_posemode(C, base);
563                 else
564                         ED_armature_enter_posemode(C, base);
565                 
566                 return OPERATOR_FINISHED;
567         }
568         
569         return OPERATOR_PASS_THROUGH;
570 }
571
572 void OBJECT_OT_posemode_toggle(wmOperatorType *ot) 
573 {
574         /* identifiers */
575         ot->name= "Toggle Pose Mode";
576         ot->idname= "OBJECT_OT_posemode_toggle";
577         ot->description= "Enables or disables posing/selecting bones";
578         
579         /* api callbacks */
580         ot->exec= posemode_exec;
581         ot->poll= ED_operator_object_active_editable;
582         
583         /* flag */
584         ot->flag= OPTYPE_REGISTER;
585 }
586
587 /* *********************** */
588
589 void check_editmode(int type)
590 {
591         Object *obedit= NULL; // XXX
592         
593         if (obedit==NULL || obedit->type==type) return;
594
595 // XXX  ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR|EM_DO_UNDO); /* freedata, and undo */
596 }
597
598 #if 0
599 // XXX should be in view3d?
600
601 /* context: ob = lamp */
602 /* code should be replaced with proper (custom) transform handles for lamp properties */
603 static void spot_interactive(Object *ob, int mode)
604 {
605         Lamp *la= ob->data;
606         float transfac, dx, dy, ratio, origval;
607         int keep_running= 1, center2d[2];
608         short mval[2], mvalo[2];
609         
610 //      getmouseco_areawin(mval);
611 //      getmouseco_areawin(mvalo);
612         
613         project_int(ob->obmat[3], center2d);
614         if( center2d[0] > 100000 ) {            /* behind camera */
615 //              center2d[0]= curarea->winx/2;
616 //              center2d[1]= curarea->winy/2;
617         }
618
619 //      helpline(mval, center2d);
620         
621         /* ratio is like scaling */
622         dx = (float)(center2d[0] - mval[0]);
623         dy = (float)(center2d[1] - mval[1]);
624         transfac = (float)sqrt( dx*dx + dy*dy);
625         if(transfac==0.0f) transfac= 1.0f;
626         
627         if(mode==1)     
628                 origval= la->spotsize;
629         else if(mode==2)        
630                 origval= la->dist;
631         else if(mode==3)        
632                 origval= la->clipsta;
633         else    
634                 origval= la->clipend;
635         
636         while (keep_running>0) {
637                 
638 //              getmouseco_areawin(mval);
639                 
640                 /* essential for idling subloop */
641                 if(mval[0]==mvalo[0] && mval[1]==mvalo[1]) {
642                         PIL_sleep_ms(2);
643                 }
644                 else {
645                         char str[32];
646                         
647                         dx = (float)(center2d[0] - mval[0]);
648                         dy = (float)(center2d[1] - mval[1]);
649                         ratio = (float)(sqrt( dx*dx + dy*dy))/transfac;
650                         
651                         /* do the trick */
652                         
653                         if(mode==1) {   /* spot */
654                                 la->spotsize = ratio*origval;
655                                 CLAMP(la->spotsize, 1.0f, 180.0f);
656                                 sprintf(str, "Spot size %.2f\n", la->spotsize);
657                         }
658                         else if(mode==2) {      /* dist */
659                                 la->dist = ratio*origval;
660                                 CLAMP(la->dist, 0.01f, 5000.0f);
661                                 sprintf(str, "Distance %.2f\n", la->dist);
662                         }
663                         else if(mode==3) {      /* sta */
664                                 la->clipsta = ratio*origval;
665                                 CLAMP(la->clipsta, 0.001f, 5000.0f);
666                                 sprintf(str, "Distance %.2f\n", la->clipsta);
667                         }
668                         else if(mode==4) {      /* end */
669                                 la->clipend = ratio*origval;
670                                 CLAMP(la->clipend, 0.1f, 5000.0f);
671                                 sprintf(str, "Clip End %.2f\n", la->clipend);
672                         }
673
674                         /* cleanup */
675                         mvalo[0]= mval[0];
676                         mvalo[1]= mval[1];
677                         
678                         /* handle shaded mode */
679 // XXX                  shade_buttons_change_3d();
680
681                         /* DRAW */      
682                         headerprint(str);
683                         force_draw_plus(SPACE_BUTS, 0);
684
685 //                      helpline(mval, center2d);
686                 }
687                 
688                 while( qtest() ) {
689                         short val;
690                         unsigned short event= extern_qread(&val);
691                         
692                         switch (event){
693                                 case ESCKEY:
694                                 case RIGHTMOUSE:
695                                         keep_running= 0;
696                                         break;
697                                 case LEFTMOUSE:
698                                 case SPACEKEY:
699                                 case PADENTER:
700                                 case RETKEY:
701                                         if(val)
702                                                 keep_running= -1;
703                                         break;
704                         }
705                 }
706         }
707
708         if(keep_running==0) {
709                 if(mode==1)     
710                         la->spotsize= origval;
711                 else if(mode==2)        
712                         la->dist= origval;
713                 else if(mode==3)        
714                         la->clipsta= origval;
715                 else    
716                         la->clipend= origval;
717         }
718
719 }
720 #endif
721
722 void special_editmenu(Scene *scene, View3D *v3d)
723 {
724 // XXX  static short numcuts= 2;
725         Object *ob= OBACT;
726         Object *obedit= NULL; // XXX
727         int nr,ret=0;
728         
729         if(ob==NULL) return;
730         
731         if(obedit==NULL) {
732                 
733                 if(ob->mode & OB_MODE_POSE) {
734 // XXX                  pose_special_editmenu();
735                 }
736                 else if(paint_facesel_test(ob)) {
737                         Mesh *me= get_mesh(ob);
738                         MTFace *tface;
739                         MFace *mface;
740                         int a;
741                         
742                         if(me==0 || me->mtface==0) return;
743                         
744                         nr= pupmenu("Specials%t|Set     Tex%x1|         Shared%x2|         Light%x3|         Invisible%x4|         Collision%x5|         TwoSide%x6|Clr     Tex%x7|         Shared%x8|         Light%x9|         Invisible%x10|         Collision%x11|         TwoSide%x12");
745                         
746                         tface= me->mtface;
747                         mface= me->mface;
748                         for(a=me->totface; a>0; a--, tface++, mface++) {
749                                 if(mface->flag & ME_FACE_SEL) {
750                                         switch(nr) {
751                                         case 1:
752                                                 tface->mode |= TF_TEX; break;
753                                         case 2:
754                                                 tface->mode |= TF_SHAREDCOL; break;
755                                         case 3:
756                                                 tface->mode |= TF_LIGHT; break; 
757                                         case 4:
758                                                 tface->mode |= TF_INVISIBLE; break;
759                                         case 5:
760                                                 tface->mode |= TF_DYNAMIC; break;
761                                         case 6:
762                                                 tface->mode |= TF_TWOSIDE; break;
763                                         case 7:
764                                                 tface->mode &= ~TF_TEX;
765                                                 tface->tpage= 0;
766                                                 break;
767                                         case 8:
768                                                 tface->mode &= ~TF_SHAREDCOL; break;
769                                         case 9:
770                                                 tface->mode &= ~TF_LIGHT; break;
771                                         case 10:
772                                                 tface->mode &= ~TF_INVISIBLE; break;
773                                         case 11:
774                                                 tface->mode &= ~TF_DYNAMIC; break;
775                                         case 12:
776                                                 tface->mode &= ~TF_TWOSIDE; break;
777                                         }
778                                 }
779                         }
780                         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
781                 }
782                 else if(ob->mode & OB_MODE_VERTEX_PAINT) {
783                         Mesh *me= get_mesh(ob);
784                         
785                         if(me==0 || (me->mcol==NULL && me->mtface==NULL) ) return;
786                         
787                         nr= pupmenu("Specials%t|Shared VertexCol%x1");
788                         if(nr==1) {
789                                 
790 // XXX                          do_shared_vertexcol(me);
791                                 
792                                 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
793                         }
794                 }
795                 else if(ob->mode & OB_MODE_WEIGHT_PAINT) {
796                         Object *par= modifiers_isDeformedByArmature(ob);
797
798                         if(par && (par->mode & OB_MODE_POSE)) {
799                                 nr= pupmenu("Specials%t|Apply Bone Envelopes to Vertex Groups %x1|Apply Bone Heat Weights to Vertex Groups %x2");
800
801 // XXX                          if(nr==1 || nr==2)
802 // XXX                                  pose_adds_vgroups(ob, (nr == 2));
803                         }
804                 }
805                 else if(ob->mode & OB_MODE_PARTICLE_EDIT) {
806 #if 0
807                         // XXX
808                         ParticleSystem *psys = PE_get_current(ob);
809                         ParticleEditSettings *pset = PE_settings();
810
811                         if(!psys)
812                                 return;
813
814                         if(pset->selectmode & SCE_SELECT_POINT)
815                                 nr= pupmenu("Specials%t|Rekey%x1|Subdivide%x2|Select First%x3|Select Last%x4|Remove Doubles%x5");
816                         else
817                                 nr= pupmenu("Specials%t|Rekey%x1|Remove Doubles%x5");
818                         
819                         switch(nr) {
820                         case 1:
821 // XXX                          if(button(&pset->totrekey, 2, 100, "Number of Keys:")==0) return;
822                                 waitcursor(1);
823                                 PE_rekey();
824                                 break;
825                         case 2:
826                                 PE_subdivide();
827                                 break;
828                         case 3:
829                                 PE_select_root();
830                                 break;
831                         case 4:
832                                 PE_select_tip();
833                                 break;
834                         case 5:
835                                 PE_remove_doubles();
836                                 break;
837                         }
838                         
839                         DAG_id_flush_update(&obedit->id, OB_RECALC_DATA);
840                         
841                         if(nr>0) waitcursor(0);
842 #endif
843                 }
844                 else {
845                         Base *base, *base_select= NULL;
846                         
847                         /* Get the active object mesh. */
848                         Mesh *me= get_mesh(ob);
849
850                         /* Booleans, if the active object is a mesh... */
851                         if (me && ob->id.lib==NULL) {
852                                 
853                                 /* Bring up a little menu with the boolean operation choices on. */
854                                 nr= pupmenu("Boolean Tools%t|Intersect%x1|Union%x2|Difference%x3|Add Intersect Modifier%x4|Add Union Modifier%x5|Add Difference Modifier%x6");
855
856                                 if (nr > 0) {
857                                         /* user has made a choice of a menu element.
858                                            All of the boolean functions require 2 mesh objects 
859                                            we search through the object list to find the other 
860                                            selected item and make sure it is distinct and a mesh. */
861
862                                         for(base= FIRSTBASE; base; base= base->next) {
863                                                 if(TESTBASELIB(v3d, base)) {
864                                                         if(base->object != ob) base_select= base;
865                                                 }
866                                         }
867
868                                         if (base_select) {
869                                                 if (get_mesh(base_select->object)) {
870                                                         if(nr <= 3){
871                                                                 waitcursor(1);
872 // XXX                                                          ret = NewBooleanMesh(BASACT,base_select,nr);
873                                                                 if (ret==0) {
874                                                                         error("An internal error occurred");
875                                                                 } else if(ret==-1) {
876                                                                         error("Selected meshes must have faces to perform boolean operations");
877                                                                 } else if (ret==-2) {
878                                                                         error("Both meshes must be a closed mesh");
879                                                                 }
880                                                                 waitcursor(0);
881                                                         } else {
882                                                                 BooleanModifierData *bmd = NULL;
883                                                                 bmd = (BooleanModifierData *)modifier_new(eModifierType_Boolean);
884                                                                 BLI_addtail(&ob->modifiers, bmd);
885                                                                 modifier_unique_name(&ob->modifiers, (ModifierData*)bmd);
886                                                                 bmd->object = base_select->object;
887                                                                 bmd->modifier.mode |= eModifierMode_Realtime;
888                                                                 switch(nr){
889                                                                         case 4: bmd->operation = eBooleanModifierOp_Intersect; break;
890                                                                         case 5: bmd->operation = eBooleanModifierOp_Union; break;
891                                                                         case 6: bmd->operation = eBooleanModifierOp_Difference; break;
892                                                                 }
893 // XXX                                                          do_common_editbuts(B_CHANGEDEP);
894                                                         }                                                               
895                                                 } else {
896                                                         error("Please select 2 meshes");
897                                                 }
898                                         } else {
899                                                 error("Please select 2 meshes");
900                                         }
901                                 }
902
903                         }
904                         else if (ob->type == OB_FONT) {
905                                 /* removed until this gets a decent implementation (ton) */
906 /*                              nr= pupmenu("Split %t|Characters%x1");
907                                 if (nr > 0) {
908                                         switch(nr) {
909                                                 case 1: split_font();
910                                         }
911                                 }
912 */
913                         }                       
914                 }
915         }
916         else if(obedit->type==OB_MESH) {
917         }
918         else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) {
919         }
920         else if(obedit->type==OB_ARMATURE) {
921                 nr= pupmenu("Specials%t|Subdivide %x1|Subdivide Multi%x2|Switch Direction%x7|Flip Left-Right Names%x3|%l|AutoName Left-Right%x4|AutoName Front-Back%x5|AutoName Top-Bottom%x6");
922 //              if(nr==1)
923 // XXX                  subdivide_armature(1);
924                 if(nr==2) {
925 // XXX                  if(button(&numcuts, 1, 128, "Number of Cuts:")==0) return;
926                         waitcursor(1);
927 // XXX                  subdivide_armature(numcuts);
928                 }
929 //              else if(nr==3)
930 // XXX                  armature_flip_names();
931                 else if(ELEM3(nr, 4, 5, 6)) {
932 // XXX                  armature_autoside_names(nr-4);
933                 }
934 //              else if(nr == 7)
935 // XXX                  switch_direction_armature();
936         }
937         else if(obedit->type==OB_LATTICE) {
938                 Lattice *lt= obedit->data;
939                 static float weight= 1.0f;
940                 { // XXX
941 // XXX          if(fbutton(&weight, 0.0f, 1.0f, 10, 10, "Set Weight")) {
942                         Lattice *editlt= lt->editlatt->latt;
943                         int a= editlt->pntsu*editlt->pntsv*editlt->pntsw;
944                         BPoint *bp= editlt->def;
945                         
946                         while(a--) {
947                                 if(bp->f1 & SELECT)
948                                         bp->weight= weight;
949                                 bp++;
950                         }
951                 }
952         }
953
954 }
955
956 static void copymenu_properties(Scene *scene, View3D *v3d, Object *ob)
957 {       
958 //XXX no longer used - to be removed - replaced by game_properties_copy_exec
959         bProperty *prop;
960         Base *base;
961         int nr, tot=0;
962         char *str;
963         
964         prop= ob->prop.first;
965         while(prop) {
966                 tot++;
967                 prop= prop->next;
968         }
969         
970         str= MEM_callocN(50 + 33*tot, "copymenu prop");
971         
972         if (tot)
973                 strcpy(str, "Copy Property %t|Replace All|Merge All|%l");
974         else
975                 strcpy(str, "Copy Property %t|Clear All (no properties on active)");
976         
977         tot= 0; 
978         prop= ob->prop.first;
979         while(prop) {
980                 tot++;
981                 strcat(str, "|");
982                 strcat(str, prop->name);
983                 prop= prop->next;
984         }
985
986         nr= pupmenu(str);
987         
988         if ( nr==1 || nr==2 ) {
989                 for(base= FIRSTBASE; base; base= base->next) {
990                         if((base != BASACT) &&(TESTBASELIB(v3d, base))) {
991                                 if (nr==1) { /* replace */
992                                         copy_properties( &base->object->prop, &ob->prop );
993                                 } else {
994                                         for(prop = ob->prop.first; prop; prop= prop->next ) {
995                                                 set_ob_property(base->object, prop);
996                                         }
997                                 }
998                         }
999                 }
1000         } else if(nr>0) {
1001                 prop = BLI_findlink(&ob->prop, nr-4); /* account for first 3 menu items & menu index starting at 1*/
1002                 
1003                 if(prop) {
1004                         for(base= FIRSTBASE; base; base= base->next) {
1005                                 if((base != BASACT) &&(TESTBASELIB(v3d, base))) {
1006                                         set_ob_property(base->object, prop);
1007                                 }
1008                         }
1009                 }
1010         }
1011         MEM_freeN(str);
1012         
1013 }
1014
1015 static void copymenu_logicbricks(Scene *scene, View3D *v3d, Object *ob)
1016 {
1017 //XXX no longer used - to be removed - replaced by logicbricks_copy_exec
1018         Base *base;
1019         
1020         for(base= FIRSTBASE; base; base= base->next) {
1021                 if(base->object != ob) {
1022                         if(TESTBASELIB(v3d, base)) {
1023                                 
1024                                 /* first: free all logic */
1025                                 free_sensors(&base->object->sensors);                           
1026                                 unlink_controllers(&base->object->controllers);
1027                                 free_controllers(&base->object->controllers);
1028                                 unlink_actuators(&base->object->actuators);
1029                                 free_actuators(&base->object->actuators);
1030                                 
1031                                 /* now copy it, this also works without logicbricks! */
1032                                 clear_sca_new_poins_ob(ob);
1033                                 copy_sensors(&base->object->sensors, &ob->sensors);
1034                                 copy_controllers(&base->object->controllers, &ob->controllers);
1035                                 copy_actuators(&base->object->actuators, &ob->actuators);
1036                                 set_sca_new_poins_ob(base->object);
1037                                 
1038                                 /* some menu settings */
1039                                 base->object->scavisflag= ob->scavisflag;
1040                                 base->object->scaflag= ob->scaflag;
1041                                 
1042                                 /* set the initial state */
1043                                 base->object->state= ob->state;
1044                                 base->object->init_state= ob->init_state;
1045                         }
1046                 }
1047         }
1048 }
1049
1050 static void copymenu_modifiers(Main *bmain, Scene *scene, View3D *v3d, Object *ob)
1051 {
1052         Base *base;
1053         int i, event;
1054         char str[512];
1055         char *errorstr= NULL;
1056
1057         strcpy(str, "Copy Modifiers %t");
1058
1059         sprintf(str+strlen(str), "|All%%x%d|%%l", NUM_MODIFIER_TYPES);
1060
1061         for (i=eModifierType_None+1; i<NUM_MODIFIER_TYPES; i++) {
1062                 ModifierTypeInfo *mti = modifierType_getInfo(i);
1063
1064                 if(ELEM3(i, eModifierType_Hook, eModifierType_Softbody, eModifierType_ParticleInstance)) continue;
1065                 
1066                 if(i == eModifierType_Collision)
1067                         continue;
1068
1069                 if (    (mti->flags&eModifierTypeFlag_AcceptsCVs) || 
1070                                 (ob->type==OB_MESH && (mti->flags&eModifierTypeFlag_AcceptsMesh))) {
1071                         sprintf(str+strlen(str), "|%s%%x%d", mti->name, i);
1072                 }
1073         }
1074
1075         event = pupmenu(str);
1076         if(event<=0) return;
1077
1078         for (base= FIRSTBASE; base; base= base->next) {
1079                 if(base->object != ob) {
1080                         if(TESTBASELIB(v3d, base)) {
1081                                 ModifierData *md;
1082
1083                                 base->object->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
1084
1085                                 if (base->object->type==ob->type) {
1086                                         /* copy all */
1087                                         if (event==NUM_MODIFIER_TYPES) {
1088                                                 object_free_modifiers(base->object);
1089
1090                                                 for (md=ob->modifiers.first; md; md=md->next) {
1091                                                         ModifierData *nmd = NULL;
1092                                                         
1093                                                         if(ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_ParticleInstance)) continue;
1094                 
1095                                                         if(md->type == eModifierType_Collision)
1096                                                                 continue;
1097                                                         
1098                                                         nmd = modifier_new(md->type);
1099                                                         modifier_copyData(md, nmd);
1100                                                         BLI_addtail(&base->object->modifiers, nmd);
1101                                                         modifier_unique_name(&base->object->modifiers, nmd);
1102                                                 }
1103
1104                                                 copy_object_particlesystems(base->object, ob);
1105                                                 copy_object_softbody(base->object, ob);
1106                                         } else {
1107                                                 /* copy specific types */
1108                                                 ModifierData *md, *mdn;
1109                                                 
1110                                                 /* remove all with type 'event' */
1111                                                 for (md=base->object->modifiers.first; md; md=mdn) {
1112                                                         mdn= md->next;
1113                                                         if(md->type==event) {
1114                                                                 BLI_remlink(&base->object->modifiers, md);
1115                                                                 modifier_free(md);
1116                                                         }
1117                                                 }
1118                                                 
1119                                                 /* copy all with type 'event' */
1120                                                 for (md=ob->modifiers.first; md; md=md->next) {
1121                                                         if (md->type==event) {
1122                                                                 
1123                                                                 mdn = modifier_new(event);
1124                                                                 BLI_addtail(&base->object->modifiers, mdn);
1125                                                                 modifier_unique_name(&base->object->modifiers, mdn);
1126
1127                                                                 modifier_copyData(md, mdn);
1128                                                         }
1129                                                 }
1130
1131                                                 if(event == eModifierType_ParticleSystem) {
1132                                                         object_free_particlesystems(base->object);
1133                                                         copy_object_particlesystems(base->object, ob);
1134                                                 }
1135                                                 else if(event == eModifierType_Softbody) {
1136                                                         object_free_softbody(base->object);
1137                                                         copy_object_softbody(base->object, ob);
1138                                                 }
1139                                         }
1140                                 }
1141                                 else
1142                                         errorstr= "Did not copy modifiers to other Object types";
1143                         }
1144                 }
1145         }
1146         
1147 //      if(errorstr) notice(errorstr);
1148         
1149         DAG_scene_sort(bmain, scene);
1150         
1151 }
1152
1153 /* both pointers should exist */
1154 static void copy_texture_space(Object *to, Object *ob)
1155 {
1156         float *poin1= NULL, *poin2= NULL;
1157         short texflag= 0;
1158         
1159         if(ob->type==OB_MESH) {
1160                 texflag= ((Mesh *)ob->data)->texflag;
1161                 poin2= ((Mesh *)ob->data)->loc;
1162         }
1163         else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
1164                 texflag= ((Curve *)ob->data)->texflag;
1165                 poin2= ((Curve *)ob->data)->loc;
1166         }
1167         else if(ob->type==OB_MBALL) {
1168                 texflag= ((MetaBall *)ob->data)->texflag;
1169                 poin2= ((MetaBall *)ob->data)->loc;
1170         }
1171         else
1172                 return;
1173                 
1174         if(to->type==OB_MESH) {
1175                 ((Mesh *)to->data)->texflag= texflag;
1176                 poin1= ((Mesh *)to->data)->loc;
1177         }
1178         else if (ELEM3(to->type, OB_CURVE, OB_SURF, OB_FONT)) {
1179                 ((Curve *)to->data)->texflag= texflag;
1180                 poin1= ((Curve *)to->data)->loc;
1181         }
1182         else if(to->type==OB_MBALL) {
1183                 ((MetaBall *)to->data)->texflag= texflag;
1184                 poin1= ((MetaBall *)to->data)->loc;
1185         }
1186         else
1187                 return;
1188         
1189         memcpy(poin1, poin2, 9*sizeof(float));  /* this was noted in DNA_mesh, curve, mball */
1190         
1191         if(to->type==OB_MESH) ;
1192         else if(to->type==OB_MBALL) tex_space_mball(to);
1193         else tex_space_curve(to->data);
1194         
1195 }
1196
1197 void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
1198 {
1199         Object *ob;
1200         Base *base;
1201         Curve *cu, *cu1;
1202         Nurb *nu;
1203         int do_scene_sort= 0;
1204         
1205         if(scene->id.lib) return;
1206
1207         if(!(ob=OBACT)) return;
1208         
1209         if(scene->obedit) { // XXX get from context
1210                 /* obedit_copymenu(); */
1211                 return;
1212         }
1213         if(event==9) {
1214                 copymenu_properties(scene, v3d, ob);
1215                 return;
1216         }
1217         else if(event==10) {
1218                 copymenu_logicbricks(scene, v3d, ob);
1219                 return;
1220         }
1221         else if(event==24) {
1222                 copymenu_modifiers(bmain, scene, v3d, ob);
1223                 return;
1224         }
1225
1226         for(base= FIRSTBASE; base; base= base->next) {
1227                 if(base != BASACT) {
1228                         if(TESTBASELIB(v3d, base)) {
1229                                 base->object->recalc |= OB_RECALC_OB;
1230                                 
1231                                 if(event==1) {  /* loc */
1232                                         VECCOPY(base->object->loc, ob->loc);
1233                                         VECCOPY(base->object->dloc, ob->dloc);
1234                                 }
1235                                 else if(event==2) {  /* rot */
1236                                         VECCOPY(base->object->rot, ob->rot);
1237                                         VECCOPY(base->object->drot, ob->drot);
1238                                         /* Quats arnt used yet */
1239                                         /*VECCOPY(base->object->quat, ob->quat);
1240                                         VECCOPY(base->object->dquat, ob->dquat);*/
1241                                 }
1242                                 else if(event==3) {  /* size */
1243                                         VECCOPY(base->object->size, ob->size);
1244                                         VECCOPY(base->object->dsize, ob->dsize);
1245                                 }
1246                                 else if(event==4) {  /* drawtype */
1247                                         base->object->dt= ob->dt;
1248                                         base->object->dtx= ob->dtx;
1249                                         base->object->empty_drawtype= ob->empty_drawtype;
1250                                         base->object->empty_drawsize= ob->empty_drawsize;
1251                                 }
1252                                 else if(event==5) {  /* time offs */
1253                                         base->object->sf= ob->sf;
1254                                 }
1255                                 else if(event==6) {  /* dupli */
1256                                         base->object->dupon= ob->dupon;
1257                                         base->object->dupoff= ob->dupoff;
1258                                         base->object->dupsta= ob->dupsta;
1259                                         base->object->dupend= ob->dupend;
1260                                         
1261                                         base->object->transflag &= ~OB_DUPLI;
1262                                         base->object->transflag |= (ob->transflag & OB_DUPLI);
1263
1264                                         base->object->dup_group= ob->dup_group;
1265                                         if(ob->dup_group)
1266                                                 id_lib_extern(&ob->dup_group->id);
1267                                 }
1268                                 else if(event==7) {     /* mass */
1269                                         base->object->mass= ob->mass;
1270                                 }
1271                                 else if(event==8) {     /* damping */
1272                                         base->object->damping= ob->damping;
1273                                         base->object->rdamping= ob->rdamping;
1274                                 }
1275                                 else if(event==11) {    /* all physical attributes */
1276                                         base->object->gameflag = ob->gameflag;
1277                                         base->object->inertia = ob->inertia;
1278                                         base->object->formfactor = ob->formfactor;
1279                                         base->object->damping= ob->damping;
1280                                         base->object->rdamping= ob->rdamping;
1281                                         base->object->min_vel= ob->min_vel;
1282                                         base->object->max_vel= ob->max_vel;
1283                                         if (ob->gameflag & OB_BOUNDS) {
1284                                                 base->object->boundtype = ob->boundtype;
1285                                         }
1286                                         base->object->margin= ob->margin;
1287                                         base->object->bsoft= copy_bulletsoftbody(ob->bsoft);
1288
1289                                 }
1290                                 else if(event==17) {    /* tex space */
1291                                         copy_texture_space(base->object, ob);
1292                                 }
1293                                 else if(event==18) {    /* font settings */
1294                                         
1295                                         if(base->object->type==ob->type) {
1296                                                 cu= ob->data;
1297                                                 cu1= base->object->data;
1298                                                 
1299                                                 cu1->spacemode= cu->spacemode;
1300                                                 cu1->spacing= cu->spacing;
1301                                                 cu1->linedist= cu->linedist;
1302                                                 cu1->shear= cu->shear;
1303                                                 cu1->fsize= cu->fsize;
1304                                                 cu1->xof= cu->xof;
1305                                                 cu1->yof= cu->yof;
1306                                                 cu1->textoncurve= cu->textoncurve;
1307                                                 cu1->wordspace= cu->wordspace;
1308                                                 cu1->ulpos= cu->ulpos;
1309                                                 cu1->ulheight= cu->ulheight;
1310                                                 if(cu1->vfont) cu1->vfont->id.us--;
1311                                                 cu1->vfont= cu->vfont;
1312                                                 id_us_plus((ID *)cu1->vfont);
1313                                                 if(cu1->vfontb) cu1->vfontb->id.us--;
1314                                                 cu1->vfontb= cu->vfontb;
1315                                                 id_us_plus((ID *)cu1->vfontb);
1316                                                 if(cu1->vfonti) cu1->vfonti->id.us--;
1317                                                 cu1->vfonti= cu->vfonti;
1318                                                 id_us_plus((ID *)cu1->vfonti);
1319                                                 if(cu1->vfontbi) cu1->vfontbi->id.us--;
1320                                                 cu1->vfontbi= cu->vfontbi;
1321                                                 id_us_plus((ID *)cu1->vfontbi);                                         
1322
1323                                                 BKE_text_to_curve(scene, base->object, 0);              /* needed? */
1324
1325                                                 
1326                                                 strcpy(cu1->family, cu->family);
1327                                                 
1328                                                 base->object->recalc |= OB_RECALC_DATA;
1329                                         }
1330                                 }
1331                                 else if(event==19) {    /* bevel settings */
1332                                         
1333                                         if(ELEM(base->object->type, OB_CURVE, OB_FONT)) {
1334                                                 cu= ob->data;
1335                                                 cu1= base->object->data;
1336                                                 
1337                                                 cu1->bevobj= cu->bevobj;
1338                                                 cu1->taperobj= cu->taperobj;
1339                                                 cu1->width= cu->width;
1340                                                 cu1->bevresol= cu->bevresol;
1341                                                 cu1->ext1= cu->ext1;
1342                                                 cu1->ext2= cu->ext2;
1343                                                 
1344                                                 base->object->recalc |= OB_RECALC_DATA;
1345                                         }
1346                                 }
1347                                 else if(event==25) {    /* curve resolution */
1348
1349                                         if(ELEM(base->object->type, OB_CURVE, OB_FONT)) {
1350                                                 cu= ob->data;
1351                                                 cu1= base->object->data;
1352                                                 
1353                                                 cu1->resolu= cu->resolu;
1354                                                 cu1->resolu_ren= cu->resolu_ren;
1355                                                 
1356                                                 nu= cu1->nurb.first;
1357                                                 
1358                                                 while(nu) {
1359                                                         nu->resolu= cu1->resolu;
1360                                                         nu= nu->next;
1361                                                 }
1362                                                 
1363                                                 base->object->recalc |= OB_RECALC_DATA;
1364                                         }
1365                                 }
1366                                 else if(event==21){
1367                                         if (base->object->type==OB_MESH) {
1368                                                 ModifierData *md = modifiers_findByType(ob, eModifierType_Subsurf);
1369
1370                                                 if (md) {
1371                                                         ModifierData *tmd = modifiers_findByType(base->object, eModifierType_Subsurf);
1372
1373                                                         if (!tmd) {
1374                                                                 tmd = modifier_new(eModifierType_Subsurf);
1375                                                                 BLI_addtail(&base->object->modifiers, tmd);
1376                                                         }
1377
1378                                                         modifier_copyData(md, tmd);
1379                                                         base->object->recalc |= OB_RECALC_DATA;
1380                                                 }
1381                                         }
1382                                 }
1383                                 else if(event==22) {
1384                                         /* Copy the constraint channels over */
1385                                         copy_constraints(&base->object->constraints, &ob->constraints, TRUE);
1386                                         
1387                                         do_scene_sort= 1;
1388                                 }
1389                                 else if(event==23) {
1390                                         base->object->softflag= ob->softflag;
1391                                         if(base->object->soft) sbFree(base->object->soft);
1392                                         
1393                                         base->object->soft= copy_softbody(ob->soft);
1394
1395                                         if (!modifiers_findByType(base->object, eModifierType_Softbody)) {
1396                                                 BLI_addhead(&base->object->modifiers, modifier_new(eModifierType_Softbody));
1397                                         }
1398                                 }
1399                                 else if(event==26) {
1400 #if 0 // XXX old animation system
1401                                         copy_nlastrips(&base->object->nlastrips, &ob->nlastrips);
1402 #endif // XXX old animation system
1403                                 }
1404                                 else if(event==27) {    /* autosmooth */
1405                                         if (base->object->type==OB_MESH) {
1406                                                 Mesh *me= ob->data;
1407                                                 Mesh *cme= base->object->data;
1408                                                 cme->smoothresh= me->smoothresh;
1409                                                 if(me->flag & ME_AUTOSMOOTH)
1410                                                         cme->flag |= ME_AUTOSMOOTH;
1411                                                 else
1412                                                         cme->flag &= ~ME_AUTOSMOOTH;
1413                                         }
1414                                 }
1415                                 else if(event==28) { /* UV orco */
1416                                         if(ELEM(base->object->type, OB_CURVE, OB_SURF)) {
1417                                                 cu= ob->data;
1418                                                 cu1= base->object->data;
1419                                                 
1420                                                 if(cu->flag & CU_UV_ORCO)
1421                                                         cu1->flag |= CU_UV_ORCO;
1422                                                 else
1423                                                         cu1->flag &= ~CU_UV_ORCO;
1424                                         }               
1425                                 }
1426                                 else if(event==29) { /* protected bits */
1427                                         base->object->protectflag= ob->protectflag;
1428                                 }
1429                                 else if(event==30) { /* index object */
1430                                         base->object->index= ob->index;
1431                                 }
1432                                 else if(event==31) { /* object color */
1433                                         QUATCOPY(base->object->col, ob->col);
1434                                 }
1435                         }
1436                 }
1437         }
1438         
1439         if(do_scene_sort)
1440                 DAG_scene_sort(bmain, scene);
1441
1442         DAG_ids_flush_update(bmain, 0);
1443 }
1444
1445 void copy_attr_menu(Main *bmain, Scene *scene, View3D *v3d)
1446 {
1447         Object *ob;
1448         short event;
1449         char str[512];
1450         
1451         if(!(ob=OBACT)) return;
1452         
1453         if (scene->obedit) { // XXX get from context
1454 //              if (ob->type == OB_MESH)
1455 // XXX                  mesh_copy_menu();
1456                 return;
1457         }
1458         
1459         /* Object Mode */
1460         
1461         /* If you change this menu, don't forget to update the menu in header_view3d.c
1462          * view3d_edit_object_copyattrmenu() and in toolbox.c
1463          */
1464         
1465         strcpy(str, "Copy Attributes %t|Location%x1|Rotation%x2|Size%x3|Draw Options%x4|Time Offset%x5|Dupli%x6|Object Color%x31|%l|Mass%x7|Damping%x8|All Physical Attributes%x11|Properties%x9|Logic Bricks%x10|Protected Transform%x29|%l");
1466         
1467         strcat (str, "|Object Constraints%x22");
1468         strcat (str, "|NLA Strips%x26");
1469         
1470 // XXX  if (OB_SUPPORT_MATERIAL(ob)) {
1471 //              strcat(str, "|Texture Space%x17");
1472 //      }       
1473         
1474         if(ob->type == OB_FONT) strcat(str, "|Font Settings%x18|Bevel Settings%x19");
1475         if(ob->type == OB_CURVE) strcat(str, "|Bevel Settings%x19|UV Orco%x28");
1476         
1477         if((ob->type == OB_FONT) || (ob->type == OB_CURVE)) {
1478                         strcat(str, "|Curve Resolution%x25");
1479         }
1480
1481         if(ob->type==OB_MESH){
1482                 strcat(str, "|Subsurf Settings%x21|AutoSmooth%x27");
1483         }
1484
1485         if(ob->soft) strcat(str, "|Soft Body Settings%x23");
1486         
1487         strcat(str, "|Pass Index%x30");
1488         
1489         if(ob->type==OB_MESH || ob->type==OB_CURVE || ob->type==OB_LATTICE || ob->type==OB_SURF){
1490                 strcat(str, "|Modifiers ...%x24");
1491         }
1492
1493         event= pupmenu(str);
1494         if(event<= 0) return;
1495         
1496         copy_attr(bmain, scene, v3d, event);
1497 }
1498
1499 /* ********************************************** */
1500 /* Motion Paths */
1501
1502 /* For the object with pose/action: update paths for those that have got them
1503  * This should selectively update paths that exist...
1504  *
1505  * To be called from various tools that do incremental updates 
1506  */
1507 void ED_objects_recalculate_paths(bContext *C, Scene *scene)
1508 {
1509         ListBase targets = {NULL, NULL};
1510         
1511         /* loop over objects in scene */
1512         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) 
1513         {
1514                 /* set flag to force recalc, then grab the relevant bones to target */
1515                 ob->avs.recalc |= ANIMVIZ_RECALC_PATHS;
1516                 animviz_get_object_motionpaths(ob, &targets);
1517         }
1518         CTX_DATA_END;
1519         
1520         /* recalculate paths, then free */
1521         animviz_calc_motionpaths(scene, &targets);
1522         BLI_freelistN(&targets);
1523 }
1524
1525 /* For the object with pose/action: create path curves for selected bones 
1526  * This recalculates the WHOLE path within the pchan->pathsf and pchan->pathef range
1527  */
1528 static int object_calculate_paths_exec (bContext *C, wmOperator *UNUSED(op))
1529 {
1530         Scene *scene= CTX_data_scene(C);
1531         
1532         /* set up path data for bones being calculated */
1533         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects)  
1534         {
1535                 /* verify makes sure that the selected bone has a bone with the appropriate settings */
1536                 animviz_verify_motionpaths(scene, ob, NULL);
1537         }
1538         CTX_DATA_END;
1539         
1540         /* calculate the bones that now have motionpaths... */
1541         // TODO: only make for the selected bones?
1542         ED_objects_recalculate_paths(C, scene);
1543         
1544         /* notifiers for updates */
1545         WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL);
1546         
1547         return OPERATOR_FINISHED; 
1548 }
1549
1550 void OBJECT_OT_paths_calculate (wmOperatorType *ot)
1551 {
1552         /* identifiers */
1553         ot->name= "Calculate Object Paths";
1554         ot->idname= "OBJECT_OT_paths_calculate";
1555         ot->description= "Calculate paths for the selected bones";
1556         
1557         /* api callbacks */
1558         ot->exec= object_calculate_paths_exec;
1559         ot->poll= ED_operator_object_active_editable;
1560         
1561         /* flags */
1562         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1563 }
1564
1565 /* --------- */
1566
1567 /* for the object with pose/action: clear path curves for selected bones only */
1568 void ED_objects_clear_paths(bContext *C)
1569 {
1570         /* loop over objects in scene */
1571         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) 
1572         {
1573                 if (ob->mpath) {
1574                         animviz_free_motionpath(ob->mpath);
1575                         ob->mpath= NULL;
1576                         ob->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
1577                 }
1578         }
1579         CTX_DATA_END;
1580 }
1581
1582 /* operator callback for this */
1583 static int object_clear_paths_exec (bContext *C, wmOperator *UNUSED(op))
1584 {       
1585         /* use the backend function for this */
1586         ED_objects_clear_paths(C);
1587         
1588         /* notifiers for updates */
1589         WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL);
1590         
1591         return OPERATOR_FINISHED; 
1592 }
1593
1594 void OBJECT_OT_paths_clear (wmOperatorType *ot)
1595 {
1596         /* identifiers */
1597         ot->name= "Clear Object Paths";
1598         ot->idname= "OBJECT_OT_paths_clear";
1599         ot->description= "Clear path caches for selected bones";
1600         
1601         /* api callbacks */
1602         ot->exec= object_clear_paths_exec;
1603         ot->poll= ED_operator_object_active_editable;
1604         
1605         /* flags */
1606         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1607 }
1608
1609
1610 /********************** Smooth/Flat *********************/
1611
1612 static int shade_smooth_exec(bContext *C, wmOperator *op)
1613 {
1614         Curve *cu;
1615         Nurb *nu;
1616         int clear= (strcmp(op->idname, "OBJECT_OT_shade_flat") == 0);
1617         int done= 0;
1618
1619         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
1620
1621                 if(ob->type==OB_MESH) {
1622                         mesh_set_smooth_flag(ob, !clear);
1623
1624                         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
1625                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
1626
1627                         done= 1;
1628                 }
1629                 else if ELEM(ob->type, OB_SURF, OB_CURVE) {
1630                         cu= ob->data;
1631
1632                         for(nu=cu->nurb.first; nu; nu=nu->next) {
1633                                 if(!clear) nu->flag |= ME_SMOOTH;
1634                                 else nu->flag &= ~ME_SMOOTH;
1635                         }
1636
1637                         DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
1638                         WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
1639
1640                         done= 1;
1641                 }
1642         }
1643         CTX_DATA_END;
1644
1645         return (done)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
1646 }
1647
1648 static int shade_poll(bContext *C)
1649 {
1650         return (ED_operator_object_active_editable(C) && !ED_operator_editmesh(C));
1651 }
1652
1653 void OBJECT_OT_shade_flat(wmOperatorType *ot)
1654 {
1655         /* identifiers */
1656         ot->name= "Shade Flat";
1657         ot->idname= "OBJECT_OT_shade_flat";
1658         
1659         /* api callbacks */
1660         ot->poll= shade_poll;
1661         ot->exec= shade_smooth_exec;
1662
1663         /* flags */
1664         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1665 }
1666
1667 void OBJECT_OT_shade_smooth(wmOperatorType *ot)
1668 {
1669         /* identifiers */
1670         ot->name= "Shade Smooth";
1671         ot->idname= "OBJECT_OT_shade_smooth";
1672         
1673         /* api callbacks */
1674         ot->poll= shade_poll;
1675         ot->exec= shade_smooth_exec;
1676         
1677         /* flags */
1678         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1679 }
1680
1681 /* ********************** */
1682
1683 void image_aspect(Scene *scene, View3D *v3d)
1684 {
1685         /* all selected objects with an image map: scale in image aspect */
1686         Base *base;
1687         Object *ob;
1688         Material *ma;
1689         Tex *tex;
1690         float x, y, space;
1691         int a, b, done;
1692         
1693         if(scene->obedit) return; // XXX get from context
1694         if(scene->id.lib) return;
1695         
1696         for(base= FIRSTBASE; base; base= base->next) {
1697                 if(TESTBASELIB(v3d, base)) {
1698                         ob= base->object;
1699                         done= 0;
1700                         
1701                         for(a=1; a<=ob->totcol; a++) {
1702                                 ma= give_current_material(ob, a);
1703                                 if(ma) {
1704                                         for(b=0; b<MAX_MTEX; b++) {
1705                                                 if(ma->mtex[b] && ma->mtex[b]->tex) {
1706                                                         tex= ma->mtex[b]->tex;
1707                                                         if(tex->type==TEX_IMAGE && tex->ima) {
1708                                                                 ImBuf *ibuf= BKE_image_get_ibuf(tex->ima, NULL);
1709                                                                 
1710                                                                 /* texturespace */
1711                                                                 space= 1.0;
1712                                                                 if(ob->type==OB_MESH) {
1713                                                                         float size[3];
1714                                                                         mesh_get_texspace(ob->data, NULL, NULL, size);
1715                                                                         space= size[0]/size[1];
1716                                                                 }
1717                                                                 else if(ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
1718                                                                         Curve *cu= ob->data;
1719                                                                         space= cu->size[0]/cu->size[1];
1720                                                                 }
1721                                                         
1722                                                                 x= ibuf->x/space;
1723                                                                 y= ibuf->y;
1724                                                                 
1725                                                                 if(x>y) ob->size[0]= ob->size[1]*x/y;
1726                                                                 else ob->size[1]= ob->size[0]*y/x;
1727                                                                 
1728                                                                 done= 1;
1729                                                                 DAG_id_flush_update(&ob->id, OB_RECALC_OB);                                                             
1730                                                         }
1731                                                 }
1732                                                 if(done) break;
1733                                         }
1734                                 }
1735                                 if(done) break;
1736                         }
1737                 }
1738         }
1739         
1740 }
1741
1742 int vergbaseco(const void *a1, const void *a2)
1743 {
1744         Base **x1, **x2;
1745         
1746         x1= (Base **) a1;
1747         x2= (Base **) a2;
1748         
1749         if( (*x1)->sy > (*x2)->sy ) return 1;
1750         else if( (*x1)->sy < (*x2)->sy) return -1;
1751         else if( (*x1)->sx > (*x2)->sx ) return 1;
1752         else if( (*x1)->sx < (*x2)->sx ) return -1;
1753
1754         return 0;
1755 }
1756
1757
1758 void auto_timeoffs(Scene *scene, View3D *v3d)
1759 {
1760         Base *base, **basesort, **bs;
1761         float start, delta;
1762         int tot=0, a;
1763         short offset=25;
1764
1765         if(BASACT==0 || v3d==NULL) return;
1766 // XXX  if(button(&offset, 0, 1000,"Total time")==0) return;
1767
1768         /* make array of all bases, xco yco (screen) */
1769         for(base= FIRSTBASE; base; base= base->next) {
1770                 if(TESTBASELIB(v3d, base)) {
1771                         tot++;
1772                 }
1773         }
1774
1775         delta= (float)offset/(float)tot;
1776         start= OBACT->sf;
1777
1778         bs= basesort= MEM_mallocN(sizeof(void *)*tot,"autotimeoffs");
1779         for(base= FIRSTBASE; base; base= base->next) {
1780                 if(TESTBASELIB(v3d, base)) {
1781                         *bs= base;
1782                         bs++;
1783                 }
1784         }
1785         qsort(basesort, tot, sizeof(void *), vergbaseco);
1786
1787         bs= basesort;
1788         for(a=0; a<tot; a++) {
1789                 
1790                 (*bs)->object->sf= start;
1791                 start+= delta;
1792
1793                 bs++;
1794         }
1795         MEM_freeN(basesort);
1796
1797 }
1798
1799 void ofs_timeoffs(Scene *scene, View3D *v3d)
1800 {
1801         float offset=0.0f;
1802
1803         if(BASACT==0 || v3d==NULL) return;
1804         
1805 // XXX  if(fbutton(&offset, -10000.0f, 10000.0f, 10, 10, "Offset")==0) return;
1806
1807         /* make array of all bases, xco yco (screen) */
1808         CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
1809                 ob->sf += offset;
1810                 if (ob->sf < -MAXFRAMEF)                ob->sf = -MAXFRAMEF;
1811                 else if (ob->sf > MAXFRAMEF)    ob->sf = MAXFRAMEF;
1812         }
1813         CTX_DATA_END;
1814
1815 }
1816
1817
1818 void rand_timeoffs(Scene *scene, View3D *v3d)
1819 {
1820         Base *base;
1821         float rand=0.0f;
1822
1823         if(BASACT==0 || v3d==NULL) return;
1824         
1825 // XXX  if(fbutton(&rand, 0.0f, 10000.0f, 10, 10, "Randomize")==0) return;
1826         
1827         rand *= 2;
1828         
1829         for(base= FIRSTBASE; base; base= base->next) {
1830                 if(TESTBASELIB(v3d, base)) {
1831                         base->object->sf += (BLI_drand()-0.5) * rand;
1832                         if (base->object->sf < -MAXFRAMEF)              base->object->sf = -MAXFRAMEF;
1833                         else if (base->object->sf > MAXFRAMEF)  base->object->sf = MAXFRAMEF;
1834                 }
1835         }
1836
1837 }
1838
1839 static EnumPropertyItem *object_mode_set_itemsf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
1840 {       
1841         EnumPropertyItem *input = object_mode_items;
1842         EnumPropertyItem *item= NULL;
1843         Object *ob;
1844         int totitem= 0;
1845         
1846         if(!C) /* needed for docs */
1847                 return object_mode_items;
1848
1849         ob = CTX_data_active_object(C);
1850         while(ob && input->identifier) {
1851                 if((input->value == OB_MODE_EDIT && ((ob->type == OB_MESH) || (ob->type == OB_ARMATURE) ||
1852                                                         (ob->type == OB_CURVE) || (ob->type == OB_SURF) ||
1853                                                          (ob->type == OB_FONT) || (ob->type == OB_MBALL) || (ob->type == OB_LATTICE))) ||
1854                    (input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) ||
1855                    (input->value == OB_MODE_PARTICLE_EDIT && ob->particlesystem.first) ||
1856                    ((input->value == OB_MODE_SCULPT || input->value == OB_MODE_VERTEX_PAINT ||
1857                          input->value == OB_MODE_WEIGHT_PAINT || input->value == OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) ||
1858                    (input->value == OB_MODE_OBJECT))
1859                         RNA_enum_item_add(&item, &totitem, input);
1860                 ++input;
1861         }
1862
1863         RNA_enum_item_end(&item, &totitem);
1864
1865         *free= 1;
1866
1867         return item;
1868 }
1869
1870 static const char *object_mode_op_string(int mode)
1871 {
1872         if(mode & OB_MODE_EDIT)
1873                 return "OBJECT_OT_editmode_toggle";
1874         if(mode == OB_MODE_SCULPT)
1875                 return "SCULPT_OT_sculptmode_toggle";
1876         if(mode == OB_MODE_VERTEX_PAINT)
1877                 return "PAINT_OT_vertex_paint_toggle";
1878         if(mode == OB_MODE_WEIGHT_PAINT)
1879                 return "PAINT_OT_weight_paint_toggle";
1880         if(mode == OB_MODE_TEXTURE_PAINT)
1881                 return "PAINT_OT_texture_paint_toggle";
1882         if(mode == OB_MODE_PARTICLE_EDIT)
1883                 return "PARTICLE_OT_particle_edit_toggle";
1884         if(mode == OB_MODE_POSE)
1885                 return "OBJECT_OT_posemode_toggle";
1886         return NULL;
1887 }
1888
1889 /* checks the mode to be set is compatible with the object
1890  * should be made into a generic function */
1891 static int object_mode_set_compat(bContext *UNUSED(C), wmOperator *op, Object *ob)
1892 {
1893         ObjectMode mode = RNA_enum_get(op->ptr, "mode");
1894
1895         if(ob) {
1896                 if(mode == OB_MODE_OBJECT)
1897                         return 1;
1898
1899                 switch(ob->type) {
1900                 case OB_MESH:
1901                         if(mode & (OB_MODE_EDIT|OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT|OB_MODE_PARTICLE_EDIT))
1902                                 return 1;
1903                         return 0;
1904                 case OB_CURVE:
1905                 case OB_SURF:
1906                 case OB_FONT:
1907                 case OB_MBALL:
1908                         if(mode & (OB_MODE_EDIT))
1909                                 return 1;
1910                         return 0;
1911                 case OB_LATTICE:
1912                         if(mode & (OB_MODE_EDIT|OB_MODE_WEIGHT_PAINT))
1913                                 return 1;
1914                 case OB_ARMATURE:
1915                         if(mode & (OB_MODE_EDIT|OB_MODE_POSE))
1916                                 return 1;
1917                 }
1918         }
1919
1920         return 0;
1921 }
1922
1923 static int object_mode_set_exec(bContext *C, wmOperator *op)
1924 {
1925         Object *ob= CTX_data_active_object(C);
1926         ObjectMode mode = RNA_enum_get(op->ptr, "mode");
1927         ObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT;
1928         int toggle = RNA_boolean_get(op->ptr, "toggle");
1929
1930         if(!ob || !object_mode_set_compat(C, op, ob))
1931                 return OPERATOR_PASS_THROUGH;
1932
1933         /* Exit current mode if it's not the mode we're setting */
1934         if(ob->mode != OB_MODE_OBJECT && ob->mode != mode)
1935                 WM_operator_name_call(C, object_mode_op_string(ob->mode), WM_OP_EXEC_REGION_WIN, NULL);
1936
1937         if(mode != OB_MODE_OBJECT) {
1938                 /* Enter new mode */
1939                 if(ob->mode != mode || toggle)
1940                         WM_operator_name_call(C, object_mode_op_string(mode), WM_OP_EXEC_REGION_WIN, NULL);
1941
1942                 if(toggle) {
1943                         if(ob->mode == mode)
1944                                 /* For toggling, store old mode so we know what to go back to */
1945                                 ob->restore_mode = restore_mode;
1946                         else if(ob->restore_mode != OB_MODE_OBJECT && ob->restore_mode != mode) {
1947                                 WM_operator_name_call(C, object_mode_op_string(ob->restore_mode), WM_OP_EXEC_REGION_WIN, NULL);
1948                         }
1949                 }
1950         }
1951
1952         return OPERATOR_FINISHED;
1953 }
1954
1955 void OBJECT_OT_mode_set(wmOperatorType *ot)
1956 {
1957         PropertyRNA *prop;
1958
1959         /* identifiers */
1960         ot->name= "Set Object Mode";
1961         ot->description = "Sets the object interaction mode";
1962         ot->idname= "OBJECT_OT_mode_set";
1963         
1964         /* api callbacks */
1965         ot->exec= object_mode_set_exec;
1966         
1967         ot->poll= ED_operator_object_active_editable;
1968         
1969         /* flags */
1970         ot->flag= 0; /* no register/undo here, leave it to operators being called */
1971         
1972         prop= RNA_def_enum(ot->srna, "mode", object_mode_items, OB_MODE_OBJECT, "Mode", "");
1973         RNA_def_enum_funcs(prop, object_mode_set_itemsf);
1974
1975         RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
1976 }
1977
1978
1979
1980 void ED_object_toggle_modes(bContext *C, int mode)
1981 {
1982         if(mode & OB_MODE_SCULPT)
1983                 WM_operator_name_call(C, "SCULPT_OT_sculptmode_toggle", WM_OP_EXEC_REGION_WIN, NULL);
1984         if(mode & OB_MODE_VERTEX_PAINT)
1985                 WM_operator_name_call(C, "PAINT_OT_vertex_paint_toggle", WM_OP_EXEC_REGION_WIN, NULL);
1986         if(mode & OB_MODE_WEIGHT_PAINT)
1987                 WM_operator_name_call(C, "PAINT_OT_weight_paint_toggle", WM_OP_EXEC_REGION_WIN, NULL);
1988         if(mode & OB_MODE_TEXTURE_PAINT)
1989                 WM_operator_name_call(C, "PAINT_OT_texture_paint_toggle", WM_OP_EXEC_REGION_WIN, NULL);
1990         if(mode & OB_MODE_PARTICLE_EDIT)
1991                 WM_operator_name_call(C, "PARTICLE_OT_particle_edit_toggle", WM_OP_EXEC_REGION_WIN, NULL);
1992         if(mode & OB_MODE_POSE)
1993                 WM_operator_name_call(C, "OBJECT_OT_posemode_toggle", WM_OP_EXEC_REGION_WIN, NULL);
1994         if(mode & OB_MODE_EDIT)
1995                 WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_EXEC_REGION_WIN, NULL);
1996 }
1997
1998 /************************ Game Properties ***********************/
1999
2000 static int game_property_new(bContext *C, wmOperator *UNUSED(op))
2001 {
2002         Object *ob= CTX_data_active_object(C);
2003         bProperty *prop;
2004
2005         if(!ob)
2006                 return OPERATOR_CANCELLED;
2007
2008         prop= new_property(PROP_FLOAT);
2009         BLI_addtail(&ob->prop, prop);
2010         unique_property(NULL, prop, 0); // make_unique_prop_names(prop->name);
2011
2012         WM_event_add_notifier(C, NC_LOGIC, NULL);
2013         return OPERATOR_FINISHED;
2014 }
2015
2016
2017 void OBJECT_OT_game_property_new(wmOperatorType *ot)
2018 {
2019         /* identifiers */
2020         ot->name= "New Game Property";
2021         ot->idname= "OBJECT_OT_game_property_new";
2022
2023         /* api callbacks */
2024         ot->exec= game_property_new;
2025         ot->poll= ED_operator_object_active_editable;
2026
2027         /* flags */
2028         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2029 }
2030
2031 static int game_property_remove(bContext *C, wmOperator *op)
2032 {
2033         Object *ob= CTX_data_active_object(C);
2034         bProperty *prop;
2035         int index= RNA_int_get(op->ptr, "index");
2036
2037         if(!ob)
2038                 return OPERATOR_CANCELLED;
2039
2040         prop= BLI_findlink(&ob->prop, index);
2041
2042         if(prop) {
2043                 BLI_remlink(&ob->prop, prop);
2044                 free_property(prop);
2045
2046                 WM_event_add_notifier(C, NC_LOGIC, NULL);
2047                 return OPERATOR_FINISHED;
2048         }
2049         else {
2050                 return OPERATOR_CANCELLED;
2051         }
2052 }
2053
2054 void OBJECT_OT_game_property_remove(wmOperatorType *ot)
2055 {
2056         /* identifiers */
2057         ot->name= "Remove Game Property";
2058         ot->idname= "OBJECT_OT_game_property_remove";
2059
2060         /* api callbacks */
2061         ot->exec= game_property_remove;
2062         ot->poll= ED_operator_object_active_editable;
2063
2064         /* flags */
2065         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2066
2067         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to remove ", 0, INT_MAX);
2068 }
2069
2070 #define COPY_PROPERTIES_REPLACE 1
2071 #define COPY_PROPERTIES_MERGE   2
2072 #define COPY_PROPERTIES_COPY    3
2073
2074 static EnumPropertyItem game_properties_copy_operations[] ={
2075         {COPY_PROPERTIES_REPLACE, "REPLACE", 0, "Replace Properties", ""},
2076         {COPY_PROPERTIES_MERGE, "MERGE", 0, "Merge Properties", ""},
2077         {COPY_PROPERTIES_COPY, "COPY", 0, "Copy a Property", ""},
2078         {0, NULL, 0, NULL, NULL}};
2079
2080 static EnumPropertyItem gameprops_items[]= {
2081         {0, NULL, 0, NULL, NULL}};
2082
2083 static EnumPropertyItem *gameprops_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
2084 {       
2085         Object *ob= ED_object_active_context(C);
2086         EnumPropertyItem tmp = {0, "", 0, "", ""};
2087         EnumPropertyItem *item= NULL;
2088         bProperty *prop;
2089         int a, totitem= 0;
2090         
2091         if(!ob)
2092                 return gameprops_items;
2093
2094         for(a=1, prop= ob->prop.first; prop; prop=prop->next, a++) {
2095                 tmp.value= a;
2096                 tmp.identifier= prop->name;
2097                 tmp.name= prop->name;
2098                 RNA_enum_item_add(&item, &totitem, &tmp);
2099         }
2100
2101         RNA_enum_item_end(&item, &totitem);
2102         *free= 1;
2103
2104         return item;
2105 }
2106
2107 static int game_property_copy_exec(bContext *C, wmOperator *op)
2108 {
2109         Object *ob=ED_object_active_context(C);
2110         bProperty *prop;
2111         int type = RNA_enum_get(op->ptr, "operation");
2112         int propid= RNA_enum_get(op->ptr, "property");
2113
2114         if(propid > 0) { /* copy */
2115                 prop = BLI_findlink(&ob->prop, propid-1);
2116                 
2117                 if(prop) {
2118                         CTX_DATA_BEGIN(C, Object*, ob_iter, selected_editable_objects) {
2119                                 if (ob != ob_iter) {
2120                                         if (ob->data != ob_iter->data)
2121                                                 set_ob_property(ob_iter, prop);
2122                                 }
2123                         } CTX_DATA_END;
2124                 }
2125         }
2126         else if (ELEM(type, COPY_PROPERTIES_REPLACE, COPY_PROPERTIES_MERGE)) {
2127                 CTX_DATA_BEGIN(C, Object*, ob_iter, selected_editable_objects) {
2128                         if (ob != ob_iter) {
2129                                 if (ob->data != ob_iter->data){
2130                                         if (type == 2) {/* merge */
2131                                                 for(prop = ob->prop.first; prop; prop= prop->next ) {
2132                                                         set_ob_property(ob_iter, prop);
2133                                                 }
2134                                         } else /* replace */
2135                                                 copy_properties( &ob_iter->prop, &ob->prop );
2136                                 }
2137                         }
2138                 }
2139                 CTX_DATA_END;
2140         }
2141
2142         return OPERATOR_FINISHED;
2143 }
2144
2145 void OBJECT_OT_game_property_copy(wmOperatorType *ot)
2146 {
2147         PropertyRNA *prop;
2148         /* identifiers */
2149         ot->name= "Copy Game Property";
2150         ot->idname= "OBJECT_OT_game_property_copy";
2151
2152         /* api callbacks */
2153         ot->exec= game_property_copy_exec;
2154         ot->poll= ED_operator_object_active_editable;
2155
2156         /* flags */
2157         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2158
2159         RNA_def_enum(ot->srna, "operation", game_properties_copy_operations, 3, "Operation", "");
2160         prop=RNA_def_enum(ot->srna, "property", gameprops_items, 0, "Property", "Properties to copy");
2161         RNA_def_enum_funcs(prop, gameprops_itemf);
2162         ot->prop=prop;
2163 }
2164
2165 static int game_property_clear_exec(bContext *C, wmOperator *UNUSED(op))
2166 {
2167         CTX_DATA_BEGIN(C, Object*, ob_iter, selected_editable_objects) {
2168                 free_properties(&ob_iter->prop);
2169         }
2170         CTX_DATA_END;
2171
2172         WM_event_add_notifier(C, NC_LOGIC, NULL);
2173         return OPERATOR_FINISHED;
2174 }
2175 void OBJECT_OT_game_property_clear(wmOperatorType *ot)
2176 {
2177         /* identifiers */
2178         ot->name= "Clear Game Property";
2179         ot->idname= "OBJECT_OT_game_property_clear";
2180
2181         /* api callbacks */
2182         ot->exec= game_property_clear_exec;
2183         ot->poll= ED_operator_object_active_editable;
2184
2185         /* flags */
2186         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2187 }
2188
2189 /************************ Copy Logic Bricks ***********************/
2190
2191 static int logicbricks_copy_exec(bContext *C, wmOperator *UNUSED(op))
2192 {
2193         Object *ob=ED_object_active_context(C);
2194
2195         CTX_DATA_BEGIN(C, Object*, ob_iter, selected_editable_objects) {
2196                 if(ob != ob_iter) {
2197                         /* first: free all logic */
2198                         free_sensors(&ob_iter->sensors);                                
2199                         unlink_controllers(&ob_iter->controllers);
2200                         free_controllers(&ob_iter->controllers);
2201                         unlink_actuators(&ob_iter->actuators);
2202                         free_actuators(&ob_iter->actuators);
2203                 
2204                         /* now copy it, this also works without logicbricks! */
2205                         clear_sca_new_poins_ob(ob);
2206                         copy_sensors(&ob_iter->sensors, &ob->sensors);
2207                         copy_controllers(&ob_iter->controllers, &ob->controllers);
2208                         copy_actuators(&ob_iter->actuators, &ob->actuators);
2209                         set_sca_new_poins_ob(ob_iter);
2210                 
2211                         /* some menu settings */
2212                         ob_iter->scavisflag= ob->scavisflag;
2213                         ob_iter->scaflag= ob->scaflag;
2214                 
2215                         /* set the initial state */
2216                         ob_iter->state= ob->state;
2217                         ob_iter->init_state= ob->init_state;
2218
2219                         if(ob_iter->totcol==ob->totcol) {
2220                                 ob_iter->actcol= ob->actcol;
2221                                 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob_iter);
2222                         }
2223                 }
2224         }
2225         CTX_DATA_END;
2226
2227         WM_event_add_notifier(C, NC_LOGIC, NULL);
2228
2229         return OPERATOR_FINISHED;
2230 }
2231
2232 void OBJECT_OT_logic_bricks_copy(wmOperatorType *ot)
2233 {
2234         /* identifiers */
2235         ot->name= "Copy Logic Bricks to Selected";
2236         ot->description = "Copy logic bricks to other selected objects.";
2237         ot->idname= "OBJECT_OT_logic_bricks_copy";
2238
2239         /* api callbacks */
2240         ot->exec= logicbricks_copy_exec;
2241         ot->poll= ED_operator_object_active_editable;
2242
2243         /* flags */
2244         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2245 }