batch remove .'s used with RNA_def_struct_ui_text
[blender.git] / source / blender / editors / armature / poseobject.c
index 331bd6fa28f7b867ba2f96b5e896aa2302f1aa43..68d0d34c1c1d0e2e47b3a415a1887b53dae6f506 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "MEM_guardedalloc.h"
 
-#include "BLI_arithb.h"
+#include "BLI_math.h"
 #include "BLI_blenlib.h"
 #include "BLI_dynstr.h"
 
@@ -51,6 +51,7 @@
 #include "DNA_view3d_types.h"
 #include "DNA_userdef_types.h"
 
+#include "BKE_anim.h"
 #include "BKE_animsys.h"
 #include "BKE_action.h"
 #include "BKE_armature.h"
@@ -92,8 +93,6 @@
 static int pupmenu() {return 0;}
 static void error() {};
 static void BIF_undo_push() {}
-static void countall() {}
-static void autokeyframe_pose_cb_func() {}
 /* ************* XXX *************** */
 
 /* This function is used to indicate that a bone is selected and needs keyframes inserted */
@@ -158,12 +157,12 @@ static short pose_has_protected_selected(Object *ob, short only_selected, short
        if (ob->proxy) {
                bPoseChannel *pchan;
                bArmature *arm= ob->data;
-               
+
                for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
                        if (pchan->bone && (pchan->bone->layer & arm->layer)) {
                                if (pchan->bone->layer & arm->layer_protected) {
-                                       if (only_selected && (pchan->bone->flag & BONE_ACTIVE));
-                                       else if (pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) 
+                                       if (only_selected && (pchan->bone == arm->act_bone));
+                                       else if (pchan->bone->flag & BONE_SELECTED || pchan->bone == arm->act_bone)
                                           break;
                                }
                        }
@@ -200,6 +199,7 @@ int ED_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
 }
 
 /* ********************************************** */
+/* Motion Paths */
 
 /* For the object with pose/action: update paths for those that have got them
  * This should selectively update paths that exist...
@@ -208,119 +208,25 @@ int ED_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
  */
 void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob)
 {
-       bArmature *arm;
-       bPoseChannel *pchan;
-       Base *base;
-       float *fp;
-       int cfra;
-       int sfra, efra;
-       
-       /* sanity checks */
-       if ELEM(NULL, ob, ob->pose)
-               return;
-       arm= ob->data;
-       
-       /* set frame values */
-       cfra = CFRA;
-       sfra = efra = cfra; 
-       for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-               if ((pchan->bone) && (arm->layer & pchan->bone->layer)) {
-                       if (pchan->path) {
-                               /* if the pathsf and pathef aren't initialised, abort! */
-                               if (ELEM(0, pchan->pathsf, pchan->pathef))      
-                                       return;
-                               
-                               /* try to increase area to do (only as much as needed) */
-                               sfra= MIN2(sfra, pchan->pathsf);
-                               efra= MAX2(efra, pchan->pathef);
-                       }
-               }
-       }
-       if (efra <= sfra) return;
-       
-       /* hack: for unsaved files, set OB_RECALC so that paths can get calculated */
-       if ((ob->recalc & OB_RECALC)==0) {
-               ob->recalc |= OB_RECALC;
-               ED_anim_object_flush_update(C, ob);
-       }
-       else
-               ED_anim_object_flush_update(C, ob);
-       
-       /* calculate path over requested range */
-       for (CFRA=sfra; CFRA<=efra; CFRA++) {
-               /* do all updates */
-               for (base= FIRSTBASE; base; base= base->next) {
-                       if (base->object->recalc) {
-                               int temp= base->object->recalc;
-                               
-                               if (base->object->adt)
-                                       BKE_animsys_evaluate_animdata(&base->object->id, base->object->adt, (float)CFRA, ADT_RECALC_ALL);
-                               
-                               /* update object */
-                               object_handle_update(scene, base->object);
-                               base->object->recalc= temp;
-                       }
-               }
-               
-               for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-                       if ((pchan->bone) && (arm->layer & pchan->bone->layer)) {
-                               if (pchan->path) {
-                                       /* only update if:
-                                        *      - in range of this pchan's existing path
-                                        *      - ... insert evil filtering/optimising conditions here...
-                                        */
-                                       if (IN_RANGE(CFRA, pchan->pathsf, pchan->pathef)) {
-                                               fp= pchan->path+3*(CFRA-sfra);
-                                               
-                                               if (arm->pathflag & ARM_PATH_HEADS) { 
-                                                       VECCOPY(fp, pchan->pose_head);
-                                               }
-                                               else {
-                                                       VECCOPY(fp, pchan->pose_tail);
-                                               }
-                                               
-                                               Mat4MulVecfl(ob->obmat, fp);
-                                       }
-                               }
-                       }
-               }
-       }
+       ListBase targets = {NULL, NULL};
        
-       /* reset flags */
-       CFRA= cfra;
-       ob->pose->flag &= ~POSE_RECALCPATHS;
+       /* set flag to force recalc, then grab the relevant bones to target */
+       ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
+       animviz_get_object_motionpaths(ob, &targets);
        
-       /* flush one final time - to restore to the original state */
-       for (base= FIRSTBASE; base; base= base->next) {
-               if (base->object->recalc) {
-                       int temp= base->object->recalc;
-                       
-                       if (base->object->adt)
-                               BKE_animsys_evaluate_animdata(&base->object->id, base->object->adt, (float)CFRA, ADT_RECALC_ALL);
-                       
-                       object_handle_update(scene, base->object);
-                       base->object->recalc= temp;
-               }
-       }
+       /* recalculate paths, then free */
+       animviz_calc_motionpaths(scene, &targets);
+       BLI_freelistN(&targets);
 }
 
-/* --------- */
-
 /* For the object with pose/action: create path curves for selected bones 
  * This recalculates the WHOLE path within the pchan->pathsf and pchan->pathef range
  */
 static int pose_calculate_paths_exec (bContext *C, wmOperator *op)
 {
-       wmWindow *win= CTX_wm_window(C);
        ScrArea *sa= CTX_wm_area(C);
        Scene *scene= CTX_data_scene(C);
        Object *ob;
-       bArmature *arm;
-       bPoseChannel *pchan;
-       Base *base;
-       float *fp;
-       int cfra;
-       int sfra, efra;
        
        /* since this call may also be used from the buttons window, we need to check for where to get the object */
        if (sa->spacetype == SPACE_BUTS) 
@@ -328,109 +234,20 @@ static int pose_calculate_paths_exec (bContext *C, wmOperator *op)
        else
                ob= CTX_data_active_object(C);
                
-       /* only continue if there's an object */
-       if ELEM(NULL, ob, ob->pose)
-               return OPERATOR_CANCELLED;
-       arm= ob->data;
-       
-       /* version patch for older files here (do_versions patch too complicated) */
-       if ((arm->pathsf == 0) || (arm->pathef == 0)) {
-               arm->pathsf = SFRA;
-               arm->pathef = EFRA;
-       }
-       if (arm->pathsize == 0) {
-               arm->pathsize = 1;
-       }
-       
-       /* get frame values to use */
-       cfra= CFRA;
-       sfra = arm->pathsf;
-       efra = arm->pathef;
-       
-       if (efra <= sfra) {
-               BKE_report(op->reports, RPT_ERROR, "Can't calculate paths when pathlen <= 0");
+       if (ELEM(NULL, ob, ob->pose))
                return OPERATOR_CANCELLED;
-       }
-       
-       /* hack: for unsaved files, set OB_RECALC so that paths can get calculated */
-       if ((ob->recalc & OB_RECALC)==0) {
-               ob->recalc |= OB_RECALC;
-               ED_anim_object_flush_update(C, ob);
-       }
-       else
-               ED_anim_object_flush_update(C, ob);
        
-       /* alloc the path cache arrays */
-       for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-               if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
-                       if (arm->layer & pchan->bone->layer) {
-                               pchan->pathlen= efra-sfra+1;
-                               pchan->pathsf= sfra;
-                               pchan->pathef= efra+1;
-                               if (pchan->path)
-                                       MEM_freeN(pchan->path);
-                               pchan->path= MEM_callocN(3*pchan->pathlen*sizeof(float), "pchan path");
-                       }
-               }
-       }
-       
-       /* step through frame range sampling the values */
-       for (CFRA=sfra; CFRA<=efra; CFRA++) {
-               /* for each frame we calculate, update time-cursor... (may be too slow) */
-               WM_timecursor(win, CFRA);
-               
-               /* do all updates */
-               for (base= FIRSTBASE; base; base= base->next) {
-                       if (base->object->recalc) {
-                               int temp= base->object->recalc;
-                               
-                               if (base->object->adt)
-                                       BKE_animsys_evaluate_animdata(&base->object->id, base->object->adt, (float)CFRA, ADT_RECALC_ALL);
-                               
-                               object_handle_update(scene, base->object);
-                               base->object->recalc= temp;
-                       }
-               }
-               
-               for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-                       if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
-                               if (arm->layer & pchan->bone->layer) {
-                                       if (pchan->path) {
-                                               fp= pchan->path+3*(CFRA-sfra);
-                                               
-                                               if (arm->pathflag & ARM_PATH_HEADS) { 
-                                                       VECCOPY(fp, pchan->pose_head);
-                                               }
-                                               else {
-                                                       VECCOPY(fp, pchan->pose_tail);
-                                               }
-                                               
-                                               Mat4MulVecfl(ob->obmat, fp);
-                                       }
-                               }
-                       }
-               }
+       /* set up path data for bones being calculated */
+       CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 
+       {
+               /* verify makes sure that the selected bone has a bone with the appropriate settings */
+               animviz_verify_motionpaths(scene, ob, pchan);
        }
+       CTX_DATA_END;
        
-       /* restore original cursor */
-       WM_cursor_restore(win);
-       
-       /* reset current frame, and clear flags */
-       CFRA= cfra;
-       ob->pose->flag &= ~POSE_RECALCPATHS;
-       
-       /* flush one final time - to restore to the original state */
-       for (base= FIRSTBASE; base; base= base->next) {
-               if (base->object->recalc) {
-                       int temp= base->object->recalc;
-                       
-                       if (base->object->adt)
-                               BKE_animsys_evaluate_animdata(&base->object->id, base->object->adt, (float)CFRA, ADT_RECALC_ALL);
-                       
-                       object_handle_update(scene, base->object);
-                       base->object->recalc= temp;
-               }
-       }
+       /* calculate the bones that now have motionpaths... */
+       // TODO: only make for the selected bones?
+       ED_pose_recalculate_paths(C, scene, ob);
        
        /* notifiers for updates */
        WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
@@ -443,7 +260,7 @@ void POSE_OT_paths_calculate (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Calculate Bone Paths";
        ot->idname= "POSE_OT_paths_calculate";
-       ot->description= "Calculate paths for the selected bones.";
+       ot->description= "Calculate paths for the selected bones";
        
        /* api callbacks */
        ot->exec= pose_calculate_paths_exec;
@@ -463,12 +280,12 @@ void ED_pose_clear_paths(Object *ob)
        if ELEM(NULL, ob, ob->pose)
                return;
        
-       /* free the path blocks */
+       /* free the motionpath blocks */
        for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
                if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
-                       if (pchan->path) {
-                               MEM_freeN(pchan->path);
-                               pchan->path= NULL;
+                       if (pchan->mpath) {
+                               animviz_free_motionpath(pchan->mpath);
+                               pchan->mpath= NULL;
                        }
                }
        }
@@ -490,7 +307,7 @@ static int pose_clear_paths_exec (bContext *C, wmOperator *op)
        if ELEM(NULL, ob, ob->pose)
                return OPERATOR_CANCELLED;
        
-       /* for now, just call the API function for this (which is shared with backend functions) */
+       /* use the backend function for this */
        ED_pose_clear_paths(ob);
        
        /* notifiers for updates */
@@ -504,7 +321,7 @@ void POSE_OT_paths_clear (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Clear Bone Paths";
        ot->idname= "POSE_OT_paths_clear";
-       ot->description= "Clear path caches for selected bones.";
+       ot->description= "Clear path caches for selected bones";
        
        /* api callbacks */
        ot->exec= pose_clear_paths_exec;
@@ -516,88 +333,43 @@ void POSE_OT_paths_clear (wmOperatorType *ot)
 
 /* ******************* Select Constraint Target Operator ************* */
 
-// XXX this function is to be removed when the other stuff is recoded
-void pose_select_constraint_target(Scene *scene)
-{
-       Object *obedit= scene->obedit; // XXX context
-       Object *ob= OBACT;
-       bArmature *arm= ob->data;
-       bPoseChannel *pchan;
-       bConstraint *con;
-       
-       /* paranoia checks */
-       if (!ob && !ob->pose) return;
-       if (ob==obedit || (ob->mode & OB_MODE_POSE)==0) return;
-       
-       for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-               if (arm->layer & pchan->bone->layer) {
-                       if (pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
-                               for (con= pchan->constraints.first; con; con= con->next) {
-                                       bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
-                                       ListBase targets = {NULL, NULL};
-                                       bConstraintTarget *ct;
-                                       
-                                       if (cti && cti->get_constraint_targets) {
-                                               cti->get_constraint_targets(con, &targets);
-                                               
-                                               for (ct= targets.first; ct; ct= ct->next) {
-                                                       if ((ct->tar == ob) && (ct->subtarget[0])) {
-                                                               bPoseChannel *pchanc= get_pose_channel(ob->pose, ct->subtarget);
-                                                               if((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE))
-                                                                       pchanc->bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-                                                       }
-                                               }
-                                               
-                                               if (cti->flush_constraint_targets)
-                                                       cti->flush_constraint_targets(con, &targets, 1);
-                                       }
-                               }
-                       }
-               }
-       }
-       
-       BIF_undo_push("Select constraint target");
-
-}
-
 static int pose_select_constraint_target_exec(bContext *C, wmOperator *op)
 {
        Object *ob= CTX_data_active_object(C);
        bArmature *arm= ob->data;
-       bPoseChannel *pchan;
        bConstraint *con;
        int found= 0;
        
-       for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-               if (arm->layer & pchan->bone->layer) {
-                       if (pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
-                               for (con= pchan->constraints.first; con; con= con->next) {
-                                       bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
-                                       ListBase targets = {NULL, NULL};
-                                       bConstraintTarget *ct;
+       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
+       {
+               if ((pchan->bone->flag & BONE_SELECTED) || (pchan->bone == arm->act_bone)) {
+                       for (con= pchan->constraints.first; con; con= con->next) {
+                               bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+                               ListBase targets = {NULL, NULL};
+                               bConstraintTarget *ct;
+                               
+                               if (cti && cti->get_constraint_targets) {
+                                       cti->get_constraint_targets(con, &targets);
                                        
-                                       if (cti && cti->get_constraint_targets) {
-                                               cti->get_constraint_targets(con, &targets);
-                                               
-                                               for (ct= targets.first; ct; ct= ct->next) {
-                                                       if ((ct->tar == ob) && (ct->subtarget[0])) {
-                                                               bPoseChannel *pchanc= get_pose_channel(ob->pose, ct->subtarget);
-                                                               if((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
-                                                                       pchanc->bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
-                                                                       found= 1;
-                                                               }
+                                       for (ct= targets.first; ct; ct= ct->next) {
+                                               if ((ct->tar == ob) && (ct->subtarget[0])) {
+                                                       bPoseChannel *pchanc= get_pose_channel(ob->pose, ct->subtarget);
+                                                       if((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
+                                                               pchanc->bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
+                                                               found= 1;
                                                        }
                                                }
-                                               
-                                               if (cti->flush_constraint_targets)
-                                                       cti->flush_constraint_targets(con, &targets, 1);
                                        }
+                                       
+                                       if (cti->flush_constraint_targets)
+                                               cti->flush_constraint_targets(con, &targets, 1);
                                }
                        }
                }
        }
+       CTX_DATA_END;
 
-       if(!found)
+       if (!found)
                return OPERATOR_CANCELLED;
 
        WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob);
@@ -625,41 +397,38 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
 {
        Object *ob= CTX_data_active_object(C);
        bArmature *arm= ob->data;
-       bPoseChannel *pchan;
        Bone *curbone, *pabone, *chbone;
        int direction = RNA_enum_get(op->ptr, "direction");
        int add_to_sel = RNA_boolean_get(op->ptr, "extend");
        int found= 0;
        
-       for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
+       {
                curbone= pchan->bone;
                
-               if ((arm->layer & curbone->layer) && (curbone->flag & BONE_UNSELECTABLE)==0) {
-                       if (curbone->flag & (BONE_ACTIVE)) {
+               if ((curbone->flag & BONE_UNSELECTABLE)==0) {
+                       if (curbone == arm->act_bone) {
                                if (direction == BONE_SELECT_PARENT) {
-                               
                                        if (pchan->parent == NULL) continue;
                                        else pabone= pchan->parent->bone;
                                        
                                        if ((arm->layer & pabone->layer) && !(pabone->flag & BONE_HIDDEN_P)) {
-                                               
                                                if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
-                                               curbone->flag &= ~BONE_ACTIVE;
-                                               pabone->flag |= (BONE_ACTIVE|BONE_SELECTED);
+                                               pabone->flag |= BONE_SELECTED;
+                                               arm->act_bone= pabone;
                                                
                                                found= 1;
                                                break;
                                        }
-                               } else { // BONE_SELECT_CHILD
-                               
+                               } 
+                               else { /* direction == BONE_SELECT_CHILD */
                                        if (pchan->child == NULL) continue;
                                        else chbone = pchan->child->bone;
                                        
                                        if ((arm->layer & chbone->layer) && !(chbone->flag & BONE_HIDDEN_P)) {
-                                       
                                                if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
-                                               curbone->flag &= ~BONE_ACTIVE;
-                                               chbone->flag |= (BONE_ACTIVE|BONE_SELECTED);
+                                               chbone->flag |= BONE_SELECTED;
+                                               arm->act_bone= chbone;
                                                
                                                found= 1;
                                                break;
@@ -668,8 +437,9 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
                        }
                }
        }
+       CTX_DATA_END;
 
-       if(!found)
+       if (found == 0)
                return OPERATOR_CANCELLED;
 
        WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, ob);
@@ -697,12 +467,171 @@ void POSE_OT_select_hierarchy(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* props */
-       RNA_def_enum(ot->srna, "direction", direction_items,
-                                BONE_SELECT_PARENT, "Direction", "");
+       ot->prop= RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
        RNA_def_boolean(ot->srna, "extend", 0, "Add to Selection", "");
        
 }
 
+/* ******************* select grouped operator ************* */
+
+static short pose_select_same_group (bContext *C, Object *ob, short extend)
+{
+       bArmature *arm= (ob)? ob->data : NULL;
+       bPose *pose= (ob)? ob->pose : NULL;
+       char *group_flags;
+       int numGroups = 0;
+       short changed=0, tagged=0;
+       
+       /* sanity checks */
+       if (ELEM3(NULL, ob, pose, arm))
+               return 0;
+               
+       /* count the number of groups */
+       numGroups= BLI_countlist(&pose->agroups);
+       if (numGroups == 0)
+               return 0;
+               
+       /* alloc a small array to keep track of the groups to use 
+        *      - each cell stores on/off state for whether group should be used
+        *      - size is numGroups + 1, since index=0 is used for no-group
+        */
+       group_flags= MEM_callocN(numGroups+1, "pose_select_same_group");
+       
+       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
+       {
+               /* keep track of group as group to use later? */
+               if ((pchan->bone->flag & BONE_SELECTED) || (pchan->bone == arm->act_bone)) {
+                       group_flags[pchan->agrp_index] = 1;
+                       tagged= 1;
+               }
+               
+               /* deselect all bones before selecting new ones? */
+               if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE)==0)
+                       pchan->bone->flag &= ~BONE_SELECTED;
+       }
+       CTX_DATA_END;
+       
+       /* small optimisation: only loop through bones a second time if there are any groups tagged */
+       if (tagged) {
+               /* only if group matches (and is not selected or current bone) */
+               CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
+               {
+                       if ((pchan->bone->flag & BONE_UNSELECTABLE)==0) {
+                               /* check if the group used by this bone is counted */
+                               if (group_flags[pchan->agrp_index]) {
+                                       pchan->bone->flag |= BONE_SELECTED;
+                                       changed= 1;
+                               }
+                       }
+               }
+               CTX_DATA_END;
+       }
+       
+       /* free temp info */
+       MEM_freeN(group_flags);
+       
+       return changed;
+}
+
+static short pose_select_same_layer (bContext *C, Object *ob, short extend)
+{
+       bPose *pose= (ob)? ob->pose : NULL;
+       bArmature *arm= (ob)? ob->data : NULL;
+       short changed= 0;
+       int layers= 0;
+       
+       if (ELEM3(NULL, ob, pose, arm))
+               return 0;
+       
+       /* figure out what bones are selected */
+       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
+       {
+               /* keep track of layers to use later? */
+               if ((pchan->bone->flag & BONE_SELECTED) || (pchan->bone == arm->act_bone))
+                       layers |= pchan->bone->layer;
+                       
+               /* deselect all bones before selecting new ones? */
+               if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE)==0)
+                       pchan->bone->flag &= ~BONE_SELECTED;
+       }
+       CTX_DATA_END;
+       if (layers == 0) 
+               return 0;
+               
+       /* select bones that are on same layers as layers flag */
+       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) 
+       {
+               /* if bone is on a suitable layer, and the bone can have its selection changed, select it */
+               if ((layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE)==0) {
+                       pchan->bone->flag |= BONE_SELECTED;
+                       changed= 1;
+               }
+       }
+       CTX_DATA_END;
+       
+       return changed;
+}
+
+
+static int pose_select_grouped_exec (bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_active_object(C);
+       short extend= RNA_boolean_get(op->ptr, "extend");
+       short changed = 0;
+       
+       /* sanity check */
+       if (ELEM(NULL, ob, ob->pose))
+               return OPERATOR_CANCELLED;
+               
+       /* selection types 
+        * NOTE: for the order of these, see the enum in POSE_OT_select_grouped()
+        */
+       switch (RNA_enum_get(op->ptr, "type")) {
+               case 1: /* group */
+                       changed= pose_select_same_group(C, ob, extend);
+                       break;
+               default: /* layer */
+                       changed= pose_select_same_layer(C, ob, extend);
+                       break;
+       }
+       
+       /* notifiers for updates */
+       WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
+       
+       /* report done status */
+       if (changed)
+               return OPERATOR_FINISHED;
+       else
+               return OPERATOR_CANCELLED;
+}
+
+void POSE_OT_select_grouped (wmOperatorType *ot)
+{
+       static EnumPropertyItem prop_select_grouped_types[] = {
+               {0, "LAYER", 0, "Layer", "Shared layers"},
+               {1, "GROUP", 0, "Group", "Shared group"},
+               {0, NULL, 0, NULL, NULL}
+       };
+
+       /* identifiers */
+       ot->name= "Select Grouped";
+       ot->description = "Select all visible bones grouped by various properties";
+       ot->idname= "POSE_OT_select_grouped";
+       
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
+       ot->exec= pose_select_grouped_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* properties */
+       RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first.");
+       ot->prop= RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
+}
+
+/* ********************************************** */
 
 void pose_copy_menu(Scene *scene)
 {
@@ -717,11 +646,7 @@ void pose_copy_menu(Scene *scene)
        if (ELEM(NULL, ob, ob->pose)) return;
        if ((ob==obedit) || (ob->mode & OB_MODE_POSE)==0) return;
        
-       /* find active */
-       for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-               if (pchan->bone->flag & BONE_ACTIVE) 
-                       break;
-       }
+       pchan= get_active_posechannel(ob);
        
        if (pchan==NULL) return;
        pchanact= pchan;
@@ -818,13 +743,13 @@ void pose_copy_menu(Scene *scene)
                                                        float tmp_quat[4];
                                                        
                                                        /* need to convert to quat first (in temp var)... */
-                                                       Mat4ToQuat(delta_mat, tmp_quat);
-                                                       QuatToAxisAngle(tmp_quat, pchan->rotAxis, &pchan->rotAngle);
+                                                       mat4_to_quat( tmp_quat,delta_mat);
+                                                       quat_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,tmp_quat);
                                                }
                                                else if (pchan->rotmode == ROT_MODE_QUAT)
-                                                       Mat4ToQuat(delta_mat, pchan->quat);
+                                                       mat4_to_quat( pchan->quat,delta_mat);
                                                else
-                                                       Mat4ToEulO(delta_mat, pchan->eul, pchan->rotmode);
+                                                       mat4_to_eulO( pchan->eul, pchan->rotmode,delta_mat);
                                        }
                                                break;
                                        case 11: /* Visual Size */
@@ -832,7 +757,7 @@ void pose_copy_menu(Scene *scene)
                                                float delta_mat[4][4], size[4];
                                                
                                                armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
-                                               Mat4ToSize(delta_mat, size);
+                                               mat4_to_size( size,delta_mat);
                                                VECCOPY(pchan->size, size);
                                        }
                                }
@@ -951,7 +876,7 @@ void POSE_OT_copy (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Copy Pose";
        ot->idname= "POSE_OT_copy";
-       ot->description= "Copies the current pose of the selected bones to copy/paste buffer.";
+       ot->description= "Copies the current pose of the selected bones to copy/paste buffer";
        
        /* api callbacks */
        ot->exec= pose_copy_exec;
@@ -1024,23 +949,23 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
                                else if (pchan->rotmode > 0) {
                                        /* quat/axis-angle to euler */
                                        if (chan->rotmode == ROT_MODE_AXISANGLE)
-                                               AxisAngleToEulO(chan->rotAxis, chan->rotAngle, pchan->eul, pchan->rotmode);
+                                               axis_angle_to_eulO( pchan->eul, pchan->rotmode,chan->rotAxis, chan->rotAngle);
                                        else
-                                               QuatToEulO(chan->quat, pchan->eul, pchan->rotmode);
+                                               quat_to_eulO( pchan->eul, pchan->rotmode,chan->quat);
                                }
                                else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
                                        /* quat/euler to axis angle */
                                        if (chan->rotmode > 0)
-                                               EulOToAxisAngle(chan->eul, chan->rotmode, pchan->rotAxis, &pchan->rotAngle);
+                                               eulO_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,chan->eul, chan->rotmode);
                                        else    
-                                               QuatToAxisAngle(chan->quat, pchan->rotAxis, &pchan->rotAngle);
+                                               quat_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,chan->quat);
                                }
                                else {
                                        /* euler/axis-angle to quat */
                                        if (chan->rotmode > 0)
-                                               EulOToQuat(chan->eul, chan->rotmode, pchan->quat);
+                                               eulO_to_quat( pchan->quat,chan->eul, chan->rotmode);
                                        else
-                                               AxisAngleToQuat(pchan->quat, chan->rotAxis, pchan->rotAngle);
+                                               axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
                                }
                                
                                /* paste flipped pose? */
@@ -1055,10 +980,10 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
                                        else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
                                                float eul[3];
                                                
-                                               AxisAngleToEulO(pchan->rotAxis, pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
+                                               axis_angle_to_eulO( eul, EULER_ORDER_DEFAULT,pchan->rotAxis, pchan->rotAngle);
                                                eul[1]*= -1;
                                                eul[2]*= -1;
-                                               EulOToAxisAngle(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, &pchan->rotAngle);
+                                               eulO_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,eul, EULER_ORDER_DEFAULT);
                                                
                                                // experimental method (uncomment to test):
 #if 0
@@ -1070,10 +995,10 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
                                        else {
                                                float eul[3];
                                                
-                                               QuatToEul(pchan->quat, eul);
+                                               quat_to_eul( eul,pchan->quat);
                                                eul[1]*= -1;
                                                eul[2]*= -1;
-                                               EulToQuat(eul, pchan->quat);
+                                               eul_to_quat( pchan->quat,eul);
                                        }
                                }
                                
@@ -1117,7 +1042,7 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
        }
        
        /* notifiers for updates */
-       WM_event_add_notifier(C, NC_OBJECT|ND_POSE|ND_TRANSFORM, ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
        WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); // XXX not really needed, but here for completeness...
 
        return OPERATOR_FINISHED;
@@ -1128,7 +1053,7 @@ void POSE_OT_paste (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Paste Pose";
        ot->idname= "POSE_OT_paste";
-       ot->description= "Pastes the stored pose on to the current pose.";
+       ot->description= "Pastes the stored pose on to the current pose";
        
        /* api callbacks */
        ot->exec= pose_paste_exec;
@@ -1143,31 +1068,6 @@ void POSE_OT_paste (wmOperatorType *ot)
 
 /* ********************************************** */
 
-/* context weightpaint and deformer in posemode */
-void pose_adds_vgroups(Scene *scene, Object *meshobj, int heatweights)
-{
-// XXX extern VPaint Gwp;         /* from vpaint */
-       Object *poseobj= modifiers_isDeformedByArmature(meshobj);
-
-       if(poseobj==NULL || (poseobj->mode & OB_MODE_POSE)==0) {
-               error("The active object must have a deforming armature in pose mode");
-               return;
-       }
-
-// XXX add_verts_to_dgroups(meshobj, poseobj, heatweights, ((Mesh *)(meshobj->data))->editflag & ME_EDIT_MIRROR_X);
-
-       if(heatweights)
-               BIF_undo_push("Apply Bone Heat Weights to Vertex Groups");
-       else
-               BIF_undo_push("Apply Bone Envelopes to Vertex Groups");
-
-       
-       // and all its relations
-       DAG_id_flush_update(&meshobj->id, OB_RECALC_DATA);
-}
-
-/* ********************************************** */
-
 
 static int pose_group_add_exec (bContext *C, wmOperator *op)
 {
@@ -1198,7 +1098,7 @@ void POSE_OT_group_add (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Add Bone Group";
        ot->idname= "POSE_OT_group_add";
-       ot->description= "Add a new bone group.";
+       ot->description= "Add a new bone group";
        
        /* api callbacks */
        ot->exec= pose_group_add_exec;
@@ -1238,7 +1138,7 @@ void POSE_OT_group_remove (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Remove Bone Group";
        ot->idname= "POSE_OT_group_remove";
-       ot->description= "Removes the active bone group.";
+       ot->description= "Removes the active bone group";
        
        /* api callbacks */
        ot->exec= pose_group_remove_exec;
@@ -1310,7 +1210,6 @@ static int pose_group_assign_exec (bContext *C, wmOperator *op)
        Object *ob;
        bArmature *arm;
        bPose *pose;
-       bPoseChannel *pchan;
        short done= 0;
        
        /* since this call may also be used from the buttons window, we need to check for where to get the object */
@@ -1334,18 +1233,12 @@ static int pose_group_assign_exec (bContext *C, wmOperator *op)
        
        /* add selected bones to group then */
        // NOTE: unfortunately, we cannot use the context-iterators here, since they might not be defined...
-       // CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans) 
-       for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
-               /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
-               // NOTE: sync this view3d_context() in space_view3d.c
-               if ((pchan->bone) && (arm->layer & pchan->bone->layer) && !(pchan->bone->flag & BONE_HIDDEN_P)) {
-                       if (pchan->bone->flag & (BONE_SELECTED|BONE_ACTIVE)) {
-                               pchan->agrp_index= pose->active_group;
-                               done= 1;
-                       }
-               }
+       CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) {
+               pchan->agrp_index= pose->active_group;
+               done= 1;
        }
-       
+       CTX_DATA_END;
+
        /* notifiers for updates */
        WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
        
@@ -1361,7 +1254,7 @@ void POSE_OT_group_assign (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Add Selected to Bone Group";
        ot->idname= "POSE_OT_group_assign";
-       ot->description= "Add selected bones to the chosen bone group.";
+       ot->description= "Add selected bones to the chosen bone group";
        
        /* api callbacks */
        ot->invoke= pose_groups_menu_invoke;
@@ -1397,14 +1290,14 @@ static int pose_group_unassign_exec (bContext *C, wmOperator *op)
        pose= ob->pose;
        arm= ob->data;
        
-       /* add selected bones to ungroup then */
+       /* find selected bones to remove from all bone groups */
        // NOTE: unfortunately, we cannot use the context-iterators here, since they might not be defined...
-       // CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans) 
+       // CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) 
        for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
                /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
                // NOTE: sync this view3d_context() in space_view3d.c
                if ((pchan->bone) && (arm->layer & pchan->bone->layer) && !(pchan->bone->flag & BONE_HIDDEN_P)) {
-                       if (pchan->bone->flag & (BONE_SELECTED|BONE_ACTIVE)) {
+                       if ((pchan->bone->flag & BONE_SELECTED) || (pchan->bone == arm->act_bone)) {
                                if (pchan->agrp_index) {
                                        pchan->agrp_index= 0;
                                        done= 1;
@@ -1428,7 +1321,7 @@ void POSE_OT_group_unassign (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Remove Selected from Bone Groups";
        ot->idname= "POSE_OT_group_unassign";
-       ot->description= "Add selected bones from all bone groups";
+       ot->description= "Remove selected bones from all bone groups";
        
        /* api callbacks */
        ot->exec= pose_group_unassign_exec;
@@ -1438,143 +1331,6 @@ void POSE_OT_group_unassign (wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-/* ----------------- */
-
-static int pose_groupOps_menu_invoke (bContext *C, wmOperator *op, wmEvent *evt)
-{
-       Object *ob= CTX_data_active_object(C);
-       uiPopupMenu *pup= uiPupMenuBegin(C, op->type->name, 0);
-       uiLayout *layout= uiPupMenuLayout(pup);
-       
-       /* sanity check - must have object with pose */
-       if ELEM(NULL, ob, ob->pose)
-               return OPERATOR_CANCELLED;
-       
-       /* get mode of action */
-       if (CTX_DATA_COUNT(C, selected_pchans)) {
-               /* if selected bone(s), include options to add/remove to active group */
-               uiItemO(layout, "Add Selected to Active Group", 0, "POSE_OT_group_assign");
-               
-               uiItemS(layout);
-               
-               uiItemO(layout, "Remove Selected from All Groups", 0, "POSE_OT_group_unassign");
-               uiItemO(layout, "Remove Active Group", 0, "POSE_OT_group_remove");
-       }
-       else {
-               /* no selected bones - so just options for groups management */
-               uiItemO(layout, "Add New Group", 0, "POSE_OT_group_add");
-               uiItemO(layout, "Remove Active Group", 0, "POSE_OT_group_remove");
-       }
-               
-       return OPERATOR_CANCELLED;
-}
-
-void POSE_OT_groups_menu (wmOperatorType *ot)
-{
-       /* identifiers */
-       ot->name= "Bone Group Tools";
-       ot->idname= "POSE_OT_groups_menu";
-       ot->description= "Menu displaying available tools for Bone Groups.";
-       
-       /* api callbacks (only invoke needed) */
-       ot->invoke= pose_groupOps_menu_invoke;
-       ot->poll= ED_operator_posemode;
-       
-       /* flags */
-       ot->flag= OPTYPE_REGISTER;
-}
-
-/* ********************************************** */
-
-static short pose_select_same_group (Object *ob)
-{
-       bPose *pose= (ob)? ob->pose : NULL;
-       bArmature *arm= (ob)? ob->data : NULL;
-       bPoseChannel *pchan, *chan;
-       short changed= 0;
-       
-       if (ELEM3(NULL, ob, pose, arm))
-               return 0;
-       
-       /* loop in loop... bad and slow! */
-       for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-               if (arm->layer & pchan->bone->layer) {
-                       if (pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
-                               
-                               /* only if group matches (and is not selected or current bone) */
-                               for (chan= ob->pose->chanbase.first; chan; chan= chan->next) {
-                                       if (arm->layer & chan->bone->layer) {
-                                               if (pchan->agrp_index == chan->agrp_index) {
-                                                       chan->bone->flag |= BONE_SELECTED;
-                                                       changed= 1;
-                                               }
-                                       }
-                               }
-                               
-                       }
-               }
-       }
-       
-       return changed;
-}
-
-static short pose_select_same_layer (Object *ob)
-{
-       bPose *pose= (ob)? ob->pose : NULL;
-       bArmature *arm= (ob)? ob->data : NULL;
-       bPoseChannel *pchan;
-       short layers= 0, changed= 0;
-       
-       if (ELEM3(NULL, ob, pose, arm))
-               return 0;
-       
-       /* figure out what bones are selected */
-       for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-               if (arm->layer & pchan->bone->layer) {
-                       if (pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
-                               layers |= pchan->bone->layer;
-                       }
-               }
-       }
-       if (layers == 0) 
-               return 0;
-               
-       /* select bones that are on same layers as layers flag */
-       for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-               if (arm->layer & pchan->bone->layer) {
-                       if (layers & pchan->bone->layer) {
-                               pchan->bone->flag |= BONE_SELECTED;
-                               changed= 1;
-                       }
-               }
-       }
-       
-       return changed;
-}
-
-void pose_select_grouped (Scene *scene, short nr)
-{
-       short changed = 0;
-       
-       if (nr == 1)            changed= pose_select_same_group(OBACT);
-       else if (nr == 2)       changed= pose_select_same_layer(OBACT);
-       
-       if (changed) {
-               countall();
-               BIF_undo_push("Select Grouped");
-       }
-}
-
-/* Shift-G in 3D-View while in PoseMode */
-void pose_select_grouped_menu (Scene *scene)
-{
-       short nr;
-       
-       /* here we go */
-       nr= pupmenu("Select Grouped%t|In Same Group%x1|In Same Layer%x2");
-       pose_select_grouped(scene, nr);
-}
-
 /* ********************************************** */
 
 static int pose_flip_names_exec (bContext *C, wmOperator *op)
@@ -1589,7 +1345,7 @@ static int pose_flip_names_exec (bContext *C, wmOperator *op)
        arm= ob->data;
        
        /* loop through selected bones, auto-naming them */
-       CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans)
+       CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones)
        {
                BLI_strncpy(newname, pchan->name, sizeof(newname));
                bone_flip_name(newname, 1);     // 1 = do strip off number extensions
@@ -1611,7 +1367,7 @@ void POSE_OT_flip_names (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Flip Names";
        ot->idname= "POSE_OT_flip_names";
-       ot->description= "Flips (and corrects) the names of selected bones.";
+       ot->description= "Flips (and corrects) the names of selected bones";
        
        /* api callbacks */
        ot->exec= pose_flip_names_exec;
@@ -1636,7 +1392,7 @@ static int pose_autoside_names_exec (bContext *C, wmOperator *op)
        arm= ob->data;
        
        /* loop through selected bones, auto-naming them */
-       CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pchans)
+       CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones)
        {
                BLI_strncpy(newname, pchan->name, sizeof(newname));
                bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis]);
@@ -1664,7 +1420,7 @@ void POSE_OT_autoside_names (wmOperatorType *ot)
        /* identifiers */
        ot->name= "AutoName by Axis";
        ot->idname= "POSE_OT_autoside_names";
-       ot->description= "Automatically renames the selected bones according to which side of the target axis they fall on.";
+       ot->description= "Automatically renames the selected bones according to which side of the target axis they fall on";
        
        /* api callbacks */
        ot->invoke= WM_menu_invoke;
@@ -1675,7 +1431,7 @@ void POSE_OT_autoside_names (wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* settings */
-       RNA_def_enum(ot->srna, "axis", axis_items, 0, "Axis", "Axis tag names with.");
+       ot->prop= RNA_def_enum(ot->srna, "axis", axis_items, 0, "Axis", "Axis tag names with.");
 }
 
 /* ********************************************** */
@@ -1692,25 +1448,21 @@ void pose_activate_flipped_bone(Scene *scene)
                ob= modifiers_isDeformedByArmature(ob);
        }
        if(ob && (ob->mode & OB_MODE_POSE)) {
-               bPoseChannel *pchan, *pchanf;
+               bPoseChannel *pchanf;
                
-               for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-                       if(arm->layer & pchan->bone->layer) {
-                               if(pchan->bone->flag & BONE_ACTIVE)
-                                       break;
-                       }
-               }
-               if(pchan) {
+               if(arm->act_bone) {
                        char name[32];
                        
-                       BLI_strncpy(name, pchan->name, 32);
+                       BLI_strncpy(name, arm->act_bone->name, 32);
                        bone_flip_name(name, 1);        // 0 = do not strip off number extensions
                        
                        pchanf= get_pose_channel(ob->pose, name);
-                       if(pchanf && pchanf!=pchan) {
-                               pchan->bone->flag &= ~(BONE_SELECTED|BONE_ACTIVE);
-                               pchanf->bone->flag |= (BONE_SELECTED|BONE_ACTIVE);
-                       
+                       if(pchanf && pchanf->bone != arm->act_bone) {
+                               arm->act_bone->flag &= ~BONE_SELECTED;
+                               pchanf->bone->flag |= BONE_SELECTED;
+
+                               arm->act_bone= pchanf->bone;
+
                                /* in weightpaint we select the associated vertex group too */
                                if(ob->mode & OB_MODE_WEIGHT_PAINT) {
                                        ED_vgroup_select_by_name(OBACT, name);
@@ -1733,7 +1485,7 @@ static int pose_armature_layers_invoke (bContext *C, wmOperator *op, wmEvent *ev
        Object *ob= CTX_data_active_object(C);
        bArmature *arm= (ob)? ob->data : NULL;
        PointerRNA ptr;
-       int layers[16]; /* hardcoded for now - we can only have 16 armature layers, so this should be fine... */
+       int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
        
        /* sanity checking */
        if (arm == NULL)
@@ -1754,7 +1506,7 @@ static int pose_armature_layers_exec (bContext *C, wmOperator *op)
        Object *ob= CTX_data_active_object(C);
        bArmature *arm= (ob)? ob->data : NULL;
        PointerRNA ptr;
-       int layers[16]; /* hardcoded for now - we can only have 16 armature layers, so this should be fine... */
+       int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
        
        /* get the values set in the operator properties */
        RNA_boolean_get_array(op->ptr, "layers", layers);
@@ -1775,7 +1527,7 @@ void POSE_OT_armature_layers (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Change Armature Layers";
        ot->idname= "POSE_OT_armature_layers";
-       ot->description= "Change the visible armature layers.";
+       ot->description= "Change the visible armature layers";
        
        /* callbacks */
        ot->invoke= pose_armature_layers_invoke;
@@ -1786,7 +1538,7 @@ void POSE_OT_armature_layers (wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* properties */
-       RNA_def_boolean_layer_member(ot->srna, "layers", 16, NULL, "Layer", "Armature layers to make visible");
+       RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
 }
 
 void ARMATURE_OT_armature_layers (wmOperatorType *ot)
@@ -1794,7 +1546,7 @@ void ARMATURE_OT_armature_layers (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Change Armature Layers";
        ot->idname= "ARMATURE_OT_armature_layers";
-       ot->description= "Change the visible armature layers.";
+       ot->description= "Change the visible armature layers";
        
        /* callbacks */
        ot->invoke= pose_armature_layers_invoke;
@@ -1805,7 +1557,7 @@ void ARMATURE_OT_armature_layers (wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* properties */
-       RNA_def_boolean_layer_member(ot->srna, "layers", 16, NULL, "Layer", "Armature layers to make visible");
+       RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
 }
 
 /* ------------------- */
@@ -1813,17 +1565,17 @@ void ARMATURE_OT_armature_layers (wmOperatorType *ot)
 /* Present a popup to get the layers that should be used */
 static int pose_bone_layers_invoke (bContext *C, wmOperator *op, wmEvent *evt)
 {
-       int layers[16]; /* hardcoded for now - we can only have 16 armature layers, so this should be fine... */
+       int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
        
        /* get layers that are active already */
        memset(&layers, 0, sizeof(layers)); /* set all layers to be off by default */
        
-       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pchans) 
+       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones) 
        {
                short bit;
                
                /* loop over the bits for this pchan's layers, adding layers where they're needed */
-               for (bit= 0; bit < 16; bit++) {
+               for (bit= 0; bit < 32; bit++) {
                        if (pchan->bone->layer & (1<<bit))
                                layers[bit]= 1;
                }
@@ -1843,13 +1595,13 @@ static int pose_bone_layers_exec (bContext *C, wmOperator *op)
        Object *ob= CTX_data_active_object(C);
        bArmature *arm= (ob)? ob->data : NULL;
        PointerRNA ptr;
-       int layers[16]; /* hardcoded for now - we can only have 16 armature layers, so this should be fine... */
+       int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
        
        /* get the values set in the operator properties */
        RNA_boolean_get_array(op->ptr, "layers", layers);
        
        /* set layers of pchans based on the values set in the operator props */
-       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pchans) 
+       CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones) 
        {
                /* get pointer for pchan, and write flags this way */
                RNA_pointer_create((ID *)arm, &RNA_Bone, pchan->bone, &ptr);
@@ -1868,7 +1620,7 @@ void POSE_OT_bone_layers (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Change Bone Layers";
        ot->idname= "POSE_OT_bone_layers";
-       ot->description= "Change the layers that the selected bones belong to.";
+       ot->description= "Change the layers that the selected bones belong to";
        
        /* callbacks */
        ot->invoke= pose_bone_layers_invoke;
@@ -1879,7 +1631,7 @@ void POSE_OT_bone_layers (wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* properties */
-       RNA_def_boolean_layer_member(ot->srna, "layers", 16, NULL, "Layer", "Armature layers that bone belongs to");
+       RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
 }
 
 /* ------------------- */
@@ -1887,7 +1639,7 @@ void POSE_OT_bone_layers (wmOperatorType *ot)
 /* Present a popup to get the layers that should be used */
 static int armature_bone_layers_invoke (bContext *C, wmOperator *op, wmEvent *evt)
 {
-       int layers[16]; /* hardcoded for now - we can only have 16 armature layers, so this should be fine... */
+       int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
        
        /* get layers that are active already */
        memset(&layers, 0, sizeof(layers)); /* set all layers to be off by default */
@@ -1897,7 +1649,7 @@ static int armature_bone_layers_invoke (bContext *C, wmOperator *op, wmEvent *ev
                short bit;
                
                /* loop over the bits for this pchan's layers, adding layers where they're needed */
-               for (bit= 0; bit < 16; bit++) {
+               for (bit= 0; bit < 32; bit++) {
                        if (ebone->layer & (1<<bit))
                                layers[bit]= 1;
                }
@@ -1917,7 +1669,7 @@ static int armature_bone_layers_exec (bContext *C, wmOperator *op)
        Object *ob= CTX_data_edit_object(C);
        bArmature *arm= (ob)? ob->data : NULL;
        PointerRNA ptr;
-       int layers[16]; /* hardcoded for now - we can only have 16 armature layers, so this should be fine... */
+       int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
        
        /* get the values set in the operator properties */
        RNA_boolean_get_array(op->ptr, "layers", layers);
@@ -1942,7 +1694,7 @@ void ARMATURE_OT_bone_layers (wmOperatorType *ot)
        /* identifiers */
        ot->name= "Change Bone Layers";
        ot->idname= "ARMATURE_OT_bone_layers";
-       ot->description= "Change the layers that the selected bones belong to.";
+       ot->description= "Change the layers that the selected bones belong to";
        
        /* callbacks */
        ot->invoke= armature_bone_layers_invoke;
@@ -1953,36 +1705,86 @@ void ARMATURE_OT_bone_layers (wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* properties */
-       RNA_def_boolean_layer_member(ot->srna, "layers", 16, NULL, "Layer", "Armature layers that bone belongs to");
+       RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
 }
 
 /* ********************************************** */
 
-/* for use in insertkey, ensure rotation goes other way around */
-void pose_flipquats(Scene *scene)
+static int pose_flip_quats_exec (bContext *C, wmOperator *op)
 {
-       Object *ob = OBACT;
-       bArmature *arm= ob->data;
-       bPoseChannel *pchan;
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
        
-       if(ob->pose==NULL)
-               return;
+       bCommonKeySrc cks;
+       ListBase dsources = {&cks, &cks};
        
-       /* find sel bones */
-       for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
-               if(pchan->bone && (pchan->bone->flag & BONE_SELECTED) && (pchan->bone->layer & arm->layer)) {
+       /* init common-key-source for use by KeyingSets */
+       memset(&cks, 0, sizeof(bCommonKeySrc));
+       cks.id= &ob->id;
+       
+       /* loop through all selected pchans, flipping and keying (as needed) */
+       CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones)
+       {
+               /* only if bone is using quaternion rotation */
+               if (pchan->rotmode == ROT_MODE_QUAT) {
                        /* quaternions have 720 degree range */
                        pchan->quat[0]= -pchan->quat[0];
                        pchan->quat[1]= -pchan->quat[1];
                        pchan->quat[2]= -pchan->quat[2];
                        pchan->quat[3]= -pchan->quat[3];
+                       
+                       /* perform auto-keying 
+                        * NOTE: paths don't need recalculation here, since the orientations shouldn't have changed
+                        */
+                       if (autokeyframe_cfra_can_key(scene, &ob->id)) {
+                               /* Set keys on pose
+                                *      - KeyingSet to use depends on rotation mode 
+                                *      (but that's handled by the templates code)  
+                                */
+                               KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
+                               
+                               /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
+                               cks.pchan= pchan;
+                               
+                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+                               
+                               /* clear any unkeyed tags */
+                               if (pchan->bone)
+                                       pchan->bone->flag &= ~BONE_UNKEYED;
+                       }
+                       else {
+                               /* add unkeyed tags */
+                               if (pchan->bone)
+                                       pchan->bone->flag |= BONE_UNKEYED;
+                       }
                }
        }
+       CTX_DATA_END;
+       
+       /* notifiers and updates */
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, ob);
+       
+       return OPERATOR_FINISHED;
+}
+
+void POSE_OT_quaternions_flip (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Flip Quats";
+       ot->idname= "POSE_OT_quaternions_flip";
+       ot->description= "Flip quaternion values to achieve desired rotations, while maintaining the same orientations";
        
-       /* do autokey */
-       autokeyframe_pose_cb_func(ob, TFM_ROTATION, 0);
+       /* callbacks */
+       ot->exec= pose_flip_quats_exec;
+       ot->poll= ED_operator_posemode;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
+/* ********************************************** */
+
 /* context: active channel */
 void pose_special_editmenu(Scene *scene)
 {