Animation Editors - Durian Request - Selection Syncing:

This commit brings back the functionality whereby the selection of F-Curves and/or relevant Group(s) is synced with the selection status of the corresponding bones when the bones are selected/deselected.
This commit is contained in:
Joshua Leung 2009-12-21 09:52:43 +00:00
parent 824b763322
commit 0fcfe8993e
4 changed files with 196 additions and 125 deletions

@ -27,25 +27,30 @@
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <math.h> #include <math.h>
#include "MEM_guardedalloc.h" #include "MEM_guardedalloc.h"
#include "DNA_action_types.h"
#include "DNA_anim_types.h" #include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_armature_types.h" #include "DNA_armature_types.h"
#include "DNA_object_types.h" #include "DNA_object_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h" #include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "BLI_blenlib.h" #include "BLI_blenlib.h"
#include "BKE_action.h"
#include "BKE_animsys.h" #include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_context.h" #include "BKE_context.h"
#include "BKE_depsgraph.h" #include "BKE_depsgraph.h"
#include "BKE_global.h" #include "BKE_global.h"
#include "BKE_main.h" #include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_scene.h" #include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_screen.h" #include "BKE_screen.h"
#include "BKE_utildefines.h" #include "BKE_utildefines.h"
@ -58,8 +63,11 @@
#include "WM_api.h" #include "WM_api.h"
#include "WM_types.h" #include "WM_types.h"
/* **************************** depsgraph tagging ******************************** */
/* tags the given anim list element for refreshes (if applicable) /* tags the given anim list element for refreshes (if applicable)
* due to Animation Editor editing */ * due to Animation Editor editing
*/
void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale) void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale)
{ {
ID *id; ID *id;
@ -67,24 +75,24 @@ void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale)
AnimData *adt; AnimData *adt;
id= ale->id; id= ale->id;
if(!id) if (!id)
return; return;
/* tag AnimData for refresh so that other views will update in realtime with these changes */ /* tag AnimData for refresh so that other views will update in realtime with these changes */
adt= BKE_animdata_from_id(id); adt= BKE_animdata_from_id(id);
if(adt) if (adt)
adt->recalc |= ADT_RECALC_ANIM; adt->recalc |= ADT_RECALC_ANIM;
/* update data */ /* update data */
fcu= (ale->datatype == ALE_FCURVE)? ale->key_data: NULL; fcu= (ale->datatype == ALE_FCURVE)? ale->key_data: NULL;
if(fcu && fcu->rna_path) { if (fcu && fcu->rna_path) {
/* if we have an fcurve, call the update for the property we /* if we have an fcurve, call the update for the property we
are editing, this is then expected to do the proper redraws are editing, this is then expected to do the proper redraws
and depsgraph updates */ and depsgraph updates */
PointerRNA id_ptr, ptr; PointerRNA id_ptr, ptr;
PropertyRNA *prop; PropertyRNA *prop;
RNA_id_pointer_create(id, &id_ptr); RNA_id_pointer_create(id, &id_ptr);
if(RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) if(RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop))
@ -101,7 +109,7 @@ void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale)
* Animation Editor editing */ * Animation Editor editing */
void ANIM_id_update(Scene *scene, ID *id) void ANIM_id_update(Scene *scene, ID *id)
{ {
if(id) { if (id) {
AnimData *adt= BKE_animdata_from_id(id); AnimData *adt= BKE_animdata_from_id(id);
/* tag AnimData for refresh so that other views will update in realtime with these changes */ /* tag AnimData for refresh so that other views will update in realtime with these changes */
@ -113,103 +121,162 @@ void ANIM_id_update(Scene *scene, ID *id)
} }
} }
/* **************************** pose <-> action syncing ******************************** */ /* **************************** animation data <-> data syncing ******************************** */
/* Summary of what needs to be synced between poses and actions: /* This code here is used to synchronise the
* 1) Flags * - selection (to find selected data easier)
* a) Visibility (only for pose to action) * - ... (insert other relevant items here later)
* b) Selection status (both ways) * status in relevant Blender data with the status stored in animation channels.
* 2) Group settings (only for pose to action) - do we also need to make sure same groups exist?
* 3) Grouping (only for pose to action for now)
*/
/* Notifier from Action/Dopesheet (this may be extended to include other things such as Python...)
* Channels in action changed, so update pose channels/groups to reflect changes.
* *
* An object (usually 'active' Object) needs to be supplied, so that its Pose-Channels can be synced with * This should be called in the refresh() callbacks for various editors in
* the channels in its active Action. * response to appropriate notifiers.
*/ */
void ANIM_action_to_pose_sync (Object *ob)
/* perform syncing updates for Action Groups */
static void animchan_sync_group (bAnimContext *ac, bAnimListElem *ale)
{ {
#if 0 bActionGroup *agrp= (bActionGroup *)ale->data;
AnimData *adt= ob->adt; ID *owner_id= ale->id;
bAction *act= adt->act;
FCurve *fcu;
bPoseChannel *pchan;
/* error checking */ /* major priority is selection status
if (ELEM3(NULL, ob, ob->adt, ob->pose) || (ob->type != OB_ARMATURE)) * so we need both a group and an owner
*/
if (ELEM(NULL, agrp, owner_id))
return; return;
/* 1b) loop through all Action-Channels (there should be fewer channels to search through here in general) */
for (achan= act->chanbase.first; achan; achan= achan->next) {
/* find matching pose-channel */
pchan= get_pose_channel(ob->pose, achan->name);
/* sync active and selected flags */ /* for standard Objects, check if group is the name of some bone */
if (pchan && pchan->bone) { if (GS(owner_id->name) == ID_OB) {
/* selection */ Object *ob= (Object *)owner_id;
if (achan->flag & ACHAN_SELECTED)
pchan->bone->flag |= BONE_SELECTED; /* check if there are bones, and whether the name matches any
else * NOTE: this feature will only really work if groups by default contain the F-Curves for a single bone
pchan->bone->flag &= ~BONE_SELECTED; */
if (ob->pose) {
bPoseChannel *pchan= get_pose_channel(ob->pose, agrp->name);
/* active */ /* if one matches, sync the selection status */
if (achan->flag & ACHAN_HILIGHTED) if (pchan) {
pchan->bone->flag |= BONE_ACTIVE; if (pchan->bone->flag & BONE_SELECTED)
else agrp->flag |= AGRP_SELECTED;
pchan->bone->flag &= ~BONE_ACTIVE; else
agrp->flag &= ~AGRP_SELECTED;
}
} }
} }
}
// TODO: add grouping changes too? For now, these tools aren't exposed to users in animation editors yet...
#endif
}
/* Notifier from 3D-View/Outliner (this is likely to include other sources too...) /* perform syncing updates for F-Curves */
* Pose channels/groups changed, so update action channels static void animchan_sync_fcurve (bAnimContext *ac, bAnimListElem *ale)
*
* An object (usually 'active' Object) needs to be supplied, so that its Pose-Channels can be synced with
* the channels in its active Action.
*/
void ANIM_pose_to_action_sync (Object *ob, ScrArea *sa)
{ {
#if 0 // XXX old animation system FCurve *fcu= (FCurve *)ale->data;
SpaceAction *saction= (SpaceAction *)sa->spacedata.first; ID *owner_id= ale->id;
bArmature *arm= (bArmature *)ob->data;
bAction *act= (bAction *)ob->action;
bActionChannel *achan;
//bActionGroup *agrp, *bgrp;
bPoseChannel *pchan;
/* error checking */ /* major priority is selection status, so refer to the checks done in anim_filter.c
if ((ob == NULL) || (ob->type != OB_ARMATURE) || ELEM3(NULL, arm, act, ob->pose)) * skip_fcurve_selected_data() for reference about what's going on here...
*/
if (ELEM3(NULL, fcu, fcu->rna_path, owner_id))
return; return;
/* 1) loop through all Action-Channels (there should be fewer channels to search through here in general) */ if (GS(owner_id->name) == ID_OB) {
for (achan= act->chanbase.first; achan; achan= achan->next) { Object *ob= (Object *)owner_id;
/* find matching pose-channel */
pchan= get_pose_channel(ob->pose, achan->name);
/* sync selection and visibility settings */ /* only affect if F-Curve involves pose.bones */
if (pchan && pchan->bone) { if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) {
/* visibility - if layer is hidden, or if bone itself is hidden */ bPoseChannel *pchan;
if (!(saction->flag & SACTION_NOHIDE) && !(saction->pin)) { char *bone_name;
if (!(pchan->bone->layer & arm->layer) || (pchan->bone->flag & BONE_HIDDEN_P))
achan->flag |= ACHAN_HIDDEN; /* get bone-name, and check if this bone is selected */
bone_name= BLI_getQuotedStr(fcu->rna_path, "pose.bones[");
pchan= get_pose_channel(ob->pose, bone_name);
if (bone_name) MEM_freeN(bone_name);
/* F-Curve selection depends on whether the bone is selected */
if ((pchan) && (pchan->bone)) {
if (pchan->bone->flag & BONE_SELECTED)
fcu->flag |= FCURVE_SELECTED;
else else
achan->flag &= ~ACHAN_HIDDEN; fcu->flag &= ~FCURVE_SELECTED;
} }
}
/* selection */ }
if (pchan->bone->flag & BONE_SELECTED) else if (GS(owner_id->name) == ID_SCE) {
achan->flag |= ACHAN_SELECTED; Scene *scene = (Scene *)owner_id;
else
achan->flag &= ~ACHAN_SELECTED; /* only affect if F-Curve involves sequence_editor.sequences */
if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
Editing *ed= seq_give_editing(scene, FALSE);
Sequence *seq;
char *seq_name;
/* get strip name, and check if this strip is selected */
seq_name= BLI_getQuotedStr(fcu->rna_path, "sequences_all[");
seq = get_seq_by_name(ed->seqbasep, seq_name, FALSE);
if (seq_name) MEM_freeN(seq_name);
/* can only add this F-Curve if it is selected */
if (seq) {
if (seq->flag & SELECT)
fcu->flag |= FCURVE_SELECTED;
else
fcu->flag &= ~FCURVE_SELECTED;
}
}
}
else if (GS(owner_id->name) == ID_NT) {
bNodeTree *ntree = (bNodeTree *)owner_id;
/* check for selected nodes */
if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) {
bNode *node;
char *node_name;
/* get strip name, and check if this strip is selected */
node_name= BLI_getQuotedStr(fcu->rna_path, "nodes[");
node = nodeFindNodebyName(ntree, node_name);
if (node_name) MEM_freeN(node_name);
/* can only add this F-Curve if it is selected */
if (node) {
if (node->flag & NODE_SELECT)
fcu->flag |= FCURVE_SELECTED;
else
fcu->flag &= ~FCURVE_SELECTED;
}
}
}
}
/* ---------------- */
/* Main call to be exported to animation editors */
void ANIM_sync_animchannels_to_data (const bContext *C)
{
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
/* 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_CHANNELS;
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);
break;
case ANIMTYPE_FCURVE:
animchan_sync_fcurve(&ac, ale);
break;
} }
} }
// XXX step 2 needs to be coded still... currently missing action/bone group API to do any more work here... BLI_freelistN(&anim_data);
// XXX step 3 needs to be coded still... it's a messy case to deal with (we'll use the temp indices for this?)
#endif // XXX old animation system
} }

@ -494,9 +494,8 @@ void ED_nla_postop_refresh(bAnimContext *ac);
void ANIM_id_update(struct Scene *scene, struct ID *id); void ANIM_id_update(struct Scene *scene, struct ID *id);
void ANIM_list_elem_update(struct Scene *scene, bAnimListElem *ale); void ANIM_list_elem_update(struct Scene *scene, bAnimListElem *ale);
/* pose <-> action syncing */ /* data -> channels syncing */
void ANIM_action_to_pose_sync(struct Object *ob); void ANIM_sync_animchannels_to_data(const struct bContext *C);
void ANIM_pose_to_action_sync(struct Object *ob, struct ScrArea *sa);
/* ************************************************* */ /* ************************************************* */
/* OPERATORS */ /* OPERATORS */

@ -356,25 +356,31 @@ static void action_listener(ScrArea *sa, wmNotifier *wmn)
/* context changes */ /* context changes */
switch (wmn->category) { switch (wmn->category) {
case NC_ANIMATION: case NC_ANIMATION:
ED_area_tag_refresh(sa); ED_area_tag_redraw(sa);
break; break;
case NC_SCENE: case NC_SCENE:
/*switch (wmn->data) { switch (wmn->data) {
case ND_OB_ACTIVE: case ND_OB_ACTIVE: /* selection changed, so force refresh to flush */
case ND_OB_SELECT: case ND_OB_SELECT:
ED_area_tag_refresh(sa); ED_area_tag_refresh(sa);
break; break;
}*/
ED_area_tag_refresh(sa); default: /* just redrawing the view will do */
ED_area_tag_redraw(sa);
break;
}
break; break;
case NC_OBJECT: case NC_OBJECT:
/*switch (wmn->data) { switch (wmn->data) {
case ND_BONE_SELECT: case ND_BONE_SELECT: /* selection changed, so force refresh to flush */
case ND_BONE_ACTIVE: case ND_BONE_ACTIVE:
ED_area_tag_refresh(sa); ED_area_tag_refresh(sa);
break; break;
}*/
ED_area_tag_refresh(sa); default: /* just redrawing the view will do */
ED_area_tag_redraw(sa);
break;
}
break; break;
case NC_SPACE: case NC_SPACE:
if(wmn->data == ND_SPACE_DOPESHEET) if(wmn->data == ND_SPACE_DOPESHEET)
@ -385,25 +391,11 @@ static void action_listener(ScrArea *sa, wmNotifier *wmn)
static void action_refresh(const bContext *C, ScrArea *sa) static void action_refresh(const bContext *C, ScrArea *sa)
{ {
SpaceAction *saction = (SpaceAction *)sa->spacedata.first; //SpaceAction *saction= CTX_wm_space_action(C);
/* updates to data needed depends on Action Editor mode... */ /* update the state of the animchannels in response to changes from the data they represent */
switch (saction->mode) { // TODO: check if we don't want this to happen
case SACTCONT_DOPESHEET: /* DopeSheet - for now, just all armatures... */ ANIM_sync_animchannels_to_data(C);
{
}
break;
case SACTCONT_ACTION: /* Action Editor - just active object will do */
{
Object *ob= CTX_data_active_object(C);
/* sync changes to bones to the corresponding action channels */
ANIM_pose_to_action_sync(ob, sa);
}
break;
}
/* region updates? */ /* region updates? */
// XXX resizing y-extents of tot should go here? // XXX resizing y-extents of tot should go here?

@ -434,25 +434,34 @@ static void graph_listener(ScrArea *sa, wmNotifier *wmn)
/* context changes */ /* context changes */
switch (wmn->category) { switch (wmn->category) {
case NC_ANIMATION: case NC_ANIMATION:
/* unlike for DopeSheet, we want refresh not redraw here,
* since F-Curve colors may need setting
*/
ED_area_tag_refresh(sa); ED_area_tag_refresh(sa);
break; break;
case NC_SCENE: case NC_SCENE:
/*switch (wmn->data) { switch (wmn->data) {
case ND_OB_ACTIVE: case ND_OB_ACTIVE: /* selection changed, so force refresh to flush */
case ND_OB_SELECT: case ND_OB_SELECT:
ED_area_tag_refresh(sa); ED_area_tag_refresh(sa);
break; break;
}*/
ED_area_tag_refresh(sa); default: /* just redrawing the view will do */
ED_area_tag_redraw(sa);
break;
}
break; break;
case NC_OBJECT: case NC_OBJECT:
/*switch (wmn->data) { switch (wmn->data) {
case ND_BONE_SELECT: case ND_BONE_SELECT: /* selection changed, so force refresh to flush */
case ND_BONE_ACTIVE: case ND_BONE_ACTIVE:
ED_area_tag_refresh(sa); ED_area_tag_refresh(sa);
break; break;
}*/
ED_area_tag_refresh(sa); default: /* just redrawing the view will do */
ED_area_tag_redraw(sa);
break;
}
break; break;
case NC_SPACE: case NC_SPACE:
if(wmn->data == ND_SPACE_GRAPH) if(wmn->data == ND_SPACE_GRAPH)
@ -489,6 +498,10 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
/* region updates? */ /* region updates? */
// XXX resizing y-extents of tot should go here? // XXX resizing y-extents of tot should go here?
/* update the state of the animchannels in response to changes from the data they represent */
// TODO: check if we don't want this to happen
ANIM_sync_animchannels_to_data(C);
/* init/adjust F-Curve colors */ /* init/adjust F-Curve colors */
if (ANIM_animdata_get_context(C, &ac)) { if (ANIM_animdata_get_context(C, &ac)) {
ListBase anim_data = {NULL, NULL}; ListBase anim_data = {NULL, NULL};