Durian request:
[blender.git] / source / blender / editors / animation / anim_filter.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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. 
10  *
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.
15  *
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation, Joshua Leung
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Joshua Leung (original author)
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /* This file contains a system used to provide a layer of abstraction between sources
30  * of animation data and tools in Animation Editors. The method used here involves 
31  * generating a list of edit structures which enable tools to naively perform the actions 
32  * they require without all the boiler-plate associated with loops within loops and checking 
33  * for cases to ignore. 
34  *
35  * While this is primarily used for the Action/Dopesheet Editor (and its accessory modes),
36  * the Graph Editor also uses this for its channel list and for determining which curves
37  * are being edited. Likewise, the NLA Editor also uses this for its channel list and in
38  * its operators.
39  *
40  * Note: much of the original system this was based on was built before the creation of the RNA
41  * system. In future, it would be interesting to replace some parts of this code with RNA queries,
42  * however, RNA does not eliminate some of the boiler-plate reduction benefits presented by this 
43  * system, so if any such work does occur, it should only be used for the internals used here...
44  *
45  * -- Joshua Leung, Dec 2008 (Last revision July 2009)
46  */
47
48 #include <string.h>
49 #include <stdio.h>
50
51 #include "DNA_listBase.h"
52 #include "DNA_ID.h"
53 #include "DNA_anim_types.h"
54 #include "DNA_action_types.h"
55 #include "DNA_armature_types.h"
56 #include "DNA_constraint_types.h"
57 #include "DNA_camera_types.h"
58 #include "DNA_curve_types.h"
59 #include "DNA_gpencil_types.h"
60 #include "DNA_ipo_types.h"
61 #include "DNA_lamp_types.h"
62 #include "DNA_lattice_types.h"
63 #include "DNA_key_types.h"
64 #include "DNA_material_types.h"
65 #include "DNA_mesh_types.h"
66 #include "DNA_meta_types.h"
67 #include "DNA_node_types.h"
68 #include "DNA_object_types.h"
69 #include "DNA_particle_types.h"
70 #include "DNA_space_types.h"
71 #include "DNA_sequence_types.h"
72 #include "DNA_scene_types.h"
73 #include "DNA_screen_types.h"
74 #include "DNA_windowmanager_types.h"
75 #include "DNA_world_types.h"
76
77 #include "MEM_guardedalloc.h"
78
79 #include "BLI_blenlib.h"
80
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_key.h"
87 #include "BKE_object.h"
88 #include "BKE_material.h"
89 #include "BKE_node.h"
90 #include "BKE_sequencer.h"
91 #include "BKE_screen.h"
92 #include "BKE_utildefines.h"
93
94 #include "ED_anim_api.h"
95 #include "ED_types.h"
96 #include "ED_util.h"
97
98 #include "WM_api.h"
99 #include "WM_types.h"
100
101 #include "BIF_gl.h"
102 #include "BIF_glutil.h"
103
104 #include "UI_interface.h"
105 #include "UI_resources.h"
106 #include "UI_view2d.h"
107
108 /* ************************************************************ */
109 /* Blender Context <-> Animation Context mapping */
110
111 /* ----------- Private Stuff - Action Editor ------------- */
112
113 /* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */
114 /* Note: there's a similar function in key.c (ob_get_key) */
115 Key *actedit_get_shapekeys (bAnimContext *ac, SpaceAction *saction) 
116 {
117     Scene *scene= ac->scene;
118     Object *ob;
119     Key *key;
120         
121     ob = OBACT;
122     if (ob == NULL) 
123                 return NULL;
124         
125         /* XXX pinning is not available in 'ShapeKey' mode... */
126         //if (saction->pin) return NULL;
127         
128         /* shapekey data is stored with geometry data */
129         switch (ob->type) {
130                 case OB_MESH:
131                         key= ((Mesh *)ob->data)->key;
132                         break;
133                         
134                 case OB_LATTICE:
135                         key= ((Lattice *)ob->data)->key;
136                         break;
137                         
138                 case OB_CURVE:
139                 case OB_SURF:
140                         key= ((Curve *)ob->data)->key;
141                         break;
142                         
143                 default:
144                         return NULL;
145         }
146         
147         if (key) {
148                 if (key->type == KEY_RELATIVE)
149                         return key;
150         }
151         
152     return NULL;
153 }
154
155 /* Get data being edited in Action Editor (depending on current 'mode') */
156 static short actedit_get_context (bAnimContext *ac, SpaceAction *saction)
157 {
158         /* sync settings with current view status, then return appropriate data */
159         switch (saction->mode) {
160                 case SACTCONT_ACTION: /* 'Action Editor' */
161                         /* if not pinned, sync with active object */
162                         if (saction->pin == 0) {
163                                 if (ac->obact && ac->obact->adt)
164                                         saction->action = ac->obact->adt->action;
165                                 else
166                                         saction->action= NULL;
167                         }
168                         
169                         ac->datatype= ANIMCONT_ACTION;
170                         ac->data= saction->action;
171                         
172                         ac->mode= saction->mode;
173                         return 1;
174                         
175                 case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */
176                         ac->datatype= ANIMCONT_SHAPEKEY;
177                         ac->data= actedit_get_shapekeys(ac, saction);
178                         
179                         ac->mode= saction->mode;
180                         return 1;
181                         
182                 case SACTCONT_GPENCIL: /* Grease Pencil */ // XXX review how this mode is handled...
183                         ac->datatype=ANIMCONT_GPENCIL;
184                         //ac->data= CTX_wm_screen(C); // FIXME: add that dopesheet type thing here!
185                         ac->data= NULL; // !!!
186                         
187                         ac->mode= saction->mode;
188                         return 1;
189                         
190                 case SACTCONT_DOPESHEET: /* DopeSheet */
191                         /* update scene-pointer (no need to check for pinning yet, as not implemented) */
192                         saction->ads.source= (ID *)ac->scene;
193                         
194                         ac->datatype= ANIMCONT_DOPESHEET;
195                         ac->data= &saction->ads;
196                         
197                         ac->mode= saction->mode;
198                         return 1;
199                 
200                 default: /* unhandled yet */
201                         ac->datatype= ANIMCONT_NONE;
202                         ac->data= NULL;
203                         
204                         ac->mode= -1;
205                         return 0;
206         }
207 }
208
209 /* ----------- Private Stuff - Graph Editor ------------- */
210
211 /* Get data being edited in Graph Editor (depending on current 'mode') */
212 static short graphedit_get_context (bAnimContext *ac, SpaceIpo *sipo)
213 {
214         /* init dopesheet data if non-existant (i.e. for old files) */
215         if (sipo->ads == NULL) {
216                 sipo->ads= MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet");
217                 sipo->ads->source= (ID *)ac->scene;
218         }
219         
220         /* set settings for Graph Editor - "Selected = Editable" */
221         if (sipo->flag & SIPO_SELCUVERTSONLY)
222                 sipo->ads->filterflag |= ADS_FILTER_SELEDIT;
223         else
224                 sipo->ads->filterflag &= ~ADS_FILTER_SELEDIT;
225         
226         /* sync settings with current view status, then return appropriate data */
227         switch (sipo->mode) {
228                 case SIPO_MODE_ANIMATION:       /* Animation F-Curve Editor */
229                         /* update scene-pointer (no need to check for pinning yet, as not implemented) */
230                         sipo->ads->source= (ID *)ac->scene;
231                         sipo->ads->filterflag &= ~ADS_FILTER_ONLYDRIVERS;
232                         
233                         ac->datatype= ANIMCONT_FCURVES;
234                         ac->data= sipo->ads;
235                         
236                         ac->mode= sipo->mode;
237                         return 1;
238                 
239                 case SIPO_MODE_DRIVERS:         /* Driver F-Curve Editor */
240                         /* update scene-pointer (no need to check for pinning yet, as not implemented) */
241                         sipo->ads->source= (ID *)ac->scene;
242                         sipo->ads->filterflag |= ADS_FILTER_ONLYDRIVERS;
243                         
244                         ac->datatype= ANIMCONT_DRIVERS;
245                         ac->data= sipo->ads;
246                         
247                         ac->mode= sipo->mode;
248                         return 1;
249                 
250                 default: /* unhandled yet */
251                         ac->datatype= ANIMCONT_NONE;
252                         ac->data= NULL;
253                         
254                         ac->mode= -1;
255                         return 0;
256         }
257 }
258
259 /* ----------- Private Stuff - NLA Editor ------------- */
260
261 /* Get data being edited in Graph Editor (depending on current 'mode') */
262 static short nlaedit_get_context (bAnimContext *ac, SpaceNla *snla)
263 {
264         /* init dopesheet data if non-existant (i.e. for old files) */
265         if (snla->ads == NULL)
266                 snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
267         
268         /* sync settings with current view status, then return appropriate data */
269         /* update scene-pointer (no need to check for pinning yet, as not implemented) */
270         snla->ads->source= (ID *)ac->scene;
271         snla->ads->filterflag |= ADS_FILTER_ONLYNLA;
272         
273         ac->datatype= ANIMCONT_NLA;
274         ac->data= snla->ads;
275         
276         return 1;
277 }
278
279 /* ----------- Public API --------------- */
280
281 /* Obtain current anim-data context, given that context info from Blender context has already been set 
282  *      - AnimContext to write to is provided as pointer to var on stack so that we don't have
283  *        allocation/freeing costs (which are not that avoidable with channels).
284  */
285 short ANIM_animdata_context_getdata (bAnimContext *ac)
286 {
287         ScrArea *sa= ac->sa;
288         short ok= 0;
289         
290         /* context depends on editor we are currently in */
291         if (sa) {
292                 switch (sa->spacetype) {
293                         case SPACE_ACTION:
294                         {
295                                 SpaceAction *saction= (SpaceAction *)sa->spacedata.first;
296                                 ok= actedit_get_context(ac, saction);
297                         }
298                                 break;
299                                 
300                         case SPACE_IPO:
301                         {
302                                 SpaceIpo *sipo= (SpaceIpo *)sa->spacedata.first;
303                                 ok= graphedit_get_context(ac, sipo);
304                         }
305                                 break;
306                                 
307                         case SPACE_NLA:
308                         {
309                                 SpaceNla *snla= (SpaceNla *)sa->spacedata.first;
310                                 ok= nlaedit_get_context(ac, snla);
311                         }
312                                 break;
313                 }
314         }
315         
316         /* check if there's any valid data */
317         if (ok && ac->data)
318                 return 1;
319         else
320                 return 0;
321 }
322
323 /* Obtain current anim-data context from Blender Context info 
324  *      - AnimContext to write to is provided as pointer to var on stack so that we don't have
325  *        allocation/freeing costs (which are not that avoidable with channels).
326  *      - Clears data and sets the information from Blender Context which is useful
327  */
328 short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac)
329 {
330         ScrArea *sa= CTX_wm_area(C);
331         ARegion *ar= CTX_wm_region(C);
332         Scene *scene= CTX_data_scene(C);
333         
334         /* clear old context info */
335         if (ac == NULL) return 0;
336         memset(ac, 0, sizeof(bAnimContext));
337         
338         /* get useful default context settings from context */
339         ac->scene= scene;
340         if (scene) {
341                 ac->markers= &scene->markers;           
342                 ac->obact= (scene->basact)?  scene->basact->object : NULL;
343         }
344         ac->sa= sa;
345         ac->ar= ar;
346         ac->spacetype= (sa) ? sa->spacetype : 0;
347         ac->regiontype= (ar) ? ar->regiontype : 0;
348         
349         /* get data context info */
350         return ANIM_animdata_context_getdata(ac);
351 }
352
353 /* ************************************************************ */
354 /* Blender Data <-- Filter --> Channels to be operated on */
355
356 /* quick macro to test if AnimData is usable */
357 #define ANIMDATA_HAS_KEYS(id) ((id)->adt && (id)->adt->action)
358
359 /* quick macro to test if AnimData is usable for drivers */
360 #define ANIMDATA_HAS_DRIVERS(id) ((id)->adt && (id)->adt->drivers.first)
361
362 /* quick macro to test if AnimData is usable for NLA */
363 #define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first)
364
365
366 /* Quick macro to test for all three avove usability tests, performing the appropriate provided 
367  * action for each when the AnimData context is appropriate. 
368  *
369  * Priority order for this goes (most important, to least): AnimData blocks, NLA, Drivers, Keyframes.
370  *
371  * For this to work correctly, a standard set of data needs to be available within the scope that this
372  * gets called in: 
373  *      - ListBase anim_data;
374  *      - bDopeSheet *ads;
375  *      - bAnimListElem *ale;
376  *      - int items;
377  *
378  *      - id: ID block which should have an AnimData pointer following it immediately, to use
379  *      - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
380  *      - nlaOk: line or block of code to execute for NLA tracks+strips case
381  *      - driversOk: line or block of code to execute for Drivers case
382  *      - keysOk: line or block of code for Keyframes case
383  *
384  * The checks for the various cases are as follows:
385  *      0) top level: checks for animdata and also that all the F-Curves for the block will be visible
386  *      1) animdata check: for filtering animdata blocks only
387  *      2A) nla tracks: include animdata block's data as there are NLA tracks+strips there
388  *      2B) actions to convert to nla: include animdata block's data as there is an action that can be 
389  *              converted to a new NLA strip, and the filtering options allow this
390  *      3) drivers: include drivers from animdata block (for Drivers mode in Graph Editor)
391  *      4) normal keyframes: only when there is an active action
392  */
393 #define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \
394         {\
395                 if ((id)->adt) {\
396                         if (!(filter_mode & ANIMFILTER_CURVEVISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) {\
397                                 if (filter_mode & ANIMFILTER_ANIMDATA) {\
398                                         adtOk\
399                                 }\
400                                 else if (ads->filterflag & ADS_FILTER_ONLYNLA) {\
401                                         if (ANIMDATA_HAS_NLA(id)) {\
402                                                 nlaOk\
403                                         }\
404                                         else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) && ANIMDATA_HAS_KEYS(id)) {\
405                                                 nlaOk\
406                                         }\
407                                 }\
408                                 else if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) {\
409                                         if (ANIMDATA_HAS_DRIVERS(id)) {\
410                                                 driversOk\
411                                         }\
412                                 }\
413                                 else {\
414                                         if (ANIMDATA_HAS_KEYS(id)) {\
415                                                 keysOk\
416                                         }\
417                                 }\
418                         }\
419                 }\
420         }
421
422
423 /* quick macro to add a pointer to an AnimData block as a channel */
424 #define ANIMDATA_ADD_ANIMDATA(id) \
425         {\
426                 ale= make_new_animlistelem((id)->adt, ANIMTYPE_ANIMDATA, NULL, ANIMTYPE_NONE, (ID *)id);\
427                 if (ale) {\
428                         BLI_addtail(anim_data, ale);\
429                         items++;\
430                 }\
431         }
432         
433 /* quick macro to test if an anim-channel representing an AnimData block is suitably active */
434 #define ANIMCHANNEL_ACTIVEOK(ale) \
435         ( !(filter_mode & ANIMFILTER_ACTIVE) || !(ale->adt) || (ale->adt->flag & ADT_UI_ACTIVE) )
436
437 /* quick macro to test if an anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */
438 #define ANIMCHANNEL_SELOK(test_func) \
439                 ( !(filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) || \
440                   ((filter_mode & ANIMFILTER_SEL) && test_func) || \
441                   ((filter_mode & ANIMFILTER_UNSEL) && test_func==0) ) 
442                   
443 /* quick macro to test if an anim-channel (F-Curve) is selected ok for editing purposes 
444  *      - _SELEDIT means that only selected curves will have visible+editable keyframes
445  */
446 // FIXME: this doesn't work cleanly yet...
447 #define ANIMCHANNEL_SELEDITOK(test_func) \
448                 ( !(filter_mode & ANIMFILTER_SELEDIT) || \
449                   (filter_mode & ANIMFILTER_CHANNELS) || \
450                   (test_func) )
451
452 /* ----------- 'Private' Stuff --------------- */
453
454 /* this function allocates memory for a new bAnimListElem struct for the 
455  * provided animation channel-data. 
456  */
457 bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, short ownertype, ID *owner_id)
458 {
459         bAnimListElem *ale= NULL;
460         
461         /* only allocate memory if there is data to convert */
462         if (data) {
463                 /* allocate and set generic data */
464                 ale= MEM_callocN(sizeof(bAnimListElem), "bAnimListElem");
465                 
466                 ale->data= data;
467                 ale->type= datatype;
468                         // XXX what is the point of the owner data?
469                 ale->owner= owner;
470                 ale->ownertype= ownertype;
471                 
472                 ale->id= owner_id;
473                 ale->adt= BKE_animdata_from_id(owner_id);
474                 
475                 /* do specifics */
476                 switch (datatype) {
477                         case ANIMTYPE_SUMMARY:
478                         {
479                                 /* nothing to include for now... this is just a dummy wrappy around all the other channels 
480                                  * in the DopeSheet, and gets included at the start of the list
481                                  */
482                                 ale->key_data= NULL;
483                                 ale->datatype= ALE_ALL;
484                         }
485                                 break;
486                         
487                         case ANIMTYPE_SCENE:
488                         {
489                                 Scene *sce= (Scene *)data;
490                                 
491                                 ale->flag= sce->flag;
492                                 
493                                 ale->key_data= sce;
494                                 ale->datatype= ALE_SCE;
495                                 
496                                 ale->adt= BKE_animdata_from_id(data);
497                         }
498                                 break;
499                         case ANIMTYPE_OBJECT:
500                         {
501                                 Base *base= (Base *)data;
502                                 Object *ob= base->object;
503                                 
504                                 ale->flag= ob->flag;
505                                 
506                                 ale->key_data= ob;
507                                 ale->datatype= ALE_OB;
508                                 
509                                 ale->adt= BKE_animdata_from_id(&ob->id);
510                         }
511                                 break;
512                         case ANIMTYPE_FILLACTD:
513                         {
514                                 bAction *act= (bAction *)data;
515                                 
516                                 ale->flag= act->flag;
517                                 
518                                 ale->key_data= act;
519                                 ale->datatype= ALE_ACT;
520                         }
521                                 break;
522                         case ANIMTYPE_FILLDRIVERS:
523                         {
524                                 AnimData *adt= (AnimData *)data;
525                                 
526                                 ale->flag= adt->flag;
527                                 
528                                         // XXX... drivers don't show summary for now
529                                 ale->key_data= NULL;
530                                 ale->datatype= ALE_NONE;
531                         }
532                                 break;
533                         case ANIMTYPE_FILLMATD:
534                         {
535                                 Object *ob= (Object *)data;
536                                 
537                                 ale->flag= FILTER_MAT_OBJC(ob);
538                                 
539                                 ale->key_data= NULL;
540                                 ale->datatype= ALE_NONE;
541                         }
542                                 break;
543                         case ANIMTYPE_FILLPARTD:
544                         {
545                                 Object *ob= (Object *)data;
546                                 
547                                 ale->flag= FILTER_PART_OBJC(ob);
548                                 
549                                 ale->key_data= NULL;
550                                 ale->datatype= ALE_NONE;
551                         }
552                                 break;
553                         
554                         case ANIMTYPE_DSMAT:
555                         {
556                                 Material *ma= (Material *)data;
557                                 AnimData *adt= ma->adt;
558                                 
559                                 ale->flag= FILTER_MAT_OBJD(ma);
560                                 
561                                 ale->key_data= (adt) ? adt->action : NULL;
562                                 ale->datatype= ALE_ACT;
563                                 
564                                 ale->adt= BKE_animdata_from_id(data);
565                         }
566                                 break;
567                         case ANIMTYPE_DSLAM:
568                         {
569                                 Lamp *la= (Lamp *)data;
570                                 AnimData *adt= la->adt;
571                                 
572                                 ale->flag= FILTER_LAM_OBJD(la);
573                                 
574                                 ale->key_data= (adt) ? adt->action : NULL;
575                                 ale->datatype= ALE_ACT;
576                                 
577                                 ale->adt= BKE_animdata_from_id(data);
578                         }
579                                 break;
580                         case ANIMTYPE_DSCAM:
581                         {
582                                 Camera *ca= (Camera *)data;
583                                 AnimData *adt= ca->adt;
584                                 
585                                 ale->flag= FILTER_CAM_OBJD(ca);
586                                 
587                                 ale->key_data= (adt) ? adt->action : NULL;
588                                 ale->datatype= ALE_ACT;
589                                 
590                                 ale->adt= BKE_animdata_from_id(data);
591                         }
592                                 break;
593                         case ANIMTYPE_DSCUR:
594                         {
595                                 Curve *cu= (Curve *)data;
596                                 AnimData *adt= cu->adt;
597                                 
598                                 ale->flag= FILTER_CUR_OBJD(cu);
599                                 
600                                 ale->key_data= (adt) ? adt->action : NULL;
601                                 ale->datatype= ALE_ACT;
602                                 
603                                 ale->adt= BKE_animdata_from_id(data);
604                         }
605                                 break;
606                         case ANIMTYPE_DSARM:
607                         {
608                                 bArmature *arm= (bArmature *)data;
609                                 AnimData *adt= arm->adt;
610                                 
611                                 ale->flag= FILTER_ARM_OBJD(arm);
612                                 
613                                 ale->key_data= (adt) ? adt->action : NULL;
614                                 ale->datatype= ALE_ACT;
615                                 
616                                 ale->adt= BKE_animdata_from_id(data);
617                         }
618                                 break;
619                         case ANIMTYPE_DSSKEY:
620                         {
621                                 Key *key= (Key *)data;
622                                 AnimData *adt= key->adt;
623                                 
624                                 ale->flag= FILTER_SKE_OBJD(key); 
625                                 
626                                 ale->key_data= (adt) ? adt->action : NULL;
627                                 ale->datatype= ALE_ACT;
628                                 
629                                 ale->adt= BKE_animdata_from_id(data);
630                         }
631                                 break;
632                         case ANIMTYPE_DSWOR:
633                         {
634                                 World *wo= (World *)data;
635                                 AnimData *adt= wo->adt;
636                                 
637                                 ale->flag= FILTER_WOR_SCED(wo); 
638                                 
639                                 ale->key_data= (adt) ? adt->action : NULL;
640                                 ale->datatype= ALE_ACT;
641                                 
642                                 ale->adt= BKE_animdata_from_id(data);
643                         }
644                                 break;
645                         case ANIMTYPE_DSNTREE:
646                         {
647                                 bNodeTree *ntree= (bNodeTree *)data;
648                                 AnimData *adt= ntree->adt;
649                                 
650                                 ale->flag= FILTER_NTREE_SCED(ntree); 
651                                 
652                                 ale->key_data= (adt) ? adt->action : NULL;
653                                 ale->datatype= ALE_ACT;
654                                 
655                                 ale->adt= BKE_animdata_from_id(data);
656                         }
657                                 break;
658                         case ANIMTYPE_DSPART:
659                         {
660                                 ParticleSettings *part= (ParticleSettings*)ale->data;
661                                 AnimData *adt= part->adt;
662                                 
663                                 ale->flag= FILTER_PART_OBJD(part); 
664                                 
665                                 ale->key_data= (adt) ? adt->action : NULL;
666                                 ale->datatype= ALE_ACT;
667                                 
668                                 ale->adt= BKE_animdata_from_id(data);
669                         }
670                                 break;
671                                 
672                         case ANIMTYPE_GROUP:
673                         {
674                                 bActionGroup *agrp= (bActionGroup *)data;
675                                 
676                                 ale->flag= agrp->flag;
677                                 
678                                 ale->key_data= NULL;
679                                 ale->datatype= ALE_GROUP;
680                         }
681                                 break;
682                         case ANIMTYPE_FCURVE:
683                         {
684                                 FCurve *fcu= (FCurve *)data;
685                                 
686                                 ale->flag= fcu->flag;
687                                 
688                                 ale->key_data= fcu;
689                                 ale->datatype= ALE_FCURVE;
690                         }
691                                 break;
692                                 
693                         case ANIMTYPE_SHAPEKEY:
694                         {
695                                 KeyBlock *kb= (KeyBlock *)data;
696                                 Key *key= (Key *)ale->id;
697                                 
698                                 ale->flag= kb->flag;
699                                 
700                                 /* whether we have keyframes depends on whether there is a Key block to find it from */
701                                 if (key) {
702                                         /* index of shapekey is defined by place in key's list */
703                                         ale->index= BLI_findindex(&key->block, kb);
704                                         
705                                         /* the corresponding keyframes are from the animdata */
706                                         if (ale->adt && ale->adt->action) {
707                                                 bAction *act= ale->adt->action;
708                                                 char *rna_path = key_get_curValue_rnaPath(key, kb);
709                                                 
710                                                 /* try to find the F-Curve which corresponds to this exactly,
711                                                  * then free the MEM_alloc'd string
712                                                  */
713                                                 if (rna_path) {
714                                                         ale->key_data= (void *)list_find_fcurve(&act->curves, rna_path, 0);
715                                                         MEM_freeN(rna_path);
716                                                 }
717                                         }
718                                         ale->datatype= (ale->key_data)? ALE_FCURVE : ALE_NONE;
719                                 }
720                         }       
721                                 break;
722                         
723                         case ANIMTYPE_GPLAYER:
724                         {
725                                 bGPDlayer *gpl= (bGPDlayer *)data;
726                                 
727                                 ale->flag= gpl->flag;
728                                 
729                                 ale->key_data= NULL;
730                                 ale->datatype= ALE_GPFRAME;
731                         }
732                                 break;
733                                 
734                         case ANIMTYPE_NLATRACK:
735                         {
736                                 NlaTrack *nlt= (NlaTrack *)data;
737                                 
738                                 ale->flag= nlt->flag;
739                                 
740                                 ale->key_data= &nlt->strips;
741                                 ale->datatype= ALE_NLASTRIP;
742                         }
743                                 break;
744                         case ANIMTYPE_NLAACTION:
745                         {
746                                 /* nothing to include for now... nothing editable from NLA-perspective here */
747                                 ale->key_data= NULL;
748                                 ale->datatype= ALE_NONE;
749                         }
750                                 break;
751                 }
752         }
753         
754         /* return created datatype */
755         return ale;
756 }
757  
758 /* ----------------------------------------- */
759
760 static int skip_fcurve_selected_data(FCurve *fcu, ID *owner_id)
761 {
762         if (GS(owner_id->name) == ID_OB) {
763                 Object *ob= (Object *)owner_id;
764                 
765                 /* only consider if F-Curve involves pose.bones */
766                 if ((fcu->rna_path) && strstr(fcu->rna_path, "bones")) {
767                         bPoseChannel *pchan;
768                         char *bone_name;
769                         
770                         /* get bone-name, and check if this bone is selected */
771                         bone_name= BLI_getQuotedStr(fcu->rna_path, "bones[");
772                         pchan= get_pose_channel(ob->pose, bone_name);
773                         if (bone_name) MEM_freeN(bone_name);
774                         
775                         /* can only add this F-Curve if it is selected */
776                         if ((pchan) && (pchan->bone) && (pchan->bone->flag & BONE_SELECTED)==0)
777                                 return 1;
778                 }
779         }
780         else if (GS(owner_id->name) == ID_SCE) {
781                 Scene *sce = (Scene *)owner_id;
782                 
783                 /* only consider if F-Curve involves sequence_editor.sequences */
784                 if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
785                         Sequence *seq;
786                         char *seq_name;
787                         
788                         /* get strip name, and check if this strip is selected */
789                         seq_name= BLI_getQuotedStr(fcu->rna_path, "sequences_all[");
790                         seq = get_seq_by_name(sce, seq_name);
791                         if (seq_name) MEM_freeN(seq_name);
792                         
793                         /* can only add this F-Curve if it is selected */
794                         if ((seq) && (seq->flag & SELECT)==0)
795                                 return 1;
796                 }
797         }
798         else if (GS(owner_id->name) == ID_NT) {
799                 bNodeTree *ntree = (bNodeTree *)owner_id;
800                 
801                 /* check for selected  nodes */
802                 if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) {
803                         bNode *node;
804                         char *node_name;
805                         
806                         /* get strip name, and check if this strip is selected */
807                         node_name= BLI_getQuotedStr(fcu->rna_path, "nodes[");
808                         node = nodeFindNodebyName(ntree, node_name);
809                         if (node_name) MEM_freeN(node_name);
810                         
811                         /* can only add this F-Curve if it is selected */
812                         if ((node) && (node->flag & NODE_SELECT)==0)
813                                 return 1;
814                 }
815         }
816         return 0;
817 }
818
819 /* find the next F-Curve that is usable for inclusion */
820 static FCurve *animdata_filter_fcurve_next (bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id)
821 {
822         FCurve *fcu = NULL;
823         
824         /* loop over F-Curves - assume that the caller of this has already checked that these should be included 
825          * NOTE: we need to check if the F-Curves belong to the same group, as this gets called for groups too...
826          */
827         for (fcu= first; ((fcu) && (fcu->grp==grp)); fcu= fcu->next) {
828                 /* special exception for Pose-Channel Based F-Curves:
829                  *      - the 'Only Selected' data filter should be applied to Pose-Channel data too, but those are
830                  *        represented as F-Curves. The way the filter for objects worked was to be the first check
831                  *        after 'normal' visibility, so this is done first here too...
832                  *      - we currently use an 'approximate' method for getting these F-Curves that doesn't require
833                  *        carefully checking the entire path
834                  *      - this will also affect things like Drivers, and also works for Bone Constraints
835                  */
836                 if ( ((ads) && (ads->filterflag & ADS_FILTER_ONLYSEL)) && (owner_id) ) {
837                         if (skip_fcurve_selected_data(fcu, owner_id))
838                                 continue;
839                 }
840                                 
841                 /* only include if visible (Graph Editor check, not channels check) */
842                 if (!(filter_mode & ANIMFILTER_CURVEVISIBLE) || (fcu->flag & FCURVE_VISIBLE)) {
843                         /* only work with this channel and its subchannels if it is editable */
844                         if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) {
845                                 /* only include this curve if selected in a way consistent with the filtering requirements */
846                                 if ( ANIMCHANNEL_SELOK(SEL_FCU(fcu)) && ANIMCHANNEL_SELEDITOK(SEL_FCU(fcu)) ) {
847                                         /* only include if this curve is active */
848                                         if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
849                                                 /* this F-Curve can be used, so return it */
850                                                 return fcu;
851                                         }
852                                 }
853                         }
854                 }
855         }
856         
857         /* no (more) F-Curves from the list are suitable... */
858         return NULL;
859 }
860
861 static int animdata_filter_fcurves (ListBase *anim_data, bDopeSheet *ads, FCurve *first, bActionGroup *grp, void *owner, short ownertype, int filter_mode, ID *owner_id)
862 {
863         FCurve *fcu;
864         int items = 0;
865         
866         /* loop over every F-Curve able to be included 
867          *      - this for-loop works like this: 
868          *              1) the starting F-Curve is assigned to the fcu pointer so that we have a starting point to search from
869          *              2) the first valid F-Curve to start from (which may include the one given as 'first') in the remaining 
870          *                 list of F-Curves is found, and verified to be non-null
871          *              3) the F-Curve referenced by fcu pointer is added to the list
872          *              4) the fcu pointer is set to the F-Curve after the one we just added, so that we can keep going through 
873          *                 the rest of the F-Curve list without an eternal loop. Back to step 2 :)
874          */
875         for (fcu=first; ( (fcu = animdata_filter_fcurve_next(ads, fcu, grp, filter_mode, owner_id)) ); fcu=fcu->next)
876         {
877                 bAnimListElem *ale = make_new_animlistelem(fcu, ANIMTYPE_FCURVE, owner, ownertype, owner_id);
878                 
879                 if (ale) {
880                         BLI_addtail(anim_data, ale);
881                         items++;
882                 }
883         }
884         
885         /* return the number of items added to the list */
886         return items;
887 }
888
889 static int animdata_filter_action (ListBase *anim_data, bDopeSheet *ads, bAction *act, int filter_mode, void *owner, short ownertype, ID *owner_id)
890 {
891         bAnimListElem *ale=NULL;
892         bActionGroup *agrp;
893         FCurve *lastchan=NULL;
894         int items = 0;
895         
896         /* loop over groups */
897         // TODO: in future, should we expect to need nested groups?
898         for (agrp= act->groups.first; agrp; agrp= agrp->next) {
899                 FCurve *first_fcu;
900                 
901                 /* store reference to last channel of group */
902                 if (agrp->channels.last) 
903                         lastchan= agrp->channels.last;
904                 
905                 /* get the first F-Curve in this group we can start to use, 
906                  * and if there isn't any F-Curve to start from, then don't 
907                  * this group at all...
908                  *
909                  * exceptions for when we might not care whether there's anything inside this group or not
910                  *      - if we're interested in channels and their selections, in which case group channel should get considered too
911                  *        even if all its sub channels are hidden...
912                  */
913                 first_fcu = animdata_filter_fcurve_next(ads, agrp->channels.first, agrp, filter_mode, owner_id);
914                 
915                 if ( (filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) ||
916                          (first_fcu) ) 
917                 {
918                         /* add this group as a channel first */
919                         if ((filter_mode & ANIMFILTER_CHANNELS) || !(filter_mode & ANIMFILTER_CURVESONLY)) {
920                                 /* check if filtering by selection */
921                                 if ( ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) ) {
922                                         ale= make_new_animlistelem(agrp, ANIMTYPE_GROUP, NULL, ANIMTYPE_NONE, owner_id);
923                                         if (ale) {
924                                                 BLI_addtail(anim_data, ale);
925                                                 items++;
926                                         }
927                                 }
928                         }
929                         
930                         /* there are some situations, where only the channels of the action group should get considered */
931                         if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) {
932                                 /* filters here are a bit convoulted...
933                                  *      - groups show a "summary" of keyframes beside their name which must accessable for tools which handle keyframes
934                                  *      - groups can be collapsed (and those tools which are only interested in channels rely on knowing that group is closed)
935                                  *
936                                  * cases when we should include F-Curves inside group:
937                                  *      - we don't care about visibility
938                                  *      - group is expanded
939                                  *      - we just need the F-Curves present
940                                  */
941                                 if ( (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_AGRP(agrp)) || (filter_mode & ANIMFILTER_CURVESONLY) ) 
942                                 {
943                                         /* for the Graph Editor, curves may be set to not be visible in the view to lessen clutter,
944                                          * but to do this, we need to check that the group doesn't have it's not-visible flag set preventing 
945                                          * all its sub-curves to be shown
946                                          */
947                                         if ( !(filter_mode & ANIMFILTER_CURVEVISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE) )
948                                         {
949                                                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
950                                                         items += animdata_filter_fcurves(anim_data, ads, first_fcu, agrp, owner, ownertype, filter_mode, owner_id);
951                                                 }
952                                         }
953                                 }
954                         }
955                 }
956         }
957         
958         /* loop over un-grouped F-Curves (only if we're not only considering those channels in the animive group) */
959         if (!(filter_mode & ANIMFILTER_ACTGROUPED))  {
960                 // XXX the 'owner' info here needs review...
961                 items += animdata_filter_fcurves(anim_data, ads, (lastchan)?(lastchan->next):(act->curves.first), NULL, owner, ownertype, filter_mode, owner_id);
962         }
963         
964         /* return the number of items added to the list */
965         return items;
966 }
967
968 /* Include NLA-Data for NLA-Editor:
969  *      - when ANIMFILTER_CHANNELS is used, that means we should be filtering the list for display
970  *        Although the evaluation order is from the first track to the last and then apply the Action on top,
971  *        we present this in the UI as the Active Action followed by the last track to the first so that we 
972  *        get the evaluation order presented as per a stack.
973  *      - for normal filtering (i.e. for editing), we only need the NLA-tracks but they can be in 'normal' evaluation
974  *        order, i.e. first to last. Otherwise, some tools may get screwed up.
975  */
976 static int animdata_filter_nla (ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, void *owner, short ownertype, ID *owner_id)
977 {
978         bAnimListElem *ale;
979         NlaTrack *nlt;
980         NlaTrack *first=NULL, *next=NULL;
981         int items = 0;
982         
983         /* if showing channels, include active action */
984         if (filter_mode & ANIMFILTER_CHANNELS) {
985                 /* there isn't really anything editable here, so skip if need editable */
986                 // TODO: currently, selection isn't checked since it doesn't matter
987                 if ((filter_mode & ANIMFILTER_FOREDIT) == 0) { 
988                         /* just add the action track now (this MUST appear for drawing)
989                          *      - as AnimData may not have an action, we pass a dummy pointer just to get the list elem created, then
990                          *        overwrite this with the real value - REVIEW THIS...
991                          */
992                         ale= make_new_animlistelem((void *)(&adt->action), ANIMTYPE_NLAACTION, owner, ownertype, owner_id);
993                         ale->data= (adt->action) ? adt->action : NULL;
994                                 
995                         if (ale) {
996                                 BLI_addtail(anim_data, ale);
997                                 items++;
998                         }
999                 }
1000                 
1001                 /* first track to include will be the last one if we're filtering by channels */
1002                 first= adt->nla_tracks.last;
1003         }
1004         else {
1005                 /* first track to include will the the first one (as per normal) */
1006                 first= adt->nla_tracks.first;
1007         }
1008         
1009         /* loop over NLA Tracks - assume that the caller of this has already checked that these should be included */
1010         for (nlt= first; nlt; nlt= next) {
1011                 /* 'next' NLA-Track to use depends on whether we're filtering for drawing or not */
1012                 if (filter_mode & ANIMFILTER_CHANNELS) 
1013                         next= nlt->prev;
1014                 else
1015                         next= nlt->next;
1016                 
1017                 /* if we're in NLA-tweakmode, don't show this track if it was disabled (due to tweaking) for now 
1018                  *      - active track should still get shown though (even though it has disabled flag set)
1019                  */
1020                 // FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel
1021                 if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && !(nlt->flag & NLATRACK_ACTIVE))
1022                         continue;
1023                 
1024                 /* only work with this channel and its subchannels if it is editable */
1025                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) {
1026                         /* only include this track if selected in a way consistent with the filtering requirements */
1027                         if ( ANIMCHANNEL_SELOK(SEL_NLT(nlt)) ) {
1028                                 /* only include if this track is active */
1029                                 if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
1030                                         ale= make_new_animlistelem(nlt, ANIMTYPE_NLATRACK, owner, ownertype, owner_id);
1031                                                 
1032                                         if (ale) {
1033                                                 BLI_addtail(anim_data, ale);
1034                                                 items++;
1035                                         }
1036                                 }
1037                         }
1038                 }
1039         }
1040         
1041         /* return the number of items added to the list */
1042         return items;
1043 }
1044
1045 /* Include ShapeKey Data for ShapeKey Editor */
1046 static int animdata_filter_shapekey (ListBase *anim_data, Key *key, int filter_mode)
1047 {
1048         bAnimListElem *ale;
1049         int items = 0;
1050         
1051         /* check if channels or only F-Curves */
1052         if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) {
1053                 KeyBlock *kb;
1054                 
1055                 /* loop through the channels adding ShapeKeys as appropriate */
1056                 for (kb= key->block.first; kb; kb= kb->next) {
1057                         /* skip the first one, since that's the non-animateable basis */
1058                         // XXX maybe in future this may become handy?
1059                         if (kb == key->block.first) continue;
1060                         
1061                         /* only work with this channel and its subchannels if it is editable */
1062                         if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_SHAPEKEY(kb)) {
1063                                 /* only include this track if selected in a way consistent with the filtering requirements */
1064                                 if ( ANIMCHANNEL_SELOK(SEL_SHAPEKEY(kb)) ) {
1065                                         // TODO: consider 'active' too?
1066                                         
1067                                         /* owner-id here must be key so that the F-Curve can be resolved... */
1068                                         ale= make_new_animlistelem(kb, ANIMTYPE_SHAPEKEY, NULL, ANIMTYPE_NONE, (ID *)key);
1069                                         
1070                                         if (ale) {
1071                                                 BLI_addtail(anim_data, ale);
1072                                                 items++;
1073                                         }
1074                                 }
1075                         }
1076                 }
1077         }
1078         else {
1079                 /* just use the action associated with the shapekey */
1080                 // FIXME: is owner-id and having no owner/dopesheet really fine?
1081                 if (key->adt) {
1082                         if (filter_mode & ANIMFILTER_ANIMDATA)
1083                                 ANIMDATA_ADD_ANIMDATA(key)
1084                         else if (key->adt->action)
1085                                 items= animdata_filter_action(anim_data, NULL, key->adt->action, filter_mode, NULL, ANIMTYPE_NONE, (ID *)key);
1086                 }
1087         }
1088         
1089         /* return the number of items added to the list */
1090         return items;
1091 }
1092
1093 #if 0
1094 // FIXME: switch this to use the bDopeSheet...
1095 static int animdata_filter_gpencil (ListBase *anim_data, bScreen *sc, int filter_mode)
1096 {
1097         bAnimListElem *ale;
1098         ScrArea *sa, *curarea;
1099         bGPdata *gpd;
1100         bGPDlayer *gpl;
1101         int items = 0;
1102         
1103         /* check if filtering types are appropriate */
1104         {
1105                 /* special hack for fullscreen area (which must be this one then):
1106                  *      - we use the curarea->full as screen to get spaces from, since the
1107                  *        old (pre-fullscreen) screen was stored there...
1108                  *      - this is needed as all data would otherwise disappear
1109                  */
1110                 // XXX need to get new alternative for curarea
1111                 if ((curarea->full) && (curarea->spacetype==SPACE_ACTION))
1112                         sc= curarea->full;
1113                 
1114                 /* loop over spaces in current screen, finding gpd blocks (could be slow!) */
1115                 for (sa= sc->areabase.first; sa; sa= sa->next) {
1116                         /* try to get gp data */
1117                         // XXX need to put back grease pencil api...
1118                         gpd= gpencil_data_get_active(sa);
1119                         if (gpd == NULL) continue;
1120                         
1121                         /* add gpd as channel too (if for drawing, and it has layers) */
1122                         if ((filter_mode & ANIMFILTER_CHANNELS) && (gpd->layers.first)) {
1123                                 /* add to list */
1124                                 ale= make_new_animlistelem(gpd, ANIMTYPE_GPDATABLOCK, sa, ANIMTYPE_SPECIALDATA);
1125                                 if (ale) {
1126                                         BLI_addtail(anim_data, ale);
1127                                         items++;
1128                                 }
1129                         }
1130                         
1131                         /* only add layers if they will be visible (if drawing channels) */
1132                         if ( !(filter_mode & ANIMFILTER_VISIBLE) || (EXPANDED_GPD(gpd)) ) {
1133                                 /* loop over layers as the conditions are acceptable */
1134                                 for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
1135                                         /* only if selected */
1136                                         if ( ANIMCHANNEL_SELOK(SEL_GPL(gpl)) ) {
1137                                                 /* only if editable */
1138                                                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) {
1139                                                         /* add to list */
1140                                                         ale= make_new_animlistelem(gpl, ANIMTYPE_GPLAYER, gpd, ANIMTYPE_GPDATABLOCK);
1141                                                         if (ale) {
1142                                                                 BLI_addtail(anim_data, ale);
1143                                                                 items++;
1144                                                         }
1145                                                 }
1146                                         }
1147                                 }
1148                         }
1149                 }
1150         }
1151         
1152         /* return the number of items added to the list */
1153         return items;
1154 }
1155 #endif 
1156
1157
1158 static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1159 {
1160         ListBase mats = {NULL, NULL};
1161         LinkData *ld;
1162         
1163         bAnimListElem *ale=NULL;
1164         Object *ob= base->object;
1165         int items=0, a=0;
1166         
1167         /* firstly check that we actuallly have some materials, by gathering all materials in a temp list */
1168         for (a=0; a < ob->totcol; a++) {
1169                 Material *ma= give_current_material(ob, a);
1170                 short ok = 0;
1171                 
1172                 /* for now, if no material returned, skip (this shouldn't confuse the user I hope) */
1173                 if (ELEM(NULL, ma, ma->adt)) 
1174                         continue;
1175                 
1176                 /* check if ok */
1177                 ANIMDATA_FILTER_CASES(ma, 
1178                         { /* AnimData blocks - do nothing... */ },
1179                         ok=1;, 
1180                         ok=1;, 
1181                         ok=1;)
1182                 if (ok == 0) continue;
1183                 
1184                 /* make a temp list elem for this */
1185                 ld= MEM_callocN(sizeof(LinkData), "DopeSheet-MaterialCache");
1186                 ld->data= ma;
1187                 BLI_addtail(&mats, ld);
1188         }
1189         
1190         /* if there were no channels found, no need to carry on */
1191         if (mats.first == NULL)
1192                 return 0;
1193         
1194         /* include materials-expand widget? */
1195         if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1196                 ale= make_new_animlistelem(ob, ANIMTYPE_FILLMATD, base, ANIMTYPE_OBJECT, (ID *)ob);
1197                 if (ale) {
1198                         BLI_addtail(anim_data, ale);
1199                         items++;
1200                 }
1201         }
1202         
1203         /* add materials? */
1204         if (FILTER_MAT_OBJC(ob) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1205                 /* for each material in cache, add channels  */
1206                 for (ld= mats.first; ld; ld= ld->next) {
1207                         Material *ma= (Material *)ld->data;
1208                         
1209                         /* include material-expand widget? */
1210                         // hmm... do we need to store the index of this material in the array anywhere?
1211                         if (filter_mode & ANIMFILTER_CHANNELS) {
1212                                 /* check if filtering by active status */
1213                                 if ANIMCHANNEL_ACTIVEOK(ma) {
1214                                         ale= make_new_animlistelem(ma, ANIMTYPE_DSMAT, base, ANIMTYPE_OBJECT, (ID *)ma);
1215                                         if (ale) {
1216                                                 BLI_addtail(anim_data, ale);
1217                                                 items++;
1218                                         }
1219                                 }
1220                         }
1221                         
1222                         /* add material's animation data */
1223                         if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_MAT_OBJD(ma) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1224                                 ANIMDATA_FILTER_CASES(ma, 
1225                                         { /* AnimData blocks - do nothing... */ },
1226                                         items += animdata_filter_nla(anim_data, ads, ma->adt, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);, 
1227                                         items += animdata_filter_fcurves(anim_data, ads, ma->adt->drivers.first, NULL, ma, ANIMTYPE_DSMAT, filter_mode, (ID *)ma);, 
1228                                         items += animdata_filter_action(anim_data, ads, ma->adt->action, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);)
1229                         }
1230                 }
1231         }
1232         
1233         /* free cache */
1234         BLI_freelistN(&mats);
1235         
1236         /* return the number of items added to the list */
1237         return items;
1238 }
1239
1240 static int animdata_filter_dopesheet_particles (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1241 {
1242         bAnimListElem *ale=NULL;
1243         Object *ob= base->object;
1244         ParticleSystem *psys = ob->particlesystem.first;
1245         int items= 0, first = 1;
1246
1247         for(; psys; psys=psys->next) {
1248                 short ok = 0;
1249
1250                 if(ELEM(NULL, psys->part, psys->part->adt))
1251                         continue;
1252
1253                 ANIMDATA_FILTER_CASES(psys->part,
1254                         { /* AnimData blocks - do nothing... */ },
1255                         ok=1;, 
1256                         ok=1;, 
1257                         ok=1;)
1258                 if (ok == 0) continue;
1259
1260                 /* include particles-expand widget? */
1261                 if (first && (filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1262                         ale= make_new_animlistelem(ob, ANIMTYPE_FILLPARTD, base, ANIMTYPE_OBJECT, (ID *)ob);
1263                         if (ale) {
1264                                 BLI_addtail(anim_data, ale);
1265                                 items++;
1266                         }
1267                         first = 0;
1268                 }
1269                 
1270                 /* add particle settings? */
1271                 if (FILTER_PART_OBJC(ob) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1272                         if ((filter_mode & ANIMFILTER_CHANNELS)) {
1273                                 /* check if filtering by active status */
1274                                 if ANIMCHANNEL_ACTIVEOK(psys->part) {
1275                                         ale = make_new_animlistelem(psys->part, ANIMTYPE_DSPART, base, ANIMTYPE_OBJECT, (ID *)psys->part);
1276                                         if (ale) {
1277                                                 BLI_addtail(anim_data, ale);
1278                                                 items++;
1279                                         }
1280                                 }
1281                         }
1282                         
1283                         if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_PART_OBJD(psys->part) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1284                                 ANIMDATA_FILTER_CASES(psys->part,
1285                                         { /* AnimData blocks - do nothing... */ },
1286                                         items += animdata_filter_nla(anim_data, ads, psys->part->adt, filter_mode, psys->part, ANIMTYPE_DSPART, (ID *)psys->part);, 
1287                                         items += animdata_filter_fcurves(anim_data, ads, psys->part->adt->drivers.first, NULL, psys->part, ANIMTYPE_DSPART, filter_mode, (ID *)psys->part);, 
1288                                         items += animdata_filter_action(anim_data, ads, psys->part->adt->action, filter_mode, psys->part, ANIMTYPE_DSPART, (ID *)psys->part);)
1289                         }
1290                 }
1291         }
1292         
1293         /* return the number of items added to the list */
1294         return items;
1295 }
1296
1297 static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1298 {
1299         bAnimListElem *ale=NULL;
1300         Object *ob= base->object;
1301         IdAdtTemplate *iat= ob->data;
1302         AnimData *adt= iat->adt;
1303         short type=0, expanded=0;
1304         int items= 0;
1305         
1306         /* get settings based on data type */
1307         switch (ob->type) {
1308                 case OB_CAMERA: /* ------- Camera ------------ */
1309                 {
1310                         Camera *ca= (Camera *)ob->data;
1311                         
1312                         type= ANIMTYPE_DSCAM;
1313                         expanded= FILTER_CAM_OBJD(ca);
1314                 }
1315                         break;
1316                 case OB_LAMP: /* ---------- Lamp ----------- */
1317                 {
1318                         Lamp *la= (Lamp *)ob->data;
1319                         
1320                         type= ANIMTYPE_DSLAM;
1321                         expanded= FILTER_LAM_OBJD(la);
1322                 }
1323                         break;
1324                 case OB_CURVE: /* ------- Curve ---------- */
1325                 {
1326                         Curve *cu= (Curve *)ob->data;
1327                         
1328                         type= ANIMTYPE_DSCUR;
1329                         expanded= FILTER_CUR_OBJD(cu);
1330                 }
1331                         break;
1332                 case OB_MBALL: /* ------- MetaBall ---------- */
1333                 {
1334                         MetaBall *mb= (MetaBall *)ob->data;
1335                         
1336                         type= ANIMTYPE_DSMBALL;
1337                         expanded= FILTER_MBALL_OBJD(mb);
1338                 }
1339                         break;
1340                 case OB_ARMATURE: /* ------- Armature ---------- */
1341                 {
1342                         bArmature *arm= (bArmature *)ob->data;
1343                         
1344                         type= ANIMTYPE_DSARM;
1345                         expanded= FILTER_ARM_OBJD(arm);
1346                 }
1347                         break;
1348         }
1349         
1350         /* special exception for drivers instead of action */
1351         if (ads->filterflag & ADS_FILTER_ONLYDRIVERS)
1352                 expanded= EXPANDED_DRVD(adt);
1353         
1354         /* include data-expand widget? */
1355         if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) {       
1356                 /* check if filtering by active status */
1357                 if ANIMCHANNEL_ACTIVEOK(iat) {
1358                         ale= make_new_animlistelem(iat, type, base, ANIMTYPE_OBJECT, (ID *)iat);
1359                         if (ale) BLI_addtail(anim_data, ale);
1360                 }
1361         }
1362         
1363         /* add object-data animation channels? */
1364         if (!(filter_mode & ANIMFILTER_VISIBLE) || (expanded) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1365                 /* filtering for channels - nla, drivers, keyframes */
1366                 ANIMDATA_FILTER_CASES(iat, 
1367                         { /* AnimData blocks - do nothing... */ },
1368                         items+= animdata_filter_nla(anim_data, ads, iat->adt, filter_mode, iat, type, (ID *)iat);,
1369                         items+= animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, iat, type, filter_mode, (ID *)iat);, 
1370                         items += animdata_filter_action(anim_data, ads, iat->adt->action, filter_mode, iat, type, (ID *)iat);)
1371         }
1372         
1373         /* return the number of items added to the list */
1374         return items;
1375 }
1376
1377 static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1378 {
1379         bAnimListElem *ale=NULL;
1380         AnimData *adt = NULL;
1381         Object *ob= base->object;
1382         Key *key= ob_get_key(ob);
1383         short obdata_ok = 0;
1384         int items = 0;
1385         
1386         /* add this object as a channel first */
1387         if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) {
1388                 /* check if filtering by selection */
1389                 if ANIMCHANNEL_SELOK((base->flag & SELECT)) {
1390                         /* check if filtering by active status */
1391                         if ANIMCHANNEL_ACTIVEOK(ob) {
1392                                 ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE, (ID *)ob);
1393                                 if (ale) {
1394                                         BLI_addtail(anim_data, ale);
1395                                         items++;
1396                                 }
1397                         }
1398                 }
1399         }
1400         
1401         /* if collapsed, don't go any further (unless adding keyframes only) */
1402         if ( ((filter_mode & ANIMFILTER_VISIBLE) && EXPANDED_OBJC(ob) == 0) &&
1403                  !(filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) )
1404                 return items;
1405         
1406         /* Action, Drivers, or NLA */
1407         if (ob->adt) {
1408                 adt= ob->adt;
1409                 ANIMDATA_FILTER_CASES(ob,
1410                         { /* AnimData blocks - do nothing... */ },
1411                         { /* nla */
1412                                 /* add NLA tracks */
1413                                 items += animdata_filter_nla(anim_data, ads, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
1414                         },
1415                         { /* drivers */
1416                                 /* include drivers-expand widget? */
1417                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1418                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, base, ANIMTYPE_OBJECT, (ID *)ob);
1419                                         if (ale) {
1420                                                 BLI_addtail(anim_data, ale);
1421                                                 items++;
1422                                         }
1423                                 }
1424                                 
1425                                 /* add F-Curve channels (drivers are F-Curves) */
1426                                 if (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1427                                         // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
1428                                         items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, ob, ANIMTYPE_OBJECT, filter_mode, (ID *)ob);
1429                                 }
1430                         },
1431                         { /* action (keyframes) */
1432                                 /* include action-expand widget? */
1433                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1434                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, base, ANIMTYPE_OBJECT, (ID *)ob);
1435                                         if (ale) {
1436                                                 BLI_addtail(anim_data, ale);
1437                                                 items++;
1438                                         }
1439                                 }
1440                                 
1441                                 /* add F-Curve channels? */
1442                                 if (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1443                                         // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
1444                                         items += animdata_filter_action(anim_data, ads, adt->action, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); 
1445                                 }
1446                         }
1447                 );
1448         }
1449         
1450         
1451         /* ShapeKeys? */
1452         if ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
1453                 adt= key->adt;
1454                 ANIMDATA_FILTER_CASES(key,
1455                         { /* AnimData blocks - do nothing... */ },
1456                         { /* nla */
1457                                 /* include shapekey-expand widget? */
1458                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1459                                         /* check if filtering by active status */
1460                                         if ANIMCHANNEL_ACTIVEOK(key) {
1461                                                 ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
1462                                                 if (ale) {
1463                                                         BLI_addtail(anim_data, ale);
1464                                                         items++;
1465                                                 }
1466                                         }
1467                                 }
1468                                 
1469                                 /* add NLA tracks - only if expanded or so */
1470                                 if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY))
1471                                         items += animdata_filter_nla(anim_data, ads, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
1472                         },
1473                         { /* drivers */
1474                                 /* include shapekey-expand widget? */
1475                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1476                                         ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
1477                                         if (ale) {
1478                                                 BLI_addtail(anim_data, ale);
1479                                                 items++;
1480                                         }
1481                                 }
1482                                 
1483                                 /* add channels */
1484                                 if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1485                                         items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, key, ANIMTYPE_DSSKEY, filter_mode, (ID *)key);
1486                                 }
1487                         },
1488                         { /* action (keyframes) */
1489                                 /* include shapekey-expand widget? */
1490                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1491                                         /* check if filtering by active status */
1492                                         if ANIMCHANNEL_ACTIVEOK(key) {
1493                                                 ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
1494                                                 if (ale) {
1495                                                         BLI_addtail(anim_data, ale);
1496                                                         items++;
1497                                                 }
1498                                         }
1499                                 }
1500                                 
1501                                 /* add channels */
1502                                 if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1503                                         items += animdata_filter_action(anim_data, ads, adt->action, filter_mode, key, ANIMTYPE_DSSKEY, (ID *)key); 
1504                                 }
1505                         }
1506                 );
1507         }
1508
1509         /* Materials? */
1510         if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT))
1511                 items += animdata_filter_dopesheet_mats(anim_data, ads, base, filter_mode);
1512         
1513         /* Object Data */
1514         switch (ob->type) {
1515                 case OB_CAMERA: /* ------- Camera ------------ */
1516                 {
1517                         Camera *ca= (Camera *)ob->data;
1518                         
1519                         if ((ads->filterflag & ADS_FILTER_NOCAM) == 0) {
1520                                 ANIMDATA_FILTER_CASES(ca,
1521                                         { /* AnimData blocks - do nothing... */ },
1522                                         obdata_ok= 1;,
1523                                         obdata_ok= 1;,
1524                                         obdata_ok= 1;)
1525                         }
1526                 }
1527                         break;
1528                 case OB_LAMP: /* ---------- Lamp ----------- */
1529                 {
1530                         Lamp *la= (Lamp *)ob->data;
1531                         
1532                         if ((ads->filterflag & ADS_FILTER_NOLAM) == 0) {
1533                                 ANIMDATA_FILTER_CASES(la,
1534                                         { /* AnimData blocks - do nothing... */ },
1535                                         obdata_ok= 1;,
1536                                         obdata_ok= 1;,
1537                                         obdata_ok= 1;)
1538                         }
1539                 }
1540                         break;
1541                 case OB_CURVE: /* ------- Curve ---------- */
1542                 {
1543                         Curve *cu= (Curve *)ob->data;
1544                         
1545                         if ((ads->filterflag & ADS_FILTER_NOCUR) == 0) {
1546                                 ANIMDATA_FILTER_CASES(cu,
1547                                         { /* AnimData blocks - do nothing... */ },
1548                                         obdata_ok= 1;,
1549                                         obdata_ok= 1;,
1550                                         obdata_ok= 1;)
1551                         }
1552                 }
1553                         break;
1554                 case OB_MBALL: /* ------- MetaBall ---------- */
1555                 {
1556                         MetaBall *mb= (MetaBall *)ob->data;
1557                         
1558                         if ((ads->filterflag & ADS_FILTER_NOMBA) == 0) {
1559                                 ANIMDATA_FILTER_CASES(mb,
1560                                         { /* AnimData blocks - do nothing... */ },
1561                                         obdata_ok= 1;,
1562                                         obdata_ok= 1;,
1563                                         obdata_ok= 1;)
1564                         }
1565                 }
1566                         break;
1567                 case OB_ARMATURE: /* ------- Armature ---------- */
1568                 {
1569                         bArmature *arm= (bArmature *)ob->data;
1570                         
1571                         if ((ads->filterflag & ADS_FILTER_NOARM) == 0) {
1572                                 ANIMDATA_FILTER_CASES(arm,
1573                                         { /* AnimData blocks - do nothing... */ },
1574                                         obdata_ok= 1;,
1575                                         obdata_ok= 1;,
1576                                         obdata_ok= 1;)
1577                         }
1578                 }
1579                         break;
1580         }
1581         if (obdata_ok) 
1582                 items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode);
1583
1584         /* particles */
1585         if (ob->particlesystem.first && !(ads->filterflag & ADS_FILTER_NOPART))
1586                 items += animdata_filter_dopesheet_particles(anim_data, ads, base, filter_mode);
1587         
1588         /* return the number of items added to the list */
1589         return items;
1590 }       
1591
1592 static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
1593 {
1594         World *wo= sce->world;
1595         bNodeTree *ntree= sce->nodetree;
1596         AnimData *adt= NULL;
1597         bAnimListElem *ale;
1598         int items = 0;
1599         
1600         /* add scene as a channel first (even if we aren't showing scenes we still need to show the scene's sub-data */
1601         if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) {
1602                 /* check if filtering by selection */
1603                 if (ANIMCHANNEL_SELOK( (sce->flag & SCE_DS_SELECTED) )) {
1604                         ale= make_new_animlistelem(sce, ANIMTYPE_SCENE, NULL, ANIMTYPE_NONE, NULL);
1605                         if (ale) {
1606                                 BLI_addtail(anim_data, ale);
1607                                 items++;
1608                         }
1609                 }
1610         }
1611         
1612         /* if collapsed, don't go any further (unless adding keyframes only) */
1613         if ( (EXPANDED_SCEC(sce) == 0) && !(filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) )
1614                 return items;
1615                 
1616         /* Action, Drivers, or NLA for Scene */
1617         if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) {
1618                 adt= sce->adt;
1619                 ANIMDATA_FILTER_CASES(sce,
1620                         { /* AnimData blocks - do nothing... */ },
1621                         { /* nla */
1622                                 /* add NLA tracks */
1623                                 items += animdata_filter_nla(anim_data, ads, adt, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce);
1624                         },
1625                         { /* drivers */
1626                                 /* include drivers-expand widget? */
1627                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1628                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, sce, ANIMTYPE_SCENE, (ID *)sce);
1629                                         if (ale) {
1630                                                 BLI_addtail(anim_data, ale);
1631                                                 items++;
1632                                         }
1633                                 }
1634                                 
1635                                 /* add F-Curve channels (drivers are F-Curves) */
1636                                 if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1637                                         items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, sce, ANIMTYPE_SCENE, filter_mode, (ID *)sce);
1638                                 }
1639                         },
1640                         { /* action */
1641                                 /* include action-expand widget? */
1642                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1643                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, sce, ANIMTYPE_SCENE, (ID *)sce);
1644                                         if (ale) {
1645                                                 BLI_addtail(anim_data, ale);
1646                                                 items++;
1647                                         }
1648                                 }
1649                                 
1650                                 /* add F-Curve channels? */
1651                                 if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1652                                         items += animdata_filter_action(anim_data, ads, adt->action, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce); 
1653                                 }
1654                         }
1655                 )
1656         }
1657         
1658         /* world */
1659         if ((wo && wo->adt) && !(ads->filterflag & ADS_FILTER_NOWOR)) {
1660                 /* Action, Drivers, or NLA for World */
1661                 adt= wo->adt;
1662                 ANIMDATA_FILTER_CASES(wo,
1663                         { /* AnimData blocks - do nothing... */ },
1664                         { /* nla */
1665                                 /* add NLA tracks */
1666                                 items += animdata_filter_nla(anim_data, ads, adt, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo);
1667                         },
1668                         { /* drivers */
1669                                 /* include world-expand widget? */
1670                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1671                                         ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)wo);
1672                                         if (ale) {
1673                                                 BLI_addtail(anim_data, ale);
1674                                                 items++;
1675                                         }
1676                                 }
1677                                 
1678                                 /* add F-Curve channels (drivers are F-Curves) */
1679                                 if (FILTER_WOR_SCED(wo)/*EXPANDED_DRVD(adt)*/ || !(filter_mode & ANIMFILTER_CHANNELS)) {
1680                                         // XXX owner info is messed up now...
1681                                         items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, wo, ANIMTYPE_DSWOR, filter_mode, (ID *)wo);
1682                                 }
1683                         },
1684                         { /* action */
1685                                 /* include world-expand widget? */
1686                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1687                                         ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)sce);
1688                                         if (ale) {
1689                                                 BLI_addtail(anim_data, ale);
1690                                                 items++;
1691                                         }
1692                                 }
1693                                 
1694                                 /* add channels */
1695                                 if (FILTER_WOR_SCED(wo) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1696                                         items += animdata_filter_action(anim_data, ads, adt->action, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo); 
1697                                 }
1698                         }
1699                 )
1700         }
1701         /* nodetree */
1702         if ((ntree && ntree->adt) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
1703                 /* Action, Drivers, or NLA for Nodetree */
1704                 adt= ntree->adt;
1705                 ANIMDATA_FILTER_CASES(ntree,
1706                         { /* AnimData blocks - do nothing... */ },
1707                         { /* nla */
1708                                 /* add NLA tracks */
1709                                 items += animdata_filter_nla(anim_data, ads, adt, filter_mode, ntree, ANIMTYPE_DSNTREE, (ID *)ntree);
1710                         },
1711                         { /* drivers */
1712                                 /* include nodetree-expand widget? */
1713                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1714                                         ale= make_new_animlistelem(ntree, ANIMTYPE_DSNTREE, sce, ANIMTYPE_SCENE, (ID *)ntree);
1715                                         if (ale) {
1716                                                 BLI_addtail(anim_data, ale);
1717                                                 items++;
1718                                         }
1719                                 }
1720                                 
1721                                 /* add F-Curve channels (drivers are F-Curves) */
1722                                 if (FILTER_NTREE_SCED(ntree)/*EXPANDED_DRVD(adt)*/ || !(filter_mode & ANIMFILTER_CHANNELS)) {
1723                                         // XXX owner info is messed up now...
1724                                         items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, ntree, ANIMTYPE_DSNTREE, filter_mode, (ID *)ntree);
1725                                 }
1726                         },
1727                         { /* action */
1728                                 /* include nodetree-expand widget? */
1729                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1730                                         ale= make_new_animlistelem(ntree, ANIMTYPE_DSNTREE, sce, ANIMTYPE_SCENE, (ID *)sce);
1731                                         if (ale) {
1732                                                 BLI_addtail(anim_data, ale);
1733                                                 items++;
1734                                         }
1735                                 }
1736                                 
1737                                 /* add channels */
1738                                 if (FILTER_NTREE_SCED(ntree) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1739                                         items += animdata_filter_action(anim_data, ads, adt->action, filter_mode, ntree, ANIMTYPE_DSNTREE, (ID *)ntree); 
1740                                 }
1741                         }
1742                 )
1743         }
1744
1745         
1746         // TODO: scene compositing nodes (these aren't standard node-trees)
1747         
1748         /* return the number of items added to the list */
1749         return items;
1750 }
1751
1752 // 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)
1753 static int animdata_filter_dopesheet (ListBase *anim_data, bAnimContext *ac, bDopeSheet *ads, int filter_mode)
1754 {
1755         Scene *sce= (Scene *)ads->source;
1756         Base *base;
1757         bAnimListElem *ale;
1758         int items = 0;
1759         
1760         /* check that we do indeed have a scene */
1761         if ((ads->source == NULL) || (GS(ads->source->name)!=ID_SCE)) {
1762                 printf("DopeSheet Error: Not scene!\n");
1763                 if (G.f & G_DEBUG)
1764                         printf("\tPointer = %p, Name = '%s' \n", ads->source, (ads->source)?ads->source->name:NULL);
1765                 return 0;
1766         }
1767         
1768         /* scene-linked animation */
1769         // TODO: sequencer, composite nodes - are we to include those here too?
1770         {
1771                 short sceOk= 0, worOk= 0, nodeOk=0;
1772                 
1773                 /* check filtering-flags if ok */
1774                 ANIMDATA_FILTER_CASES(sce, 
1775                         {
1776                                 /* for the special AnimData blocks only case, we only need to add
1777                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1778                                  */
1779                                 ANIMDATA_ADD_ANIMDATA(sce);
1780                                 sceOk=0;
1781                         },
1782                         sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, 
1783                         sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, 
1784                         sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);)
1785                 if (sce->world) {
1786                         ANIMDATA_FILTER_CASES(sce->world, 
1787                                 {
1788                                         /* for the special AnimData blocks only case, we only need to add
1789                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
1790                                          */
1791                                         ANIMDATA_ADD_ANIMDATA(sce->world);
1792                                         worOk=0;
1793                                 },
1794                                 worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, 
1795                                 worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, 
1796                                 worOk= !(ads->filterflag & ADS_FILTER_NOWOR);)
1797                 }
1798                 if (sce->nodetree) {
1799                         ANIMDATA_FILTER_CASES(sce->nodetree, 
1800                                 {
1801                                         /* for the special AnimData blocks only case, we only need to add
1802                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
1803                                          */
1804                                         ANIMDATA_ADD_ANIMDATA(sce->nodetree);
1805                                         nodeOk=0;
1806                                 },
1807                                 nodeOk= !(ads->filterflag & ADS_FILTER_NONTREE);, 
1808                                 nodeOk= !(ads->filterflag & ADS_FILTER_NONTREE);, 
1809                                 nodeOk= !(ads->filterflag & ADS_FILTER_NONTREE);)
1810                 }
1811                 
1812                 /* if only F-Curves with visible flags set can be shown, check that 
1813                  * datablocks haven't been set to invisible 
1814                  */
1815                 if (filter_mode & ANIMFILTER_CURVEVISIBLE) {
1816                         if ((sce->adt) && (sce->adt->flag & ADT_CURVES_NOT_VISIBLE))
1817                                 sceOk= worOk= nodeOk= 0;
1818                 }
1819                 
1820                 /* check if not all bad (i.e. so there is something to show) */
1821                 if ( !(!sceOk && !worOk && !nodeOk) ) {
1822                         /* add scene data to the list of filtered channels */
1823                         items += animdata_filter_dopesheet_scene(anim_data, ads, sce, filter_mode);
1824                 }
1825         }
1826         
1827         
1828         /* loop over all bases in the scene */
1829         for (base= sce->base.first; base; base= base->next) {
1830                 /* check if there's an object (all the relevant checks are done in the ob-function) */
1831                 if (base->object) {
1832                         Object *ob= base->object;
1833                         Key *key= ob_get_key(ob);
1834                         short actOk=1, keyOk=1, dataOk=1, matOk=1, partOk=1;
1835                         
1836                         /* firstly, check if object can be included, by the following factors:
1837                          *      - if only visible, must check for layer and also viewport visibility
1838                          *      - if only selected, must check if object is selected 
1839                          *      - there must be animation data to edit
1840                          */
1841                         // TODO: if cache is implemented, just check name here, and then 
1842                         if (filter_mode & ANIMFILTER_VISIBLE) {
1843                                 /* layer visibility - we check both object and base, since these may not be in sync yet */
1844                                 if ((sce->lay & (ob->lay|base->lay))==0) continue;
1845                                 
1846                                 /* outliner restrict-flag */
1847                                 if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
1848                         }
1849                         
1850                         /* if only F-Curves with visible flags set can be shown, check that 
1851                          * datablock hasn't been set to invisible 
1852                          */
1853                         if (filter_mode & ANIMFILTER_CURVEVISIBLE) {
1854                                 if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE))
1855                                         continue;
1856                         }
1857                         
1858                         /* additionally, dopesheet filtering also affects what objects to consider */
1859                         if (ads->filterflag) {
1860                                 /* check selection and object type filters */
1861                                 if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/) )  {
1862                                         /* only selected should be shown */
1863                                         continue;
1864                                 }
1865                                 
1866                                 /* check filters for datatypes */
1867                                         /* object */
1868                                 actOk= 0;
1869                                 keyOk= 0;
1870                                 ANIMDATA_FILTER_CASES(ob, 
1871                                         {
1872                                                 /* for the special AnimData blocks only case, we only need to add
1873                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1874                                                  */
1875                                                 ANIMDATA_ADD_ANIMDATA(ob);
1876                                                 actOk=0;
1877                                         },
1878                                         actOk= 1;, 
1879                                         actOk= 1;, 
1880                                         actOk= 1;)
1881                                 if (key) {
1882                                         /* shapekeys */
1883                                         ANIMDATA_FILTER_CASES(key, 
1884                                                 {
1885                                                         /* for the special AnimData blocks only case, we only need to add
1886                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
1887                                                          */
1888                                                         ANIMDATA_ADD_ANIMDATA(key);
1889                                                         keyOk=0;
1890                                                 },
1891                                                 keyOk= 1;, 
1892                                                 keyOk= 1;, 
1893                                                 keyOk= 1;)
1894                                 }
1895                                 
1896                                 /* materials - only for geometric types */
1897                                 matOk= 0; /* by default, not ok... */
1898                                 if ( !(ads->filterflag & ADS_FILTER_NOMAT) && (ob->totcol) && 
1899                                          ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) ) 
1900                                 {
1901                                         int a;
1902                                         
1903                                         /* firstly check that we actuallly have some materials */
1904                                         for (a=0; a < ob->totcol; a++) {
1905                                                 Material *ma= give_current_material(ob, a);
1906                                                 
1907                                                 if (ma) {
1908                                                         /* if material has relevant animation data, break */
1909                                                         ANIMDATA_FILTER_CASES(ma, 
1910                                                                 {
1911                                                                         /* for the special AnimData blocks only case, we only need to add
1912                                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
1913                                                                          */
1914                                                                         ANIMDATA_ADD_ANIMDATA(ma);
1915                                                                         matOk=0;
1916                                                                 },
1917                                                                 matOk= 1;, 
1918                                                                 matOk= 1;, 
1919                                                                 matOk= 1;)
1920                                                 }
1921                                                         
1922                                                 if (matOk) 
1923                                                         break;
1924                                         }
1925                                 }
1926                                 
1927                                 /* data */
1928                                 switch (ob->type) {
1929                                         case OB_CAMERA: /* ------- Camera ------------ */
1930                                         {
1931                                                 Camera *ca= (Camera *)ob->data;
1932                                                 dataOk= 0;
1933                                                 ANIMDATA_FILTER_CASES(ca, 
1934                                                         if ((ads->filterflag & ADS_FILTER_NOCAM)==0) {
1935                                                                 /* for the special AnimData blocks only case, we only need to add
1936                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1937                                                                  */
1938                                                                 ANIMDATA_ADD_ANIMDATA(ca);
1939                                                                 dataOk=0;
1940                                                         },
1941                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, 
1942                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, 
1943                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);)
1944                                         }
1945                                                 break;
1946                                         case OB_LAMP: /* ---------- Lamp ----------- */
1947                                         {
1948                                                 Lamp *la= (Lamp *)ob->data;
1949                                                 dataOk= 0;
1950                                                 ANIMDATA_FILTER_CASES(la, 
1951                                                         if ((ads->filterflag & ADS_FILTER_NOLAM)==0) {
1952                                                                 /* for the special AnimData blocks only case, we only need to add
1953                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1954                                                                  */
1955                                                                 ANIMDATA_ADD_ANIMDATA(la);
1956                                                                 dataOk=0;
1957                                                         },
1958                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, 
1959                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, 
1960                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);)
1961                                         }
1962                                                 break;
1963                                         case OB_CURVE: /* ------- Curve ---------- */
1964                                         {
1965                                                 Curve *cu= (Curve *)ob->data;
1966                                                 dataOk= 0;
1967                                                 ANIMDATA_FILTER_CASES(cu, 
1968                                                         if ((ads->filterflag & ADS_FILTER_NOCUR)==0) {
1969                                                                 /* for the special AnimData blocks only case, we only need to add
1970                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1971                                                                  */
1972                                                                 ANIMDATA_ADD_ANIMDATA(cu);
1973                                                                 dataOk=0;
1974                                                         },
1975                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, 
1976                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, 
1977                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);)
1978                                         }
1979                                                 break;
1980                                         case OB_MBALL: /* ------- MetaBall ---------- */
1981                                         {
1982                                                 MetaBall *mb= (MetaBall *)ob->data;
1983                                                 dataOk= 0;
1984                                                 ANIMDATA_FILTER_CASES(mb, 
1985                                                         if ((ads->filterflag & ADS_FILTER_NOMBA)==0) {
1986                                                                 /* for the special AnimData blocks only case, we only need to add
1987                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1988                                                                  */
1989                                                                 ANIMDATA_ADD_ANIMDATA(mb);
1990                                                                 dataOk=0;
1991                                                         },
1992                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);, 
1993                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);, 
1994                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);)
1995                                         }
1996                                                 break;
1997                                         case OB_ARMATURE: /* ------- Armature ---------- */
1998                                         {
1999                                                 bArmature *arm= (bArmature *)ob->data;
2000                                                 dataOk= 0;
2001                                                 ANIMDATA_FILTER_CASES(arm, 
2002                                                         if ((ads->filterflag & ADS_FILTER_NOARM)==0) {
2003                                                                 /* for the special AnimData blocks only case, we only need to add
2004                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
2005                                                                  */
2006                                                                 ANIMDATA_ADD_ANIMDATA(arm);
2007                                                                 dataOk=0;
2008                                                         },
2009                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOARM);, 
2010                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOARM);, 
2011                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOARM);)
2012                                         }
2013                                                 break;
2014                                         default: /* --- other --- */
2015                                                 dataOk= 0;
2016                                                 break;
2017                                 }
2018                                 
2019                                 /* particles */
2020                                 partOk = 0;
2021                                 if (!(ads->filterflag & ADS_FILTER_NOPART) && ob->particlesystem.first) {
2022                                         ParticleSystem *psys = ob->particlesystem.first;
2023                                         for(; psys; psys=psys->next) {
2024                                                 if (psys->part) {
2025                                                         /* if particlesettings has relevant animation data, break */
2026                                                         ANIMDATA_FILTER_CASES(psys->part, 
2027                                                                 {
2028                                                                         /* for the special AnimData blocks only case, we only need to add
2029                                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
2030                                                                          */
2031                                                                         ANIMDATA_ADD_ANIMDATA(psys->part);
2032                                                                         partOk=0;
2033                                                                 },
2034                                                                 partOk= 1;, 
2035                                                                 partOk= 1;, 
2036                                                                 partOk= 1;)
2037                                                 }
2038                                                         
2039                                                 if (partOk) 
2040                                                         break;
2041                                         }
2042                                 }
2043                                 
2044                                 /* check if all bad (i.e. nothing to show) */
2045                                 if (!actOk && !keyOk && !dataOk && !matOk && !partOk)
2046                                         continue;
2047                         }
2048                         else {
2049                                 /* check data-types */
2050                                 actOk= ANIMDATA_HAS_KEYS(ob);
2051                                 keyOk= (key != NULL);
2052                                 
2053                                 /* materials - only for geometric types */
2054                                 matOk= 0; /* by default, not ok... */
2055                                 if (ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) && (ob->totcol)) 
2056                                 {
2057                                         int a;
2058                                         
2059                                         /* firstly check that we actuallly have some materials */
2060                                         for (a=0; a < ob->totcol; a++) {
2061                                                 Material *ma= give_current_material(ob, a);
2062                                                 
2063                                                 if ((ma) && ANIMDATA_HAS_KEYS(ma)) {
2064                                                         matOk= 1;
2065                                                         break;
2066                                                 }
2067                                         }
2068                                 }
2069                                 
2070                                 /* data */
2071                                 switch (ob->type) {
2072                                         case OB_CAMERA: /* ------- Camera ------------ */
2073                                         {
2074                                                 Camera *ca= (Camera *)ob->data;
2075                                                 dataOk= ANIMDATA_HAS_KEYS(ca);                                          
2076                                         }
2077                                                 break;
2078                                         case OB_LAMP: /* ---------- Lamp ----------- */
2079                                         {
2080                                                 Lamp *la= (Lamp *)ob->data;
2081                                                 dataOk= ANIMDATA_HAS_KEYS(la);  
2082                                         }
2083                                                 break;
2084                                         case OB_CURVE: /* -------- Curve ---------- */
2085                                         {
2086                                                 Curve *cu= (Curve *)ob->data;
2087                                                 dataOk= ANIMDATA_HAS_KEYS(cu);  
2088                                         }
2089                                                 break;
2090                                         case OB_MBALL: /* -------- Metas ---------- */
2091                                         {
2092                                                 MetaBall *mb= (MetaBall *)ob->data;
2093                                                 dataOk= ANIMDATA_HAS_KEYS(mb);  
2094                                         }
2095                                                 break;
2096                                         case OB_ARMATURE: /* -------- Armature ---------- */
2097                                         {
2098                                                 bArmature *arm= (bArmature *)ob->data;
2099                                                 dataOk= ANIMDATA_HAS_KEYS(arm); 
2100                                         }
2101                                                 break;
2102                                         default: /* --- other --- */
2103                                                 dataOk= 0;
2104                                                 break;
2105                                 }
2106                                 
2107                                 /* particles */
2108                                 partOk = 0;
2109                                 if (ob->particlesystem.first) {
2110                                         ParticleSystem *psys = ob->particlesystem.first;
2111                                         for(; psys; psys=psys->next) {
2112                                                 if(psys->part && ANIMDATA_HAS_KEYS(psys->part)) {
2113                                                         partOk = 1;
2114                                                         break;
2115                                                 }
2116                                         }
2117                                 }
2118                                 
2119                                 /* check if all bad (i.e. nothing to show) */
2120                                 if (!actOk && !keyOk && !dataOk && !matOk && !partOk)
2121                                         continue;
2122                         }
2123                         
2124                         /* since we're still here, this object should be usable */
2125                         items += animdata_filter_dopesheet_ob(anim_data, ads, base, filter_mode);
2126                 }
2127         }
2128         
2129         /* return the number of items in the list */
2130         return items;
2131 }
2132
2133 /* Summary track for DopeSheet/Action Editor 
2134  *      - return code is whether the summary lets the other channels get drawn
2135  */
2136 static short animdata_filter_dopesheet_summary (bAnimContext *ac, ListBase *anim_data, int filter_mode, int *items)
2137 {
2138         bDopeSheet *ads = NULL;
2139         
2140         /* get the DopeSheet information to use 
2141          *      - we should only need to deal with the DopeSheet/Action Editor, 
2142          *        since all the other Animation Editors won't have this concept
2143          *        being applicable.
2144          */
2145         if ((ac && ac->sa) && (ac->sa->spacetype == SPACE_ACTION)) {
2146                 SpaceAction *saction= (SpaceAction *)ac->sa->spacedata.first;
2147                 ads= &saction->ads;
2148         }
2149         else {
2150                 /* invalid space type - skip this summary channels */
2151                 return 1;
2152         }
2153         
2154         /* dopesheet summary 
2155          *      - only for drawing and/or selecting keyframes in channels, but not for real editing 
2156          *      - only useful for DopeSheet Editor, where the summary is useful
2157          */
2158         // TODO: we should really check if some other prohibited filters are also active, but that can be for later
2159         if ((filter_mode & ANIMFILTER_CHANNELS) && (ads->filterflag & ADS_FILTER_SUMMARY)) {
2160                 bAnimListElem *ale= make_new_animlistelem(ac, ANIMTYPE_SUMMARY, NULL, ANIMTYPE_NONE, NULL);
2161                 if (ale) {
2162                         BLI_addtail(anim_data, ale);
2163                         (*items)++;
2164                 }
2165                 
2166                 /* if summary is collapsed, don't show other channels beneath this 
2167                  *      - this check is put inside the summary check so that it doesn't interfere with normal operation
2168                  */ 
2169                 if (ads->flag & ADS_FLAG_SUMMARY_COLLAPSED)
2170                         return 0;
2171         }
2172         
2173         /* the other channels beneath this can be shown */
2174         return 1;
2175 }  
2176
2177 /* ----------- Public API --------------- */
2178
2179 /* This function filters the active data source to leave only animation channels suitable for
2180  * usage by the caller. It will return the length of the list 
2181  * 
2182  *      *anim_data: is a pointer to a ListBase, to which the filtered animation channels
2183  *              will be placed for use.
2184  *      filter_mode: how should the data be filtered - bitmapping accessed flags
2185  */
2186 int ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode, void *data, short datatype)
2187 {
2188         int items = 0;
2189         
2190         /* only filter data if there's somewhere to put it */
2191         if (data && anim_data) {
2192                 bAnimListElem *ale, *next;
2193                 Object *obact= (ac) ? ac->obact : NULL;
2194                 
2195                 /* firstly filter the data */
2196                 switch (datatype) {
2197                         case ANIMCONT_ACTION:   /* 'Action Editor' */
2198                         {
2199                                 /* the check for the DopeSheet summary is included here since the summary works here too */
2200                                 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
2201                                         items += animdata_filter_action(anim_data, NULL, data, filter_mode, NULL, ANIMTYPE_NONE, (ID *)obact);
2202                         }
2203                                 break;
2204                                 
2205                         case ANIMCONT_SHAPEKEY: /* 'ShapeKey Editor' */
2206                         {
2207                                 /* the check for the DopeSheet summary is included here since the summary works here too */
2208                                 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
2209                                         items= animdata_filter_shapekey(anim_data, data, filter_mode);
2210                         }
2211                                 break;
2212                                 
2213                         case ANIMCONT_GPENCIL:
2214                         {
2215                                 //items= animdata_filter_gpencil(anim_data, data, filter_mode);
2216                         }
2217                                 break;
2218                                 
2219                         case ANIMCONT_DOPESHEET: /* 'DopeSheet Editor' */
2220                         {
2221                                 /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */
2222                                 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
2223                                         items += animdata_filter_dopesheet(anim_data, ac, data, filter_mode);
2224                         }
2225                                 break;
2226                                 
2227                         case ANIMCONT_FCURVES: /* Graph Editor -> FCurves/Animation Editing */
2228                         case ANIMCONT_DRIVERS: /* Graph Editor -> Drivers Editing */
2229                         case ANIMCONT_NLA: /* NLA Editor */
2230                         {
2231                                 /* all of these editors use the basic DopeSheet data for filtering options, but don't have all the same features */
2232                                 items = animdata_filter_dopesheet(anim_data, ac, data, filter_mode);
2233                         }
2234                                 break;
2235                 }
2236                         
2237                 /* remove any weedy entries */
2238                 // XXX this is weedy code!
2239                 for (ale= anim_data->first; ale; ale= next) {
2240                         next= ale->next;
2241                         
2242                         if (ale->type == ANIMTYPE_NONE) {
2243                                 items--;
2244                                 BLI_freelinkN(anim_data, ale);
2245                         }
2246                 }
2247         }
2248         
2249         /* return the number of items in the list */
2250         return items;
2251 }
2252
2253 /* ************************************************************ */