Bugfix [#27652] Selecting a bone doesn't update Driver Properties panel
authorJoshua Leung <aligorith@gmail.com>
Sat, 18 Aug 2012 05:14:21 +0000 (05:14 +0000)
committerJoshua Leung <aligorith@gmail.com>
Sat, 18 Aug 2012 05:14:21 +0000 (05:14 +0000)
More specifically, selecting bones didn't update the active F-Curve/Groups. This
meant that when editing drivers, it was often easy to accidentally edit the
drivers for the wrong bone.

source/blender/editors/animation/anim_deps.c

index 3cc3923871325a5e24d8cb618b32249716041252..3e0380929f8554dee93e8269a6d52acdb83917e4 100644 (file)
@@ -125,7 +125,7 @@ void ANIM_id_update(Scene *UNUSED(scene), ID *id)
  */
 
 /* perform syncing updates for Action Groups */
-static void animchan_sync_group(bAnimContext *UNUSED(ac), bAnimListElem *ale)
+static void animchan_sync_group(bAnimContext *ac, bAnimListElem *ale, bActionGroup **active_agrp)
 {
        bActionGroup *agrp = (bActionGroup *)ale->data;
        ID *owner_id = ale->id;
@@ -143,22 +143,42 @@ static void animchan_sync_group(bAnimContext *UNUSED(ac), bAnimListElem *ale)
                /* check if there are bones, and whether the name matches any 
                 * NOTE: this feature will only really work if groups by default contain the F-Curves for a single bone
                 */
+               // TODO: if bone gets renamed, it would be best to be able to rename the group
+               // TODO: sync bone/group colors
                if (ob->pose) {
                        bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name);
+                       bArmature *arm = ob->data;
                        
-                       /* if one matches, sync the selection status */
                        if (pchan) {
-                               if (pchan->bone && pchan->bone->flag & BONE_SELECTED)
+                               /* if one matches, sync the selection status */
+                               if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))
                                        agrp->flag |= AGRP_SELECTED;
                                else
                                        agrp->flag &= ~AGRP_SELECTED;
+                                       
+                               /* also sync active group status */
+                               if ((ob == ac->obact) && (pchan->bone == arm->act_bone)) {
+                                       /* if no previous F-Curve has active flag, then we're the first and only one to get it */
+                                       if (*active_agrp == NULL) {
+                                               agrp->flag |= AGRP_ACTIVE;
+                                               *active_agrp = agrp;
+                                       }
+                                       else {
+                                               /* someone else has already taken it - set as not active */
+                                               agrp->flag &= ~AGRP_ACTIVE;
+                                       }
+                               }
+                               else {
+                                       /* this can't possibly be active now */
+                                       agrp->flag &= ~AGRP_ACTIVE;
+                               }
                        }
                }
        }
 }
  
 /* perform syncing updates for F-Curves */
-static void animchan_sync_fcurve(bAnimContext *UNUSED(ac), bAnimListElem *ale)
+static void animchan_sync_fcurve(bAnimContext *ac, bAnimListElem *ale, FCurve **active_fcurve)
 {
        FCurve *fcu = (FCurve *)ale->data;
        ID *owner_id = ale->id;
@@ -168,12 +188,13 @@ static void animchan_sync_fcurve(bAnimContext *UNUSED(ac), bAnimListElem *ale)
         */
        if (ELEM3(NULL, fcu, fcu->rna_path, owner_id))
                return;
-               
+       
        if (GS(owner_id->name) == ID_OB) {
                Object *ob = (Object *)owner_id;
                
                /* only affect if F-Curve involves pose.bones */
                if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) {
+                       bArmature *arm = (bArmature *)ob->data;
                        bPoseChannel *pchan;
                        char *bone_name;
                        
@@ -184,10 +205,30 @@ static void animchan_sync_fcurve(bAnimContext *UNUSED(ac), bAnimListElem *ale)
                        
                        /* F-Curve selection depends on whether the bone is selected */
                        if ((pchan) && (pchan->bone)) {
+                               /* F-Curve selection */
                                if (pchan->bone->flag & BONE_SELECTED)
                                        fcu->flag |= FCURVE_SELECTED;
                                else
                                        fcu->flag &= ~FCURVE_SELECTED;
+                                       
+                               /* Active F-Curve - it should be the first one for this bone on the 
+                                * active object to be considered as active
+                                */
+                               if ((ob == ac->obact) && (pchan->bone == arm->act_bone)) {
+                                       /* if no previous F-Curve has active flag, then we're the first and only one to get it */
+                                       if (*active_fcurve == NULL) {
+                                               fcu->flag |= FCURVE_ACTIVE;
+                                               *active_fcurve = fcu;
+                                       }
+                                       else {
+                                               /* someone else has already taken it - set as not active */
+                                               fcu->flag &= ~FCURVE_ACTIVE;
+                                       }
+                               }
+                               else {
+                                       /* this can't possibly be active now */
+                                       fcu->flag &= ~FCURVE_ACTIVE;
+                               }
                        }
                }
        }
@@ -248,25 +289,30 @@ void ANIM_sync_animchannels_to_data(const bContext *C)
        bAnimListElem *ale;
        int filter;
        
+       bActionGroup *active_agrp = NULL;
+       FCurve *active_fcurve = NULL;
+       
        /* get animation context info for filtering the channels */
        // TODO: check on whether we need to set the area specially instead, since active area might not be ok?
        if (ANIM_animdata_get_context(C, &ac) == 0)
                return;
        
        /* filter data */
-       /* NOTE: we want all channels, since we want to be able to set selection status on some of them even when collapsed */
-       filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS;
+       /* NOTE: we want all channels, since we want to be able to set selection status on some of them even when collapsed 
+        *       However, don't include duplicates so that selection statuses don't override each other
+        */
+       filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS;
        ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
        
        /* flush settings as appropriate depending on the types of the channels */
        for (ale = anim_data.first; ale; ale = ale->next) {
                switch (ale->type) {
                        case ANIMTYPE_GROUP:
-                               animchan_sync_group(&ac, ale);
+                               animchan_sync_group(&ac, ale, &active_agrp);
                                break;
                        
                        case ANIMTYPE_FCURVE:
-                               animchan_sync_fcurve(&ac, ale);
+                               animchan_sync_fcurve(&ac, ale, &active_fcurve);
                                break;
                }
        }