2.5
authorTon Roosendaal <ton@blender.org>
Fri, 30 Jan 2009 15:01:14 +0000 (15:01 +0000)
committerTon Roosendaal <ton@blender.org>
Fri, 30 Jan 2009 15:01:14 +0000 (15:01 +0000)
Edit mesh: Separate options back. Use SHIFT+P for it, PKEY has been
stolen! :)

source/blender/editors/include/ED_object.h
source/blender/editors/mesh/editmesh.c
source/blender/editors/mesh/mesh_intern.h
source/blender/editors/mesh/mesh_ops.c
source/blender/editors/object/object_edit.c

index e0a6ed86695f936a3bda59344792b1745c5afd9a..8ff716476adf535a059c6784f686cd0ee48769f2 100644 (file)
@@ -40,6 +40,7 @@ struct Lattice;
 struct Mesh;
 struct Curve;
 
+/* object_edit.c */
 void ED_operatortypes_object(void);
 void ED_keymap_object(struct wmWindowManager *wm);
 
@@ -51,6 +52,8 @@ void ED_base_object_activate(struct bContext *C, struct Base *base);
 void ED_base_object_free_and_unlink(struct Scene *scene, struct Base *base);
 
 void ED_object_apply_obmat(struct Object *ob);
+       /* single object duplicate, if dupflag==0, fully linked, else it uses U.dupflag */
+Base *ED_object_add_duplicate(struct Scene *scene, struct Base *base, int usedupflag);
 
 
 /* bitflags for enter/exit editmode */
index f61d340808aa877503be4ae8cd2ece32d83cb6be..58041120a428b8a3fe424c1e243bc880ab476262 100644 (file)
 #include "ED_mesh.h"
 #include "ED_object.h"
 #include "ED_util.h"
+#include "ED_screen.h"
 #include "ED_view3d.h"
 
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
 /* own include */
 #include "mesh_intern.h"
 
@@ -94,7 +101,6 @@ editmesh.c:
 /* XXX */
 static void BIF_undo_push() {}
 static void error() {}
-static int pupmenu() {return 0;}
 
 
 /* ***************** HASH ********************* */
@@ -581,6 +587,7 @@ static void editMesh_set_hash(EditMesh *em)
 {
        EditEdge *eed;
 
+       if(em->hashedgetab) MEM_freeN(em->hashedgetab);
        em->hashedgetab= NULL;
        
        for(eed=em->edges.first; eed; eed= eed->next)  {
@@ -1424,353 +1431,199 @@ void remake_editMesh(Scene *scene, Object *ob)
        BIF_undo_push("Undo all changes");
 }
 
-/* ***************             (partial exit editmode) *************/
-
+/* *************** Operator: separate parts *************/
 
+static EnumPropertyItem prop_separate_types[] = {
+       {0, "SELECTED", "Selection", ""},
+       {1, "MATERIAL", "By Material", ""},
+       {2, "LOOSE", "By loose parts", ""},
+       {0, NULL, NULL, NULL}
+};
 
-
-void separate_mesh(Scene *scene, Object *obedit)
+/* return 1: success */
+static int mesh_separate_selected(Scene *scene, Base *editbase)
 {
-       EditMesh *em, emcopy;
+       EditMesh *em, *emnew;
        EditVert *eve, *v1;
        EditEdge *eed, *e1;
-       EditFace *efa, *vl1;
-       Object *oldob;
-       Mesh *me, *men;
-       Base *base, *oldbase;
-       ListBase edve, eded, edvl;
+       EditFace *efa, *f1;
+       Object *obedit;
+       Mesh *me, *menew;
+       Base *basenew;
        
-       if(obedit==NULL) return;
-
+       if(editbase==NULL) return 0;
+       
+       obedit= editbase->object;
        me= obedit->data;
        em= me->edit_mesh;
        if(me->key) {
                error("Can't separate with vertex keys");
-               return;
+               return 0;
        }
        
-       if(em->selected.first) BLI_freelistN(&(em->selected)); /* clear the selection order */
+       if(em->selected.first) 
+               BLI_freelistN(&(em->selected)); /* clear the selection order */
                
        EM_selectmode_set(em);  // enforce full consistant selection flags 
        
-       /* we are going to abuse the system as follows:
-        * 1. add a duplicate object: this will be the new one, we remember old pointer
-        * 2: then do a split if needed.
-        * 3. put apart: all NOT selected verts, edges, faces
-        * 4. call load_editMesh(): this will be the new object
-        * 5. freelist and get back old verts, edges, facs
+       EM_stats_update(em);
+       
+       if(em->totvertsel==0) return 0;
+       
+       /* we are going to work as follows:
+        * 1. add a linked duplicate object: this will be the new one, we remember old pointer
+        * 2. give new object empty mesh and put in editmode
+        * 3: do a split if needed on current editmesh.
+        * 4. copy over: all NOT selected verts, edges, faces
+        * 5. call load_editMesh() on the new object
         */
        
-       /* make only obedit selected */
-       base= FIRSTBASE;
-       while(base) {
-//     XXX     if(base->lay & G.vd->lay) {
-                       if(base->object==obedit) base->flag |= SELECT;
-                       else base->flag &= ~SELECT;
-//             }
-               base= base->next;
-       }
+       /* 1 */
+       basenew= ED_object_add_duplicate(scene, editbase, 0);   /* 0 = fully linked */
+       ED_base_object_select(basenew, BA_DESELECT);
+       
+       /* 2 */
+       basenew->object->data= menew= add_mesh(me->id.name);    /* empty */
+       me->id.us--;
+       make_editMesh(scene, basenew->object);
+       emnew= menew->edit_mesh;
        
-       /* no test for split, split doesn't split when a loose part is selected */
+       /* 3 */
        /* SPLIT: first make duplicate */
        adduplicateflag(em, SELECT);
-
        /* SPLIT: old faces have 3x flag 128 set, delete these ones */
        delfaceflag(em, 128);
-       
        /* since we do tricky things with verts/edges/faces, this makes sure all is selected coherent */
        EM_selectmode_set(em);
        
-       /* set apart: everything that is not selected */
-       edve.first= edve.last= eded.first= eded.last= edvl.first= edvl.last= 0;
-       eve= em->verts.first;
-       while(eve) {
+       /* 4 */
+       /* move over: everything that is selected */
+       for(eve= em->verts.first; eve; eve= v1) {
                v1= eve->next;
-               if((eve->f & SELECT)==0) {
+               if(eve->f & SELECT) {
                        BLI_remlink(&em->verts, eve);
-                       BLI_addtail(&edve, eve);
+                       BLI_addtail(&emnew->verts, eve);
                }
-               
-               eve= v1;
        }
-       eed= em->edges.first;
-       while(eed) {
+       
+       for(eed= em->edges.first; eed; eed= e1) {
                e1= eed->next;
-               if((eed->f & SELECT)==0) {
+               if(eed->f & SELECT) {
                        BLI_remlink(&em->edges, eed);
-                       BLI_addtail(&eded, eed);
+                       BLI_addtail(&emnew->edges, eed);
                }
-               eed= e1;
        }
-       efa= em->faces.first;
-       while(efa) {
-               vl1= efa->next;
+       
+       for(efa= em->faces.first; efa; efa= f1) {
+               f1= efa->next;
                if (efa == em->act_face && (efa->f & SELECT)) {
                        EM_set_actFace(em, NULL);
                }
 
-               if((efa->f & SELECT)==0) {
+               if(efa->f & SELECT) {
                        BLI_remlink(&em->faces, efa);
-                       BLI_addtail(&edvl, efa);
+                       BLI_addtail(&emnew->faces, efa);
                }
-               efa= vl1;
        }
+
+       /* 5 */
+       load_editMesh(scene, basenew->object);
+       free_editMesh(emnew);
        
-       oldob= obedit;
-       oldbase= BASACT;
-       
-// XXX adduplicate(1, 0); /* notrans and a linked duplicate */
-       
-       obedit= BASACT->object; /* basact was set in adduplicate()  */
-       
-       men= copy_mesh(me);
-       set_mesh(obedit, men);
-       /* because new mesh is a copy: reduce user count */
-       men->id.us--;
-       
-       load_editMesh(scene, obedit);
-       
-       BASACT->flag &= ~SELECT;
-       
-       /* we cannot free the original buffer... */
-       emcopy= *em;
-       emcopy.allverts= NULL;
-       emcopy.alledges= NULL;
-       emcopy.allfaces= NULL;
-       emcopy.derivedFinal= emcopy.derivedCage= NULL;
-       memset(&emcopy.vdata, 0, sizeof(emcopy.vdata));
-       memset(&emcopy.fdata, 0, sizeof(emcopy.fdata));
-       free_editMesh(&emcopy);
-       
-       em->verts= edve;
-       em->edges= eded;
-       em->faces= edvl;
-       
-       /* hashedges are freed now, make new! */
+       /* hashedges are invalid now, make new! */
        editMesh_set_hash(em);
 
        DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
-       obedit= oldob;
-       BASACT= oldbase;
-       BASACT->flag |= SELECT;
-       
-       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
+       DAG_object_flush_update(scene, basenew->object, OB_RECALC_DATA);        
 
+       return 1;
 }
 
-void separate_material(Scene *scene, Object *obedit)
+/* return 1: success */
+static int mesh_separate_material(Scene *scene, Base *editbase)
 {
-       Mesh *me;
-       EditMesh *em;
+       Mesh *me= editbase->object->data;
+       EditMesh *em= me->edit_mesh;
        unsigned char curr_mat;
        
-       me= obedit->data;
-       em= me->edit_mesh;
-       if(me->key) {
-               error("Can't separate with vertex keys");
-               return;
-       }
-       
-       if(obedit && em) {
-               if(obedit->type == OB_MESH) {
-                       for (curr_mat = 1; curr_mat < obedit->totcol; ++curr_mat) {
-                               /* clear selection, we're going to use that to select material group */
-                               EM_clear_flag_all(em, SELECT);
-                               /* select the material */
-                               editmesh_select_by_material(em, curr_mat);
-                               /* and now separate */
-                               separate_mesh(scene, obedit);
-                       }
-               }
+       for (curr_mat = 1; curr_mat < editbase->object->totcol; ++curr_mat) {
+               /* clear selection, we're going to use that to select material group */
+               EM_clear_flag_all(em, SELECT);
+               /* select the material */
+               editmesh_select_by_material(em, curr_mat);
+               /* and now separate */
+               if(0==mesh_separate_selected(scene, editbase))
+                       return 0;
        }
-       
-       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-       
+       return 1;
 }
 
-
-void separate_mesh_loose(Scene *scene, Object *obedit)
+/* return 1: success */
+static int mesh_separate_loose(Scene *scene, Base *editbase)
 {
-       EditMesh *em, emcopy;
-       EditVert *eve, *v1;
-       EditEdge *eed, *e1;
-       EditFace *efa, *vl1;
-       Object *oldob=NULL;
-       Mesh *me, *men;
-       Base *base, *oldbase;
-       ListBase edve, eded, edvl;
-       int vertsep=0;  
-       short done=0, check=1;
-                       
-       me= obedit->data;
+       Mesh *me;
+       EditMesh *em;
+       int doit= 1;
+       
+       me= editbase->object->data;
        em= me->edit_mesh;
+       
        if(me->key) {
-               error("Can't separate a mesh with vertex keys");
-               return;
+               error("Can't separate with vertex keys");
+               return 0;
        }
-
-       /* we are going to abuse the system as follows:
-        * 1. add a duplicate object: this will be the new one, we remember old pointer
-        * 2: then do a split if needed.
-        * 3. put apart: all NOT selected verts, edges, faces
-        * 4. call load_editMesh(): this will be the new object
-        * 5. freelist and get back old verts, edges, facs
-        */
-                       
-       while(!done){           
-               vertsep=check=1;
-               
-               /* make only obedit selected */
-               base= FIRSTBASE;
-               while(base) {
-//                     if(base->lay & G.vd->lay) {
-                               if(base->object==obedit) base->flag |= SELECT;
-                               else base->flag &= ~SELECT;
-//                     }
-                       base= base->next;
-               }               
-               
-               /*--------- Select connected-----------*/               
-               
-               EM_clear_flag_all(em, SELECT);
-
+       
+       EM_clear_flag_all(em, SELECT);
+       
+       while(doit && em->verts.first) {
                /* Select a random vert to start with */
-               eve= em->verts.first;
+               EditVert *eve= em->verts.first;
                eve->f |= SELECT;
                
-               while(check==1) {
-                       check= 0;                       
-                       eed= em->edges.first;                   
-                       while(eed) {                            
-                               if(eed->h==0) {
-                                       if(eed->v1->f & SELECT) {
-                                               if( (eed->v2->f & SELECT)==0 ) {
-                                                       eed->v2->f |= SELECT;
-                                                       vertsep++;
-                                                       check= 1;
-                                               }
-                                       }
-                                       else if(eed->v2->f & SELECT) {
-                                               if( (eed->v1->f & SELECT)==0 ) {
-                                                       eed->v1->f |= SELECT;
-                                                       vertsep++;
-                                                       check= SELECT;
-                                               }
-                                       }
-                               }
-                               eed= eed->next;                         
-                       }
-               }               
-               /*----------End of select connected--------*/
-               
+               selectconnected_mesh_all(em);
                
-               /* If the amount of vertices that is about to be split == the total amount 
-                  of verts in the mesh, it means that there is only 1 unconnected object, so we don't have to separate
-               */
-               if(em->totvert==vertsep) done=1;                                
-               else{                   
-                       /* No splitting: select connected goes fine */
-                       
-                       EM_select_flush(em);    // from verts->edges->faces
+               /* and now separate */
+               doit= mesh_separate_selected(scene, editbase);
+       }
+       return 1;
+}
 
-                       /* set apart: everything that is not selected */
-                       edve.first= edve.last= eded.first= eded.last= edvl.first= edvl.last= 0;
-                       eve= em->verts.first;
-                       while(eve) {
-                               v1= eve->next;
-                               if((eve->f & SELECT)==0) {
-                                       BLI_remlink(&em->verts, eve);
-                                       BLI_addtail(&edve, eve);
-                               }
-                               eve= v1;
-                       }
-                       eed= em->edges.first;
-                       while(eed) {
-                               e1= eed->next;
-                               if( (eed->f & SELECT)==0 ) {
-                                       BLI_remlink(&em->edges, eed);
-                                       BLI_addtail(&eded, eed);
-                               }
-                               eed= e1;
-                       }
-                       efa= em->faces.first;
-                       while(efa) {
-                               vl1= efa->next;
-                               if( (efa->f & SELECT)==0 ) {
-                                       BLI_remlink(&em->faces, efa);
-                                       BLI_addtail(&edvl, efa);
-                               }
-                               efa= vl1;
-                       }
-                       
-                       oldob= obedit;
-                       oldbase= BASACT;
-                       
-// XXX                 adduplicate(1, 0); /* notrans and a linked duplicate*/
-                       
-                       obedit= BASACT->object; /* basact was set in adduplicate()  */
 
-                       men= copy_mesh(me);
-                       set_mesh(obedit, men);
-                       /* because new mesh is a copy: reduce user count */
-                       men->id.us--;
-                       
-                       load_editMesh(scene, obedit);
-                       
-                       BASACT->flag &= ~SELECT;
-                       
-                       /* we cannot free the original buffer... */
-                       emcopy= *em;
-                       emcopy.allverts= NULL;
-                       emcopy.alledges= NULL;
-                       emcopy.allfaces= NULL;
-                       emcopy.derivedFinal= emcopy.derivedCage= NULL;
-                       memset(&emcopy.vdata, 0, sizeof(emcopy.vdata));
-                       memset(&emcopy.fdata, 0, sizeof(emcopy.fdata));
-                       free_editMesh(&emcopy);
-                       
-                       em->verts= edve;
-                       em->edges= eded;
-                       em->faces= edvl;
-                       
-                       /* hashedges are freed now, make new! */
-                       editMesh_set_hash(em);
-                       
-                       obedit= oldob;
-                       BASACT= oldbase;
-                       BASACT->flag |= SELECT; 
-                                       
-               }               
+static int mesh_separate_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Base *base= CTX_data_active_base(C);
+       int retval= 0;
+       
+       if(RNA_enum_is_equal(op->ptr, "type", "SELECTED"))
+               retval= mesh_separate_selected(scene, base);
+       else if(RNA_enum_is_equal(op->ptr, "type", "MATERIAL"))
+               retval= mesh_separate_material (scene, base);
+       else if(RNA_enum_is_equal(op->ptr, "type", "LOOSE"))
+               retval= mesh_separate_loose(scene, base);
+          
+       if(retval) {
+               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, base->object);
+               return OPERATOR_FINISHED;
        }
-       
-       /* unselect the vertices that we (ab)used for the separation*/
-       EM_clear_flag_all(em, SELECT);
-               
-       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
+       return OPERATOR_CANCELLED;
 }
 
-void separatemenu(Scene *scene, Object *obedit)
+void MESH_OT_separate(wmOperatorType *ot)
 {
-       Mesh *me= obedit->data;
-       short event;
+       /* identifiers */
+       ot->name= "Mesh Separate";
+       ot->idname= "MESH_OT_separate";
        
-       if(me->edit_mesh->verts.first==NULL) return;
-          
-       event = pupmenu("Separate %t|Selected%x1|All Loose Parts%x2|By Material%x3");
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
+       ot->exec= mesh_separate_exec;
+       ot->poll= ED_operator_editmesh;
        
-       if (event==0) return;
+       /* flags */
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
        
-       switch (event) {
-               case 1: 
-                       separate_mesh(scene, obedit);
-                       break;
-               case 2:                     
-                       separate_mesh_loose(scene, obedit);
-                       break;
-               case 3:
-                       separate_material(scene, obedit);
-                       break;
-       }
+       RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
 }
 
 
index dae2feb388b27a44d32d25370f915e2bd82121e7..a6d899e245185024cc44b9f35402025da15529de 100644 (file)
@@ -93,6 +93,8 @@ int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed);
 
 void em_setup_viewcontext(struct bContext *C, ViewContext *vc);
 
+void MESH_OT_separate(struct wmOperatorType *ot);
+
 /* ******************* editmesh_add.c */
 void MESH_OT_add_primitive_plane(struct wmOperatorType *ot);
 void MESH_OT_add_primitive_cube(struct wmOperatorType *ot);
@@ -185,6 +187,7 @@ extern void EM_automerge(int update);
 void editmesh_select_by_material(EditMesh *em, int index);
 void righthandfaces(EditMesh *em, int select); /* makes faces righthand turning */
 void EM_select_more(EditMesh *em);
+void selectconnected_mesh_all(EditMesh *em);
 
 /**
  * findnearestvert
index 80839ea12e263a7602c889cad19329a7108ab015..892db9e4dbce890b6a814b62b8edeb5c7a03ca58 100644 (file)
@@ -137,6 +137,7 @@ void ED_operatortypes_mesh(void)
        WM_operatortype_append(MESH_OT_removedoublesflag);
        WM_operatortype_append(MESH_OT_extrude_mesh);
        WM_operatortype_append(MESH_OT_edit_faces);
+       WM_operatortype_append(MESH_OT_separate);
        
 }
 
@@ -179,5 +180,8 @@ void ED_keymap_mesh(wmWindowManager *wm)
        /* add */
        WM_keymap_add_item(keymap, "MESH_OT_add_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
        WM_keymap_add_item(keymap, "OBJECT_OT_mesh_add", AKEY, KM_PRESS, KM_SHIFT, 0);
+       WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, KM_SHIFT, 0);
+       
+       
 }
 
index 6bf8cde79425add9e9a0cadf583452608464e3f1..9d997b5498291dc8cfe8b5cc9728fed5d3fc09a9 100644 (file)
@@ -610,7 +610,7 @@ static void copy_object_set_idnew(Scene *scene, View3D *v3d, int dupflag)
 #endif // XXX old animation system
        int a;
        
-       /* check object pointers */
+       /* XXX check object pointers */
        for(base= FIRSTBASE; base; base= base->next) {
                if(TESTBASELIB(v3d, base)) {
                        ob= base->object;
@@ -5758,95 +5758,85 @@ void make_local_menu(Scene *scene, View3D *v3d)
        U.dupflag for default operations or you can construct a flag as python does
        if the dupflag is 0 then no data will be copied (linked duplicate) */
 
-static int add_duplicate_exec(bContext *C, wmOperator *op)
+/* used below, assumes id.new is correct */
+/* leaves selection of base/object unaltered */
+static Base *object_add_duplicate_internal(Scene *scene, Base *base, int dupflag)
 {
-       Scene *scene= CTX_data_scene(C);
-       View3D *v3d= CTX_wm_view3d(C);
-       Base *basen;
+       Base *basen= NULL;
        Material ***matarar;
        Object *ob, *obn;
        ID *id;
-       int dupflag= U.dupflag;
        int a, didit;
-       
-       clear_id_newpoins();
-       clear_sca_new_poins();  /* sensor/contr/act */
-       
-       CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
+
+       ob= base->object;
+       if(ob->flag & OB_POSEMODE) {
+               ; /* nothing? */
+       }
+       else {
+               obn= copy_object(ob);
+               obn->recalc |= OB_RECALC;
                
-               ob= base->object;
-               if(ob->flag & OB_POSEMODE) {
-                       ; /* nothing? */
+               basen= MEM_mallocN(sizeof(Base), "duplibase");
+               *basen= *base;
+               BLI_addhead(&scene->base, basen);       /* addhead: prevent eternal loop */
+               basen->object= obn;
+               
+               if(basen->flag & OB_FROMGROUP) {
+                       Group *group;
+                       for(group= G.main->group.first; group; group= group->id.next) {
+                               if(object_in_group(ob, group))
+                                       add_to_group(group, obn);
+                       }
+                       obn->flag |= OB_FROMGROUP; /* this flag is unset with copy_object() */
                }
-               else {
-                       obn= copy_object(ob);
-                       obn->recalc |= OB_RECALC;
-                       
-                       basen= MEM_mallocN(sizeof(Base), "duplibase");
-                       *basen= *base;
-                       BLI_addhead(&scene->base, basen);       /* addhead: prevent eternal loop */
-                       basen->object= obn;
-                       base->flag &= ~SELECT;
+               
+               /* duplicates using userflags */
+#if 0 // XXX old animation system                              
+               if(dupflag & USER_DUP_IPO) {
+                       bConstraintChannel *chan;
+                       id= (ID *)obn->ipo;
                        
-                       if(basen->flag & OB_FROMGROUP) {
-                               Group *group;
-                               for(group= G.main->group.first; group; group= group->id.next) {
-                                       if(object_in_group(ob, group))
-                                               add_to_group(group, obn);
-                               }
-                               obn->flag |= OB_FROMGROUP; /* this flag is unset with copy_object() */
+                       if(id) {
+                               ID_NEW_US( obn->ipo)
+                               else obn->ipo= copy_ipo(obn->ipo);
+                               id->us--;
                        }
-                       
-                       if(BASACT==base)
-                               ED_base_object_activate(C, basen);
-
-                       /* duplicates using userflags */
-#if 0 // XXX old animation system                              
-                       if(dupflag & USER_DUP_IPO) {
-                               bConstraintChannel *chan;
-                               id= (ID *)obn->ipo;
-                               
+                       /* Handle constraint ipos */
+                       for (chan=obn->constraintChannels.first; chan; chan=chan->next){
+                               id= (ID *)chan->ipo;
                                if(id) {
-                                       ID_NEW_US( obn->ipo)
-                                       else obn->ipo= copy_ipo(obn->ipo);
+                                       ID_NEW_US( chan->ipo)
+                                       else chan->ipo= copy_ipo(chan->ipo);
                                        id->us--;
                                }
-                               /* Handle constraint ipos */
-                               for (chan=obn->constraintChannels.first; chan; chan=chan->next){
-                                       id= (ID *)chan->ipo;
-                                       if(id) {
-                                               ID_NEW_US( chan->ipo)
-                                               else chan->ipo= copy_ipo(chan->ipo);
-                                               id->us--;
-                                       }
-                               }
                        }
-                       if(dupflag & USER_DUP_ACT){ /* Not buttons in the UI to modify this, add later? */
-                               id= (ID *)obn->action;
-                               if (id){
-                                       ID_NEW_US(obn->action)
-                                       else{
-                                               obn->action= copy_action(obn->action);
-                                       }
-                                       id->us--;
+               }
+               if(dupflag & USER_DUP_ACT){ /* Not buttons in the UI to modify this, add later? */
+                       id= (ID *)obn->action;
+                       if (id){
+                               ID_NEW_US(obn->action)
+                               else{
+                                       obn->action= copy_action(obn->action);
                                }
+                               id->us--;
                        }
+               }
 #endif // XXX old animation system
-                       if(dupflag & USER_DUP_MAT) {
-                               for(a=0; a<obn->totcol; a++) {
-                                       id= (ID *)obn->mat[a];
-                                       if(id) {
-                                               ID_NEW_US(obn->mat[a])
-                                               else obn->mat[a]= copy_material(obn->mat[a]);
-                                               id->us--;
-                                       }
+               if(dupflag & USER_DUP_MAT) {
+                       for(a=0; a<obn->totcol; a++) {
+                               id= (ID *)obn->mat[a];
+                               if(id) {
+                                       ID_NEW_US(obn->mat[a])
+                                       else obn->mat[a]= copy_material(obn->mat[a]);
+                                       id->us--;
                                }
                        }
-                       
-                       id= obn->data;
-                       didit= 0;
-                       
-                       switch(obn->type) {
+               }
+               
+               id= obn->data;
+               didit= 0;
+               
+               switch(obn->type) {
                        case OB_MESH:
                                if(dupflag & USER_DUP_MESH) {
                                        ID_NEW_US2( obn->data )
@@ -5854,7 +5844,7 @@ static int add_duplicate_exec(bContext *C, wmOperator *op)
                                                obn->data= copy_mesh(obn->data);
                                                
                                                if(obn->fluidsimSettings) {
-                                               obn->fluidsimSettings->orgMesh = (Mesh *)obn->data;
+                                                       obn->fluidsimSettings->orgMesh = (Mesh *)obn->data;
                                                }
                                                
                                                didit= 1;
@@ -5909,22 +5899,22 @@ static int add_duplicate_exec(bContext *C, wmOperator *op)
                                        id->us--;
                                }
                                break;
-
+                               
                        case OB_ARMATURE:
                                obn->recalc |= OB_RECALC_DATA;
                                if(obn->pose) obn->pose->flag |= POSE_RECALC;
-                               
-                               if(dupflag & USER_DUP_ARM) {
-                                       ID_NEW_US2(obn->data )
-                                       else {
-                                               obn->data= copy_armature(obn->data);
-                                               armature_rebuild_pose(obn, obn->data);
-                                               didit= 1;
+                                       
+                                       if(dupflag & USER_DUP_ARM) {
+                                               ID_NEW_US2(obn->data )
+                                               else {
+                                                       obn->data= copy_armature(obn->data);
+                                                       armature_rebuild_pose(obn, obn->data);
+                                                       didit= 1;
+                                               }
+                                               id->us--;
                                        }
-                                       id->us--;
-                               }
-                               
-                               break;
+                                               
+                                               break;
                                
                        case OB_LATTICE:
                                if(dupflag!=0) {
@@ -5940,26 +5930,66 @@ static int add_duplicate_exec(bContext *C, wmOperator *op)
                                        id->us--;
                                }
                                break;
-                       }
-                       
-                       if(dupflag & USER_DUP_MAT) {
-                               matarar= give_matarar(obn);
-                               if(didit && matarar) {
-                                       for(a=0; a<obn->totcol; a++) {
-                                               id= (ID *)(*matarar)[a];
-                                               if(id) {
-                                                       ID_NEW_US( (*matarar)[a] )
-                                                       else (*matarar)[a]= copy_material((*matarar)[a]);
-                                                       
-                                                       id->us--;
-                                               }
+               }
+               
+               if(dupflag & USER_DUP_MAT) {
+                       matarar= give_matarar(obn);
+                       if(didit && matarar) {
+                               for(a=0; a<obn->totcol; a++) {
+                                       id= (ID *)(*matarar)[a];
+                                       if(id) {
+                                               ID_NEW_US( (*matarar)[a] )
+                                               else (*matarar)[a]= copy_material((*matarar)[a]);
+                                               
+                                               id->us--;
                                        }
                                }
                        }
                }
        }
+       return basen;
+}
+
+/* single object duplicate, if dupflag==0, fully linked, else it uses U.dupflag */
+/* leaves selection of base/object unaltered */
+Base *ED_object_add_duplicate(Scene *scene, Base *base, int usedupflag)
+{
+       Base *basen;
+       int dupflag= usedupflag?U.dupflag:0;
+
+       clear_id_newpoins();
+       clear_sca_new_poins();  /* sensor/contr/act */
+       
+       basen= object_add_duplicate_internal(scene, base, dupflag);
+       
+       DAG_scene_sort(scene);
+       
+       return basen;
+}
+
+/* contextual operator dupli */
+static int add_duplicate_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       View3D *v3d= CTX_wm_view3d(C);
+       int dupflag= U.dupflag;
+       
+       clear_id_newpoins();
+       clear_sca_new_poins();  /* sensor/contr/act */
+       
+       CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
+               Base *basen= object_add_duplicate_internal(scene, base, dupflag);
+               
+               /* XXX context conflict maybe, itterator could solve this? */
+               ED_base_object_select(base, BA_DESELECT);
+               /* new object becomes active */
+               if(BASACT==base)
+                       ED_base_object_activate(C, basen);
+               
+       }
        CTX_DATA_END;
 
+       /* XXX fix this for context */
        copy_object_set_idnew(scene, v3d, dupflag);
 
        DAG_scene_sort(scene);