4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation, Joshua Leung
21 * All rights reserved.
24 * Contributor(s): Joshua Leung (original author)
26 * ***** END GPL LICENSE BLOCK *****
29 /** \file blender/editors/animation/anim_filter.c
30 * \ingroup edanimation
34 /* This file contains a system used to provide a layer of abstraction between sources
35 * of animation data and tools in Animation Editors. The method used here involves
36 * generating a list of edit structures which enable tools to naively perform the actions
37 * they require without all the boiler-plate associated with loops within loops and checking
38 * for cases to ignore.
40 * While this is primarily used for the Action/Dopesheet Editor (and its accessory modes),
41 * the Graph Editor also uses this for its channel list and for determining which curves
42 * are being edited. Likewise, the NLA Editor also uses this for its channel list and in
45 * Note: much of the original system this was based on was built before the creation of the RNA
46 * system. In future, it would be interesting to replace some parts of this code with RNA queries,
47 * however, RNA does not eliminate some of the boiler-plate reduction benefits presented by this
48 * system, so if any such work does occur, it should only be used for the internals used here...
50 * -- Joshua Leung, Dec 2008 (Last revision July 2009)
55 #include "DNA_anim_types.h"
56 #include "DNA_armature_types.h"
57 #include "DNA_camera_types.h"
58 #include "DNA_lamp_types.h"
59 #include "DNA_lattice_types.h"
60 #include "DNA_key_types.h"
61 #include "DNA_material_types.h"
62 #include "DNA_mesh_types.h"
63 #include "DNA_meta_types.h"
64 #include "DNA_node_types.h"
65 #include "DNA_particle_types.h"
66 #include "DNA_space_types.h"
67 #include "DNA_sequence_types.h"
68 #include "DNA_scene_types.h"
69 #include "DNA_screen_types.h"
70 #include "DNA_speaker_types.h"
71 #include "DNA_world_types.h"
72 #include "DNA_gpencil_types.h"
73 #include "DNA_object_types.h"
75 #include "MEM_guardedalloc.h"
77 #include "BLI_blenlib.h"
78 #include "BLI_utildefines.h"
79 #include "BLI_ghash.h"
81 #include "BKE_animsys.h"
82 #include "BKE_action.h"
83 #include "BKE_fcurve.h"
84 #include "BKE_context.h"
85 #include "BKE_global.h"
86 #include "BKE_group.h"
89 #include "BKE_material.h"
91 #include "BKE_sequencer.h"
92 #include "BKE_utildefines.h"
94 #include "ED_anim_api.h"
95 #include "ED_markers.h"
97 /* ************************************************************ */
98 /* Blender Context <-> Animation Context mapping */
100 /* ----------- Private Stuff - Action Editor ------------- */
102 /* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */
103 /* Note: there's a similar function in key.c (ob_get_key) */
104 static Key *actedit_get_shapekeys (bAnimContext *ac)
106 Scene *scene= ac->scene;
114 /* XXX pinning is not available in 'ShapeKey' mode... */
115 //if (saction->pin) return NULL;
117 /* shapekey data is stored with geometry data */
121 if (key->type == KEY_RELATIVE)
128 /* Get data being edited in Action Editor (depending on current 'mode') */
129 static short actedit_get_context (bAnimContext *ac, SpaceAction *saction)
132 ac->ads = &saction->ads;
134 /* sync settings with current view status, then return appropriate data */
135 switch (saction->mode) {
136 case SACTCONT_ACTION: /* 'Action Editor' */
137 /* if not pinned, sync with active object */
138 if (/*saction->pin == 0*/1) {
139 if (ac->obact && ac->obact->adt)
140 saction->action = ac->obact->adt->action;
142 saction->action= NULL;
145 ac->datatype= ANIMCONT_ACTION;
146 ac->data= saction->action;
148 ac->mode= saction->mode;
151 case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */
152 ac->datatype= ANIMCONT_SHAPEKEY;
153 ac->data= actedit_get_shapekeys(ac);
155 ac->mode= saction->mode;
158 case SACTCONT_GPENCIL: /* Grease Pencil */ // XXX review how this mode is handled...
159 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
160 saction->ads.source= (ID *)ac->scene;
162 ac->datatype= ANIMCONT_GPENCIL;
163 ac->data= &saction->ads;
165 ac->mode= saction->mode;
168 case SACTCONT_DOPESHEET: /* DopeSheet */
169 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
170 saction->ads.source= (ID *)ac->scene;
172 ac->datatype= ANIMCONT_DOPESHEET;
173 ac->data= &saction->ads;
175 ac->mode= saction->mode;
178 default: /* unhandled yet */
179 ac->datatype= ANIMCONT_NONE;
187 /* ----------- Private Stuff - Graph Editor ------------- */
189 /* Get data being edited in Graph Editor (depending on current 'mode') */
190 static short graphedit_get_context (bAnimContext *ac, SpaceIpo *sipo)
192 /* init dopesheet data if non-existant (i.e. for old files) */
193 if (sipo->ads == NULL) {
194 sipo->ads= MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet");
195 sipo->ads->source= (ID *)ac->scene;
199 /* set settings for Graph Editor - "Selected = Editable" */
200 if (sipo->flag & SIPO_SELCUVERTSONLY)
201 sipo->ads->filterflag |= ADS_FILTER_SELEDIT;
203 sipo->ads->filterflag &= ~ADS_FILTER_SELEDIT;
205 /* sync settings with current view status, then return appropriate data */
206 switch (sipo->mode) {
207 case SIPO_MODE_ANIMATION: /* Animation F-Curve Editor */
208 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
209 sipo->ads->source= (ID *)ac->scene;
210 sipo->ads->filterflag &= ~ADS_FILTER_ONLYDRIVERS;
212 ac->datatype= ANIMCONT_FCURVES;
215 ac->mode= sipo->mode;
218 case SIPO_MODE_DRIVERS: /* Driver F-Curve Editor */
219 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
220 sipo->ads->source= (ID *)ac->scene;
221 sipo->ads->filterflag |= ADS_FILTER_ONLYDRIVERS;
223 ac->datatype= ANIMCONT_DRIVERS;
226 ac->mode= sipo->mode;
229 default: /* unhandled yet */
230 ac->datatype= ANIMCONT_NONE;
238 /* ----------- Private Stuff - NLA Editor ------------- */
240 /* Get data being edited in Graph Editor (depending on current 'mode') */
241 static short nlaedit_get_context (bAnimContext *ac, SpaceNla *snla)
243 /* init dopesheet data if non-existant (i.e. for old files) */
244 if (snla->ads == NULL)
245 snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
248 /* sync settings with current view status, then return appropriate data */
249 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
250 snla->ads->source= (ID *)ac->scene;
251 snla->ads->filterflag |= ADS_FILTER_ONLYNLA;
253 ac->datatype= ANIMCONT_NLA;
259 /* ----------- Public API --------------- */
261 /* Obtain current anim-data context, given that context info from Blender context has already been set
262 * - AnimContext to write to is provided as pointer to var on stack so that we don't have
263 * allocation/freeing costs (which are not that avoidable with channels).
265 short ANIM_animdata_context_getdata (bAnimContext *ac)
267 SpaceLink *sl = ac->sl;
270 /* context depends on editor we are currently in */
272 switch (ac->spacetype) {
275 SpaceAction *saction= (SpaceAction *)sl;
276 ok= actedit_get_context(ac, saction);
282 SpaceIpo *sipo= (SpaceIpo *)sl;
283 ok= graphedit_get_context(ac, sipo);
289 SpaceNla *snla= (SpaceNla *)sl;
290 ok= nlaedit_get_context(ac, snla);
296 /* check if there's any valid data */
303 /* Obtain current anim-data context from Blender Context info
304 * - AnimContext to write to is provided as pointer to var on stack so that we don't have
305 * allocation/freeing costs (which are not that avoidable with channels).
306 * - Clears data and sets the information from Blender Context which is useful
308 short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac)
310 ScrArea *sa= CTX_wm_area(C);
311 ARegion *ar= CTX_wm_region(C);
312 SpaceLink *sl= CTX_wm_space_data(C);
313 Scene *scene= CTX_data_scene(C);
315 /* clear old context info */
316 if (ac == NULL) return 0;
317 memset(ac, 0, sizeof(bAnimContext));
319 /* get useful default context settings from context */
322 ac->markers= ED_context_get_markers(C);
323 ac->obact= (scene->basact)? scene->basact->object : NULL;
328 ac->spacetype= (sa) ? sa->spacetype : 0;
329 ac->regiontype= (ar) ? ar->regiontype : 0;
331 /* get data context info */
332 return ANIM_animdata_context_getdata(ac);
335 /* ************************************************************ */
336 /* Blender Data <-- Filter --> Channels to be operated on */
338 /* macros to use before/after getting the sub-channels of some channel,
339 * to abstract away some of the tricky logic involved
342 * 1) Graph Edit main area (just data) OR channels visible in Channel List
343 * 2) If not showing channels, we're only interested in the data (Action Editor's editing)
344 * 3) We don't care what data, we just care there is some (so that a collapsed
345 * channel can be kept around). No need to clear channels-flag in order to
346 * keep expander channels with no sub-data out, as those cases should get
347 * dealt with by the recursive detection idiom in place.
349 #define BEGIN_ANIMFILTER_SUBCHANNELS(expanded_check) \
351 int _filter = filter_mode; \
352 short _doSubChannels = 0; \
353 if (!(filter_mode & ANIMFILTER_LIST_VISIBLE) || (expanded_check)) \
355 else if (!(filter_mode & ANIMFILTER_LIST_CHANNELS)) \
358 filter_mode |= ANIMFILTER_TMP_PEEK; \
360 /* ... standard sub-channel filtering can go on here now ... */
361 #define END_ANIMFILTER_SUBCHANNELS \
362 filter_mode = _filter; \
365 /* ............................... */
367 /* quick macro to test if AnimData is usable */
368 #define ANIMDATA_HAS_KEYS(id) ((id)->adt && (id)->adt->action)
370 /* quick macro to test if AnimData is usable for drivers */
371 #define ANIMDATA_HAS_DRIVERS(id) ((id)->adt && (id)->adt->drivers.first)
373 /* quick macro to test if AnimData is usable for NLA */
374 #define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first)
376 /* Quick macro to test for all three above usability tests, performing the appropriate provided
377 * action for each when the AnimData context is appropriate.
379 * Priority order for this goes (most important, to least): AnimData blocks, NLA, Drivers, Keyframes.
381 * For this to work correctly, a standard set of data needs to be available within the scope that this
383 * - ListBase anim_data;
385 * - bAnimListElem *ale;
388 * - id: ID block which should have an AnimData pointer following it immediately, to use
389 * - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
390 * - nlaOk: line or block of code to execute for NLA tracks+strips case
391 * - driversOk: line or block of code to execute for Drivers case
392 * - keysOk: line or block of code for Keyframes case
394 * The checks for the various cases are as follows:
395 * 0) top level: checks for animdata and also that all the F-Curves for the block will be visible
396 * 1) animdata check: for filtering animdata blocks only
397 * 2A) nla tracks: include animdata block's data as there are NLA tracks+strips there
398 * 2B) actions to convert to nla: include animdata block's data as there is an action that can be
399 * converted to a new NLA strip, and the filtering options allow this
400 * 2C) allow non-animated datablocks to be included so that datablocks can be added
401 * 3) drivers: include drivers from animdata block (for Drivers mode in Graph Editor)
402 * 4) normal keyframes: only when there is an active action
404 #define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \
407 if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) {\
408 if (filter_mode & ANIMFILTER_ANIMDATA) {\
411 else if (ads->filterflag & ADS_FILTER_ONLYNLA) {\
412 if (ANIMDATA_HAS_NLA(id)) {\
415 else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) && ANIMDATA_HAS_KEYS(id)) {\
419 else if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) {\
420 if (ANIMDATA_HAS_DRIVERS(id)) {\
425 if (ANIMDATA_HAS_KEYS(id)) {\
433 /* ............................... */
435 /* Add a new animation channel, taking into account the "peek" flag, which is used to just check
436 * whether any channels will be added (but without needing them to actually get created).
438 * ! This causes the calling function to return early if we're only "peeking" for channels
440 // XXX: ale_statement stuff is really a hack for one special case. It shouldn't really be needed...
441 #define ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, ale_statement) \
442 if (filter_mode & ANIMFILTER_TMP_PEEK) \
445 bAnimListElem *ale= make_new_animlistelem(channel_data, channel_type, (ID *)owner_id); \
447 BLI_addtail(anim_data, ale); \
453 #define ANIMCHANNEL_NEW_CHANNEL(channel_data, channel_type, owner_id) \
454 ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, {})
456 /* ............................... */
458 /* quick macro to test if an anim-channel representing an AnimData block is suitably active */
459 #define ANIMCHANNEL_ACTIVEOK(ale) \
460 ( !(filter_mode & ANIMFILTER_ACTIVE) || !(ale->adt) || (ale->adt->flag & ADT_UI_ACTIVE) )
462 /* quick macro to test if an anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */
463 #define ANIMCHANNEL_SELOK(test_func) \
464 ( !(filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) || \
465 ((filter_mode & ANIMFILTER_SEL) && test_func) || \
466 ((filter_mode & ANIMFILTER_UNSEL) && test_func==0) )
468 /* quick macro to test if an anim-channel (F-Curve) is selected ok for editing purposes
469 * - _SELEDIT means that only selected curves will have visible+editable keyframes
471 * checks here work as follows:
472 * 1) seledit off - don't need to consider the implications of this option
473 * 2) foredit off - we're not considering editing, so channel is ok still
474 * 3) test_func (i.e. selection test) - only if selected, this test will pass
476 #define ANIMCHANNEL_SELEDITOK(test_func) \
477 ( !(filter_mode & ANIMFILTER_SELEDIT) || \
478 !(filter_mode & ANIMFILTER_FOREDIT) || \
481 /* ----------- 'Private' Stuff --------------- */
483 /* this function allocates memory for a new bAnimListElem struct for the
484 * provided animation channel-data.
486 static bAnimListElem *make_new_animlistelem (void *data, short datatype, ID *owner_id)
488 bAnimListElem *ale= NULL;
490 /* only allocate memory if there is data to convert */
492 /* allocate and set generic data */
493 ale= MEM_callocN(sizeof(bAnimListElem), "bAnimListElem");
499 ale->adt= BKE_animdata_from_id(owner_id);
503 case ANIMTYPE_SUMMARY:
505 /* nothing to include for now... this is just a dummy wrappy around all the other channels
506 * in the DopeSheet, and gets included at the start of the list
509 ale->datatype= ALE_ALL;
515 Scene *sce= (Scene *)data;
517 ale->flag= sce->flag;
520 ale->datatype= ALE_SCE;
522 ale->adt= BKE_animdata_from_id(data);
525 case ANIMTYPE_OBJECT:
527 Base *base= (Base *)data;
528 Object *ob= base->object;
533 ale->datatype= ALE_OB;
535 ale->adt= BKE_animdata_from_id(&ob->id);
538 case ANIMTYPE_FILLACTD:
540 bAction *act= (bAction *)data;
542 ale->flag= act->flag;
545 ale->datatype= ALE_ACT;
548 case ANIMTYPE_FILLDRIVERS:
550 AnimData *adt= (AnimData *)data;
552 ale->flag= adt->flag;
554 // XXX... drivers don't show summary for now
556 ale->datatype= ALE_NONE;
562 Material *ma= (Material *)data;
563 AnimData *adt= ma->adt;
565 ale->flag= FILTER_MAT_OBJD(ma);
567 ale->key_data= (adt) ? adt->action : NULL;
568 ale->datatype= ALE_ACT;
570 ale->adt= BKE_animdata_from_id(data);
575 Lamp *la= (Lamp *)data;
576 AnimData *adt= la->adt;
578 ale->flag= FILTER_LAM_OBJD(la);
580 ale->key_data= (adt) ? adt->action : NULL;
581 ale->datatype= ALE_ACT;
583 ale->adt= BKE_animdata_from_id(data);
588 Camera *ca= (Camera *)data;
589 AnimData *adt= ca->adt;
591 ale->flag= FILTER_CAM_OBJD(ca);
593 ale->key_data= (adt) ? adt->action : NULL;
594 ale->datatype= ALE_ACT;
596 ale->adt= BKE_animdata_from_id(data);
601 Curve *cu= (Curve *)data;
602 AnimData *adt= cu->adt;
604 ale->flag= FILTER_CUR_OBJD(cu);
606 ale->key_data= (adt) ? adt->action : NULL;
607 ale->datatype= ALE_ACT;
609 ale->adt= BKE_animdata_from_id(data);
614 bArmature *arm= (bArmature *)data;
615 AnimData *adt= arm->adt;
617 ale->flag= FILTER_ARM_OBJD(arm);
619 ale->key_data= (adt) ? adt->action : NULL;
620 ale->datatype= ALE_ACT;
622 ale->adt= BKE_animdata_from_id(data);
625 case ANIMTYPE_DSMESH:
627 Mesh *me= (Mesh *)data;
628 AnimData *adt= me->adt;
630 ale->flag= FILTER_MESH_OBJD(me);
632 ale->key_data= (adt) ? adt->action : NULL;
633 ale->datatype= ALE_ACT;
635 ale->adt= BKE_animdata_from_id(data);
640 Lattice *lt= (Lattice *)data;
641 AnimData *adt= lt->adt;
643 ale->flag= FILTER_LATTICE_OBJD(lt);
645 ale->key_data= (adt) ? adt->action : NULL;
646 ale->datatype= ALE_ACT;
648 ale->adt= BKE_animdata_from_id(data);
653 Speaker *spk= (Speaker *)data;
654 AnimData *adt= spk->adt;
656 ale->flag= FILTER_SPK_OBJD(spk);
658 ale->key_data= (adt) ? adt->action : NULL;
659 ale->datatype= ALE_ACT;
661 ale->adt= BKE_animdata_from_id(data);
664 case ANIMTYPE_DSSKEY:
666 Key *key= (Key *)data;
667 AnimData *adt= key->adt;
669 ale->flag= FILTER_SKE_OBJD(key);
671 ale->key_data= (adt) ? adt->action : NULL;
672 ale->datatype= ALE_ACT;
674 ale->adt= BKE_animdata_from_id(data);
679 World *wo= (World *)data;
680 AnimData *adt= wo->adt;
682 ale->flag= FILTER_WOR_SCED(wo);
684 ale->key_data= (adt) ? adt->action : NULL;
685 ale->datatype= ALE_ACT;
687 ale->adt= BKE_animdata_from_id(data);
690 case ANIMTYPE_DSNTREE:
692 bNodeTree *ntree= (bNodeTree *)data;
693 AnimData *adt= ntree->adt;
695 ale->flag= FILTER_NTREE_DATA(ntree);
697 ale->key_data= (adt) ? adt->action : NULL;
698 ale->datatype= ALE_ACT;
700 ale->adt= BKE_animdata_from_id(data);
703 case ANIMTYPE_DSPART:
705 ParticleSettings *part= (ParticleSettings*)ale->data;
706 AnimData *adt= part->adt;
708 ale->flag= FILTER_PART_OBJD(part);
710 ale->key_data= (adt) ? adt->action : NULL;
711 ale->datatype= ALE_ACT;
713 ale->adt= BKE_animdata_from_id(data);
718 Tex *tex= (Tex *)data;
719 AnimData *adt= tex->adt;
721 ale->flag= FILTER_TEX_DATA(tex);
723 ale->key_data= (adt) ? adt->action : NULL;
724 ale->datatype= ALE_ACT;
726 ale->adt= BKE_animdata_from_id(data);
732 bActionGroup *agrp= (bActionGroup *)data;
734 ale->flag= agrp->flag;
737 ale->datatype= ALE_GROUP;
740 case ANIMTYPE_FCURVE:
742 FCurve *fcu= (FCurve *)data;
744 ale->flag= fcu->flag;
747 ale->datatype= ALE_FCURVE;
751 case ANIMTYPE_SHAPEKEY:
753 KeyBlock *kb= (KeyBlock *)data;
754 Key *key= (Key *)ale->id;
758 /* whether we have keyframes depends on whether there is a Key block to find it from */
760 /* index of shapekey is defined by place in key's list */
761 ale->index= BLI_findindex(&key->block, kb);
763 /* the corresponding keyframes are from the animdata */
764 if (ale->adt && ale->adt->action) {
765 bAction *act= ale->adt->action;
766 char *rna_path = key_get_curValue_rnaPath(key, kb);
768 /* try to find the F-Curve which corresponds to this exactly,
769 * then free the MEM_alloc'd string
772 ale->key_data= (void *)list_find_fcurve(&act->curves, rna_path, 0);
776 ale->datatype= (ale->key_data)? ALE_FCURVE : ALE_NONE;
781 case ANIMTYPE_GPLAYER:
783 bGPDlayer *gpl= (bGPDlayer *)data;
785 ale->flag= gpl->flag;
788 ale->datatype= ALE_GPFRAME;
792 case ANIMTYPE_NLATRACK:
794 NlaTrack *nlt= (NlaTrack *)data;
796 ale->flag= nlt->flag;
798 ale->key_data= &nlt->strips;
799 ale->datatype= ALE_NLASTRIP;
802 case ANIMTYPE_NLAACTION:
804 /* nothing to include for now... nothing editable from NLA-perspective here */
806 ale->datatype= ALE_NONE;
812 /* return created datatype */
816 /* ----------------------------------------- */
818 /* 'Only Selected' selected data filtering
819 * NOTE: when this function returns true, the F-Curve is to be skipped
821 static size_t skip_fcurve_selected_data (bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode)
823 if (GS(owner_id->name) == ID_OB) {
824 Object *ob= (Object *)owner_id;
826 /* only consider if F-Curve involves pose.bones */
827 if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) {
831 /* get bone-name, and check if this bone is selected */
832 bone_name= BLI_getQuotedStr(fcu->rna_path, "pose.bones[");
833 pchan= get_pose_channel(ob->pose, bone_name);
834 if (bone_name) MEM_freeN(bone_name);
836 /* check whether to continue or skip */
837 if ((pchan) && (pchan->bone)) {
838 /* if only visible channels, skip if bone not visible unless user wants channels from hidden data too */
839 if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
840 bArmature *arm= (bArmature *)ob->data;
842 if ((arm->layer & pchan->bone->layer) == 0)
844 // TODO: manually hidden using flags
847 /* can only add this F-Curve if it is selected */
848 if ((pchan->bone->flag & BONE_SELECTED) == 0)
853 else if (GS(owner_id->name) == ID_SCE) {
854 Scene *scene = (Scene *)owner_id;
856 /* only consider if F-Curve involves sequence_editor.sequences */
857 if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
858 Editing *ed= seq_give_editing(scene, FALSE);
862 /* get strip name, and check if this strip is selected */
863 seq_name= BLI_getQuotedStr(fcu->rna_path, "sequences_all[");
864 seq = get_seq_by_name(ed->seqbasep, seq_name, FALSE);
865 if (seq_name) MEM_freeN(seq_name);
867 /* can only add this F-Curve if it is selected */
868 if (seq==NULL || (seq->flag & SELECT)==0)
872 else if (GS(owner_id->name) == ID_NT) {
873 bNodeTree *ntree = (bNodeTree *)owner_id;
875 /* check for selected nodes */
876 if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) {
880 /* get strip name, and check if this strip is selected */
881 node_name= BLI_getQuotedStr(fcu->rna_path, "nodes[");
882 node = nodeFindNodebyName(ntree, node_name);
883 if (node_name) MEM_freeN(node_name);
885 /* can only add this F-Curve if it is selected */
886 if ((node) && (node->flag & NODE_SELECT)==0)
893 /* (Display-)Name-based F-Curve filtering
894 * NOTE: when this function returns true, the F-Curve is to be skipped
896 static short skip_fcurve_with_name (bDopeSheet *ads, FCurve *fcu, ID *owner_id)
898 bAnimListElem ale_dummy = {0};
899 bAnimChannelType *acf;
901 /* create a dummy wrapper for the F-Curve */
902 ale_dummy.type = ANIMTYPE_FCURVE;
903 ale_dummy.id = owner_id;
904 ale_dummy.data = fcu;
906 /* get type info for channel */
907 acf = ANIM_channel_get_typeinfo(&ale_dummy);
908 if (acf && acf->name) {
909 char name[256]; /* hopefully this will be enough! */
912 acf->name(&ale_dummy, name);
914 /* check for partial match with the match string, assuming case insensitive filtering
915 * if match, this channel shouldn't be ignored!
917 return BLI_strcasestr(name, ads->searchstr) == NULL;
920 /* just let this go... */
924 /* find the next F-Curve that is usable for inclusion */
925 static FCurve *animfilter_fcurve_next (bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id)
929 /* loop over F-Curves - assume that the caller of this has already checked that these should be included
930 * NOTE: we need to check if the F-Curves belong to the same group, as this gets called for groups too...
932 for (fcu= first; ((fcu) && (fcu->grp==grp)); fcu= fcu->next) {
933 /* special exception for Pose-Channel/Sequence-Strip/Node Based F-Curves:
934 * - the 'Only Selected' data filter should be applied to Pose-Channel data too, but those are
935 * represented as F-Curves. The way the filter for objects worked was to be the first check
936 * after 'normal' visibility, so this is done first here too...
937 * - we currently use an 'approximate' method for getting these F-Curves that doesn't require
938 * carefully checking the entire path
939 * - this will also affect things like Drivers, and also works for Bone Constraints
941 if ( ((ads) && (ads->filterflag & ADS_FILTER_ONLYSEL)) && (owner_id) ) {
942 if (skip_fcurve_selected_data(ads, fcu, owner_id, filter_mode))
946 /* only include if visible (Graph Editor check, not channels check) */
947 if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || (fcu->flag & FCURVE_VISIBLE)) {
948 /* only work with this channel and its subchannels if it is editable */
949 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) {
950 /* only include this curve if selected in a way consistent with the filtering requirements */
951 if ( ANIMCHANNEL_SELOK(SEL_FCU(fcu)) && ANIMCHANNEL_SELEDITOK(SEL_FCU(fcu)) ) {
952 /* only include if this curve is active */
953 if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
954 /* name based filtering... */
955 if ( ((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id) ) {
956 if (skip_fcurve_with_name(ads, fcu, owner_id))
960 /* this F-Curve can be used, so return it */
968 /* no (more) F-Curves from the list are suitable... */
972 static size_t animfilter_fcurves (ListBase *anim_data, bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id)
977 /* loop over every F-Curve able to be included
978 * - this for-loop works like this:
979 * 1) the starting F-Curve is assigned to the fcu pointer so that we have a starting point to search from
980 * 2) the first valid F-Curve to start from (which may include the one given as 'first') in the remaining
981 * list of F-Curves is found, and verified to be non-null
982 * 3) the F-Curve referenced by fcu pointer is added to the list
983 * 4) the fcu pointer is set to the F-Curve after the one we just added, so that we can keep going through
984 * the rest of the F-Curve list without an eternal loop. Back to step 2 :)
986 for (fcu=first; ( (fcu = animfilter_fcurve_next(ads, fcu, grp, filter_mode, owner_id)) ); fcu=fcu->next)
988 ANIMCHANNEL_NEW_CHANNEL(fcu, ANIMTYPE_FCURVE, owner_id);
991 /* return the number of items added to the list */
995 static size_t animfilter_act_group (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAction *act, bActionGroup *agrp, int filter_mode, ID *owner_id)
997 ListBase tmp_data = {NULL, NULL};
998 size_t tmp_items = 0;
1000 //int ofilter = filter_mode;
1002 /* if we care about the selection status of the channels,
1003 * but the group isn't expanded (1)...
1004 * (1) this only matters if we actually care about the hierarchy though.
1005 * - Hierarchy matters: this hack should be applied
1006 * - Hierarchy ignored: cases like [#21276] won't work properly, unless we skip this hack
1008 if ( ((filter_mode & ANIMFILTER_LIST_VISIBLE) && EXPANDED_AGRP(ac, agrp)==0) && /* care about hierarchy but group isn't expanded */
1009 (filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) ) /* care about selection status */
1011 /* if the group itself isn't selected appropriately, we shouldn't consider it's children either */
1012 if (ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) == 0)
1015 /* if we're still here, then the selection status of the curves within this group should not matter,
1016 * since this creates too much overhead for animators (i.e. making a slow workflow)
1018 * Tools affected by this at time of coding (2010 Feb 09):
1019 * - inserting keyframes on selected channels only
1020 * - pasting keyframes
1021 * - creating ghost curves in Graph Editor
1023 filter_mode &= ~(ANIMFILTER_SEL|ANIMFILTER_UNSEL|ANIMFILTER_LIST_VISIBLE);
1026 /* add grouped F-Curves */
1027 BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_AGRP(ac, agrp))
1029 /* special filter so that we can get just the F-Curves within the active group */
1030 if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) {
1031 /* for the Graph Editor, curves may be set to not be visible in the view to lessen clutter,
1032 * but to do this, we need to check that the group doesn't have it's not-visible flag set preventing
1033 * all its sub-curves to be shown
1035 if ( !(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE) )
1037 /* group must be editable for its children to be editable (if we care about this) */
1038 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
1039 /* get first F-Curve which can be used here */
1040 FCurve *first_fcu = animfilter_fcurve_next(ads, agrp->channels.first, agrp, filter_mode, owner_id);
1042 /* filter list, starting from this F-Curve */
1043 tmp_items += animfilter_fcurves(&tmp_data, ads, first_fcu, agrp, filter_mode, owner_id);
1048 END_ANIMFILTER_SUBCHANNELS;
1050 /* did we find anything? */
1052 /* add this group as a channel first */
1053 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1054 /* restore original filter mode so that this next step works ok... */
1055 //filter_mode = ofilter;
1057 /* filter selection of channel specially here again, since may be open and not subject to previous test */
1058 if ( ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) ) {
1059 ANIMCHANNEL_NEW_CHANNEL(agrp, ANIMTYPE_GROUP, owner_id);
1063 /* now add the list of collected channels */
1064 BLI_movelisttolist(anim_data, &tmp_data);
1065 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1069 /* return the number of items added to the list */
1073 static size_t animfilter_action (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAction *act, int filter_mode, ID *owner_id)
1076 FCurve *lastchan = NULL;
1079 /* don't include anything from this action if it is linked in from another file,
1080 * and we're getting stuff for editing...
1082 // TODO: need a way of tagging other channels that may also be affected...
1083 if ((filter_mode & ANIMFILTER_FOREDIT) && (act->id.lib))
1087 // TODO: do nested groups?
1088 for (agrp = act->groups.first; agrp; agrp = agrp->next) {
1089 /* store reference to last channel of group */
1090 if (agrp->channels.last)
1091 lastchan= agrp->channels.last;
1093 /* action group's channels */
1094 items += animfilter_act_group(ac, anim_data, ads, act, agrp, filter_mode, owner_id);
1097 /* un-grouped F-Curves (only if we're not only considering those channels in the active group) */
1098 if (!(filter_mode & ANIMFILTER_ACTGROUPED)) {
1099 FCurve *firstfcu = (lastchan)? (lastchan->next) : (act->curves.first);
1100 items += animfilter_fcurves(anim_data, ads, firstfcu, NULL, filter_mode, owner_id);
1103 /* return the number of items added to the list */
1107 /* Include NLA-Data for NLA-Editor:
1108 * - when ANIMFILTER_LIST_CHANNELS is used, that means we should be filtering the list for display
1109 * Although the evaluation order is from the first track to the last and then apply the Action on top,
1110 * we present this in the UI as the Active Action followed by the last track to the first so that we
1111 * get the evaluation order presented as per a stack.
1112 * - for normal filtering (i.e. for editing), we only need the NLA-tracks but they can be in 'normal' evaluation
1113 * order, i.e. first to last. Otherwise, some tools may get screwed up.
1115 static size_t animfilter_nla (bAnimContext *UNUSED(ac), ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id)
1118 NlaTrack *first=NULL, *next=NULL;
1121 /* if showing channels, include active action */
1122 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1123 /* if NLA action-line filtering is off, don't show unless there are keyframes,
1124 * in order to keep things more compact for doing transforms
1126 if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || (adt->action)) {
1127 /* there isn't really anything editable here, so skip if need editable */
1128 if ((filter_mode & ANIMFILTER_FOREDIT) == 0) {
1129 /* just add the action track now (this MUST appear for drawing)
1130 * - as AnimData may not have an action, we pass a dummy pointer just to get the list elem created, then
1131 * overwrite this with the real value - REVIEW THIS...
1133 ANIMCHANNEL_NEW_CHANNEL_FULL((void *)(&adt->action), ANIMTYPE_NLAACTION, owner_id,
1135 ale->data= adt->action ? adt->action : NULL;
1140 /* first track to include will be the last one if we're filtering by channels */
1141 first= adt->nla_tracks.last;
1144 /* first track to include will the the first one (as per normal) */
1145 first= adt->nla_tracks.first;
1148 /* loop over NLA Tracks - assume that the caller of this has already checked that these should be included */
1149 for (nlt= first; nlt; nlt= next) {
1150 /* 'next' NLA-Track to use depends on whether we're filtering for drawing or not */
1151 if (filter_mode & ANIMFILTER_LIST_CHANNELS)
1156 /* if we're in NLA-tweakmode, don't show this track if it was disabled (due to tweaking) for now
1157 * - active track should still get shown though (even though it has disabled flag set)
1159 // FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel
1160 if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && !(nlt->flag & NLATRACK_ACTIVE))
1163 /* only work with this channel and its subchannels if it is editable */
1164 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) {
1165 /* only include this track if selected in a way consistent with the filtering requirements */
1166 if ( ANIMCHANNEL_SELOK(SEL_NLT(nlt)) ) {
1167 /* only include if this track is active */
1168 if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
1169 ANIMCHANNEL_NEW_CHANNEL(nlt, ANIMTYPE_NLATRACK, owner_id);
1175 /* return the number of items added to the list */
1179 /* determine what animation data from AnimData block should get displayed */
1180 static size_t animfilter_block_data (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *id, int filter_mode)
1182 IdAdtTemplate *iat = (IdAdtTemplate*)id;
1183 AnimData *adt = BKE_animdata_from_id(id);
1186 /* NOTE: this macro is used instead of inlining the logic here, since this sort of filtering is still needed
1187 * in a few places in he rest of the code still - notably for the few cases where special mode-based
1188 * different types of data expanders are required.
1190 ANIMDATA_FILTER_CASES(iat,
1192 /* specifically filter animdata block */
1193 ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id);
1196 items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id);
1199 items += animfilter_fcurves(anim_data, ads, adt->drivers.first, NULL, filter_mode, id);
1202 items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id);
1210 /* Include ShapeKey Data for ShapeKey Editor */
1211 static size_t animdata_filter_shapekey (bAnimContext *ac, ListBase *anim_data, Key *key, int filter_mode)
1215 /* check if channels or only F-Curves */
1216 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1219 /* loop through the channels adding ShapeKeys as appropriate */
1220 for (kb= key->block.first; kb; kb= kb->next) {
1221 /* skip the first one, since that's the non-animateable basis */
1222 // XXX maybe in future this may become handy?
1223 if (kb == key->block.first) continue;
1225 /* only work with this channel and its subchannels if it is editable */
1226 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_SHAPEKEY(kb)) {
1227 /* only include this track if selected in a way consistent with the filtering requirements */
1228 if ( ANIMCHANNEL_SELOK(SEL_SHAPEKEY(kb)) ) {
1229 // TODO: consider 'active' too?
1231 /* owner-id here must be key so that the F-Curve can be resolved... */
1232 ANIMCHANNEL_NEW_CHANNEL(kb, ANIMTYPE_SHAPEKEY, key);
1238 /* just use the action associated with the shapekey */
1239 // TODO: somehow manage to pass dopesheet info down here too?
1241 if (filter_mode & ANIMFILTER_ANIMDATA) {
1242 ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key);
1244 else if (key->adt->action) {
1245 items= animfilter_action(ac, anim_data, NULL, key->adt->action, filter_mode, (ID *)key);
1250 /* return the number of items added to the list */
1254 static size_t animdata_filter_gpencil_data (ListBase *anim_data, bGPdata *gpd, int filter_mode)
1259 /* loop over layers as the conditions are acceptable */
1260 for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
1261 /* only if selected */
1262 if ( ANIMCHANNEL_SELOK(SEL_GPL(gpl)) ) {
1263 /* only if editable */
1264 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) {
1266 if (!(filter_mode & ANIMFILTER_ACTIVE) || (gpl->flag & GP_LAYER_ACTIVE)) {
1268 ANIMCHANNEL_NEW_CHANNEL(gpl, ANIMTYPE_GPLAYER, gpd);
1277 /* Grab all Grase Pencil datablocks in file */
1278 // TODO: should this be amalgamated with the dopesheet filtering code?
1279 static size_t animdata_filter_gpencil (ListBase *anim_data, void *UNUSED(data), int filter_mode)
1284 /* for now, grab grease pencil datablocks directly from main */
1285 // XXX: this is not good...
1286 for (gpd = G.main->gpencil.first; gpd; gpd = gpd->id.next) {
1287 ListBase tmp_data = {NULL, NULL};
1288 size_t tmp_items = 0;
1290 /* only show if gpd is used by something... */
1291 if (ID_REAL_USERS(gpd) < 1)
1294 /* add gpencil animation channels */
1295 BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd))
1297 tmp_items += animdata_filter_gpencil_data(&tmp_data, gpd, filter_mode);
1299 END_ANIMFILTER_SUBCHANNELS;
1301 /* did we find anything? */
1303 /* include data-expand widget first */
1304 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1305 /* add gpd as channel too (if for drawing, and it has layers) */
1306 ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
1309 /* now add the list of collected channels */
1310 BLI_movelisttolist(anim_data, &tmp_data);
1311 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1316 /* return the number of items added to the list */
1320 /* NOTE: owner_id is scene, material, or texture block, which is the direct owner of the node tree in question */
1321 // TODO: how to handle group nodes is still unclear...
1322 static size_t animdata_filter_ds_nodetree (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, bNodeTree *ntree, int filter_mode)
1324 ListBase tmp_data = {NULL, NULL};
1325 size_t tmp_items = 0;
1328 /* add nodetree animation channels */
1329 BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_NTREE_DATA(ntree))
1331 /* animation data filtering */
1332 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ntree, filter_mode);
1334 END_ANIMFILTER_SUBCHANNELS;
1336 /* did we find anything? */
1338 /* include data-expand widget first */
1339 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1340 /* check if filtering by active status */
1341 if ANIMCHANNEL_ACTIVEOK(ntree) {
1342 ANIMCHANNEL_NEW_CHANNEL(ntree, ANIMTYPE_DSNTREE, owner_id);
1346 /* now add the list of collected channels */
1347 BLI_movelisttolist(anim_data, &tmp_data);
1348 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1352 /* return the number of items added to the list */
1356 /* NOTE: owner_id is either material, lamp, or world block, which is the direct owner of the texture stack in question */
1357 static size_t animdata_filter_ds_textures (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, int filter_mode)
1363 /* get datatype specific data first */
1364 if (owner_id == NULL)
1367 switch (GS(owner_id->name)) {
1370 Material *ma= (Material *)owner_id;
1371 mtex= (MTex**)(&ma->mtex);
1376 Lamp *la= (Lamp *)owner_id;
1377 mtex= (MTex**)(&la->mtex);
1382 World *wo= (World *)owner_id;
1383 mtex= (MTex**)(&wo->mtex);
1388 /* invalid/unsupported option */
1390 printf("ERROR: unsupported owner_id (i.e. texture stack) for filter textures - %s \n", owner_id->name);
1395 /* firstly check that we actuallly have some textures, by gathering all textures in a temp list */
1396 for (a=0; a < MAX_MTEX; a++) {
1397 Tex *tex= (mtex[a]) ? mtex[a]->tex : NULL;
1398 ListBase tmp_data = {NULL, NULL};
1399 size_t tmp_items = 0;
1401 /* for now, if no texture returned, skip (this shouldn't confuse the user I hope) */
1405 /* add texture's animation data to temp collection */
1406 BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_TEX_DATA(tex))
1408 /* texture animdata */
1409 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)tex, filter_mode);
1412 if ((tex->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
1413 /* owner_id as id instead of texture, since it'll otherwise be impossible to track the depth */
1414 // FIXME: perhaps as a result, textures should NOT be included under materials, but under their own section instead
1415 // so that free-floating textures can also be animated
1416 tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)tex, tex->nodetree, filter_mode);
1419 END_ANIMFILTER_SUBCHANNELS;
1421 /* did we find anything? */
1423 /* include texture-expand widget? */
1424 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1425 /* check if filtering by active status */
1426 if ANIMCHANNEL_ACTIVEOK(tex) {
1427 ANIMCHANNEL_NEW_CHANNEL(tex, ANIMTYPE_DSTEX, owner_id);
1431 /* now add the list of collected channels */
1432 BLI_movelisttolist(anim_data, &tmp_data);
1433 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1438 /* return the number of items added to the list */
1442 static size_t animdata_filter_ds_materials (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
1447 /* firstly check that we actuallly have some materials, by gathering all materials in a temp list */
1448 for (a=1; a <= ob->totcol; a++) {
1449 Material *ma= give_current_material(ob, a);
1450 ListBase tmp_data = {NULL, NULL};
1451 size_t tmp_items = 0;
1453 /* if no material returned, skip - so that we don't get weird blank entries... */
1454 if (ma == NULL) continue;
1456 /* add material's animation data to temp collection */
1457 BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_MAT_OBJD(ma))
1459 /* material's animation data */
1460 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ma, filter_mode);
1463 if (!(ads->filterflag & ADS_FILTER_NOTEX))
1464 tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)ma, filter_mode);
1467 if ((ma->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE))
1468 tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)ma, ma->nodetree, filter_mode);
1470 END_ANIMFILTER_SUBCHANNELS;
1472 /* did we find anything? */
1474 /* include material-expand widget first */
1475 // hmm... do we need to store the index of this material in the array anywhere?
1476 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1477 /* check if filtering by active status */
1478 if ANIMCHANNEL_ACTIVEOK(ma) {
1479 ANIMCHANNEL_NEW_CHANNEL(ma, ANIMTYPE_DSMAT, ma);
1483 /* now add the list of collected channels */
1484 BLI_movelisttolist(anim_data, &tmp_data);
1485 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1490 /* return the number of items added to the list */
1494 static size_t animdata_filter_ds_particles (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
1496 ParticleSystem *psys;
1499 for (psys = ob->particlesystem.first; psys; psys=psys->next) {
1500 ListBase tmp_data = {NULL, NULL};
1501 size_t tmp_items = 0;
1503 /* if no material returned, skip - so that we don't get weird blank entries... */
1504 if (ELEM(NULL, psys->part, psys->part->adt))
1507 /* add particle-system's animation data to temp collection */
1508 BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_PART_OBJD(psys->part))
1510 /* material's animation data */
1511 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)psys->part, filter_mode);
1513 END_ANIMFILTER_SUBCHANNELS;
1515 /* did we find anything? */
1517 /* include particle-expand widget first */
1518 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1519 /* check if filtering by active status */
1520 if ANIMCHANNEL_ACTIVEOK(psys->part) {
1521 ANIMCHANNEL_NEW_CHANNEL(psys->part, ANIMTYPE_DSPART, psys->part);
1525 /* now add the list of collected channels */
1526 BLI_movelisttolist(anim_data, &tmp_data);
1527 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1532 /* return the number of items added to the list */
1536 static size_t animdata_filter_ds_obdata (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
1538 ListBase tmp_data = {NULL, NULL};
1539 size_t tmp_items = 0;
1542 IdAdtTemplate *iat= ob->data;
1543 short type=0, expanded=0;
1545 /* get settings based on data type */
1547 case OB_CAMERA: /* ------- Camera ------------ */
1549 Camera *ca= (Camera *)ob->data;
1551 if (ads->filterflag & ADS_FILTER_NOCAM)
1554 type= ANIMTYPE_DSCAM;
1555 expanded= FILTER_CAM_OBJD(ca);
1558 case OB_LAMP: /* ---------- Lamp ----------- */
1560 Lamp *la= (Lamp *)ob->data;
1562 if (ads->filterflag & ADS_FILTER_NOLAM)
1565 type= ANIMTYPE_DSLAM;
1566 expanded= FILTER_LAM_OBJD(la);
1569 case OB_CURVE: /* ------- Curve ---------- */
1570 case OB_SURF: /* ------- Nurbs Surface ---------- */
1571 case OB_FONT: /* ------- Text Curve ---------- */
1573 Curve *cu= (Curve *)ob->data;
1575 if (ads->filterflag & ADS_FILTER_NOCUR)
1578 type= ANIMTYPE_DSCUR;
1579 expanded= FILTER_CUR_OBJD(cu);
1582 case OB_MBALL: /* ------- MetaBall ---------- */
1584 MetaBall *mb= (MetaBall *)ob->data;
1586 if (ads->filterflag & ADS_FILTER_NOMBA)
1589 type= ANIMTYPE_DSMBALL;
1590 expanded= FILTER_MBALL_OBJD(mb);
1593 case OB_ARMATURE: /* ------- Armature ---------- */
1595 bArmature *arm= (bArmature *)ob->data;
1597 if (ads->filterflag & ADS_FILTER_NOARM)
1600 type= ANIMTYPE_DSARM;
1601 expanded= FILTER_ARM_OBJD(arm);
1604 case OB_MESH: /* ------- Mesh ---------- */
1606 Mesh *me= (Mesh *)ob->data;
1608 if (ads->filterflag & ADS_FILTER_NOMESH)
1611 type= ANIMTYPE_DSMESH;
1612 expanded= FILTER_MESH_OBJD(me);
1615 case OB_LATTICE: /* ---- Lattice ---- */
1617 Lattice *lt = (Lattice *)ob->data;
1619 if (ads->filterflag & ADS_FILTER_NOLAT)
1622 type= ANIMTYPE_DSLAT;
1623 expanded= FILTER_LATTICE_OBJD(lt);
1626 case OB_SPEAKER: /* ---------- Speaker ----------- */
1628 Speaker *spk= (Speaker *)ob->data;
1630 type= ANIMTYPE_DSSPK;
1631 expanded= FILTER_SPK_OBJD(spk);
1636 /* add object data animation channels */
1637 BEGIN_ANIMFILTER_SUBCHANNELS(expanded)
1639 /* animation data filtering */
1640 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)iat, filter_mode);
1642 /* sub-data filtering... */
1644 case OB_LAMP: /* lamp - textures */
1647 if (!(ads->filterflag & ADS_FILTER_NOTEX))
1648 tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, ob->data, filter_mode);
1653 END_ANIMFILTER_SUBCHANNELS;
1655 /* did we find anything? */
1657 /* include data-expand widget first */
1658 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1659 /* check if filtering by active status */
1660 if ANIMCHANNEL_ACTIVEOK(iat) {
1661 ANIMCHANNEL_NEW_CHANNEL(iat, type, iat);
1665 /* now add the list of collected channels */
1666 BLI_movelisttolist(anim_data, &tmp_data);
1667 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1671 /* return the number of items added to the list */
1675 /* shapekey-level animation */
1676 static size_t animdata_filter_ds_keyanim (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, Key *key, int filter_mode)
1678 ListBase tmp_data = {NULL, NULL};
1679 size_t tmp_items = 0;
1682 /* add shapekey-level animation channels */
1683 BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_SKE_OBJD(key))
1685 /* animation data filtering */
1686 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)key, filter_mode);
1688 END_ANIMFILTER_SUBCHANNELS;
1690 /* did we find anything? */
1692 /* include key-expand widget first */
1693 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1694 if ANIMCHANNEL_ACTIVEOK(key) {
1695 ANIMCHANNEL_NEW_CHANNEL(key, ANIMTYPE_DSSKEY, ob);
1699 /* now add the list of collected channels */
1700 BLI_movelisttolist(anim_data, &tmp_data);
1701 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1705 /* return the number of items added to the list */
1709 /* object-level animation */
1710 static size_t animdata_filter_ds_obanim (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
1712 ListBase tmp_data = {NULL, NULL};
1713 size_t tmp_items = 0;
1716 AnimData *adt = ob->adt;
1717 short type=0, expanded=1;
1720 /* determine the type of expander channels to use */
1721 // this is the best way to do this for now...
1722 ANIMDATA_FILTER_CASES(ob,
1723 {/* AnimData - no channel, but consider data */},
1724 {/* NLA - no channel, but consider data */},
1726 type = ANIMTYPE_FILLDRIVERS;
1728 expanded = EXPANDED_DRVD(adt);
1731 type = ANIMTYPE_FILLACTD;
1732 cdata = adt->action;
1733 expanded = EXPANDED_ACTC(adt->action);
1736 /* add object-level animation channels */
1737 BEGIN_ANIMFILTER_SUBCHANNELS(expanded)
1739 /* animation data filtering */
1740 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ob, filter_mode);
1742 END_ANIMFILTER_SUBCHANNELS;
1744 /* did we find anything? */
1746 /* include anim-expand widget first */
1747 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1748 if (type != ANIMTYPE_NONE) {
1749 /* NOTE: active-status (and the associated checks) don't apply here... */
1750 ANIMCHANNEL_NEW_CHANNEL(cdata, type, ob);
1754 /* now add the list of collected channels */
1755 BLI_movelisttolist(anim_data, &tmp_data);
1756 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1760 /* return the number of items added to the list */
1764 /* get animation channels from object2 */
1765 static size_t animdata_filter_dopesheet_ob (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1767 ListBase tmp_data = {NULL, NULL};
1768 Object *ob= base->object;
1769 size_t tmp_items = 0;
1772 /* filter data contained under object first */
1773 BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_OBJC(ob))
1775 Key *key= ob_get_key(ob);
1777 /* object-level animation */
1778 if ((ob->adt) && !(ads->filterflag & ADS_FILTER_NOOBJ)) {
1779 tmp_items += animdata_filter_ds_obanim(ac, &tmp_data, ads, ob, filter_mode);
1783 if ((key && key->adt) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
1784 tmp_items += animdata_filter_ds_keyanim(ac, &tmp_data, ads, ob, key, filter_mode);
1788 if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT)) {
1789 tmp_items += animdata_filter_ds_materials(ac, &tmp_data, ads, ob, filter_mode);
1794 tmp_items += animdata_filter_ds_obdata(ac, &tmp_data, ads, ob, filter_mode);
1798 if ((ob->particlesystem.first) && !(ads->filterflag & ADS_FILTER_NOPART)) {
1799 tmp_items += animdata_filter_ds_particles(ac, &tmp_data, ads, ob, filter_mode);
1802 END_ANIMFILTER_SUBCHANNELS;
1805 /* if we collected some channels, add these to the new list... */
1807 /* firstly add object expander if required */
1808 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1809 /* check if filtering by selection */
1810 // XXX: double-check on this - most of the time, a lot of tools need to filter out these channels!
1811 if ANIMCHANNEL_SELOK((base->flag & SELECT)) {
1812 /* check if filtering by active status */
1813 if (ANIMCHANNEL_ACTIVEOK(ob)) {
1814 ANIMCHANNEL_NEW_CHANNEL(base, ANIMTYPE_OBJECT, ob);
1819 /* now add the list of collected channels */
1820 BLI_movelisttolist(anim_data, &tmp_data);
1821 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1825 /* return the number of items added */
1829 static size_t animdata_filter_ds_world (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, World *wo, int filter_mode)
1831 ListBase tmp_data = {NULL, NULL};
1832 size_t tmp_items = 0;
1835 /* add world animation channels */
1836 BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_WOR_SCED(wo))
1838 /* animation data filtering */
1839 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)wo, filter_mode);
1841 /* textures for world */
1842 if (!(ads->filterflag & ADS_FILTER_NOTEX))
1843 items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)wo, filter_mode);
1845 END_ANIMFILTER_SUBCHANNELS;
1847 /* did we find anything? */
1849 /* include data-expand widget first */
1850 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1851 /* check if filtering by active status */
1852 if ANIMCHANNEL_ACTIVEOK(wo) {
1853 ANIMCHANNEL_NEW_CHANNEL(wo, ANIMTYPE_DSWOR, sce);
1857 /* now add the list of collected channels */
1858 BLI_movelisttolist(anim_data, &tmp_data);
1859 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1863 /* return the number of items added to the list */
1867 static size_t animdata_filter_ds_scene (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
1869 ListBase tmp_data = {NULL, NULL};
1870 size_t tmp_items = 0;
1873 AnimData *adt = sce->adt;
1874 short type=0, expanded=1;
1877 /* determine the type of expander channels to use */
1878 // this is the best way to do this for now...
1879 ANIMDATA_FILTER_CASES(sce,
1880 {/* AnimData - no channel, but consider data */},
1881 {/* NLA - no channel, but consider data */},
1883 type = ANIMTYPE_FILLDRIVERS;
1885 expanded = EXPANDED_DRVD(adt);
1888 type = ANIMTYPE_FILLACTD;
1889 cdata = adt->action;
1890 expanded = EXPANDED_ACTC(adt->action);
1893 /* add scene-level animation channels */
1894 BEGIN_ANIMFILTER_SUBCHANNELS(expanded)
1896 /* animation data filtering */
1897 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)sce, filter_mode);
1899 END_ANIMFILTER_SUBCHANNELS;
1901 /* did we find anything? */
1903 /* include anim-expand widget first */
1904 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1905 if (type != ANIMTYPE_NONE) {
1906 /* NOTE: active-status (and the associated checks) don't apply here... */
1907 ANIMCHANNEL_NEW_CHANNEL(cdata, type, sce);
1911 /* now add the list of collected channels */
1912 BLI_movelisttolist(anim_data, &tmp_data);
1913 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1917 /* return the number of items added to the list */
1921 static size_t animdata_filter_dopesheet_scene (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
1923 ListBase tmp_data = {NULL, NULL};
1924 size_t tmp_items = 0;
1927 /* filter data contained under object first */
1928 BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_SCEC(sce))
1930 bNodeTree *ntree= sce->nodetree;
1931 World *wo= sce->world;
1933 /* Action, Drivers, or NLA for Scene */
1934 if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) {
1935 tmp_items += animdata_filter_ds_scene(ac, &tmp_data, ads, sce, filter_mode);
1939 if ((wo && wo->adt) && !(ads->filterflag & ADS_FILTER_NOWOR)) {
1940 tmp_items += animdata_filter_ds_world(ac, &tmp_data, ads, sce, wo, filter_mode);
1944 if ((ntree && ntree->adt) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
1945 tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)sce, ntree, filter_mode);
1948 // TODO: one day, when sequencer becomes its own datatype, perhaps it should be included here
1950 END_ANIMFILTER_SUBCHANNELS;
1952 /* if we collected some channels, add these to the new list... */
1954 /* firstly add object expander if required */
1955 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1956 /* check if filtering by selection */
1957 if ANIMCHANNEL_SELOK((sce->flag & SCE_DS_SELECTED)) {
1958 /* NOTE: active-status doesn't matter for this! */
1959 ANIMCHANNEL_NEW_CHANNEL(sce, ANIMTYPE_SCENE, sce);
1963 /* now add the list of collected channels */
1964 BLI_movelisttolist(anim_data, &tmp_data);
1965 BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
1969 /* return the number of items added */
1973 // TODO: implement pinning... (if and when pinning is done, what we need to do is to provide freeing mechanisms - to protect against data that was deleted)
1974 static size_t animdata_filter_dopesheet (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode)
1976 Scene *sce= (Scene *)ads->source;
1980 /* check that we do indeed have a scene */
1981 if ((ads->source == NULL) || (GS(ads->source->name)!=ID_SCE)) {
1982 printf("DopeSheet Error: Not scene!\n");
1984 printf("\tPointer = %p, Name = '%s' \n", (void *)ads->source, (ads->source)?ads->source->name:NULL);
1988 /* augment the filter-flags with settings based on the dopesheet filterflags
1989 * so that some temp settings can get added automagically...
1991 if (ads->filterflag & ADS_FILTER_SELEDIT) {
1992 /* only selected F-Curves should get their keyframes considered for editability */
1993 filter_mode |= ANIMFILTER_SELEDIT;
1996 /* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */
1997 items += animdata_filter_dopesheet_scene(ac, anim_data, ads, sce, filter_mode);
1999 /* loop over all bases (i.e.objects) in the scene */
2000 for (base= sce->base.first; base; base= base->next) {
2001 /* check if there's an object (all the relevant checks are done in the ob-function) */
2003 Object *ob= base->object;
2005 /* firstly, check if object can be included, by the following factors:
2006 * - if only visible, must check for layer and also viewport visibility
2007 * --> while tools may demand only visible, user setting takes priority
2008 * as user option controls whether sets of channels get included while
2009 * tool-flag takes into account collapsed/open channels too
2010 * - if only selected, must check if object is selected
2011 * - there must be animation data to edit (this is done recursively as we
2012 * try to add the channels)
2014 if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
2015 /* layer visibility - we check both object and base, since these may not be in sync yet */
2016 if ((sce->lay & (ob->lay|base->lay))==0) continue;
2018 /* outliner restrict-flag */
2019 if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
2022 /* if only F-Curves with visible flags set can be shown, check that
2023 * datablock hasn't been set to invisible
2025 if (filter_mode & ANIMFILTER_CURVE_VISIBLE) {
2026 if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE))
2030 /* check selection and object type filters */
2031 if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/) ) {
2032 /* only selected should be shown */
2036 /* check if object belongs to the filtering group if option to filter
2037 * objects by the grouped status is on
2038 * - used to ease the process of doing multiple-character choreographies
2040 if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) {
2041 if (object_in_group(ob, ads->filter_grp) == 0)
2045 /* since we're still here, this object should be usable */
2046 items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode);
2050 /* return the number of items in the list */
2054 /* Summary track for DopeSheet/Action Editor
2055 * - return code is whether the summary lets the other channels get drawn
2057 static short animdata_filter_dopesheet_summary (bAnimContext *ac, ListBase *anim_data, int filter_mode, size_t *items)
2059 bDopeSheet *ads = NULL;
2061 /* get the DopeSheet information to use
2062 * - we should only need to deal with the DopeSheet/Action Editor,
2063 * since all the other Animation Editors won't have this concept
2066 if ((ac && ac->sl) && (ac->spacetype == SPACE_ACTION)) {
2067 SpaceAction *saction= (SpaceAction *)ac->sl;
2071 /* invalid space type - skip this summary channels */
2075 /* dopesheet summary
2076 * - only for drawing and/or selecting keyframes in channels, but not for real editing
2077 * - only useful for DopeSheet/Action/etc. editors where it is actually useful
2079 if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && (ads->filterflag & ADS_FILTER_SUMMARY)) {
2080 bAnimListElem *ale= make_new_animlistelem(ac, ANIMTYPE_SUMMARY, NULL);
2082 BLI_addtail(anim_data, ale);
2086 /* if summary is collapsed, don't show other channels beneath this
2087 * - this check is put inside the summary check so that it doesn't interfere with normal operation
2089 if (ads->flag & ADS_FLAG_SUMMARY_COLLAPSED)
2093 /* the other channels beneath this can be shown */
2097 /* ......................... */
2099 /* filter data associated with a channel - usually for handling summary-channels in DopeSheet */
2100 static size_t animdata_filter_animchan (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAnimListElem *channel, int filter_mode)
2104 /* data to filter depends on channel type */
2105 // XXX: only common channel-types have been handled for now
2106 switch (channel->type) {
2107 case ANIMTYPE_SUMMARY:
2108 items += animdata_filter_dopesheet(ac, anim_data, ads, filter_mode);
2111 case ANIMTYPE_SCENE:
2112 items += animdata_filter_dopesheet_scene(ac, anim_data, ads, channel->data, filter_mode);
2115 case ANIMTYPE_OBJECT:
2116 items += animdata_filter_dopesheet_ob(ac, anim_data, ads, channel->data, filter_mode);
2123 /* ----------- Cleanup API --------------- */
2125 /* Remove entries with invalid types in animation channel list */
2126 static size_t animdata_filter_remove_invalid (ListBase *anim_data)
2128 bAnimListElem *ale, *next;
2131 /* only keep entries with valid types */
2132 for (ale= anim_data->first; ale; ale= next) {
2135 if (ale->type == ANIMTYPE_NONE)
2136 BLI_freelinkN(anim_data, ale);
2144 /* Remove duplicate entries in animation channel list */
2145 static size_t animdata_filter_remove_duplis (ListBase *anim_data)
2147 bAnimListElem *ale, *next;
2151 /* build new hashtable to efficiently store and retrieve which entries have been
2152 * encountered already while searching
2154 gh= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "animdata_filter_duplis_remove gh");
2156 /* loop through items, removing them from the list if a similar item occurs already */
2157 for (ale = anim_data->first; ale; ale = next) {
2160 /* check if hash has any record of an entry like this
2161 * - just use ale->data for now, though it would be nicer to involve
2162 * ale->type in combination too to capture corner cases (where same data performs differently)
2164 if (BLI_ghash_haskey(gh, ale->data) == 0) {
2165 /* this entry is 'unique' and can be kept */
2166 BLI_ghash_insert(gh, ale->data, NULL);
2170 /* this entry isn't needed anymore */
2171 BLI_freelinkN(anim_data, ale);
2175 /* free the hash... */
2176 BLI_ghash_free(gh, NULL, NULL);
2178 /* return the number of items still in the list */
2182 /* ----------- Public API --------------- */
2184 /* This function filters the active data source to leave only animation channels suitable for
2185 * usage by the caller. It will return the length of the list
2187 * *anim_data: is a pointer to a ListBase, to which the filtered animation channels
2188 * will be placed for use.
2189 * filter_mode: how should the data be filtered - bitmapping accessed flags
2191 size_t ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode, void *data, short datatype)
2195 /* only filter data if there's somewhere to put it */
2196 if (data && anim_data) {
2197 Object *obact= (ac) ? ac->obact : NULL;
2199 /* firstly filter the data */
2201 case ANIMCONT_ACTION: /* 'Action Editor' */
2203 SpaceAction *saction = (SpaceAction *)ac->sl;
2204 bDopeSheet *ads = (saction)? &saction->ads : NULL;
2206 /* the check for the DopeSheet summary is included here since the summary works here too */
2207 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
2208 items += animfilter_action(ac, anim_data, ads, data, filter_mode, (ID *)obact);
2212 case ANIMCONT_SHAPEKEY: /* 'ShapeKey Editor' */
2214 /* the check for the DopeSheet summary is included here since the summary works here too */
2215 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
2216 items= animdata_filter_shapekey(ac, anim_data, data, filter_mode);
2220 case ANIMCONT_GPENCIL:
2222 items= animdata_filter_gpencil(anim_data, data, filter_mode);
2226 case ANIMCONT_DOPESHEET: /* 'DopeSheet Editor' */
2228 /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */
2229 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
2230 items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode);
2234 case ANIMCONT_FCURVES: /* Graph Editor -> FCurves/Animation Editing */
2235 case ANIMCONT_DRIVERS: /* Graph Editor -> Drivers Editing */
2236 case ANIMCONT_NLA: /* NLA Editor */
2238 /* all of these editors use the basic DopeSheet data for filtering options, but don't have all the same features */
2239 items = animdata_filter_dopesheet(ac, anim_data, data, filter_mode);
2243 case ANIMCONT_CHANNEL: /* animation channel */
2245 bDopeSheet *ads = ac->ads;
2247 /* based on the channel type, filter relevant data for this */
2248 items = animdata_filter_animchan(ac, anim_data, ads, data, filter_mode);
2253 /* remove any 'weedy' entries */
2254 items = animdata_filter_remove_invalid(anim_data);
2256 /* remove duplicates (if required) */
2257 if (filter_mode & ANIMFILTER_NODUPLIS)
2258 items = animdata_filter_remove_duplis(anim_data);
2261 /* return the number of items in the list */
2265 /* ************************************************************ */