RNA
[blender.git] / source / blender / editors / armature / editarmature.c
index 964f0031be95d6f959566fdff09aa9aecf83d4fa..7155bdd6850b3940f912c3dfb349da6165ddaf92 100644 (file)
@@ -33,8 +33,6 @@
 
 #include "MEM_guardedalloc.h"
 
-#include "BMF_Api.h"
-
 #include "DNA_action_types.h"
 #include "DNA_armature_types.h"
 #include "DNA_constraint_types.h"
 #include "BKE_global.h"
 #include "BKE_main.h"
 #include "BKE_object.h"
+#include "BKE_report.h"
 #include "BKE_subsurf.h"
 #include "BKE_utildefines.h"
 #include "BKE_modifier.h"
 #include "PIL_time.h"
 
 #include "BIF_gl.h"
+#include "BIF_transform.h"
+#include "BIF_generate.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
 
 #include "ED_armature.h"
 #include "ED_mesh.h"
 #include "ED_object.h"
+#include "ED_screen.h"
 #include "ED_util.h"
 #include "ED_view3d.h"
 
+#include "UI_interface.h"
+
 #include "armature_intern.h"
 #include "meshlaplacian.h"
 
@@ -95,20 +105,30 @@ static void error() {};
 static void error_libdata() {}
 static void BIF_undo_push() {}
 static void adduplicate() {}
-static void countall() {}
-static void vertexgroup_select_by_name() {}
-static void deselect_actionchannels() {}
-static void *add_defgroup_name() {return NULL;}
-static void add_vert_to_defgroup() {}
-#define WEIGHT_REPLACE 0
-static void create_dverts() {}
-static void remove_vert_defgroup() {}
-static int mesh_get_x_mirror_vert() {return 0;}
-static void select_actionchannel_by_name() {}
 /* ************* XXX *************** */
 
 /* **************** tools on Editmode Armature **************** */
 
+/* Sync selection to parent for connected children */
+static void armature_sync_selection(ListBase *edbo)
+{
+       EditBone *ebo;
+       
+       for (ebo=edbo->first; ebo; ebo= ebo->next) {
+               if ((ebo->flag & BONE_CONNECTED) && (ebo->parent)) {
+                       if (ebo->parent->flag & BONE_TIPSEL)
+                               ebo->flag |= BONE_ROOTSEL;
+                       else
+                               ebo->flag &= ~BONE_ROOTSEL;
+               }
+               
+               if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL))
+                       ebo->flag |= BONE_SELECTED;
+               else
+                       ebo->flag &= ~BONE_SELECTED;
+       }                               
+}
+
 /* converts Bones to EditBone list, used for tools as well */
 void make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent)
 {
@@ -142,18 +162,18 @@ void make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent)
                VECCOPY(eBone->head, curBone->arm_head);
                VECCOPY(eBone->tail, curBone->arm_tail);                
                
-               eBone->roll= 0.0;
+               eBone->roll= 0.0f;
                
                /* roll fixing */
                VecSubf(delta, eBone->tail, eBone->head);
-               vec_roll_to_mat3(delta, 0.0, postmat);
+               vec_roll_to_mat3(delta, 0.0f, postmat);
                
                Mat3CpyMat4(premat, curBone->arm_mat);
                
                Mat3Inv(imat, postmat);
                Mat3MulMat3(difmat, imat, premat);
                
-               eBone->roll = atan2(difmat[2][0], difmat[2][2]);
+               eBone->roll = (float)atan2(difmat[2][0], difmat[2][2]);
                
                /* rest of stuff copy */
                eBone->length= curBone->length;
@@ -214,7 +234,7 @@ static void fix_bonelist_roll (ListBase *bonelist, ListBase *editbonelist)
                        printmatrix4("difmat", difmat);
                        printf ("Roll = %f\n",  (-atan2(difmat[2][0], difmat[2][2]) * (180.0/M_PI)));
 #endif
-                       curBone->roll = -atan2(difmat[2][0], difmat[2][2]);
+                       curBone->roll = (float)-atan2(difmat[2][0], difmat[2][2]);
                        
                        /* and set restposition again */
                        where_is_armature_bone(curBone, curBone->parent);
@@ -383,13 +403,13 @@ void docenter_armature (Scene *scene, View3D *v3d, Object *ob, int centermode)
                        DO_MINMAX(ebone->tail, min, max);
                }
                
-               cent[0]= (min[0]+max[0])/2.0f;
-               cent[1]= (min[1]+max[1])/2.0f;
-               cent[2]= (min[2]+max[2])/2.0f;
+               cent[0]= (min[0] + max[0]) / 2.0f;
+               cent[1]= (min[1] + max[1]) / 2.0f;
+               cent[2]= (min[2] + max[2]) / 2.0f;
        }
        
        /* Do the adjustments */
-       for (ebone= arm->edbo->first; ebone; ebone=ebone->next){
+       for (ebone= arm->edbo->first; ebone; ebone=ebone->next) {
                VecSubf(ebone->head, ebone->head, cent);
                VecSubf(ebone->tail, ebone->tail, cent);
        }
@@ -402,9 +422,9 @@ void docenter_armature (Scene *scene, View3D *v3d, Object *ob, int centermode)
                Mat3CpyMat4(omat, ob->obmat);
                
                Mat3MulVecfl(omat, cent);
-               ob->loc[0]+= cent[0];
-               ob->loc[1]+= cent[1];
-               ob->loc[2]+= cent[2];
+               ob->loc[0] += cent[0];
+               ob->loc[1] += cent[1];
+               ob->loc[2] += cent[2];
        }
        else 
                ED_armature_edit_free(ob);
@@ -442,13 +462,16 @@ static EditBone *editbone_name_exists (ListBase *edbo, char *name)
 }
 
 /* note: there's a unique_bone_name() too! */
-void unique_editbone_name (ListBase *edbo, char *name)
+void unique_editbone_name (ListBase *edbo, char *name, EditBone *bone)
 {
+       EditBone *dupli;
        char            tempname[64];
        int                     number;
        char            *dot;
+
+       dupli = editbone_name_exists(edbo, name);
        
-       if (editbone_name_exists(edbo, name)) {
+       if (dupli && bone != dupli) {
                /*      Strip off the suffix, if it's a number */
                number= strlen(name);
                if (number && isdigit(name[number-1])) {
@@ -457,7 +480,7 @@ void unique_editbone_name (ListBase *edbo, char *name)
                                *dot=0;
                }
                
-               for (number = 1; number <=999; number++) {
+               for (number = 1; number <= 999; number++) {
                        sprintf(tempname, "%s.%03d", name, number);
                        if (!editbone_name_exists(edbo, tempname)) {
                                BLI_strncpy(name, tempname, 32);
@@ -584,7 +607,7 @@ static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChann
                                        
                                        /* action constraint? */
                                        if (con->type == CONSTRAINT_TYPE_ACTION) {
-                                               bActionConstraint *data= con->data;
+                                               bActionConstraint *data= con->data; // XXX old animation system
                                                bAction *act;
                                                bActionChannel *achan;
                                                
@@ -658,7 +681,7 @@ int join_armature(Scene *scene, View3D *v3d)
        
        /*      Ensure we're not in editmode and that the active object is an armature*/
        if (ob->type!=OB_ARMATURE) return 0;
-       if(arm->edbo) return 0;
+       if (arm->edbo) return 0;
        
        if (object_data_is_libdata(ob)) {
                error_libdata();
@@ -696,7 +719,7 @@ int join_armature(Scene *scene, View3D *v3d)
                                        curbone= editbone_name_exists(curarm->edbo, pchan->name);
                                        
                                        /* Get new name */
-                                       unique_editbone_name(arm->edbo, curbone->name);
+                                       unique_editbone_name(arm->edbo, curbone->name, NULL);
                                        
                                        /* Transform the bone */
                                        {
@@ -711,6 +734,7 @@ int join_armature(Scene *scene, View3D *v3d)
                                                VecSubf(delta, curbone->tail, curbone->head);
                                                vec_roll_to_mat3(delta, curbone->roll, temp);
                                                
+                                               Mat4One(premat); /* Mat4MulMat34 only sets 3x3 part */
                                                Mat4MulMat34(premat, temp, mat);
                                                
                                                Mat4MulVecfl(mat, curbone->head);
@@ -725,14 +749,14 @@ int join_armature(Scene *scene, View3D *v3d)
                                                Mat4Invert(imat, premat);
                                                Mat4MulMat4(difmat, postmat, imat);
                                                
-                                               curbone->roll -= atan2(difmat[2][0], difmat[2][2]);
+                                               curbone->roll -= (float)atan2(difmat[2][0], difmat[2][2]);
                                        }
                                        
                                        /* Fix Constraints and Other Links to this Bone and Armature */
                                        joined_armature_fix_links(ob, base->object, pchan, curbone);
                                        
                                        /* Rename pchan */
-                                       sprintf(pchan->name, curbone->name);
+                                       BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name));
                                        
                                        /* Jump Ship! */
                                        BLI_remlink(curarm->edbo, curbone);
@@ -1021,8 +1045,6 @@ void separate_armature (Scene *scene, View3D *v3d)
        
        /* recalc/redraw + cleanup */
        waitcursor(0);
-
-       countall(); // flush!
        
        BIF_undo_push("Separate Armature");
 }
@@ -1119,25 +1141,25 @@ static void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *
 
 /* used by posemode as well editmode */
 /* only checks scene->basact! */
-static void *get_nearest_bone (Scene *scene, short findunsel)
+/* x and y are mouse coords (area space) */
+static void *get_nearest_bone (bContext *C, short findunsel, int x, int y)
 {
        ViewContext vc;
        rcti rect;
        unsigned int buffer[MAXPICKBUF];
        short hits;
        
-       memset(&vc, 0, sizeof(ViewContext));
-       vc.scene= scene;
-       vc.obedit= scene->obedit;
-       // XXX fill in further!
+       view3d_set_viewcontext(C, &vc);
        
        // rect.xmin= ... mouseco!
+       rect.xmin= rect.xmax= x;
+       rect.ymin= rect.ymax= y;
        
        glInitNames();
        hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
 
        if (hits>0)
-               return get_bone_from_selectbuffer(scene, scene->basact, buffer, hits, findunsel);
+               return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel);
        
        return NULL;
 }
@@ -1154,7 +1176,6 @@ static void bone_setflag (int *bone, int flag, short mode)
                                *bone &= ~flag;
                        else
                                *bone ^= flag;
-
                }
                else {
                        if (mode == 2)
@@ -1186,60 +1207,6 @@ static EditBone *editbone_get_child(bArmature *arm, EditBone *pabone, short use_
        return chbone;
 }
 
-void armature_select_hierarchy(Scene *scene, short direction, short add_to_sel)
-{
-       Object *obedit= scene->obedit; // XXX get from context
-       Object *ob;
-       bArmature *arm;
-       EditBone *curbone, *pabone, *chbone;
-
-       if (!obedit) return;
-       else ob= obedit;
-       arm= (bArmature *)ob->data;
-       
-       for (curbone= arm->edbo->first; curbone; curbone= curbone->next) {
-               if (EBONE_VISIBLE(arm, curbone)) {
-                       if (curbone->flag & (BONE_ACTIVE)) {
-                               if (direction == BONE_SELECT_PARENT) {
-                                       if (curbone->parent == NULL) continue;
-                                       else pabone = curbone->parent;
-                                       
-                                       if (EBONE_VISIBLE(arm, pabone)) {
-                                               pabone->flag |= (BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
-                                               if (pabone->parent)     pabone->parent->flag |= BONE_TIPSEL;
-                                               
-                                               if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
-                                               curbone->flag &= ~BONE_ACTIVE;
-                                               break;
-                                       }
-                                       
-                               } 
-                               else { // BONE_SELECT_CHILD
-                                       chbone = editbone_get_child(arm, curbone, 1);
-                                       if (chbone == NULL) continue;
-                                       
-                                       if (EBONE_VISIBLE(arm, chbone)) {
-                                               chbone->flag |= (BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
-                                               
-                                               if (!add_to_sel) {
-                                                       curbone->flag &= ~(BONE_SELECTED|BONE_ROOTSEL);
-                                                       if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
-                                               }
-                                               curbone->flag &= ~BONE_ACTIVE;
-                                               break;
-                                       }
-                               }
-                       }
-               }
-       }
-
-       countall(); // flushes selection!
-       
-       if (direction==BONE_SELECT_PARENT)
-               BIF_undo_push("Select edit bone parent");
-       if (direction==BONE_SELECT_CHILD)
-               BIF_undo_push("Select edit bone child");
-}
 
 /* used by posemode and editmode */
 void setflag_armature (Scene *scene, short mode)
@@ -1318,7 +1285,8 @@ static void selectconnected_posebonechildren (Object *ob, Bone *bone)
        if (!(bone->flag & BONE_CONNECTED))
                return;
        
-       select_actionchannel_by_name (ob->action, bone->name, !(shift));
+               // XXX old cruft! use notifiers instead
+       //select_actionchannel_by_name (ob->action, bone->name, !(shift));
        
        if (shift)
                bone->flag &= ~BONE_SELECTED;
@@ -1331,25 +1299,34 @@ static void selectconnected_posebonechildren (Object *ob, Bone *bone)
 }
 
 /* within active object context */
-void selectconnected_posearmature(Scene *scene)
-{
-       Bone *bone, *curBone, *next;
-       Object *ob= OBACT;
-       int shift= 0; // XXX
-       
-       if(!ob || !ob->pose) return;
+/* previously known as "selectconnected_posearmature" */
+static int pose_select_connected_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{  
+       Bone *bone, *curBone, *next= NULL;
+       int shift= 0; // XXX in pose mode, Shift+L is bound to another command
+                                 // named "PoseLib Add Current Pose"
+       int x, y;
+       ARegion *ar;
+       Object *ob= CTX_data_edit_object(C);
+       ar= CTX_wm_region(C);
+
+       x= event->x - ar->winrct.xmin;
+       y= event->y - ar->winrct.ymin;
+
+       view3d_operator_needs_opengl(C);
        
        if (shift)
-               bone= get_nearest_bone(scene, 0);
+               bone= get_nearest_bone(C, 0, x, y);
        else
-               bone = get_nearest_bone(scene, 1);
+               bone= get_nearest_bone(C, 1, x, y);
        
        if (!bone)
-               return;
+               return OPERATOR_CANCELLED;
        
        /* Select parents */
        for (curBone=bone; curBone; curBone=next){
-               select_actionchannel_by_name (ob->action, curBone->name, !(shift));
+                       // XXX old cruft! use notifiers instead
+               //select_actionchannel_by_name (ob->action, curBone->name, !(shift));
                if (shift)
                        curBone->flag &= ~BONE_SELECTED;
                else
@@ -1366,29 +1343,58 @@ void selectconnected_posearmature(Scene *scene)
                selectconnected_posebonechildren (ob, curBone);
        }
        
-       countall(); // flushes selection!
+       // XXX this only counted the number of pose channels selected
+       //countall(); // flushes selection!
+       WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob);
 
-       BIF_undo_push("Select connected");
+       return OPERATOR_FINISHED;
+}
 
+void POSE_OT_select_linked(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select Connected";
+       ot->idname= "POSE_OT_select_linked";
+       
+       /* api callbacks */
+       ot->exec= NULL;
+       ot->invoke= pose_select_connected_invoke;
+       ot->poll= ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */     
 }
 
 /* **************** END Posemode stuff ********************** */
 /* **************** EditMode stuff ********************** */
 
 /* called in space.c */
-void selectconnected_armature(Scene *scene, View3D *v3d, Object *obedit)
+/* previously "selectconnected_armature" */
+static int armature_select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
-       bArmature *arm= obedit->data;
+       bArmature *arm;
        EditBone *bone, *curBone, *next;
        int shift= 0; // XXX
+       int x, y;
+       ARegion *ar;
+       Object *obedit= CTX_data_edit_object(C);
+       arm= obedit->data;
+       ar= CTX_wm_region(C);
+
+       x= event->x - ar->winrct.xmin;
+       y= event->y - ar->winrct.ymin;
+
+       view3d_operator_needs_opengl(C);
 
        if (shift)
-               bone= get_nearest_bone(scene, 0);
+               bone= get_nearest_bone(C, 0, x, y);
        else
-               bone= get_nearest_bone(scene, 1);
+               bone= get_nearest_bone(C, 1, x, y);
 
        if (!bone)
-               return;
+               return OPERATOR_CANCELLED;
 
        /* Select parents */
        for (curBone=bone; curBone; curBone=next){
@@ -1429,17 +1435,36 @@ void selectconnected_armature(Scene *scene, View3D *v3d, Object *obedit)
 
        }
 
-       countall(); // flushes selection!
+       armature_sync_selection(arm->edbo);
+
+       /* BIF_undo_push("Select connected"); */
+
+       WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, obedit);
 
-       BIF_undo_push("Select connected");
+       return OPERATOR_FINISHED;
+}
 
+void ARMATURE_OT_select_linked(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select Connected";
+       ot->idname= "ARMATURE_OT_select_linked";
+       
+       /* api callbacks */
+       ot->exec= NULL;
+       ot->invoke= armature_select_linked_invoke;
+       ot->poll= ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */     
 }
 
 /* does bones and points */
 /* note that BONE ROOT only gets drawn for root bones (or without IK) */
-static EditBone * get_nearest_editbonepoint (Scene *scene, Object *obedit, ListBase *edbo, int findunsel, int *selmask)
+static EditBone *get_nearest_editbonepoint (ViewContext *vc, short mval[2], ListBase *edbo, int findunsel, int *selmask)
 {
-       ViewContext vc;
        EditBone *ebone;
        rcti rect;
        unsigned int buffer[MAXPICKBUF];
@@ -1447,20 +1472,21 @@ static EditBone * get_nearest_editbonepoint (Scene *scene, Object *obedit, ListB
        int i, mindep= 4;
        short hits;
 
-       memset(&vc, 0, sizeof(ViewContext));
-       vc.scene= scene;
-       vc.obedit= scene->obedit;
-       
        glInitNames();
        
-//     getmouseco_areawin(mval);
-       // fill in rect! +- 5 
+       rect.xmin= mval[0]-5;
+       rect.xmax= mval[0]+5;
+       rect.ymin= mval[1]-5;
+       rect.ymax= mval[1]+5;
        
-       hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
-       if(hits==0)
-               // rect +- 12
-               hits= view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
-               
+       hits= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
+       if(hits==0) {
+               rect.xmin= mval[0]-12;
+               rect.xmax= mval[0]+12;
+               rect.ymin= mval[1]-12;
+               rect.ymax= mval[1]+12;
+               hits= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
+       }
        /* See if there are any selected bones in this group */
        if (hits>0) {
                
@@ -1541,11 +1567,14 @@ static void delete_bone(ListBase *edbo, EditBone* exBone)
 }
 
 /* context: editmode armature */
-EditBone *armature_bone_get_mirrored(ListBase *edbo, EditBone *ebo)
+EditBone *ED_armature_bone_get_mirrored(ListBase *edbo, EditBone *ebo)
 {
        EditBone *eboflip= NULL;
        char name[32];
        
+       if (ebo == NULL)
+               return NULL;
+       
        BLI_strncpy(name, ebo->name, sizeof(name));
        bone_flip_name(name, 0);                // 0 = don't strip off number extensions
        
@@ -1559,22 +1588,29 @@ EditBone *armature_bone_get_mirrored(ListBase *edbo, EditBone *ebo)
        return eboflip;
 }
 
+
+/* previously delete_armature */
 /* only editmode! */
-void delete_armature(Scene *scene)
+static int armature_delete_selected_exec(bContext *C, wmOperator *op)
 {
-       Object *obedit= scene->obedit; // XXX get from context
-       bArmature *arm= obedit->data;
+       bArmature *arm;
        EditBone        *curBone, *next;
        bConstraint *con;
-       
-       if (okee("Erase selected bone(s)")==0) return;
+       Object *obedit= CTX_data_edit_object(C); // XXX get from context
+       arm = obedit->data;
+
+       /* cancel if nothing selected */
+       if (CTX_DATA_COUNT(C, selected_bones) == 0)
+         return OPERATOR_CANCELLED;
+
+       /* if (okee("Erase selected bone(s)")==0) return; */
 
        /* Select mirrored bones */
        if (arm->flag & ARM_MIRROR_EDIT) {
                for (curBone=arm->edbo->first; curBone; curBone=curBone->next) {
                        if (arm->layer & curBone->layer) {
                                if (curBone->flag & BONE_SELECTED) {
-                                       next = armature_bone_get_mirrored(arm->edbo, curBone);
+                                       next = ED_armature_bone_get_mirrored(arm->edbo, curBone);
                                        if (next)
                                                next->flag |= BONE_SELECTED;
                                }
@@ -1632,16 +1668,33 @@ void delete_armature(Scene *scene)
        }
        
        
-       countall(); // flushes selection!
+       armature_sync_selection(arm->edbo);
+
+       WM_event_add_notifier(C, NC_OBJECT, obedit);
+
+       return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_delete(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Delete Selected Bone(s)";
+       ot->idname= "ARMATURE_OT_delete";
+       
+       /* api callbacks */
+       ot->invoke = WM_operator_confirm;
+       ot->exec = armature_delete_selected_exec;
+       ot->poll = ED_operator_editarmature;
        
-       BIF_undo_push("Delete bone(s)");
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
 /* toggle==0: deselect
-toggle==1: swap (based on test)
-toggle==2: only active tag
-toggle==3: swap (no test)
-*/
+ * toggle==1: swap (based on test)
+ * toggle==2: only active tag
+ * toggle==3: swap (no test)
+ */
 void deselectall_armature(Object *obedit, int toggle, int doundo)
 {
        bArmature *arm= obedit->data;
@@ -1689,7 +1742,7 @@ void deselectall_armature(Object *obedit, int toggle, int doundo)
                }
        }
        
-       countall(); // flushes selection!
+       armature_sync_selection(arm->edbo);
        if (doundo) {
                if (sel==1) BIF_undo_push("Select All");
                else BIF_undo_push("Deselect All");
@@ -1697,29 +1750,32 @@ void deselectall_armature(Object *obedit, int toggle, int doundo)
 }
 
 
-/* context: editmode armature */
-void mouse_armature(Scene *scene, Object *obedit)
+/* context: editmode armature in view3d */
+void mouse_armature(bContext *C, short mval[2], int extend)
 {
+       Object *obedit= CTX_data_edit_object(C);
        bArmature *arm= obedit->data;
+       ViewContext vc;
        EditBone *nearBone = NULL, *ebone;
        int     selmask;
-       int shift= 0; // XXX
 
-       nearBone= get_nearest_editbonepoint(scene, obedit, arm->edbo, 1, &selmask);
+       view3d_set_viewcontext(C, &vc);
+       
+       BIF_sk_selectStroke(C, mval, extend);
+       
+       nearBone= get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask);
        if (nearBone) {
-               
-               if (!(shift)) {
+
+               if (!extend)
                        deselectall_armature(obedit, 0, 0);
-               }
                
                /* by definition the non-root connected bones have no root point drawn,
-              so a root selection needs to be delivered to the parent tip,
-              countall() (bad location) flushes these flags */
+              so a root selection needs to be delivered to the parent tip */
                
                if(selmask & BONE_SELECTED) {
                        if(nearBone->parent && (nearBone->flag & BONE_CONNECTED)) {
                                /* click in a chain */
-                               if(shift) {
+                               if(extend) {
                                        /* hold shift inverts this bone's selection */
                                        if(nearBone->flag & BONE_SELECTED) {
                                                /* deselect this bone */
@@ -1741,7 +1797,7 @@ void mouse_armature(Scene *scene, Object *obedit)
                                }
                        }
                        else {
-                               if(shift) {
+                               if(extend) {
                                        /* hold shift inverts this bone's selection */
                                        if(nearBone->flag & BONE_SELECTED)
                                           nearBone->flag &= ~(BONE_TIPSEL|BONE_ROOTSEL);
@@ -1752,13 +1808,13 @@ void mouse_armature(Scene *scene, Object *obedit)
                        }
                }
                else {
-                       if ((shift) && (nearBone->flag & selmask))
+                       if (extend && (nearBone->flag & selmask))
                                nearBone->flag &= ~selmask;
                        else
                                nearBone->flag |= selmask;
                }
-
-               countall(); // flushes selection!
+               
+               armature_sync_selection(arm->edbo);
                
                if(nearBone) {
                        /* then now check for active status */
@@ -1766,9 +1822,8 @@ void mouse_armature(Scene *scene, Object *obedit)
                        if(nearBone->flag & BONE_SELECTED) nearBone->flag |= BONE_ACTIVE;
                }
                
+               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
        }
-
-//     rightmouse_transform();
 }
 
 void ED_armature_edit_free(struct Object *ob)
@@ -1801,13 +1856,15 @@ void ED_armature_to_edit(Object *ob)
        ED_armature_edit_free(ob);
        arm->edbo= MEM_callocN(sizeof(ListBase), "edbo armature");
        make_boneList(arm->edbo, &arm->bonebase,NULL);
+
+//     BIF_freeTemplates(); /* force template update when entering editmode */
 }
 
 
 /* adjust bone roll to align Z axis with vector
  * vec is in local space and is normalized
  */
-float rollBoneToVector(EditBone *bone, float new_up_axis[3])
+float ED_rollBoneToVector(EditBone *bone, float new_up_axis[3])
 {
        float mat[3][3], nor[3], up_axis[3], vec[3];
        float roll;
@@ -1829,90 +1886,129 @@ float rollBoneToVector(EditBone *bone, float new_up_axis[3])
        return roll;
 }
 
-/* Sets the roll value of selected bones, depending on the mode
- *     mode == 0: their z-axes point upwards 
- *     mode == 1: their z-axes point towards 3d-cursor
- */
-void auto_align_armature(Scene *scene, View3D *v3d, short mode)
+
+/* Set roll value for given bone -> Z-Axis Point up (original method) */
+void auto_align_ebone_zaxisup(Scene *scene, View3D *v3d, EditBone *ebone)
+{
+       float   delta[3], curmat[3][3];
+       float   xaxis[3]={1.0f, 0.0f, 0.0f}, yaxis[3], zaxis[3]={0.0f, 0.0f, 1.0f};
+       float   targetmat[3][3], imat[3][3], diffmat[3][3];
+       
+       /* Find the current bone matrix */
+       VecSubf(delta, ebone->tail, ebone->head);
+       vec_roll_to_mat3(delta, 0.0f, curmat);
+       
+       /* Make new matrix based on y axis & z-up */
+       VECCOPY(yaxis, curmat[1]);
+       
+       Mat3One(targetmat);
+       VECCOPY(targetmat[0], xaxis);
+       VECCOPY(targetmat[1], yaxis);
+       VECCOPY(targetmat[2], zaxis);
+       Mat3Ortho(targetmat);
+       
+       /* Find the difference between the two matrices */
+       Mat3Inv(imat, targetmat);
+       Mat3MulMat3(diffmat, imat, curmat);
+       
+       // old-method... let's see if using mat3_to_vec_roll is more accurate
+       //ebone->roll = atan2(diffmat[2][0], diffmat[2][2]);  
+       mat3_to_vec_roll(diffmat, delta, &ebone->roll);
+}
+
+/* Set roll value for given bone -> Z-Axis point towards cursor */
+void auto_align_ebone_tocursor(Scene *scene, View3D *v3d, EditBone *ebone)
 {
        Object *obedit= scene->obedit; // XXX get from context
-       bArmature *arm= obedit->data;
-       EditBone *ebone;
-       EditBone *flipbone = NULL;
-       float   delta[3];
-       float   curmat[3][3];
        float   *cursor= give_cursor(scene, v3d);
+       float   delta[3], curmat[3][3];
+       float   mat[4][4], tmat[4][4], imat[4][4];
+       float   rmat[4][4], rot[3];
+       float   vec[3];
+       
+       /* find the current bone matrix as a 4x4 matrix (in Armature Space) */
+       VecSubf(delta, ebone->tail, ebone->head);
+       vec_roll_to_mat3(delta, ebone->roll, curmat);
+       Mat4CpyMat3(mat, curmat);
+       VECCOPY(mat[3], ebone->head);
+       
+       /* multiply bone-matrix by object matrix (so that bone-matrix is in WorldSpace) */
+       Mat4MulMat4(tmat, mat, obedit->obmat);
+       Mat4Invert(imat, tmat);
+       
+       /* find position of cursor relative to bone */
+       VecMat4MulVecfl(vec, imat, cursor);
+       
+       /* check that cursor is in usable position */
+       if ((IS_EQ(vec[0], 0)==0) && (IS_EQ(vec[2], 0)==0)) {
+               /* Compute a rotation matrix around y */
+               rot[1] = (float)atan2(vec[0], vec[2]);
+               rot[0] = rot[2] = 0.0f;
+               EulToMat4(rot, rmat);
                
-       for (ebone = arm->edbo->first; ebone; ebone=ebone->next) {
-               if (EBONE_VISIBLE(arm, ebone)) {
-                       if (arm->flag & ARM_MIRROR_EDIT)
-                               flipbone = armature_bone_get_mirrored(arm->edbo, ebone);
-                       
-                       if ((ebone->flag & BONE_SELECTED) || 
-                               (flipbone && (flipbone->flag & BONE_SELECTED))) 
-                       {
-                               /* specific method used to calculate roll depends on mode */
-                               if (mode == 1) {
-                                       /* Z-Axis point towards cursor */
-                                       float   mat[4][4], tmat[4][4], imat[4][4];
-                                       float   rmat[4][4], rot[3];
-                                       float   vec[3];
-                                       
-                                       /* find the current bone matrix as a 4x4 matrix (in Armature Space) */
-                                       VecSubf(delta, ebone->tail, ebone->head);
-                                       vec_roll_to_mat3(delta, ebone->roll, curmat);
-                                       Mat4CpyMat3(mat, curmat);
-                                       VECCOPY(mat[3], ebone->head);
-                                       
-                                       /* multiply bone-matrix by object matrix (so that bone-matrix is in WorldSpace) */
-                                       Mat4MulMat4(tmat, mat, obedit->obmat);
-                                       Mat4Invert(imat, tmat);
-                                       
-                                       /* find position of cursor relative to bone */
-                                       VecMat4MulVecfl(vec, imat, cursor);
-                                       
-                                       /* check that cursor is in usable position */
-                                       if ((IS_EQ(vec[0], 0)==0) && (IS_EQ(vec[2], 0)==0)) {
-                                               /* Compute a rotation matrix around y */
-                                               rot[1] = atan2(vec[0], vec[2]);
-                                               rot[0] = rot[2] = 0.0f;
-                                               EulToMat4(rot, rmat);
-                                               
-                                               /* Multiply the bone matrix by rotation matrix. This should be new bone-matrix */
-                                               Mat4MulMat4(tmat, rmat, mat);
-                                               Mat3CpyMat4(curmat, tmat);
-                                               
-                                               /* Now convert from new bone-matrix, back to a roll value (in radians) */
-                                               mat3_to_vec_roll(curmat, delta, &ebone->roll);
-                                       }
-                               }
-                               else { 
-                                       /* Z-Axis Point Up */
-                                       float   xaxis[3]={1.0, 0.0, 0.0}, yaxis[3], zaxis[3]={0.0, 0.0, 1.0};
-                                       float   targetmat[3][3], imat[3][3], diffmat[3][3];
-                                       
-                                       /* Find the current bone matrix */
-                                       VecSubf(delta, ebone->tail, ebone->head);
-                                       vec_roll_to_mat3(delta, 0.0, curmat);
-                                       
-                                       /* Make new matrix based on y axis & z-up */
-                                       VECCOPY (yaxis, curmat[1]);
-                                       
-                                       Mat3One(targetmat);
-                                       VECCOPY (targetmat[0], xaxis);
-                                       VECCOPY (targetmat[1], yaxis);
-                                       VECCOPY (targetmat[2], zaxis);
-                                       Mat3Ortho(targetmat);
-                                       
-                                       /* Find the difference between the two matrices */
-                                       Mat3Inv(imat, targetmat);
-                                       Mat3MulMat3(diffmat, imat, curmat);
-                                       
-                                       ebone->roll = atan2(diffmat[2][0], diffmat[2][2]);
-                               }                               
-                       }
-               }
+               /* Multiply the bone matrix by rotation matrix. This should be new bone-matrix */
+               Mat4MulMat4(tmat, rmat, mat);
+               Mat3CpyMat4(curmat, tmat);
+               
+               /* Now convert from new bone-matrix, back to a roll value (in radians) */
+               mat3_to_vec_roll(curmat, delta, &ebone->roll);
+       }
+}
+
+
+static EnumPropertyItem prop_calc_roll_types[] = {
+       {0, "GLOBALUP", 0, "Z-Axis Up", ""},
+       {1, "CURSOR", 0, "Z-Axis to Cursor", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+static int armature_calc_roll_exec(bContext *C, wmOperator *op) 
+{
+       Scene *scene= CTX_data_scene(C);
+       View3D *v3d= (View3D *)CTX_wm_space_data(C);
+       Object *ob= CTX_data_edit_object(C);
+       void (*roll_func)(Scene *, View3D *, EditBone *) = NULL;
+       
+       /* specific method used to calculate roll depends on mode */
+       switch (RNA_enum_get(op->ptr, "type")) {
+               case 1:  /* Z-Axis point towards cursor */
+                       roll_func= auto_align_ebone_tocursor;
+                       break;
+               default: /* Z-Axis Point Up */
+                       roll_func= auto_align_ebone_zaxisup;
+                       break;
        }
+       
+       /* recalculate roll on selected bones */
+       CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) {
+               /* roll func is a callback which assumes that all is well */
+               roll_func(scene, v3d, ebone);
+       }
+       CTX_DATA_END;
+       
+
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
+       
+       return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Recalculate Roll";
+       ot->idname= "ARMATURE_OT_calculate_roll";
+       
+       /* api callbacks */
+       ot->invoke = WM_menu_invoke;
+       ot->exec = armature_calc_roll_exec;
+       ot->poll = ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* properties */
+       RNA_def_enum(ot->srna, "type", prop_calc_roll_types, 0, "Type", "");
 }
 
 /* **************** undo for armatures ************** */
@@ -1973,11 +2069,21 @@ static void free_undoBones(void *lbv)
        MEM_freeN(lb);
 }
 
+static void *get_armature_edit(bContext *C)
+{
+       Object *obedit= CTX_data_edit_object(C);
+       if(obedit && obedit->type==OB_ARMATURE) {
+               bArmature *arm= obedit->data;
+               return arm->edbo;
+       }
+       return NULL;
+}
+
 /* and this is all the undo system needs to know */
 void undo_push_armature(bContext *C, char *name)
 {
        // XXX solve getdata()
-       undo_editmode_push(C, name, NULL, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
+       undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
 }
 
 
@@ -1986,33 +2092,40 @@ void undo_push_armature(bContext *C, char *name)
 /* *************** Adding stuff in editmode *************** */
 
 /* default bone add, returns it selected, but without tail set */
-static EditBone *add_editbone(Object *obedit, char *name)
+EditBone *addEditBone(bArmature *arm, char *name)
 {
-       bArmature *arm= obedit->data;
-       
        EditBone *bone= MEM_callocN(sizeof(EditBone), "eBone");
        
        BLI_strncpy(bone->name, name, 32);
-       unique_editbone_name(arm->edbo, bone->name);
+       unique_editbone_name(arm->edbo, bone->name, NULL);
        
        BLI_addtail(arm->edbo, bone);
        
        bone->flag |= BONE_TIPSEL;
-       bone->weight= 1.0F;
-       bone->dist= 0.25F;
-       bone->xwidth= 0.1;
-       bone->zwidth= 0.1;
-       bone->ease1= 1.0;
-       bone->ease2= 1.0;
-       bone->rad_head= 0.10;
-       bone->rad_tail= 0.05;
+       bone->weight= 1.0f;
+       bone->dist= 0.25f;
+       bone->xwidth= 0.1f;
+       bone->zwidth= 0.1f;
+       bone->ease1= 1.0f;
+       bone->ease2= 1.0f;
+       bone->rad_head= 0.10f;
+       bone->rad_tail= 0.05f;
        bone->segments= 1;
        bone->layer= arm->layer;
        
        return bone;
 }
 
-static void add_primitive_bone(Scene *scene, View3D *v3d, short newob)
+/* default bone add, returns it selected, but without tail set */
+static EditBone *add_editbone(Object *obedit, char *name)
+{
+       bArmature *arm= obedit->data;
+
+       return addEditBone(arm, name);
+}
+
+/* v3d and rv3d are allowed to be NULL */
+void add_primitive_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d)
 {
        Object *obedit= scene->obedit; // XXX get from context
        float           obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
@@ -2024,7 +2137,8 @@ static void add_primitive_bone(Scene *scene, View3D *v3d, short newob)
        Mat4Invert(obedit->imat, obedit->obmat);
        Mat4MulVecfl(obedit->imat, curs);
 
-       if ( !(newob) || (U.flag & USER_ADD_VIEWALIGNED) ) Mat3CpyMat4(obmat, v3d->viewmat);
+       if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
+               Mat3CpyMat4(obmat, rv3d->viewmat);
        else Mat3One(obmat);
        
        Mat3CpyMat4(viewmat, obedit->obmat);
@@ -2038,59 +2152,30 @@ static void add_primitive_bone(Scene *scene, View3D *v3d, short newob)
 
        VECCOPY(bone->head, curs);
        
-       if ( !(newob) || (U.flag & USER_ADD_VIEWALIGNED) )
+       if ( (U.flag & USER_ADD_VIEWALIGNED) )
                VecAddf(bone->tail, bone->head, imat[1]);       // bone with unit length 1
        else
                VecAddf(bone->tail, bone->head, imat[2]);       // bone with unit length 1, pointing up Z
        
 }
 
-void add_primitiveArmature(Scene *scene, View3D *v3d, int type)
-{
-       Object *obedit= scene->obedit; // XXX get from context
-       short newob=0;
-       
-       if(scene->id.lib) return;
-       
-       G.f &= ~(G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT+G_SCULPTMODE);
-//     setcursor_space(SPACE_VIEW3D, CURSOR_STD);
-
-// XXX check_editmode(OB_ARMATURE);
-       
-       /* If we're not the "obedit", make a new object and enter editmode */
-       if (obedit==NULL) {
-               add_object(scene, OB_ARMATURE);
-               ED_object_base_init_from_view(scene, v3d, BASACT);
-               obedit= BASACT->object;
-               
-               where_is_object(scene, obedit);
-               
-               ED_armature_to_edit(obedit);
-//             setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
-               newob=1;
-       }
-       
-       /* no primitive support yet */
-       add_primitive_bone(scene, v3d, newob);
-       
-       countall(); // flushes selection!
-
-       if ((newob) && !(U.flag & USER_ADD_EDITMODE)) {
-               ED_armature_from_edit(scene, obedit);
-               ED_armature_edit_free(obedit);
-       }
-       
-       BIF_undo_push("Add primitive");
-}
 
+/* previously addvert_armature */
 /* the ctrl-click method */
-void addvert_armature(Scene *scene, View3D *v3d)
+static int armature_click_extrude_exec(bContext *C, wmOperator *op)
 {
-       Object *obedit= scene->obedit; // XXX get from context
-       bArmature *arm= obedit->data;
+       View3D *v3d;
+       bArmature *arm;
        EditBone *ebone, *newbone, *flipbone;
        float *curs, mat[3][3],imat[3][3];
        int a, to_root= 0;
+       Object *obedit;
+       Scene *scene;
+
+       scene = CTX_data_scene(C);
+       v3d= CTX_wm_view3d(C);
+       obedit= CTX_data_edit_object(C);
+       arm= obedit->data;
        
        /* find the active or selected bone */
        for (ebone = arm->edbo->first; ebone; ebone=ebone->next) {
@@ -2108,7 +2193,7 @@ void addvert_armature(Scene *scene, View3D *v3d)
                        }
                }
                if (ebone == NULL) 
-                       return;
+                       return OPERATOR_CANCELLED;
                
                to_root= 1;
        }
@@ -2118,7 +2203,7 @@ void addvert_armature(Scene *scene, View3D *v3d)
        /* we re-use code for mirror editing... */
        flipbone= NULL;
        if (arm->flag & ARM_MIRROR_EDIT)
-               flipbone= armature_bone_get_mirrored(arm->edbo, ebone);
+               flipbone= ED_armature_bone_get_mirrored(arm->edbo, ebone);
 
        for (a=0; a<2; a++) {
                if (a==1) {
@@ -2161,9 +2246,84 @@ void addvert_armature(Scene *scene, View3D *v3d)
                
        }
        
-       countall();
+       armature_sync_selection(arm->edbo);
+
+       WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, obedit);
+       
+       return OPERATOR_FINISHED;
+}
+
+static int armature_click_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       /* TODO most of this code is copied from set3dcursor_invoke,
+          it would be better to reuse code in set3dcursor_invoke */
+
+       /* temporarily change 3d cursor position */
+       Scene *scene;
+       ARegion *ar;
+       View3D *v3d;
+       RegionView3D *rv3d;
+       float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
+       short mx, my, mval[2];
+       int retv;
+
+       scene= CTX_data_scene(C);
+       ar= CTX_wm_region(C);
+       v3d = CTX_wm_view3d(C);
+       rv3d= CTX_wm_region_view3d(C);
+       
+       fp= give_cursor(scene, v3d);
+       
+       VECCOPY(oldcurs, fp);
+       
+       mx= event->x - ar->winrct.xmin;
+       my= event->y - ar->winrct.ymin;
+       project_short_noclip(ar, fp, mval);
+       
+       initgrabz(rv3d, fp[0], fp[1], fp[2]);
+       
+       if(mval[0]!=IS_CLIPPED) {
+               
+               window_to_3d_delta(ar, dvec, mval[0]-mx, mval[1]-my);
+               VecSubf(fp, fp, dvec);
+       }
+       else {
+               
+               dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
+               dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
+               
+               fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
+               fz= fz/rv3d->zfac;
+               
+               fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
+               fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
+               fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
+       }
+
+       /* extrude to the where new cursor is and store the operation result */
+       retv= armature_click_extrude_exec(C, op);
+
+       /* restore previous 3d cursor position */
+       VECCOPY(fp, oldcurs);
+
+       return retv;
+}
+
+void ARMATURE_OT_click_extrude(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Click-Extrude";
+       ot->idname= "ARMATURE_OT_click_extrude";
+       
+       /* api callbacks */
+       ot->invoke = armature_click_extrude_invoke;
+       ot->exec = armature_click_extrude_exec;
+       ot->poll = ED_operator_editarmature;
        
-       BIF_undo_push("Add Bone");
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* props */
 }
 
 /* adds an EditBone between the nominated locations (should be in the right space) */
@@ -2194,19 +2354,35 @@ static EditBone *get_named_editbone(ListBase *edbo, char *name)
        return NULL;
 }
 
-static void update_dup_subtarget(Object *obedit, EditBone *dupBone)
+/* Call this before doing any duplications
+ * */
+void preEditBoneDuplicate(ListBase *editbones)
+{
+       EditBone *eBone;
+       
+       /* clear temp */
+       for (eBone = editbones->first; eBone; eBone = eBone->next)
+       {
+               eBone->temp = NULL;
+       }
+}
+
+/*
+ * Note: When duplicating cross objects, editbones here is the list of bones
+ * from the SOURCE object but ob is the DESTINATION object
+ * */
+void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Object *src_ob, Object *dst_ob)
 {
        /* If an edit bone has been duplicated, lets
         * update it's constraints if the subtarget
         * they point to has also been duplicated
         */
-       bArmature    *arm = obedit->data;
        EditBone     *oldtarget, *newtarget;
        bPoseChannel *chan;
        bConstraint  *curcon;
        ListBase     *conlist;
        
-       if ( (chan = verify_pose_channel(obedit->pose, dupBone->name)) ) {
+       if ( (chan = verify_pose_channel(dst_ob->pose, dupBone->name)) ) {
                if ( (conlist = &chan->constraints) ) {
                        for (curcon = conlist->first; curcon; curcon=curcon->next) {
                                /* does this constraint have a subtarget in
@@ -2220,14 +2396,15 @@ static void update_dup_subtarget(Object *obedit, EditBone *dupBone)
                                        cti->get_constraint_targets(curcon, &targets);
                                        
                                        for (ct= targets.first; ct; ct= ct->next) {
-                                               if ((ct->tar == obedit) && (ct->subtarget[0])) {
-                                                       oldtarget = get_named_editbone(arm->edbo, ct->subtarget);
+                                               if ((ct->tar == src_ob) && (ct->subtarget[0])) {
+                                                       ct->tar = dst_ob; /* update target */ 
+                                                       oldtarget = get_named_editbone(editbones, ct->subtarget);
                                                        if (oldtarget) {
                                                                /* was the subtarget bone duplicated too? If
                                                                 * so, update the constraint to point at the 
                                                                 * duplicate of the old subtarget.
                                                                 */
-                                                               if (oldtarget->flag & BONE_SELECTED){
+                                                               if (oldtarget->temp) {
                                                                        newtarget = (EditBone *) oldtarget->temp;
                                                                        strcpy(ct->subtarget, newtarget->name);
                                                                }
@@ -2243,44 +2420,126 @@ static void update_dup_subtarget(Object *obedit, EditBone *dupBone)
        }
 }
 
+void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob)
+{
+       updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
+}
+
 
-void adduplicate_armature(Scene *scene)
+EditBone *duplicateEditBoneObjects(EditBone *curBone, char *name, ListBase *editbones, Object *src_ob, Object *dst_ob)
 {
-       Object *obedit= scene->obedit; // XXX get from context
-       bArmature *arm= obedit->data;
-       EditBone        *eBone = NULL;
-       EditBone        *curBone;
-       EditBone        *firstDup=NULL; /*      The beginning of the duplicated bones in the edbo list */
+       EditBone *eBone = MEM_callocN(sizeof(EditBone), "addup_editbone");
        
-       countall(); // flushes selection!
-
-       /* Select mirrored bones */
-       if (arm->flag & ARM_MIRROR_EDIT) {
-               for (curBone=arm->edbo->first; curBone; curBone=curBone->next) {
-                       if (EBONE_VISIBLE(arm, curBone)) {
-                               if (curBone->flag & BONE_SELECTED) {
-                                       eBone = armature_bone_get_mirrored(arm->edbo, curBone);
-                                       if (eBone)
-                                               eBone->flag |= BONE_SELECTED;
-                               }
-                       }
-               }
-       }
+       /*      Copy data from old bone to new bone */
+       memcpy(eBone, curBone, sizeof(EditBone));
        
-       /*      Find the selected bones and duplicate them as needed */
+       curBone->temp = eBone;
+       eBone->temp = curBone;
+       
+       if (name != NULL)
+       {
+               BLI_strncpy(eBone->name, name, 32);
+       }
+
+       unique_editbone_name(editbones, eBone->name, NULL);
+       BLI_addtail(editbones, eBone);
+       
+       /* Lets duplicate the list of constraints that the
+        * current bone has.
+        */
+       if (src_ob->pose) {
+               bPoseChannel *chanold, *channew;
+               ListBase     *listold, *listnew;
+               
+               chanold = verify_pose_channel(src_ob->pose, curBone->name);
+               if (chanold) {
+                       listold = &chanold->constraints;
+                       if (listold) {
+                               /* WARNING: this creates a new posechannel, but there will not be an attached bone 
+                                *              yet as the new bones created here are still 'EditBones' not 'Bones'. 
+                                */
+                               channew = 
+                                       verify_pose_channel(dst_ob->pose, eBone->name);
+                               if (channew) {
+                                       /* copy transform locks */
+                                       channew->protectflag = chanold->protectflag;
+                                       
+                                       /* copy bone group */
+                                       channew->agrp_index= chanold->agrp_index;
+                                       
+                                       /* ik (dof) settings */
+                                       channew->ikflag = chanold->ikflag;
+                                       VECCOPY(channew->limitmin, chanold->limitmin);
+                                       VECCOPY(channew->limitmax, chanold->limitmax);
+                                       VECCOPY(channew->stiffness, chanold->stiffness);
+                                       channew->ikstretch= chanold->ikstretch;
+                                       
+                                       /* constraints */
+                                       listnew = &channew->constraints;
+                                       copy_constraints(listnew, listold);
+                                       
+                                       /* custom shape */
+                                       channew->custom= chanold->custom;
+                               }
+                       }
+               }
+       }
+       
+       return eBone;
+}
+
+EditBone *duplicateEditBone(EditBone *curBone, char *name, ListBase *editbones, Object *ob)
+{
+       return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
+}
+
+/* previously adduplicate_armature */
+static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
+{
+       bArmature *arm;
+       EditBone        *eBone = NULL;
+       EditBone        *curBone;
+       EditBone        *firstDup=NULL; /*      The beginning of the duplicated bones in the edbo list */
+
+       Object *obedit= CTX_data_edit_object(C);
+       arm= obedit->data;
+
+       /* cancel if nothing selected */
+       if (CTX_DATA_COUNT(C, selected_bones) == 0)
+         return OPERATOR_CANCELLED;
+       
+       armature_sync_selection(arm->edbo); // XXX why is this needed?
+
+       preEditBoneDuplicate(arm->edbo);
+
+       /* Select mirrored bones */
+       if (arm->flag & ARM_MIRROR_EDIT) {
+               for (curBone=arm->edbo->first; curBone; curBone=curBone->next) {
+                       if (EBONE_VISIBLE(arm, curBone)) {
+                               if (curBone->flag & BONE_SELECTED) {
+                                       eBone = ED_armature_bone_get_mirrored(arm->edbo, curBone);
+                                       if (eBone)
+                                               eBone->flag |= BONE_SELECTED;
+                               }
+                       }
+               }
+       }
+
+       
+       /*      Find the selected bones and duplicate them as needed */
        for (curBone=arm->edbo->first; curBone && curBone!=firstDup; curBone=curBone->next) {
                if (EBONE_VISIBLE(arm, curBone)) {
                        if (curBone->flag & BONE_SELECTED) {
                                eBone=MEM_callocN(sizeof(EditBone), "addup_editbone");
                                eBone->flag |= BONE_SELECTED;
                                
-                               /*      Copy data from old bone to new bone */
+                               /* Copy data from old bone to new bone */
                                memcpy(eBone, curBone, sizeof(EditBone));
                                
                                curBone->temp = eBone;
                                eBone->temp = curBone;
                                
-                               unique_editbone_name(arm->edbo, eBone->name);
+                               unique_editbone_name(arm->edbo, eBone->name, NULL);
                                BLI_addtail(arm->edbo, eBone);
                                if (!firstDup)
                                        firstDup=eBone;
@@ -2288,11 +2547,11 @@ void adduplicate_armature(Scene *scene)
                                /* Lets duplicate the list of constraints that the
                                 * current bone has.
                                 */
-                               if (OBACT->pose) {
+                               if (obedit->pose) {
                                        bPoseChannel *chanold, *channew;
                                        ListBase     *listold, *listnew;
                                        
-                                       chanold = verify_pose_channel(OBACT->pose, curBone->name);
+                                       chanold = verify_pose_channel(obedit->pose, curBone->name);
                                        if (chanold) {
                                                listold = &chanold->constraints;
                                                if (listold) {
@@ -2300,7 +2559,7 @@ void adduplicate_armature(Scene *scene)
                                                         *              yet as the new bones created here are still 'EditBones' not 'Bones'. 
                                                         */
                                                        channew = 
-                                                               verify_pose_channel(OBACT->pose, eBone->name);
+                                                               verify_pose_channel(obedit->pose, eBone->name);
                                                        if (channew) {
                                                                /* copy transform locks */
                                                                channew->protectflag = chanold->protectflag;
@@ -2335,43 +2594,74 @@ void adduplicate_armature(Scene *scene)
                        if (curBone->flag & BONE_SELECTED) {
                                eBone=(EditBone*) curBone->temp;
                                
-                               /*      If this bone has no parent,
-                               Set the duplicate->parent to NULL
-                               */
-                               if (!curBone->parent)
+                               if (!curBone->parent) {
+                                       /* If this bone has no parent,
+                                        * Set the duplicate->parent to NULL
+                                        */
                                        eBone->parent = NULL;
-                               /*      If this bone has a parent that IS selected,
-                                       Set the duplicate->parent to the curBone->parent->duplicate
-                                       */
-                               else if (curBone->parent->flag & BONE_SELECTED)
+                               }
+                               else if (curBone->parent->temp) {
+                                       /* If this bone has a parent that was duplicated,
+                                        * Set the duplicate->parent to the curBone->parent->temp
+                                        */
                                        eBone->parent= (EditBone *)curBone->parent->temp;
-                               /*      If this bone has a parent that IS not selected,
-                                       Set the duplicate->parent to the curBone->parent
-                                       */
+                               }
                                else {
+                                       /* If this bone has a parent that IS not selected,
+                                        * Set the duplicate->parent to the curBone->parent
+                                        */
                                        eBone->parent=(EditBone*) curBone->parent; 
                                        eBone->flag &= ~BONE_CONNECTED;
                                }
                                
                                /* Lets try to fix any constraint subtargets that might
-                                       have been duplicated */
-                               update_dup_subtarget(obedit, eBone);
+                                * have been duplicated 
+                                */
+                               updateDuplicateSubtarget(eBone, arm->edbo, obedit);
                        }
                }
        } 
        
        /*      Deselect the old bones and select the new ones */
-       
        for (curBone=arm->edbo->first; curBone && curBone!=firstDup; curBone=curBone->next) {
                if (EBONE_VISIBLE(arm, curBone))
                        curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL | BONE_ACTIVE);
        }
+
+       WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, obedit);
        
-// XXX BIF_TransformSetUndo("Add Duplicate");
-//     initTransform(TFM_TRANSLATION, CTX_NO_PET);
-//     Transform();
+       return OPERATOR_FINISHED;
+}
+
+static int armature_duplicate_selected_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       int retv= armature_duplicate_selected_exec(C, op);
+
+       if (retv == OPERATOR_FINISHED) {
+               RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
+               WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
+       }
+
+       return retv;
 }
 
+void ARMATURE_OT_duplicate_selected(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Duplicate Selected Bone(s)";
+       ot->idname= "ARMATURE_OT_duplicate_selected";
+       
+       /* api callbacks */
+       ot->invoke = armature_duplicate_selected_invoke;
+       ot->exec = armature_duplicate_selected_exec;
+       ot->poll = ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* to give to transform */
+       RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
+}
 
 
 /* *************** END Adding stuff in editmode *************** */
@@ -2768,7 +3058,7 @@ void merge_armature(Scene *scene)
        }
        
        /* undo + updates */
-       countall();
+       armature_sync_selection(arm->edbo);
        BIF_undo_push("Merge Bones");
 }
 
@@ -2790,7 +3080,7 @@ void hide_selected_armature_bones(Scene *scene)
                        }
                }
        }
-       countall();
+       armature_sync_selection(arm->edbo);
        BIF_undo_push("Hide Bones");
 }
 
@@ -2810,7 +3100,7 @@ void hide_unselected_armature_bones(Scene *scene)
                        }
                }
        }
-       countall();
+       armature_sync_selection(arm->edbo);
        BIF_undo_push("Hide Unselected Bones");
 }
 
@@ -2828,207 +3118,24 @@ void show_all_armature_bones(Scene *scene)
                        }
                }
        }
-       countall();
+       armature_sync_selection(arm->edbo);
        BIF_undo_push("Reveal Bones");
 }
 
-/* check for null, before calling! */
-static void bone_connect_to_existing_parent(EditBone *bone)
-{
-       bone->flag |= BONE_CONNECTED;
-       VECCOPY(bone->head, bone->parent->tail);
-       bone->rad_head = bone->parent->rad_tail;
-}
-
-static void bone_connect_to_new_parent(ListBase *edbo, EditBone *selbone, EditBone *actbone, short mode)
-{
-       EditBone *ebone;
-       float offset[3];
-       
-       if ((selbone->parent) && (selbone->flag & BONE_CONNECTED))
-               selbone->parent->flag &= ~(BONE_TIPSEL);
-       
-       /* make actbone the parent of selbone */
-       selbone->parent= actbone;
-       
-       /* in actbone tree we cannot have a loop */
-       for (ebone= actbone->parent; ebone; ebone= ebone->parent) {
-               if (ebone->parent==selbone) {
-                       ebone->parent= NULL;
-                       ebone->flag &= ~BONE_CONNECTED;
-               }
-       }
-       
-       if (mode == 1) {        
-               /* Connected: Child bones will be moved to the parent tip */
-               selbone->flag |= BONE_CONNECTED;
-               VecSubf(offset, actbone->tail, selbone->head);
-               
-               VECCOPY(selbone->head, actbone->tail);
-               selbone->rad_head= actbone->rad_tail;
-               
-               VecAddf(selbone->tail, selbone->tail, offset);
-               
-               /* offset for all its children */
-               for (ebone = edbo->first; ebone; ebone=ebone->next) {
-                       EditBone *par;
-                       
-                       for (par= ebone->parent; par; par= par->parent) {
-                               if (par==selbone) {
-                                       VecAddf(ebone->head, ebone->head, offset);
-                                       VecAddf(ebone->tail, ebone->tail, offset);
-                                       break;
-                               }
-                       }
-               }
-       }
-       else {
-               /* Offset: Child bones will retain their distance from the parent tip */
-               selbone->flag &= ~BONE_CONNECTED;
-       }
-}
-
-void make_bone_parent(Scene *scene)
-{
-       Object *obedit= scene->obedit; // XXX get from context
-       bArmature *arm= obedit->data;
-       EditBone *actbone, *ebone, *selbone;
-       EditBone *flipbone, *flippar;
-       short allchildbones= 0, foundselbone= 0;
-       short val;
-       
-       /* find active bone to parent to */
-       for (actbone = arm->edbo->first; actbone; actbone=actbone->next) {
-               if (EBONE_VISIBLE(arm, actbone)) {
-                       if (actbone->flag & BONE_ACTIVE)
-                               break;
-               }
-       }
-       if (actbone == NULL) {
-               error("Needs an active bone");
-               return; 
-       }
-
-       /* find selected bones */
-       for (ebone = arm->edbo->first; ebone; ebone=ebone->next) {
-               if (EBONE_VISIBLE(arm, ebone)) {
-                       if ((ebone->flag & BONE_SELECTED) && (ebone != actbone)) {
-                               foundselbone++;
-                               if (ebone->parent != actbone) allchildbones= 1; 
-                       }       
-               }
-       }
-       /* abort if no selected bones, and active bone doesn't have a parent to work with instead */
-       if (foundselbone==0 && actbone->parent==NULL) {
-               error("Need selected bone(s)");
-               return;
-       }
-       
-       /* 'Keep Offset' option is only displayed if it's likely to be useful */
-       if (allchildbones)
-               val= pupmenu("Make Parent%t|Connected%x1|Keep Offset%x2");
-       else
-               val= pupmenu("Make Parent%t|Connected%x1");
-       
-       if (val < 1) return;
-
-       if (foundselbone==0 && actbone->parent) {
-               /* When only the active bone is selected, and it has a parent,
-                * connect it to the parent, as that is the only possible outcome. 
-                */
-               bone_connect_to_existing_parent(actbone);
-               
-               if (arm->flag & ARM_MIRROR_EDIT) {
-                       flipbone = armature_bone_get_mirrored(arm->edbo, actbone);
-                       if (flipbone)
-                               bone_connect_to_existing_parent(flipbone);
-               }
-       }
-       else {
-               /* loop through all editbones, parenting all selected bones to the active bone */
-               for (selbone = arm->edbo->first; selbone; selbone=selbone->next) {
-                       if (EBONE_VISIBLE(arm, selbone)) {
-                               if ((selbone->flag & BONE_SELECTED) && (selbone!=actbone)) {
-                                       /* parent selbone to actbone */
-                                       bone_connect_to_new_parent(arm->edbo, selbone, actbone, val);
-                                       
-                                       if (arm->flag & ARM_MIRROR_EDIT) {
-                                               /* - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone 
-                                                *      (i.e.  selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
-                                                *      This is useful for arm-chains, for example parenting lower arm to upper arm
-                                                * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
-                                                *      then just use actbone. Useful when doing upper arm to spine.
-                                                */
-                                               flipbone = armature_bone_get_mirrored(arm->edbo, selbone);
-                                               flippar = armature_bone_get_mirrored(arm->edbo, actbone);
-                                               
-                                               if (flipbone) {
-                                                       if (flippar)
-                                                               bone_connect_to_new_parent(arm->edbo, flipbone, flippar, val);
-                                                       else
-                                                               bone_connect_to_new_parent(arm->edbo, flipbone, actbone, val);
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-
-       countall(); /* checks selection */
-       BIF_undo_push("Make Parent");
-
-       return;
-}
-
-static void editbone_clear_parent(EditBone *ebone, int mode)
-{
-       if (ebone->parent) {
-               /* for nice selection */
-               ebone->parent->flag &= ~(BONE_TIPSEL);
-       }
-       
-       if (mode==1) ebone->parent= NULL;
-       ebone->flag &= ~BONE_CONNECTED;
-}
-
-void clear_bone_parent(Scene *scene)
-{
-       Object *obedit= scene->obedit; // XXX get from context
-       bArmature *arm= obedit->data;
-       EditBone *ebone;
-       EditBone *flipbone = NULL;
-       short val;
-       
-       val= pupmenu("Clear Parent%t|Clear Parent%x1|Disconnect Bone%x2");
-       if (val<1) return;
-       
-       for (ebone = arm->edbo->first; ebone; ebone=ebone->next) {
-               if (EBONE_VISIBLE(arm, ebone)) {
-                       if (ebone->flag & BONE_SELECTED) {
-                               if (arm->flag & ARM_MIRROR_EDIT)
-                                       flipbone = armature_bone_get_mirrored(arm->edbo, ebone);
-                                       
-                               if (flipbone)
-                                       editbone_clear_parent(flipbone, val);
-                               editbone_clear_parent(ebone, val);
-                       }
-               }
-       }
-       
-       countall(); // checks selection
-       BIF_undo_push("Clear Parent");
-}
-       
-
+/* previously extrude_armature */
 /* context; editmode armature */
 /* if forked && mirror-edit: makes two bones with flipped names */
-void extrude_armature(Scene *scene, int forked)
+static int armature_extrude_exec(bContext *C, wmOperator *op)
 {
-       Object *obedit= scene->obedit; // XXX get from context
-       bArmature *arm= obedit->data;
+       Object *obedit;
+       bArmature *arm;
        EditBone *newbone, *ebone, *flipbone, *first=NULL;
        int a, totbone= 0, do_extrude;
-       
+       int forked = RNA_boolean_get(op->ptr, "forked");
+
+       obedit= CTX_data_edit_object(C);
+       arm= obedit->data;
+
        /* since we allow root extrude too, we have to make sure selection is OK */
        for (ebone = arm->edbo->first; ebone; ebone=ebone->next) {
                if (EBONE_VISIBLE(arm, ebone)) {
@@ -3058,7 +3165,7 @@ void extrude_armature(Scene *scene, int forked)
                                /* we re-use code for mirror editing... */
                                flipbone= NULL;
                                if (arm->flag & ARM_MIRROR_EDIT) {
-                                       flipbone= armature_bone_get_mirrored(arm->edbo, ebone);
+                                       flipbone= ED_armature_bone_get_mirrored(arm->edbo, ebone);
                                        if (flipbone) {
                                                forked= 0;      // we extrude 2 different bones
                                                if (flipbone->flag & (BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED))
@@ -3121,7 +3228,7 @@ void extrude_armature(Scene *scene, int forked)
                                                        else strcat(newbone->name, "_R");
                                                }
                                        }
-                                       unique_editbone_name(arm->edbo, newbone->name);
+                                       unique_editbone_name(arm->edbo, newbone->name, NULL);
                                        
                                        /* Add the new bone to the list */
                                        BLI_addtail(arm->edbo, newbone);
@@ -3140,121 +3247,305 @@ void extrude_armature(Scene *scene, int forked)
        }
        /* if only one bone, make this one active */
        if (totbone==1 && first) first->flag |= BONE_ACTIVE;
+
+       if (totbone==0) return OPERATOR_CANCELLED;
        
        /* Transform the endpoints */
-       countall(); // flushes selection!
-// XXX BIF_TransformSetUndo("Extrude");
-//     initTransform(TFM_TRANSLATION, CTX_NO_PET);
-//     Transform();
-       
+       armature_sync_selection(arm->edbo);
+
+       return OPERATOR_FINISHED;
 }
 
-/* context; editmode armature */
-void subdivide_armature(Scene *scene, int numcuts)
+static int armature_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
-       Object *obedit= scene->obedit; // XXX get from context
-       bArmature *arm= obedit->data;
-       EditBone *ebone, *newbone, *tbone, *mbone;
-       int a, i;
-       
-       if (numcuts < 1) return;
-
-       for (mbone = arm->edbo->last; mbone; mbone= mbone->prev) {
-               if (EBONE_VISIBLE(arm, mbone)) {
-                       if (mbone->flag & BONE_SELECTED) {
-                               for (i=numcuts+1; i>1; i--) {
-                                       /* compute cut ratio first */
-                                       float cutratio= 1/(float)i;
-                                       float cutratioI= 1-cutratio;
-                                       
-                                       /* take care of mirrored stuff */
-                                       for (a=0; a<2; a++) {
-                                               float val1[3];
-                                               float val2[3];
-                                               float val3[3];
-                                               
-                                               /* try to find mirrored bone on a != 0 */
-                                               if (a) {
-                                                       if (arm->flag & ARM_MIRROR_EDIT)
-                                                               ebone= armature_bone_get_mirrored(arm->edbo, mbone);
-                                                       else 
-                                                               ebone= NULL;
-                                               }
-                                               else
-                                                       ebone= mbone;
-                                                       
-                                               if (ebone) {
-                                                       newbone= MEM_mallocN(sizeof(EditBone), "ebone subdiv");
-                                                       *newbone = *ebone;
-                                                       BLI_addtail(arm->edbo, newbone);
-                                                       
-                                                       /* calculate location of newbone->head */
-                                                       VECCOPY(val1, ebone->head);
-                                                       VECCOPY(val2, ebone->tail);
-                                                       VECCOPY(val3, newbone->head);
-                                                       
-                                                       val3[0]= val1[0]*cutratio+val2[0]*cutratioI;
-                                                       val3[1]= val1[1]*cutratio+val2[1]*cutratioI;
-                                                       val3[2]= val1[2]*cutratio+val2[2]*cutratioI;
-                                                       
-                                                       VECCOPY(newbone->head, val3);
-                                                       VECCOPY(newbone->tail, ebone->tail);
-                                                       VECCOPY(ebone->tail, newbone->head);
-                                                       
-                                                       newbone->rad_head= 0.5*(ebone->rad_head+ebone->rad_tail);
-                                                       ebone->rad_tail= newbone->rad_head;
-                                                       
-                                                       newbone->flag |= BONE_CONNECTED;
-                                                       
-                                                       unique_editbone_name (arm->edbo, newbone->name);
-                                                       
-                                                       /* correct parent bones */
-                                                       for (tbone = arm->edbo->first; tbone; tbone=tbone->next) {
-                                                               if (tbone->parent==ebone)
-                                                                       tbone->parent= newbone;
-                                                       }
-                                                       newbone->parent= ebone;
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-       
-       if (numcuts==1) BIF_undo_push("Subdivide");
-       else BIF_undo_push("Subdivide multi");
+       if (OPERATOR_CANCELLED == armature_extrude_exec(C, op))
+               return OPERATOR_CANCELLED;
+
+       RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
+       WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
+
+       return OPERATOR_FINISHED;
 }
 
-/* switch direction of bone chains */
-void switch_direction_armature (Scene *scene)
+void ARMATURE_OT_extrude(wmOperatorType *ot)
 {
-       Object *obedit= scene->obedit; // XXX get from context
-       bArmature *arm= (obedit) ? obedit->data : NULL;
-       ListBase chains = {NULL, NULL};
-       LinkData *chain;
+       /* identifiers */
+       ot->name= "Extrude";
+       ot->idname= "ARMATURE_OT_extrude";
+       
+       /* api callbacks */
+       ot->invoke= armature_extrude_invoke;
+       ot->exec= armature_extrude_exec;
+       ot->poll= ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_boolean(ot->srna, "forked", 0, "Forked", "");
+       /* to give to transform */
+       RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
+}
+/* ********************** Bone Add ********************/
+
+/*op makes a new bone and returns it with its tip selected */
+
+static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) 
+{
+       RegionView3D *rv3d= CTX_wm_region_view3d(C);
+       Object *obedit = CTX_data_edit_object(C);
+       EditBone *bone;
+       float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
+       char name[32];
        
-       /* error checking paranoia */
-       if (arm == NULL)
-               return;
+       RNA_string_get(op->ptr, "name", name);
        
-       /* get chains of bones (ends on chains) */
-       chains_find_tips(arm->edbo, &chains);
-       if (chains.first == NULL) return;
+       VECCOPY(curs, give_cursor(CTX_data_scene(C),CTX_wm_view3d(C))); 
+
+       /* Get inverse point for head and orientation for tail */
+       Mat4Invert(obedit->imat, obedit->obmat);
+       Mat4MulVecfl(obedit->imat, curs);
+
+       if (U.flag & USER_ADD_VIEWALIGNED)
+               Mat3CpyMat4(obmat, rv3d->viewmat);
+       else Mat3One(obmat);
        
-       /* loop over chains, only considering selected and visible bones */
-       for (chain= chains.first; chain; chain= chain->next) {
-               EditBone *ebo, *child=NULL, *parent=NULL;
-               
-               /* loop over bones in chain */
-               for (ebo= chain->data; ebo; ebo= parent) {
-                       /* parent is this bone's original parent
-                        *      - we store this, as the next bone that is checked is this one
-                        *        but the value of ebo->parent may change here...
-                        */
-                       parent= ebo->parent;
-                       
-                       /* only if selected and editable */
-                       if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {                           
+       Mat3CpyMat4(viewmat, obedit->obmat);
+       Mat3MulMat3(totmat, obmat, viewmat);
+       Mat3Inv(imat, totmat);
+       
+       deselectall_armature(obedit, 0, 0);
+       
+       /*      Create a bone   */
+       bone= add_editbone(obedit, name);
+
+       VECCOPY(bone->head, curs);
+       
+       if(U.flag & USER_ADD_VIEWALIGNED)
+               VecAddf(bone->tail, bone->head, imat[1]);       // bone with unit length 1
+       else
+               VecAddf(bone->tail, bone->head, imat[2]);       // bone with unit length 1, pointing up Z
+
+       WM_event_add_notifier(C, NC_OBJECT, obedit);
+       
+       return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Add Bone";
+       ot->idname= "ARMATURE_OT_bone_primitive_add";
+       
+       /* api callbacks */
+       ot->exec = armature_bone_primitive_add_exec;
+       ot->poll = ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       RNA_def_string(ot->srna, "name", "Bone", 32, "Name", "Name of the newly created bone");
+       
+}
+
+
+/* ----------- */
+
+/* Subdivide Operators:
+ * This group of operators all use the same 'exec' callback, but they are called
+ * through several different operators - a combined menu (which just calls the exec in the 
+ * appropriate ways), and two separate ones.
+ */
+
+static int armature_subdivide_exec(bContext *C, wmOperator *op)
+{
+       Object *obedit= CTX_data_edit_object(C);
+       bArmature *arm= obedit->data;
+       EditBone *newbone, *tbone;
+       int numcuts, i;
+       
+       /* there may not be a number_cuts property defined (for 'simple' subdivide) */
+       if (RNA_property_is_set(op->ptr, "number_cuts"))
+               numcuts= RNA_int_get(op->ptr, "number_cuts");
+       else
+               numcuts= 1;
+       
+       /* loop over all editable bones */
+       // XXX the old code did this in reverse order though!
+       CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) 
+       {
+               for (i=numcuts+1; i>1; i--) {
+                       /* compute cut ratio first */
+                       float cutratio= 1.0f / (float)i;
+                       float cutratioI= 1.0f - cutratio;
+                       
+                       float val1[3];
+                       float val2[3];
+                       float val3[3];
+                       
+                       newbone= MEM_mallocN(sizeof(EditBone), "ebone subdiv");
+                       *newbone = *ebone;
+                       BLI_addtail(arm->edbo, newbone);
+                       
+                       /* calculate location of newbone->head */
+                       VECCOPY(val1, ebone->head);
+                       VECCOPY(val2, ebone->tail);
+                       VECCOPY(val3, newbone->head);
+                       
+                       val3[0]= val1[0]*cutratio + val2[0]*cutratioI;
+                       val3[1]= val1[1]*cutratio + val2[1]*cutratioI;
+                       val3[2]= val1[2]*cutratio + val2[2]*cutratioI;
+                       
+                       VECCOPY(newbone->head, val3);
+                       VECCOPY(newbone->tail, ebone->tail);
+                       VECCOPY(ebone->tail, newbone->head);
+                       
+                       newbone->rad_head= 0.5f * (ebone->rad_head + ebone->rad_tail);
+                       ebone->rad_tail= newbone->rad_head;
+                       
+                       newbone->flag |= BONE_CONNECTED;
+                       
+                       unique_editbone_name(arm->edbo, newbone->name, NULL);
+                       
+                       /* correct parent bones */
+                       for (tbone = arm->edbo->first; tbone; tbone=tbone->next) {
+                               if (tbone->parent==ebone)
+                                       tbone->parent= newbone;
+                       }
+                       newbone->parent= ebone;
+               }
+       }
+       CTX_DATA_END;
+       
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, obedit);
+       
+       return OPERATOR_FINISHED;
+}
+
+
+void ARMATURE_OT_subdivide_simple(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Subdivide Simple";
+       ot->idname= "ARMATURE_OT_subdivide_simple";
+       
+       /* api callbacks */
+       ot->exec = armature_subdivide_exec;
+       ot->poll = ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+void ARMATURE_OT_subdivide_multi(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Subdivide Multi";
+       ot->idname= "ARMATURE_OT_subdivide_multi";
+       
+       /* api callbacks */
+       ot->exec = armature_subdivide_exec;
+       ot->poll = ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* Properties */
+       RNA_def_int(ot->srna, "number_cuts", 2, 1, 10, "Number of Cuts", "", 1, INT_MAX);
+}
+
+
+
+static int armature_subdivs_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       uiPopupMenu *pup;
+       uiLayout *layout;
+
+       pup= uiPupMenuBegin(C, "Subdivision Type", 0);
+       layout= uiPupMenuLayout(pup);
+       uiItemsEnumO(layout, "ARMATURE_OT_subdivs", "type");
+       uiPupMenuEnd(C, pup);
+       
+       return OPERATOR_CANCELLED;
+}
+
+static int armature_subdivs_exec(bContext *C, wmOperator *op)
+{      
+       switch (RNA_int_get(op->ptr, "type"))
+       {
+               case 0: /* simple */
+                       RNA_int_set(op->ptr, "number_cuts", 1);
+                       armature_subdivide_exec(C, op);
+                       break;
+               case 1: /* multi */
+                       armature_subdivide_exec(C, op);
+                       break;
+       }
+       
+       return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_subdivs(wmOperatorType *ot)
+{
+       static EnumPropertyItem type_items[]= {
+               {0, "SIMPLE", 0, "Simple", ""},
+               {1, "MULTI", 0, "Multi", ""},
+               {0, NULL, 0, NULL, NULL}};
+
+       /* identifiers */
+       ot->name= "subdivs";
+       ot->idname= "ARMATURE_OT_subdivs";
+       
+       /* api callbacks */
+       ot->invoke= armature_subdivs_invoke;
+       ot->exec= armature_subdivs_exec;
+       
+       ot->poll= ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
+       
+       /* this is temp, the ops are different, but they are called from subdivs, so all the possible props should be here as well*/
+       RNA_def_int(ot->srna, "number_cuts", 2, 1, 10, "Number of Cuts", "", 1, INT_MAX); 
+}
+
+/* ----------- */
+
+/* Switch Direction operator:
+ * Currently, this does not use context loops, as context loops do not make it
+ * easy to retrieve any hierarchial/chain relationships which are necessary for
+ * this to be done easily.
+ */
+
+static int armature_switch_direction_exec(bContext *C, wmOperator *op) 
+{
+       Object *ob= CTX_data_edit_object(C);
+       bArmature *arm= (bArmature *)ob->data;
+       ListBase chains = {NULL, NULL};
+       LinkData *chain;
+       
+       /* get chains of bones (ends on chains) */
+       chains_find_tips(arm->edbo, &chains);
+       if (chains.first == NULL) return OPERATOR_CANCELLED;
+       
+       /* loop over chains, only considering selected and visible bones */
+       for (chain= chains.first; chain; chain= chain->next) {
+               EditBone *ebo, *child=NULL, *parent=NULL;
+               
+               /* loop over bones in chain */
+               for (ebo= chain->data; ebo; ebo= parent) {
+                       /* parent is this bone's original parent
+                        *      - we store this, as the next bone that is checked is this one
+                        *        but the value of ebo->parent may change here...
+                        */
+                       parent= ebo->parent;
+                       
+                       /* only if selected and editable */
+                       if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {                           
                                /* swap head and tail coordinates */
                                SWAP(float, ebo->head[0], ebo->tail[0]);
                                SWAP(float, ebo->head[1], ebo->tail[1]);
@@ -3283,23 +3574,428 @@ void switch_direction_armature (Scene *scene)
                                        ebo->parent= NULL;
                                        ebo->flag &= ~BONE_CONNECTED;
                                }
-                               
-                               /* get next bones
-                                *      - child will become new parent of next bone (not swapping occurred, 
-                                *        so set to NULL to prevent infinite-loop)
-                                */
-                               child= NULL;
+                               
+                               /* get next bones
+                                *      - child will become new parent of next bone (not swapping occurred, 
+                                *        so set to NULL to prevent infinite-loop)
+                                */
+                               child= NULL;
+                       }
+               }
+       }
+       
+       /* free chains */
+       BLI_freelistN(&chains); 
+
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
+       
+       return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_switch_direction(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Switch Direction";
+       ot->idname= "ARMATURE_OT_switch_direction";
+       
+       /* api callbacks */
+       ot->exec = armature_switch_direction_exec;
+       ot->poll = ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+/* ***************** Parenting *********************** */
+
+/* armature parenting options */
+#define ARM_PAR_CONNECT 1
+#define ARM_PAR_OFFSET 2
+
+/* check for null, before calling! */
+static void bone_connect_to_existing_parent(EditBone *bone)
+{
+       bone->flag |= BONE_CONNECTED;
+       VECCOPY(bone->head, bone->parent->tail);
+       bone->rad_head = bone->parent->rad_tail;
+}
+
+static void bone_connect_to_new_parent(ListBase *edbo, EditBone *selbone, EditBone *actbone, short mode)
+{
+       EditBone *ebone;
+       float offset[3];
+       
+       if ((selbone->parent) && (selbone->flag & BONE_CONNECTED))
+               selbone->parent->flag &= ~(BONE_TIPSEL);
+       
+       /* make actbone the parent of selbone */
+       selbone->parent= actbone;
+       
+       /* in actbone tree we cannot have a loop */
+       for (ebone= actbone->parent; ebone; ebone= ebone->parent) {
+               if (ebone->parent==selbone) {
+                       ebone->parent= NULL;
+                       ebone->flag &= ~BONE_CONNECTED;
+               }
+       }
+       
+       if (mode == ARM_PAR_CONNECT) {  
+               /* Connected: Child bones will be moved to the parent tip */
+               selbone->flag |= BONE_CONNECTED;
+               VecSubf(offset, actbone->tail, selbone->head);
+               
+               VECCOPY(selbone->head, actbone->tail);
+               selbone->rad_head= actbone->rad_tail;
+               
+               VecAddf(selbone->tail, selbone->tail, offset);
+               
+               /* offset for all its children */
+               for (ebone = edbo->first; ebone; ebone=ebone->next) {
+                       EditBone *par;
+                       
+                       for (par= ebone->parent; par; par= par->parent) {
+                               if (par==selbone) {
+                                       VecAddf(ebone->head, ebone->head, offset);
+                                       VecAddf(ebone->tail, ebone->tail, offset);
+                                       break;
+                               }
+                       }
+               }
+       }
+       else {
+               /* Offset: Child bones will retain their distance from the parent tip */
+               selbone->flag &= ~BONE_CONNECTED;
+       }
+}
+
+static EnumPropertyItem prop_editarm_make_parent_types[] = {
+       {ARM_PAR_CONNECT, "CONNECTED", 0, "Connected", ""},
+       {ARM_PAR_OFFSET, "OFFSET", 0, "Keep Offset", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+static int armature_parent_set_exec(bContext *C, wmOperator *op) 
+{
+       Object *ob= CTX_data_edit_object(C);
+       bArmature *arm= (bArmature *)ob->data;
+       EditBone *actbone = CTX_data_active_bone(C);
+       EditBone *actmirb = NULL;
+       short val = RNA_enum_get(op->ptr, "type");
+       
+       /* there must be an active bone */
+       if (actbone == NULL) {
+               BKE_report(op->reports, RPT_ERROR, "Operation requires an Active Bone");
+               return OPERATOR_CANCELLED;
+       }
+       else if (arm->flag & ARM_MIRROR_EDIT) {
+               /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
+                * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone 
+                *      (i.e.  selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
+                *      This is useful for arm-chains, for example parenting lower arm to upper arm
+                * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
+                *      then just use actbone. Useful when doing upper arm to spine.
+                */
+               actmirb= ED_armature_bone_get_mirrored(arm->edbo, actbone);
+               if (actmirb == NULL) 
+                       actmirb= actbone;
+       }
+       
+       /* if there is only 1 selected bone, we assume that that is the active bone, 
+        * since a user will need to have clicked on a bone (thus selecting it) to make it active
+        */
+       if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
+               /* When only the active bone is selected, and it has a parent,
+                * connect it to the parent, as that is the only possible outcome. 
+                */
+               if (actbone->parent) {
+                       bone_connect_to_existing_parent(actbone);
+                       
+                       if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
+                               bone_connect_to_existing_parent(actmirb);
+               }
+       }
+       else {
+               /* Parent 'selected' bones to the active one
+                * - the context iterator contains both selected bones and their mirrored copies,
+                *   so we assume that unselected bones are mirrored copies of some selected bone
+                * - since the active one (and/or its mirror) will also be selected, we also need 
+                *      to check that we are not trying to opearate on them, since such an operation 
+                *      would cause errors
+                */
+               
+               /* parent selected bones to the active one */
+               CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) {
+                       if (ELEM(ebone, actbone, actmirb) == 0) {
+                               if (ebone->flag & BONE_SELECTED) 
+                                       bone_connect_to_new_parent(arm->edbo, ebone, actbone, val);
+                               else
+                                       bone_connect_to_new_parent(arm->edbo, ebone, actmirb, val);
+                       }
+               }
+               CTX_DATA_END;
+       }
+       
+
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
+       
+       return OPERATOR_FINISHED;
+}
+
+static int armature_parent_set_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       EditBone *actbone = CTX_data_active_bone(C);
+       uiPopupMenu *pup= uiPupMenuBegin(C, "Make Parent ", 0);
+       uiLayout *layout= uiPupMenuLayout(pup);
+       int allchildbones = 0;
+       
+       CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) {
+               if (ebone != actbone) {
+                       if (ebone->parent != actbone) allchildbones= 1; 
+               }       
+       }
+       CTX_DATA_END;
+
+       uiItemEnumO(layout, NULL, 0, "ARMATURE_OT_parent_set", "type", ARM_PAR_CONNECT);
+       
+       /* ob becomes parent, make the associated menus */
+       if (allchildbones)
+               uiItemEnumO(layout, NULL, 0, "ARMATURE_OT_parent_set", "type", ARM_PAR_OFFSET); 
+               
+       uiPupMenuEnd(C, pup);
+       
+       return OPERATOR_CANCELLED;
+}
+
+void ARMATURE_OT_parent_set(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Make Parent";
+       ot->idname= "ARMATURE_OT_parent_set";
+       
+       /* api callbacks */
+       ot->invoke = armature_parent_set_invoke;
+       ot->exec = armature_parent_set_exec;
+       ot->poll = ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       RNA_def_enum(ot->srna, "type", prop_editarm_make_parent_types, 0, "ParentType", "Type of parenting");
+}
+
+static EnumPropertyItem prop_editarm_clear_parent_types[] = {
+       {1, "CLEAR", 0, "Clear Parent", ""},
+       {2, "DISCONNECT", 0, "Disconnect Bone", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+static void editbone_clear_parent(EditBone *ebone, int mode)
+{
+       if (ebone->parent) {
+               /* for nice selection */
+               ebone->parent->flag &= ~(BONE_TIPSEL);
+       }
+       
+       if (mode==1) ebone->parent= NULL;
+       ebone->flag &= ~BONE_CONNECTED;
+}
+
+static int armature_parent_clear_exec(bContext *C, wmOperator *op) 
+{
+       Object *ob= CTX_data_edit_object(C);
+       bArmature *arm= (bArmature *)ob->data;
+       int val = RNA_enum_get(op->ptr, "type");
+               
+       CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) {
+               editbone_clear_parent(ebone, val);
+       }
+       CTX_DATA_END;
+       
+       armature_sync_selection(arm->edbo);
+
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT, ob);
+       
+       return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_parent_clear(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Clear Parent";
+       ot->idname= "ARMATURE_OT_parent_clear";
+       
+       /* api callbacks */
+       ot->invoke = WM_menu_invoke;
+       ot->exec = armature_parent_clear_exec;
+       ot->poll = ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       RNA_def_enum(ot->srna, "type", prop_editarm_clear_parent_types, 0, "ClearType", "What way to clear parenting");
+}
+
+/* ****************  Selections  ******************/
+
+static int armature_select_invert_exec(bContext *C, wmOperator *op)
+{
+       /*      Set the flags */
+       CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) {
+               /* select bone */
+               ebone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+               ebone->flag &= ~BONE_ACTIVE;
+       }
+       CTX_DATA_END;   
+
+       WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, NULL);
+       
+       return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_select_invert(wmOperatorType *ot)
+{
+       
+       /* identifiers */
+       ot->name= "Invert Selection";
+       ot->idname= "ARMATURE_OT_select_invert";
+       
+       /* api callbacks */
+       ot->exec= armature_select_invert_exec;
+       ot->poll= ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+}
+static int armature_de_select_all_exec(bContext *C, wmOperator *op)
+{
+       int     sel=1;
+
+       /*      Determine if there are any selected bones
+       And therefore whether we are selecting or deselecting */
+       if (CTX_DATA_COUNT(C, selected_bones) > 0)      sel=0;
+       
+       /*      Set the flags */
+       CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) {
+               if (sel==1) {
+                       /* select bone */
+                       ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+                       if(ebone->parent)
+                               ebone->parent->flag |= (BONE_TIPSEL);
+               }
+               else {
+                       /* deselect bone */
+                       ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL | BONE_ACTIVE);
+               }
+       }
+       CTX_DATA_END;   
+
+       WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, NULL);
+       
+       return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_select_all_toggle(wmOperatorType *ot)
+{
+       
+       /* identifiers */
+       ot->name= "deselect all editbone";
+       ot->idname= "ARMATURE_OT_select_all_toggle";
+       
+       /* api callbacks */
+       ot->exec= armature_de_select_all_exec;
+       ot->poll= ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+}
+
+/* ********************* select hierarchy operator ************** */
+
+static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
+{
+       Object *obedit= CTX_data_edit_object(C);
+       Object *ob;
+       bArmature *arm;
+       EditBone *curbone, *pabone, *chbone;
+       int direction = RNA_enum_get(op->ptr, "direction");
+       int add_to_sel = RNA_boolean_get(op->ptr, "extend");
+       
+       ob= obedit;
+       arm= (bArmature *)ob->data;
+       
+       for (curbone= arm->edbo->first; curbone; curbone= curbone->next) {
+               if (EBONE_VISIBLE(arm, curbone)) {
+                       if (curbone->flag & (BONE_ACTIVE)) {
+                               if (direction == BONE_SELECT_PARENT) {
+                                       if (curbone->parent == NULL) continue;
+                                       else pabone = curbone->parent;
+                                       
+                                       if (EBONE_VISIBLE(arm, pabone)) {
+                                               pabone->flag |= (BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+                                               if (pabone->parent)     pabone->parent->flag |= BONE_TIPSEL;
+                                               
+                                               if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+                                               curbone->flag &= ~BONE_ACTIVE;
+                                               break;
+                                       }
+                                       
+                               } 
+                               else { // BONE_SELECT_CHILD
+                                       chbone = editbone_get_child(arm, curbone, 1);
+                                       if (chbone == NULL) continue;
+                                       
+                                       if (EBONE_VISIBLE(arm, chbone)) {
+                                               chbone->flag |= (BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+                                               
+                                               if (!add_to_sel) {
+                                                       curbone->flag &= ~(BONE_SELECTED|BONE_ROOTSEL);
+                                                       if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
+                                               }
+                                               curbone->flag &= ~BONE_ACTIVE;
+                                               break;
+                                       }
+                               }
                        }
                }
        }
        
-       /* free chains */
-       BLI_freelistN(&chains);
+       armature_sync_selection(arm->edbo);
+       
+       WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob);
        
-       BIF_undo_push("Switch Direction");
+       return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
+{
+       static EnumPropertyItem direction_items[]= {
+       {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
+       {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
+       {0, NULL, 0, NULL, NULL}
+       };
+       
+       /* identifiers */
+       ot->name= "Select Hierarchy";
+       ot->idname= "ARMATURE_OT_select_hierarchy";
+       
+       /* api callbacks */
+       ot->exec= armature_select_hierarchy_exec;
+       ot->poll= ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* props */
+       RNA_def_enum(ot->srna, "direction", direction_items,
+                    BONE_SELECT_PARENT, "Direction", "");
+       RNA_def_boolean(ot->srna, "extend", 0, "Add to Selection", "");
 }
 
-/* editbone alignment */
+/* ***************** EditBone Alignment ********************* */
 
 /* helper to fix a ebone position if its parent has moved due to alignment*/
 static void fix_connected_bone(EditBone *ebone)
@@ -3351,159 +4047,90 @@ static void bone_align_to_bone(ListBase *edbo, EditBone *selbone, EditBone *actb
        return;
 }
 
-void align_selected_bones(Scene *scene)
+static int armature_align_bones_exec(bContext *C, wmOperator *op) 
 {
-       Object *obedit= scene->obedit; // XXX get from context
-       bArmature *arm= obedit->data;
-       EditBone *actbone, *ebone, *selbone;
-       EditBone *flipbone, *flippar;
-       short allchildbones= 0, foundselbone= 0;
-       
-       /* find active bone to align to */
-       for (actbone = arm->edbo->first; actbone; actbone=actbone->next) {
-               if (arm->layer & actbone->layer) {
-                       if (actbone->flag & BONE_ACTIVE)
-                               break;
-               }
-       }
+       Object *ob= CTX_data_edit_object(C);
+       bArmature *arm= (bArmature *)ob->data;
+       EditBone *actbone= CTX_data_active_bone(C);
+       EditBone *actmirb= NULL;
+       
+       /* there must be an active bone */
        if (actbone == NULL) {
-               error("Needs an active bone");
-               return; 
-       }
-
-       /* find selected bones */
-       for (ebone = arm->edbo->first; ebone; ebone=ebone->next) {
-               if (arm->layer & ebone->layer) {
-                       if ((ebone->flag & BONE_SELECTED) && (ebone != actbone)) {
-                               foundselbone++;
-                               if (ebone->parent != actbone) allchildbones= 1; 
-                       }       
-               }
-       }
-       /* abort if no selected bones, and active bone doesn't have a parent to work with instead */
-       if (foundselbone==0 && actbone->parent==NULL) {
-               error("Need selected bone(s)");
-               return;
+               BKE_report(op->reports, RPT_ERROR, "Operation requires an Active Bone");
+               return OPERATOR_CANCELLED;
+       }
+       else if (arm->flag & ARM_MIRROR_EDIT) {
+               /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
+                * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone 
+                *      (i.e.  selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
+                *      This is useful for arm-chains, for example parenting lower arm to upper arm
+                * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
+                *      then just use actbone. Useful when doing upper arm to spine.
+                */
+               actmirb= ED_armature_bone_get_mirrored(arm->edbo, actbone);
+               if (actmirb == NULL) 
+                       actmirb= actbone;
        }
        
-       if (foundselbone==0 && actbone->parent) {
+       /* if there is only 1 selected bone, we assume that that is the active bone, 
+        * since a user will need to have clicked on a bone (thus selecting it) to make it active
+        */
+       if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
                /* When only the active bone is selected, and it has a parent,
                 * align it to the parent, as that is the only possible outcome. 
                 */
-               bone_align_to_bone(arm->edbo, actbone, actbone->parent);
-               
-               if (arm->flag & ARM_MIRROR_EDIT) {
-                       flipbone = armature_bone_get_mirrored(arm->edbo, actbone);
-                       if (flipbone)
-                               bone_align_to_bone(arm->edbo, flipbone, flipbone->parent);
+               if (actbone->parent) {
+                       bone_align_to_bone(arm->edbo, actbone, actbone->parent);
+                       
+                       if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
+                               bone_align_to_bone(arm->edbo, actmirb, actmirb->parent);
                }
        }
        else {
-               /* loop through all editbones, aligning all selected bones to the active bone */
-               for (selbone = arm->edbo->first; selbone; selbone=selbone->next) {
-                       if (arm->layer & selbone->layer) {
-                               if ((selbone->flag & BONE_SELECTED) && (selbone!=actbone)) {
-                                       /* align selbone to actbone */
-                                       bone_align_to_bone(arm->edbo, selbone, actbone);
-                                       
-                                       if (arm->flag & ARM_MIRROR_EDIT) {
-                                               /* - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone 
-                                                *      (i.e.  selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
-                                                *      This is useful for arm-chains, for example parenting lower arm to upper arm
-                                                * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
-                                                *      then just use actbone. Useful when doing upper arm to spine.
-                                                */
-                                               flipbone = armature_bone_get_mirrored(arm->edbo, selbone);
-                                               flippar = armature_bone_get_mirrored(arm->edbo, actbone);
-                                               
-                                               if (flipbone) {
-                                                       if (flippar)
-                                                               bone_align_to_bone(arm->edbo, flipbone, flippar);
-                                                       else
-                                                               bone_align_to_bone(arm->edbo, flipbone, actbone);
-                                               }
-                                       }
-                               }
+               /* Align 'selected' bones to the active one
+                * - the context iterator contains both selected bones and their mirrored copies,
+                *   so we assume that unselected bones are mirrored copies of some selected bone
+                * - since the active one (and/or its mirror) will also be selected, we also need 
+                *      to check that we are not trying to opearate on them, since such an operation 
+                *      would cause errors
+                */
+               
+               /* align selected bones to the active one */
+               CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) {
+                       if (ELEM(ebone, actbone, actmirb) == 0) {
+                               if (ebone->flag & BONE_SELECTED)
+                                       bone_align_to_bone(arm->edbo, ebone, actbone);
+                               else
+                                       bone_align_to_bone(arm->edbo, ebone, actmirb);
                        }
                }
+               CTX_DATA_END;
        }
+       
 
-       countall(); /* checks selection */
-       BIF_undo_push("Align bones");
-
-       return;
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
+       
+       return OPERATOR_FINISHED;
 }
 
-/* ***************** Pose tools ********************* */
-
-void clear_armature(Scene *scene, Object *ob, char mode)
+void ARMATURE_OT_bones_align(wmOperatorType *ot)
 {
-       bPoseChannel *pchan;
-       bArmature       *arm= ob->data;
+       /* identifiers */
+       ot->name= "Align Bones";
+       ot->idname= "ARMATURE_OT_bones_align";
        
-       /* only clear those channels that are not locked */
-       for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-               if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
-                       if (arm->layer & pchan->bone->layer) {
-                               switch (mode) {
-                                       case 'r':
-                                               if (pchan->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ)) {
-                                                       float eul[3], oldeul[3], quat1[4];
-                                                       
-                                                       QUATCOPY(quat1, pchan->quat);
-                                                       QuatToEul(pchan->quat, oldeul);
-                                                       eul[0]= eul[1]= eul[2]= 0.0f;
-                                                       
-                                                       if (pchan->protectflag & OB_LOCK_ROTX)
-                                                               eul[0]= oldeul[0];
-                                                       if (pchan->protectflag & OB_LOCK_ROTY)
-                                                               eul[1]= oldeul[1];
-                                                       if (pchan->protectflag & OB_LOCK_ROTZ)
-                                                               eul[2]= oldeul[2];
-                                                       
-                                                       EulToQuat(eul, pchan->quat);
-                                                       /* quaternions flip w sign to accumulate rotations correctly */
-                                                       if ((quat1[0]<0.0f && pchan->quat[0]>0.0f) || (quat1[0]>0.0f && pchan->quat[0]<0.0f)) {
-                                                               QuatMulf(pchan->quat, -1.0f);
-                                                       }
-                                               }                                               
-                                               else { 
-                                                       pchan->quat[1]=pchan->quat[2]=pchan->quat[3]=0.0F; 
-                                                       pchan->quat[0]=1.0F;
-                                               }
-                                               break;
-                                       case 'g':
-                                               if ((pchan->protectflag & OB_LOCK_LOCX)==0)
-                                                       pchan->loc[0]= 0.0f;
-                                               if ((pchan->protectflag & OB_LOCK_LOCY)==0)
-                                                       pchan->loc[1]= 0.0f;
-                                               if ((pchan->protectflag & OB_LOCK_LOCZ)==0)
-                                                       pchan->loc[2]= 0.0f;
-                                               break;
-                                       case 's':
-                                               if ((pchan->protectflag & OB_LOCK_SCALEX)==0)
-                                                       pchan->size[0]= 1.0f;
-                                               if ((pchan->protectflag & OB_LOCK_SCALEY)==0)
-                                                       pchan->size[1]= 1.0f;
-                                               if ((pchan->protectflag & OB_LOCK_SCALEZ)==0)
-                                                       pchan->size[2]= 1.0f;
-                                               break;
-                                               
-                               }
-                               
-                               /* the current values from IPO's may not be zero, so tag as unkeyed */
-                               pchan->bone->flag |= BONE_UNKEYED;
-                       }
-               }
-       }
+       /* api callbacks */
+       ot->invoke = WM_operator_confirm;
+       ot->exec = armature_align_bones_exec;
+       ot->poll = ED_operator_editarmature;
        
-       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-       /* no update for this object, this will execute the action again */
-       /* is weak... like for ipo editing which uses ctime now... */
-       where_is_pose (scene, ob);
-       ob->recalc= 0;
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
+/* ***************** Pose tools ********************* */
+
 /* helper for function below */
 static int clear_active_flag(Object *ob, Bone *bone, void *data) 
 {
@@ -3512,6 +4139,7 @@ static int clear_active_flag(Object *ob, Bone *bone, void *data)
 }
 
 
+// XXX bone_looper is only to be used when we want to access settings (i.e. editability/visibility/selected) that context doesn't offer 
 static int bone_looper(Object *ob, Bone *bone, void *data,
                                int (*bone_func)(Object *, Bone *, void *)) 
 {
@@ -3540,12 +4168,11 @@ static int bone_looper(Object *ob, Bone *bone, void *data,
 }
 
 /* called from editview.c, for mode-less pose selection */
-/* assumes scene obact and basact... XXX */
-int do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits)
+/* assumes scene obact and basact is still on old situation */
+int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits, short extend)
 {
        Object *ob= base->object;
        Bone *nearBone;
-       int shift= 0; // XXX
        
        if (!ob || !ob->pose) return 0;
 
@@ -3555,10 +4182,12 @@ int do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short h
                bArmature *arm= ob->data;
                
                /* since we do unified select, we don't shift+select a bone if the armature object was not active yet */
-               if (!(shift) || (base != scene->basact)) {
+               if (!(extend) || (base != scene->basact)) {
                        ED_pose_deselectall(ob, 0, 0);
                        nearBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
-                       select_actionchannel_by_name(ob->action, nearBone->name, 1);
+                       
+                               // XXX old cruft! use notifiers instead
+                       //select_actionchannel_by_name(ob->action, nearBone->name, 1);
                }
                else {
                        if (nearBone->flag & BONE_SELECTED) {
@@ -3569,22 +4198,26 @@ int do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short h
                                }
                                else {
                                        nearBone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
-                                       select_actionchannel_by_name(ob->action, nearBone->name, 0);
+                                       
+                                               // XXX old cruft! use notifiers instead
+                                       //select_actionchannel_by_name(ob->action, nearBone->name, 0);
                                }
                        }
                        else {
                                bone_looper(ob, arm->bonebase.first, NULL, clear_active_flag);
                                
                                nearBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
-                               select_actionchannel_by_name(ob->action, nearBone->name, 1);
+                               
+                                       // XXX old cruft! use notifiers instead
+                               //select_actionchannel_by_name(ob->action, nearBone->name, 1);
                        }
                }
                
                /* in weightpaint we select the associated vertex group too */
                if (G.f & G_WEIGHTPAINT) {
                        if (nearBone->flag & BONE_ACTIVE) {
-                               vertexgroup_select_by_name(ob, nearBone->name);
-                               DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+                               vertexgroup_select_by_name(OBACT, nearBone->name);
+                               DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA);
                        }
                }
                
@@ -3637,17 +4270,7 @@ void ED_pose_deselectall (Object *ob, int test, int doundo)
                }
        }
        
-       /* action editor */
-       if (test == 3) {
-               deselect_actionchannels(ob->action, 2); /* inverts selection */
-       }
-       else {
-               deselect_actionchannels(ob->action, 0); /* deselects for sure */
-               if (selectmode == 1)
-                       deselect_actionchannels(ob->action, 1); /* swaps */
-       }
-       
-       countall();
+       //countall(); // XXX need an equivalent to this...
        
        if (doundo) {
                if (selectmode==1) BIF_undo_push("Select All");
@@ -3837,7 +4460,7 @@ void add_verts_to_dgroups(Scene *scene, Object *ob, Object *par, int heat, int m
         * when parenting, or simply the original mesh coords.
         */
 
-       bArmature *arm= ob->data;
+       bArmature *arm= par->data;
        Bone **bonelist, *bone;
        bDeformGroup **dgrouplist, **dgroupflip;
        bDeformGroup *dgroup, *curdg;
@@ -3950,89 +4573,366 @@ void add_verts_to_dgroups(Scene *scene, Object *ob, Object *par, int heat, int m
     mesh = (Mesh*)ob->data;
        verts = MEM_callocN(mesh->totvert*sizeof(*verts), "closestboneverts");
 
-       if (wpmode) {
-               /* if in weight paint mode, use final verts from derivedmesh */
-               DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
-               
-               if (dm->foreachMappedVert) {
-                       dm->foreachMappedVert(dm, add_vgroups__mapFunc, (void*)verts);
-                       vertsfilled = 1;
-               }
-               
-               dm->release(dm);
-       }
-       else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
-               /* is subsurf on? Lets use the verts on the limit surface then.
-                * = same amount of vertices as mesh, but vertices  moved to the
-                * subsurfed position, like for 'optimal'. */
-               subsurf_calculate_limit_positions(mesh, verts);
-               vertsfilled = 1;
-       }
+       if (wpmode) {
+               /* if in weight paint mode, use final verts from derivedmesh */
+               DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+               
+               if (dm->foreachMappedVert) {
+                       dm->foreachMappedVert(dm, add_vgroups__mapFunc, (void*)verts);
+                       vertsfilled = 1;
+               }
+               
+               dm->release(dm);
+       }
+       else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
+               /* is subsurf on? Lets use the verts on the limit surface then.
+                * = same amount of vertices as mesh, but vertices  moved to the
+                * subsurfed position, like for 'optimal'. */
+               subsurf_calculate_limit_positions(mesh, verts);
+               vertsfilled = 1;
+       }
+
+       /* transform verts to global space */
+       for (i=0; i < mesh->totvert; i++) {
+               if (!vertsfilled)
+                       VECCOPY(verts[i], mesh->mvert[i].co)
+               Mat4MulVecfl(ob->obmat, verts[i]);
+       }
+
+       /* compute the weights based on gathered vertices and bones */
+       if (heat) {
+               heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip,
+                       root, tip, selected);
+       }
+       else {
+               envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist,
+                       dgroupflip, root, tip, selected, Mat4ToScalef(par->obmat));
+       }
+       
+    /* free the memory allocated */
+    MEM_freeN(bonelist);
+    MEM_freeN(dgrouplist);
+       MEM_freeN(dgroupflip);
+       MEM_freeN(root);
+       MEM_freeN(tip);
+       MEM_freeN(selected);
+       MEM_freeN(verts);
+}
+
+void create_vgroups_from_armature(Scene *scene, Object *ob, Object *par)
+{
+       /* Lets try to create some vertex groups 
+        * based on the bones of the parent armature.
+        */
+       bArmature *arm= par->data;
+       short mode;
+
+       /* Prompt the user on whether/how they want the vertex groups
+        * added to the child mesh */
+    mode= pupmenu("Create Vertex Groups? %t|"
+                                 "Don't Create Groups %x1|"
+                                 "Name Groups %x2|"
+                  "Create From Envelopes %x3|"
+                                 "Create From Bone Heat %x4|");
+       
+       mode= 3; // XXX
+       
+       switch (mode) {
+       case 2:
+               /* Traverse the bone list, trying to create empty vertex 
+                * groups cooresponding to the bone.
+                */
+               bone_looper(ob, arm->bonebase.first, NULL,
+                                       add_defgroup_unique_bone);
+               if (ob->type == OB_MESH)
+                       create_dverts(ob->data);
+               
+               break;
+       
+       case 3:
+       case 4:
+               /* Traverse the bone list, trying to create vertex groups 
+                * that are populated with the vertices for which the
+                * bone is closest.
+                */
+               add_verts_to_dgroups(scene, ob, par, (mode == 4), 0);
+               break;
+       }
+} 
+/* ************* Clear Pose *****************************/
+
+static int pose_clear_scale_exec(bContext *C, wmOperator *op) 
+{
+       Scene *scene = CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       
+       /* only clear those channels that are not locked */
+       CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans) {
+               if ((pchan->protectflag & OB_LOCK_SCALEX)==0)
+                       pchan->size[0]= 1.0f;
+               if ((pchan->protectflag & OB_LOCK_SCALEY)==0)
+                       pchan->size[1]= 1.0f;
+               if ((pchan->protectflag & OB_LOCK_SCALEZ)==0)
+                       pchan->size[2]= 1.0f;
+                       
+               /* the current values from IPO's may not be zero, so tag as unkeyed */
+               //pchan->bone->flag |= BONE_UNKEYED;
+       }
+       CTX_DATA_END;
+       
+       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
+       
+       return OPERATOR_FINISHED;
+}
+
+void POSE_OT_scale_clear(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Clear Pose Scale";
+       ot->idname= "POSE_OT_scale_clear";
+       
+       /* api callbacks */
+       ot->invoke = WM_operator_confirm;
+       ot->exec = pose_clear_scale_exec;
+       ot->poll = ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int pose_clear_loc_exec(bContext *C, wmOperator *op) 
+{
+       Scene *scene = CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       
+       /* only clear those channels that are not locked */
+       CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans) {
+               if ((pchan->protectflag & OB_LOCK_LOCX)==0)
+                       pchan->loc[0]= 0.0f;
+               if ((pchan->protectflag & OB_LOCK_LOCY)==0)
+                       pchan->loc[1]= 0.0f;
+               if ((pchan->protectflag & OB_LOCK_LOCZ)==0)
+                       pchan->loc[2]= 0.0f;
+                       
+               /* the current values from IPO's may not be zero, so tag as unkeyed */
+               //pchan->bone->flag |= BONE_UNKEYED;
+       }
+       CTX_DATA_END;
+       
+       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
+       
+       return OPERATOR_FINISHED;
+}
+
+void POSE_OT_loc_clear(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Clear Pose Location";
+       ot->idname= "POSE_OT_loc_clear";
+       
+       /* api callbacks */
+       ot->invoke = WM_operator_confirm;
+       ot->exec = pose_clear_loc_exec;
+       ot->poll = ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int pose_clear_rot_exec(bContext *C, wmOperator *op) 
+{
+       Scene *scene = CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       
+       /* only clear those channels that are not locked */
+       CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans) {
+               if (pchan->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ)) {
+                       float eul[3], oldeul[3], quat1[4];
+                       
+                       if (pchan->rotmode == PCHAN_ROT_QUAT) {
+                               QUATCOPY(quat1, pchan->quat);
+                               QuatToEul(pchan->quat, oldeul);
+                       }
+                       else {
+                               VECCOPY(oldeul, pchan->eul);
+                       }
+                       eul[0]= eul[1]= eul[2]= 0.0f;
+                       
+                       if (pchan->protectflag & OB_LOCK_ROTX)
+                               eul[0]= oldeul[0];
+                       if (pchan->protectflag & OB_LOCK_ROTY)
+                               eul[1]= oldeul[1];
+                       if (pchan->protectflag & OB_LOCK_ROTZ)
+                               eul[2]= oldeul[2];
+                       
+                       if (pchan->rotmode == PCHAN_ROT_QUAT) {
+                               EulToQuat(eul, pchan->quat);
+                               /* quaternions flip w sign to accumulate rotations correctly */
+                               if ((quat1[0]<0.0f && pchan->quat[0]>0.0f) || (quat1[0]>0.0f && pchan->quat[0]<0.0f)) {
+                                       QuatMulf(pchan->quat, -1.0f);
+                               }
+                       }
+                       else {
+                               VECCOPY(pchan->eul, eul);
+                       }
+               }                                               
+               else { 
+                       if (pchan->rotmode == PCHAN_ROT_QUAT) {
+                               pchan->quat[1]=pchan->quat[2]=pchan->quat[3]= 0.0f; 
+                               pchan->quat[0]= 1.0f;
+                       }
+                       else {
+                               pchan->eul[0]= pchan->eul[1]= pchan->eul[2]= 0.0f;
+                       }
+               }
+               
+               /* the current values from IPO's may not be zero, so tag as unkeyed */
+               //pchan->bone->flag |= BONE_UNKEYED;
+       }
+       CTX_DATA_END;
+       
+       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
+       
+       return OPERATOR_FINISHED;
+}
+
+void POSE_OT_rot_clear(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Clear Pose Rotation";
+       ot->idname= "POSE_OT_rot_clear";
+       
+       /* api callbacks */
+       ot->invoke = WM_operator_confirm;
+       ot->exec = pose_clear_rot_exec;
+       ot->poll = ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+}
+
+/* ***************** selections ********************** */
+
+static int pose_select_invert_exec(bContext *C, wmOperator *op)
+{
+       
+       /*      Set the flags */
+       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pchans) {
+               pchan->bone->flag ^= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+               pchan->bone->flag &= ~BONE_ACTIVE;
+       }       
+       CTX_DATA_END;
+       
+       WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, NULL);
+       
+       return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_invert(wmOperatorType *ot)
+{
+       
+       /* identifiers */
+       ot->name= "Invert Selection";
+       ot->idname= "POSE_OT_select_invert";
+       
+       /* api callbacks */
+       ot->exec= pose_select_invert_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+}
+static int pose_de_select_all_exec(bContext *C, wmOperator *op)
+{
+       int     sel=1;
 
-       /* transform verts to global space */
-       for (i=0; i < mesh->totvert; i++) {
-               if (!vertsfilled)
-                       VECCOPY(verts[i], mesh->mvert[i].co)
-               Mat4MulVecfl(ob->obmat, verts[i]);
+       /*      Determine if there are any selected bones
+       And therefore whether we are selecting or deselecting */
+       if (CTX_DATA_COUNT(C, selected_pchans) > 0)     sel=0;
+       
+       /*      Set the flags */
+       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pchans) {
+               /* select pchan */
+               if (sel==0) pchan->bone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
+               else pchan->bone->flag |= BONE_SELECTED;
        }
+       CTX_DATA_END;   
 
-       /* compute the weights based on gathered vertices and bones */
-       if (heat) {
-               heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip,
-                       root, tip, selected);
+       WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, NULL);
+       
+       return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_all_toggle(wmOperatorType *ot)
+{
+       
+       /* identifiers */
+       ot->name= "deselect all bones";
+       ot->idname= "POSE_OT_select_all_toggle";
+       
+       /* api callbacks */
+       ot->exec= pose_de_select_all_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+}
+
+static int pose_select_parent_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_active_object(C);
+       bPoseChannel *pchan,*parent;
+
+       /*      Determine if there is an active bone */
+       pchan=CTX_data_active_pchan(C);
+       if (pchan) {
+               parent=pchan->parent;
+               if ((parent) && !(parent->bone->flag & BONE_HIDDEN_P)) {
+                       parent->bone->flag |= BONE_SELECTED;
+                       parent->bone->flag |= BONE_ACTIVE;
+                       pchan->bone->flag &= ~BONE_ACTIVE;
+               }
+               else {
+                       return OPERATOR_CANCELLED;
+               }
        }
        else {
-               envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist,
-                       dgroupflip, root, tip, selected, Mat4ToScalef(par->obmat));
+               return OPERATOR_CANCELLED;
        }
+
+       WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob);
        
-    /* free the memory allocated */
-    MEM_freeN(bonelist);
-    MEM_freeN(dgrouplist);
-       MEM_freeN(dgroupflip);
-       MEM_freeN(root);
-       MEM_freeN(tip);
-       MEM_freeN(selected);
-       MEM_freeN(verts);
+       return OPERATOR_FINISHED;
 }
 
-void create_vgroups_from_armature(Scene *scene, Object *ob, Object *par)
+void POSE_OT_select_parent(wmOperatorType *ot)
 {
-       /* Lets try to create some vertex groups 
-        * based on the bones of the parent armature.
-        */
-       bArmature *arm= ob->data;
-       short mode;
+       /* identifiers */
+       ot->name= "select parent bone";
+       ot->idname= "POSE_OT_select_parent";
 
-       /* Prompt the user on whether/how they want the vertex groups
-        * added to the child mesh */
-    mode= pupmenu("Create Vertex Groups? %t|"
-                                 "Don't Create Groups %x1|"
-                                 "Name Groups %x2|"
-                  "Create From Envelopes %x3|"
-                                 "Create From Bone Heat %x4|");
-       switch (mode) {
-       case 2:
-               /* Traverse the bone list, trying to create empty vertex 
-                * groups cooresponding to the bone.
-                */
-               bone_looper(ob, arm->bonebase.first, NULL,
-                                       add_defgroup_unique_bone);
-               if (ob->type == OB_MESH)
-                       create_dverts(ob->data);
-               
-               break;
+       /* api callbacks */
+       ot->exec= pose_select_parent_exec;
+       ot->poll= ED_operator_posemode;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
-       case 3:
-       case 4:
-               /* Traverse the bone list, trying to create vertex groups 
-                * that are populated with the vertices for which the
-                * bone is closest.
-                */
-               add_verts_to_dgroups(scene, ob, par, (mode == 4), 0);
-               break;
-       }
-} 
+}
+
+/* ************* hide/unhide pose bones ******************* */
 
 static int hide_selected_pose_bone(Object *ob, Bone *bone, void *ptr) 
 {
@@ -4047,20 +4947,6 @@ static int hide_selected_pose_bone(Object *ob, Bone *bone, void *ptr)
        return 0;
 }
 
-/* active object is armature */
-void hide_selected_pose_bones(Object *ob) 
-{
-       bArmature *arm= ob->data;
-
-       if (!arm)
-               return;
-
-       bone_looper(ob, arm->bonebase.first, NULL, 
-                               hide_selected_pose_bone);
-       
-       BIF_undo_push("Hide Bones");
-}
-
 static int hide_unselected_pose_bone(Object *ob, Bone *bone, void *ptr) 
 {
        bArmature *arm= ob->data;
@@ -4075,15 +4961,40 @@ static int hide_unselected_pose_bone(Object *ob, Bone *bone, void *ptr)
        return 0;
 }
 
-/* active object is armature */
-void hide_unselected_pose_bones(Object *ob
+/* active object is armature in posemode, poll checked */
+static int pose_hide_exec(bContext *C, wmOperator *op
 {
-       bArmature               *arm= ob->data;
+       Object *ob= CTX_data_active_object(C);
+       bArmature *arm= ob->data;
 
-       bone_looper(ob, arm->bonebase.first, NULL, 
+       if(RNA_boolean_get(op->ptr, "unselected"))
+          bone_looper(ob, arm->bonebase.first, NULL, 
                                hide_unselected_pose_bone);
+       else
+          bone_looper(ob, arm->bonebase.first, NULL, 
+                                  hide_selected_pose_bone);
+       
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob);
+       
+       return OPERATOR_FINISHED;
+}
 
-       BIF_undo_push("Hide Unselected Bone");
+void POSE_OT_hide(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Hide Selected";
+       ot->idname= "POSE_OT_hide";
+       
+       /* api callbacks */
+       ot->exec= pose_hide_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "");
 }
 
 static int show_pose_bone(Object *ob, Bone *bone, void *ptr) 
@@ -4096,21 +5007,37 @@ static int show_pose_bone(Object *ob, Bone *bone, void *ptr)
                        bone->flag |= BONE_SELECTED;
                }
        }
-
+       
        return 0;
 }
 
-/* active object is armature in posemode */
-void show_all_pose_bones(Object *ob
+/* active object is armature in posemode, poll checked */
+static int pose_reveal_exec(bContext *C, wmOperator *op
 {
-       bArmature               *arm= ob->data;
-
-       bone_looper(ob, arm->bonebase.first, NULL, 
-                               show_pose_bone);
+       Object *ob= CTX_data_active_object(C);
+       bArmature *arm= ob->data;
+       
+       bone_looper(ob, arm->bonebase.first, NULL, show_pose_bone);
+       
+       /* note, notifier might evolve */
+       WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob);
 
-       BIF_undo_push("Reveal Bones");
+       return OPERATOR_FINISHED;
 }
 
+void POSE_OT_reveal(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Reveal Selected";
+       ot->idname= "POSE_OT_reveal";
+       
+       /* api callbacks */
+       ot->exec= pose_reveal_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
 
 /* ************* RENAMING DISASTERS ************ */
 
@@ -4174,7 +5101,6 @@ static void constraint_bone_name_fix(Object *ob, ListBase *conlist, char *oldnam
 void armature_bone_rename(Object *ob, char *oldnamep, char *newnamep)
 {
        bArmature *arm= ob->data;
-       Ipo *ipo;
        char newname[MAXBONENAME];
        char oldname[MAXBONENAME];
        
@@ -4192,7 +5118,7 @@ void armature_bone_rename(Object *ob, char *oldnamep, char *newnamep)
                        
                        eBone= editbone_name_exists(arm->edbo, oldname);
                        if (eBone) {
-                               unique_editbone_name(arm->edbo, newname);
+                               unique_editbone_name(arm->edbo, newname, NULL);
                                BLI_strncpy(eBone->name, newname, MAXBONENAME);
                        }
                        else return;
@@ -4212,11 +5138,12 @@ void armature_bone_rename(Object *ob, char *oldnamep, char *newnamep)
                        /* we have the object using the armature */
                        if (arm==ob->data) {
                                Object *cob;
-                               bAction  *act;
-                               bActionChannel *achan;
-                               bActionStrip *strip;
+                               //bAction  *act;
+                               //bActionChannel *achan;
+                               //bActionStrip *strip;
                                
                                /* Rename action channel if necessary */
+#if 0 // XXX old animation system
                                act = ob->action;
                                if (act && !act->id.lib) {
                                        /*      Find the appropriate channel */
@@ -4224,6 +5151,7 @@ void armature_bone_rename(Object *ob, char *oldnamep, char *newnamep)
                                        if (achan) 
                                                BLI_strncpy(achan->name, newname, MAXBONENAME);
                                }
+#endif // XXX old animation system
                
                                /* Rename the pose channel, if it exists */
                                if (ob->pose) {
@@ -4233,6 +5161,7 @@ void armature_bone_rename(Object *ob, char *oldnamep, char *newnamep)
                                }
                                
                                /* check all nla-strips too */
+#if 0 // XXX old animation system
                                for (strip= ob->nlastrips.first; strip; strip= strip->next) {
                                        /* Rename action channel if necessary */
                                        act = strip->act;
@@ -4243,6 +5172,7 @@ void armature_bone_rename(Object *ob, char *oldnamep, char *newnamep)
                                                        BLI_strncpy(achan->name, newname, MAXBONENAME);
                                        }
                                }
+#endif // XXX old animation system
                                
                                /* Update any object constraints to use the new bone name */
                                for (cob= G.main->object.first; cob; cob= cob->id.next) {
@@ -4277,6 +5207,7 @@ void armature_bone_rename(Object *ob, char *oldnamep, char *newnamep)
                }
                
                /* do entire db - ipo's for the drivers */
+#if 0 // XXX old animation system
                for (ipo= G.main->ipo.first; ipo; ipo= ipo->id.next) {
                        IpoCurve *icu;
                        
@@ -4297,6 +5228,7 @@ void armature_bone_rename(Object *ob, char *oldnamep, char *newnamep)
                                }
                        }                       
                }
+#endif // XXX old animation system
        }
 }
 
@@ -4352,7 +5284,7 @@ void transform_armature_mirror_update(Object *obedit)
        for (ebo= arm->edbo->first; ebo; ebo=ebo->next) {
                /* no layer check, correct mirror is more important */
                if (ebo->flag & (BONE_TIPSEL|BONE_ROOTSEL)) {
-                       eboflip= armature_bone_get_mirrored(arm->edbo, ebo);
+                       eboflip= ED_armature_bone_get_mirrored(arm->edbo, ebo);
                        
                        if (eboflip) {
                                /* we assume X-axis flipping for now */
@@ -4413,9 +5345,9 @@ EditBone * subdivideByAngle(Scene *scene, Object *obedit, ReebArc *arc, ReebNode
        
        if (scene->toolsettings->skgen_options & SKGEN_CUT_ANGLE)
        {
-               ReebArcIterator iter;
-               EmbedBucket *current = NULL;
-               EmbedBucket *previous = NULL;
+               ReebArcIterator arc_iter;
+               BArcIterator *iter = (BArcIterator*)&arc_iter;
+               float *previous = NULL, *current = NULL;
                EditBone *child = NULL;
                EditBone *parent = NULL;
                EditBone *root = NULL;
@@ -4427,22 +5359,28 @@ EditBone * subdivideByAngle(Scene *scene, Object *obedit, ReebArc *arc, ReebNode
                
                root = parent;
                
-               for (initArcIterator(&iter, arc, head), previous = nextBucket(&iter), current = nextBucket(&iter);
-                       current;
-                       previous = current, current = nextBucket(&iter))
+               initArcIterator(iter, arc, head);
+               IT_next(iter);
+               previous = iter->p;
+               
+               for (IT_next(iter);
+                       IT_stopped(iter) == 0;
+                       previous = iter->p, IT_next(iter))
                {
                        float vec1[3], vec2[3];
                        float len1, len2;
+                       
+                       current = iter->p;
 
-                       VecSubf(vec1, previous->p, parent->head);
-                       VecSubf(vec2, current->p, previous->p);
+                       VecSubf(vec1, previous, parent->head);
+                       VecSubf(vec2, current, previous);
 
                        len1 = Normalize(vec1);
                        len2 = Normalize(vec2);
 
                        if (len1 > 0.0f && len2 > 0.0f && Inpf(vec1, vec2) < angleLimit)
                        {
-                               VECCOPY(parent->tail, previous->p);
+                               VECCOPY(parent->tail, previous);
 
                                child = add_editbone(obedit, "Bone");
                                VECCOPY(child->head, parent->tail);
@@ -4469,182 +5407,29 @@ EditBone * subdivideByAngle(Scene *scene, Object *obedit, ReebArc *arc, ReebNode
        return lastBone;
 }
 
-float calcVariance(ReebArc *arc, int start, int end, float v0[3], float n[3])
-{
-       int len = 2 + abs(end - start);
-       
-       if (len > 2)
-       {
-               ReebArcIterator iter;
-               EmbedBucket *bucket = NULL;
-               float avg_t = 0.0f;
-               float s_t = 0.0f;
-               float s_xyz = 0.0f;
-               
-               /* First pass, calculate average */
-               for (initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter);
-                       bucket;
-                       bucket = nextBucket(&iter))
-               {
-                       float v[3];
-                       
-                       VecSubf(v, bucket->p, v0);
-                       avg_t += Inpf(v, n);
-               }
-               
-               avg_t /= Inpf(n, n);
-               avg_t += 1.0f; /* adding start (0) and end (1) values */
-               avg_t /= len;
-               
-               /* Second pass, calculate s_xyz and s_t */
-               for (initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter);
-                       bucket;
-                       bucket = nextBucket(&iter))
-               {
-                       float v[3], d[3];
-                       float dt;
-                       
-                       VecSubf(v, bucket->p, v0);
-                       Projf(d, v, n);
-                       VecSubf(v, v, d);
-                       
-                       dt = VecLength(d) - avg_t;
-                       
-                       s_t += dt * dt;
-                       s_xyz += Inpf(v, v);
-               }
-               
-               /* adding start(0) and end(1) values to s_t */
-               s_t += (avg_t * avg_t) + (1 - avg_t) * (1 - avg_t);
-               
-               return s_xyz / s_t; 
-       }
-       else
-       {
-               return 0;
-       }
-}
-
-float calcDistance(ReebArc *arc, int start, int end, float head[3], float tail[3])
-{
-       ReebArcIterator iter;
-       EmbedBucket *bucket = NULL;
-       float max_dist = 0;
-       
-       /* calculate maximum distance */
-       for (initArcIterator2(&iter, arc, start, end), bucket = nextBucket(&iter);
-               bucket;
-               bucket = nextBucket(&iter))
-       {
-               float v1[3], v2[3], c[3];
-               float dist;
-               
-               VecSubf(v1, head, tail);
-               VecSubf(v2, bucket->p, tail);
-
-               Crossf(c, v1, v2);
-               
-               dist = Inpf(c, c) / Inpf(v1, v1);
-               
-               max_dist = dist > max_dist ? dist : max_dist;
-       }
-       
-       
-       return max_dist; 
-}
-
-EditBone * subdivideByCorrelation(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail)
+EditBone * test_subdivideByCorrelation(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail)
 {
-       ReebArcIterator iter;
-       float n[3];
-       float ADAPTIVE_THRESHOLD = scene->toolsettings->skgen_correlation_limit;
        EditBone *lastBone = NULL;
-       
-       /* init iterator to get start and end from head */
-       initArcIterator(&iter, arc, head);
-       
-       /* Calculate overall */
-       VecSubf(n, arc->buckets[iter.end].p, head->p);
-       
+
        if (scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION)
        {
-               EmbedBucket *bucket = NULL;
-               EmbedBucket *previous = NULL;
-               EditBone *child = NULL;
-               EditBone *parent = NULL;
-               float normal[3] = {0, 0, 0};
-               float avg_normal[3];
-               int total = 0;
-               int boneStart = iter.start;
-               
-               parent = add_editbone(obedit, "Bone");
-               parent->flag = BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-               VECCOPY(parent->head, head->p);
+               float invmat[4][4] = {  {1, 0, 0, 0},
+                                                               {0, 1, 0, 0},
+                                                               {0, 0, 1, 0},
+                                                               {0, 0, 0, 1}};
+               float tmat[3][3] = {    {1, 0, 0},
+                                                               {0, 1, 0},
+                                                               {0, 0, 1}};
+               ReebArcIterator arc_iter;
+               BArcIterator *iter = (BArcIterator*)&arc_iter;
+               bArmature *arm= obedit->data;
                
-               for (previous = nextBucket(&iter), bucket = nextBucket(&iter);
-                       bucket;
-                       previous = bucket, bucket = nextBucket(&iter))
-               {
-                       float btail[3];
-                       float value = 0;
-
-                       if (scene->toolsettings->skgen_options & SKGEN_STICK_TO_EMBEDDING)
-                       {
-                               VECCOPY(btail, bucket->p);
-                       }
-                       else
-                       {
-                               float length;
-                               
-                               /* Calculate normal */
-                               VecSubf(n, bucket->p, parent->head);
-                               length = Normalize(n);
-                               
-                               total += 1;
-                               VecAddf(normal, normal, n);
-                               VECCOPY(avg_normal, normal);
-                               VecMulf(avg_normal, 1.0f / total);
-                                
-                               VECCOPY(btail, avg_normal);
-                               VecMulf(btail, length);
-                               VecAddf(btail, btail, parent->head);
-                       }
-
-                       if (scene->toolsettings->skgen_options & SKGEN_ADAPTIVE_DISTANCE)
-                       {
-                               value = calcDistance(arc, boneStart, iter.index, parent->head, btail);
-                       }
-                       else
-                       {
-                               float n[3];
-                               
-                               VecSubf(n, btail, parent->head);
-                               value = calcVariance(arc, boneStart, iter.index, parent->head, n);
-                       }
-
-                       if (value > ADAPTIVE_THRESHOLD)
-                       {
-                               VECCOPY(parent->tail, btail);
-
-                               child = add_editbone(obedit, "Bone");
-                               VECCOPY(child->head, parent->tail);
-                               child->parent = parent;
-                               child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-                               
-                               parent = child; // new child is next parent
-                               boneStart = iter.index; // start from end
-                               
-                               normal[0] = normal[1] = normal[2] = 0;
-                               total = 0;
-                       }
-               }
-
-               VECCOPY(parent->tail, tail->p);
+               initArcIterator(iter, arc, head);
                
-               lastBone = parent; /* set last bone in the chain */
+               lastBone = subdivideArcBy(arm, arm->edbo, iter, invmat, tmat, nextAdaptativeSubdivision);
        }
        
-       return lastBone;
+       return lastBone;
 }
 
 float arcLengthRatio(ReebArc *arc)
@@ -4674,108 +5459,26 @@ float arcLengthRatio(ReebArc *arc)
        return embedLength / arcLength; 
 }
 
-EditBone * subdivideByLength(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail)
+EditBone * test_subdivideByLength(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail)
 {
        EditBone *lastBone = NULL;
-       
        if ((scene->toolsettings->skgen_options & SKGEN_CUT_LENGTH) &&
-               arcLengthRatio(arc) >= scene->toolsettings->skgen_length_ratio)
+               arcLengthRatio(arc) >= G.scene->toolsettings->skgen_length_ratio)
        {
-               ReebArcIterator iter;
-               EmbedBucket *bucket = NULL;
-               EmbedBucket *previous = NULL;
-               EditBone *child = NULL;
-               EditBone *parent = NULL;
-               float lengthLimit = scene->toolsettings->skgen_length_limit;
-               int same = 0;
-               
-               parent = add_editbone(obedit, "Bone");
-               parent->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-               VECCOPY(parent->head, head->p);
-
-               initArcIterator(&iter, arc, head);
-
-               bucket = nextBucket(&iter);
+               float invmat[4][4] = {  {1, 0, 0, 0},
+                                                               {0, 1, 0, 0},
+                                                               {0, 0, 1, 0},
+                                                               {0, 0, 0, 1}};
+               float tmat[3][3] = {    {1, 0, 0},
+                                                               {0, 1, 0},
+                                                               {0, 0, 1}};
+               ReebArcIterator arc_iter;
+               BArcIterator *iter = (BArcIterator*)&arc_iter;
+               bArmature *arm= obedit->data;
                
-               while (bucket != NULL)
-               {
-                       float *vec0 = NULL;
-                       float *vec1 = bucket->p;
-
-                       /* first bucket. Previous is head */
-                       if (previous == NULL)
-                       {
-                               vec0 = head->p;
-                       }
-                       /* Previous is a valid bucket */
-                       else
-                       {
-                               vec0 = previous->p;
-                       }
-                       
-                       /* If lengthLimit hits the current segment */
-                       if (VecLenf(vec1, parent->head) > lengthLimit)
-                       {
-                               if (same == 0)
-                               {
-                                       float dv[3], off[3];
-                                       float a, b, c, f;
-                                       
-                                       /* Solve quadratic distance equation */
-                                       VecSubf(dv, vec1, vec0);
-                                       a = Inpf(dv, dv);
-                                       
-                                       VecSubf(off, vec0, parent->head);
-                                       b = 2 * Inpf(dv, off);
-                                       
-                                       c = Inpf(off, off) - (lengthLimit * lengthLimit);
-                                       
-                                       f = (-b + (float)sqrt(b * b - 4 * a * c)) / (2 * a);
-                                       
-                                       //printf("a %f, b %f, c %f, f %f\n", a, b, c, f);
-                                       
-                                       if (isnan(f) == 0 && f < 1.0f)
-                                       {
-                                               VECCOPY(parent->tail, dv);
-                                               VecMulf(parent->tail, f);
-                                               VecAddf(parent->tail, parent->tail, vec0);
-                                       }
-                                       else
-                                       {
-                                               VECCOPY(parent->tail, vec1);
-                                       }
-                               }
-                               else
-                               {
-                                       float dv[3];
-                                       
-                                       VecSubf(dv, vec1, vec0);
-                                       Normalize(dv);
-                                        
-                                       VECCOPY(parent->tail, dv);
-                                       VecMulf(parent->tail, lengthLimit);
-                                       VecAddf(parent->tail, parent->tail, parent->head);
-                               }
-                               
-                               child = add_editbone(obedit, "Bone");
-                               VECCOPY(child->head, parent->tail);
-                               child->parent = parent;
-                               child->flag |= BONE_CONNECTED|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-                               
-                               parent = child; // new child is next parent
-                               
-                               same = 1; // mark as same
-                       }
-                       else
-                       {
-                               previous = bucket;
-                               bucket = nextBucket(&iter);
-                               same = 0; // Reset same
-                       }
-               }
-               VECCOPY(parent->tail, tail->p);
+               initArcIterator(iter, arc, head);
                
-               lastBone = parent; /* set last bone in the chain */
+               lastBone = subdivideArcBy(arm, arm->edbo, iter, invmat, tmat, nextLengthSubdivision);
        }
        
        return lastBone;
@@ -4801,7 +5504,7 @@ void generateSkeletonFromReebGraph(Scene *scene, ReebGraph *rg)
        }
        
        dst = add_object(scene, OB_ARMATURE);
-       ED_object_base_init_from_view(scene, NULL, scene->basact);
+       ED_object_base_init_from_view(NULL, scene->basact);     // XXX NULL is C
        obedit= scene->basact->object;
        
        /* Copy orientation from source */
@@ -4870,13 +5573,13 @@ void generateSkeletonFromReebGraph(Scene *scene, ReebGraph *rg)
                        switch(scene->toolsettings->skgen_subdivisions[i])
                        {
                                case SKGEN_SUB_LENGTH:
-                                       lastBone = subdivideByLength(scene, obedit, arc, head, tail);
+                                       lastBone = test_subdivideByLength(scene, obedit, arc, head, tail);
                                        break;
                                case SKGEN_SUB_ANGLE:
                                        lastBone = subdivideByAngle(scene, obedit, arc, head, tail);
                                        break;
                                case SKGEN_SUB_CORRELATION:
-                                       lastBone = subdivideByCorrelation(scene, obedit, arc, head, tail);
+                                       lastBone = test_subdivideByCorrelation(scene, obedit, arc, head, tail);
                                        break;
                        }
                }