From 0fcfe8993e63d2490320cf90a0e2567588ea54f6 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 21 Dec 2009 09:52:43 +0000 Subject: [PATCH] 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. --- source/blender/editors/animation/anim_deps.c | 241 +++++++++++------- source/blender/editors/include/ED_anim_api.h | 5 +- .../editors/space_action/space_action.c | 46 ++-- .../blender/editors/space_graph/space_graph.c | 29 ++- 4 files changed, 196 insertions(+), 125 deletions(-) diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index 0e81dab380c..1d7483d661f 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -27,25 +27,30 @@ */ #include +#include #include #include "MEM_guardedalloc.h" -#include "DNA_action_types.h" #include "DNA_anim_types.h" +#include "DNA_action_types.h" #include "DNA_armature_types.h" #include "DNA_object_types.h" +#include "DNA_node_types.h" #include "DNA_scene_types.h" +#include "DNA_sequence_types.h" #include "BLI_blenlib.h" -#include "BKE_action.h" #include "BKE_animsys.h" +#include "BKE_action.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_node.h" #include "BKE_scene.h" +#include "BKE_sequencer.h" #include "BKE_screen.h" #include "BKE_utildefines.h" @@ -58,8 +63,11 @@ #include "WM_api.h" #include "WM_types.h" +/* **************************** depsgraph tagging ******************************** */ + /* 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) { ID *id; @@ -67,24 +75,24 @@ void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale) AnimData *adt; id= ale->id; - if(!id) + if (!id) return; /* tag AnimData for refresh so that other views will update in realtime with these changes */ adt= BKE_animdata_from_id(id); - if(adt) + if (adt) adt->recalc |= ADT_RECALC_ANIM; /* update data */ 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 are editing, this is then expected to do the proper redraws and depsgraph updates */ PointerRNA id_ptr, ptr; PropertyRNA *prop; - + RNA_id_pointer_create(id, &id_ptr); 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 */ void ANIM_id_update(Scene *scene, ID *id) { - if(id) { + if (id) { AnimData *adt= BKE_animdata_from_id(id); /* 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 ******************************** */ -/* Summary of what needs to be synced between poses and actions: - * 1) Flags - * a) Visibility (only for pose to action) - * b) Selection status (both ways) - * 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. +/* **************************** animation data <-> data syncing ******************************** */ +/* This code here is used to synchronise the + * - selection (to find selected data easier) + * - ... (insert other relevant items here later) + * status in relevant Blender data with the status stored in animation channels. * - * An object (usually 'active' Object) needs to be supplied, so that its Pose-Channels can be synced with - * the channels in its active Action. + * This should be called in the refresh() callbacks for various editors in + * 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 - AnimData *adt= ob->adt; - bAction *act= adt->act; - FCurve *fcu; - bPoseChannel *pchan; + bActionGroup *agrp= (bActionGroup *)ale->data; + ID *owner_id= ale->id; - /* error checking */ - if (ELEM3(NULL, ob, ob->adt, ob->pose) || (ob->type != OB_ARMATURE)) + /* major priority is selection status + * so we need both a group and an owner + */ + if (ELEM(NULL, agrp, owner_id)) 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 */ - if (pchan && pchan->bone) { - /* selection */ - if (achan->flag & ACHAN_SELECTED) - pchan->bone->flag |= BONE_SELECTED; - else - pchan->bone->flag &= ~BONE_SELECTED; + /* for standard Objects, check if group is the name of some bone */ + if (GS(owner_id->name) == ID_OB) { + Object *ob= (Object *)owner_id; + + /* 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 + */ + if (ob->pose) { + bPoseChannel *pchan= get_pose_channel(ob->pose, agrp->name); - /* active */ - if (achan->flag & ACHAN_HILIGHTED) - pchan->bone->flag |= BONE_ACTIVE; - else - pchan->bone->flag &= ~BONE_ACTIVE; + /* if one matches, sync the selection status */ + if (pchan) { + if (pchan->bone->flag & BONE_SELECTED) + agrp->flag |= AGRP_SELECTED; + 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...) - * Pose channels/groups changed, so update action channels - * - * 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) +/* perform syncing updates for F-Curves */ +static void animchan_sync_fcurve (bAnimContext *ac, bAnimListElem *ale) { -#if 0 // XXX old animation system - SpaceAction *saction= (SpaceAction *)sa->spacedata.first; - bArmature *arm= (bArmature *)ob->data; - bAction *act= (bAction *)ob->action; - bActionChannel *achan; - //bActionGroup *agrp, *bgrp; - bPoseChannel *pchan; + FCurve *fcu= (FCurve *)ale->data; + ID *owner_id= ale->id; - /* error checking */ - if ((ob == NULL) || (ob->type != OB_ARMATURE) || ELEM3(NULL, arm, act, ob->pose)) + /* major priority is selection status, so refer to the checks done in anim_filter.c + * skip_fcurve_selected_data() for reference about what's going on here... + */ + if (ELEM3(NULL, fcu, fcu->rna_path, owner_id)) return; - /* 1) 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); + if (GS(owner_id->name) == ID_OB) { + Object *ob= (Object *)owner_id; - /* sync selection and visibility settings */ - if (pchan && pchan->bone) { - /* visibility - if layer is hidden, or if bone itself is hidden */ - if (!(saction->flag & SACTION_NOHIDE) && !(saction->pin)) { - if (!(pchan->bone->layer & arm->layer) || (pchan->bone->flag & BONE_HIDDEN_P)) - achan->flag |= ACHAN_HIDDEN; + /* only affect if F-Curve involves pose.bones */ + if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) { + bPoseChannel *pchan; + char *bone_name; + + /* 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 - achan->flag &= ~ACHAN_HIDDEN; + fcu->flag &= ~FCURVE_SELECTED; } - - /* selection */ - if (pchan->bone->flag & BONE_SELECTED) - achan->flag |= ACHAN_SELECTED; - else - achan->flag &= ~ACHAN_SELECTED; + } + } + else if (GS(owner_id->name) == ID_SCE) { + Scene *scene = (Scene *)owner_id; + + /* 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... - // 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 + BLI_freelistN(&anim_data); } diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 7f8df38741d..48e2eff0d31 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -494,9 +494,8 @@ void ED_nla_postop_refresh(bAnimContext *ac); void ANIM_id_update(struct Scene *scene, struct ID *id); void ANIM_list_elem_update(struct Scene *scene, bAnimListElem *ale); -/* pose <-> action syncing */ -void ANIM_action_to_pose_sync(struct Object *ob); -void ANIM_pose_to_action_sync(struct Object *ob, struct ScrArea *sa); +/* data -> channels syncing */ +void ANIM_sync_animchannels_to_data(const struct bContext *C); /* ************************************************* */ /* OPERATORS */ diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 67b4d6e848b..1bc300395ca 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -356,25 +356,31 @@ static void action_listener(ScrArea *sa, wmNotifier *wmn) /* context changes */ switch (wmn->category) { case NC_ANIMATION: - ED_area_tag_refresh(sa); + ED_area_tag_redraw(sa); break; case NC_SCENE: - /*switch (wmn->data) { - case ND_OB_ACTIVE: + switch (wmn->data) { + case ND_OB_ACTIVE: /* selection changed, so force refresh to flush */ case ND_OB_SELECT: ED_area_tag_refresh(sa); break; - }*/ - ED_area_tag_refresh(sa); + + default: /* just redrawing the view will do */ + ED_area_tag_redraw(sa); + break; + } break; case NC_OBJECT: - /*switch (wmn->data) { - case ND_BONE_SELECT: + switch (wmn->data) { + case ND_BONE_SELECT: /* selection changed, so force refresh to flush */ case ND_BONE_ACTIVE: ED_area_tag_refresh(sa); break; - }*/ - ED_area_tag_refresh(sa); + + default: /* just redrawing the view will do */ + ED_area_tag_redraw(sa); + break; + } break; case NC_SPACE: 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) { - SpaceAction *saction = (SpaceAction *)sa->spacedata.first; + //SpaceAction *saction= CTX_wm_space_action(C); - /* updates to data needed depends on Action Editor mode... */ - switch (saction->mode) { - case SACTCONT_DOPESHEET: /* DopeSheet - for now, just all armatures... */ - { - - } - 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; - } + /* 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); /* region updates? */ // XXX resizing y-extents of tot should go here? diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index c3f241ef300..8902f4df314 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -434,25 +434,34 @@ static void graph_listener(ScrArea *sa, wmNotifier *wmn) /* context changes */ switch (wmn->category) { case NC_ANIMATION: + /* unlike for DopeSheet, we want refresh not redraw here, + * since F-Curve colors may need setting + */ ED_area_tag_refresh(sa); break; case NC_SCENE: - /*switch (wmn->data) { - case ND_OB_ACTIVE: + switch (wmn->data) { + case ND_OB_ACTIVE: /* selection changed, so force refresh to flush */ case ND_OB_SELECT: ED_area_tag_refresh(sa); break; - }*/ - ED_area_tag_refresh(sa); + + default: /* just redrawing the view will do */ + ED_area_tag_redraw(sa); + break; + } break; case NC_OBJECT: - /*switch (wmn->data) { - case ND_BONE_SELECT: + switch (wmn->data) { + case ND_BONE_SELECT: /* selection changed, so force refresh to flush */ case ND_BONE_ACTIVE: ED_area_tag_refresh(sa); break; - }*/ - ED_area_tag_refresh(sa); + + default: /* just redrawing the view will do */ + ED_area_tag_redraw(sa); + break; + } break; case NC_SPACE: if(wmn->data == ND_SPACE_GRAPH) @@ -489,6 +498,10 @@ static void graph_refresh(const bContext *C, ScrArea *sa) /* region updates? */ // 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 */ if (ANIM_animdata_get_context(C, &ac)) { ListBase anim_data = {NULL, NULL};