svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r21899:21908
[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.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Joshua Leung
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 IPO Editor also uses this for it's channel list and for determining which curves
37  * are being edited.
38  *
39  * Note: much of the original system this was based on was built before the creation of the RNA
40  * system. In future, it would be interesting to replace some parts of this code with RNA queries,
41  * however, RNA does not eliminate some of the boiler-plate reduction benefits presented by this 
42  * system, so if any such work does occur, it should only be used for the internals used here...
43  *
44  * -- Joshua Leung, Dec 2008
45  */
46
47 #include <string.h>
48 #include <stdio.h>
49
50 #include "DNA_listBase.h"
51 #include "DNA_ID.h"
52 #include "DNA_anim_types.h"
53 #include "DNA_action_types.h"
54 #include "DNA_constraint_types.h"
55 #include "DNA_camera_types.h"
56 #include "DNA_curve_types.h"
57 #include "DNA_gpencil_types.h"
58 #include "DNA_ipo_types.h"
59 #include "DNA_lamp_types.h"
60 #include "DNA_lattice_types.h"
61 #include "DNA_key_types.h"
62 #include "DNA_material_types.h"
63 #include "DNA_mesh_types.h"
64 #include "DNA_object_types.h"
65 #include "DNA_particle_types.h"
66 #include "DNA_space_types.h"
67 #include "DNA_scene_types.h"
68 #include "DNA_screen_types.h"
69 #include "DNA_windowmanager_types.h"
70 #include "DNA_world_types.h"
71
72 #include "MEM_guardedalloc.h"
73
74 #include "BLI_blenlib.h"
75
76 #include "BKE_context.h"
77 #include "BKE_global.h"
78 #include "BKE_key.h"
79 #include "BKE_object.h"
80 #include "BKE_material.h"
81 #include "BKE_screen.h"
82 #include "BKE_utildefines.h"
83
84 #include "ED_anim_api.h"
85 #include "ED_types.h"
86 #include "ED_util.h"
87
88 #include "WM_api.h"
89 #include "WM_types.h"
90
91 #include "BIF_gl.h"
92 #include "BIF_glutil.h"
93
94 #include "UI_interface.h"
95 #include "UI_resources.h"
96 #include "UI_view2d.h"
97
98 /* ************************************************************ */
99 /* Blender Context <-> Animation Context mapping */
100
101 /* ----------- Private Stuff - Action Editor ------------- */
102
103 /* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */
104 /* Note: there's a similar function in key.c (ob_get_key) */
105 Key *actedit_get_shapekeys (bAnimContext *ac, SpaceAction *saction) 
106 {
107     Scene *scene= ac->scene;
108     Object *ob;
109     Key *key;
110         
111     ob = OBACT;
112     if (ob == NULL) 
113                 return NULL;
114         
115         /* XXX pinning is not available in 'ShapeKey' mode... */
116         //if (saction->pin) return NULL;
117         
118         /* shapekey data is stored with geometry data */
119         switch (ob->type) {
120                 case OB_MESH:
121                         key= ((Mesh *)ob->data)->key;
122                         break;
123                         
124                 case OB_LATTICE:
125                         key= ((Lattice *)ob->data)->key;
126                         break;
127                         
128                 case OB_CURVE:
129                 case OB_SURF:
130                         key= ((Curve *)ob->data)->key;
131                         break;
132                         
133                 default:
134                         return NULL;
135         }
136         
137         if (key) {
138                 if (key->type == KEY_RELATIVE)
139                         return key;
140         }
141         
142     return NULL;
143 }
144
145 /* Get data being edited in Action Editor (depending on current 'mode') */
146 static short actedit_get_context (bAnimContext *ac, SpaceAction *saction)
147 {
148         /* sync settings with current view status, then return appropriate data */
149         switch (saction->mode) {
150                 case SACTCONT_ACTION: /* 'Action Editor' */
151                         /* if not pinned, sync with active object */
152                         if (saction->pin == 0) {
153                                 if (ac->obact && ac->obact->adt)
154                                         saction->action = ac->obact->adt->action;
155                                 else
156                                         saction->action= NULL;
157                         }
158                         
159                         ac->datatype= ANIMCONT_ACTION;
160                         ac->data= saction->action;
161                         
162                         ac->mode= saction->mode;
163                         return 1;
164                         
165                 case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */
166                         ac->datatype= ANIMCONT_SHAPEKEY;
167                         ac->data= actedit_get_shapekeys(ac, saction);
168                         
169                         ac->mode= saction->mode;
170                         return 1;
171                         
172                 case SACTCONT_GPENCIL: /* Grease Pencil */ // XXX review how this mode is handled...
173                         ac->datatype=ANIMCONT_GPENCIL;
174                         //ac->data= CTX_wm_screen(C); // FIXME: add that dopesheet type thing here!
175                         ac->data= NULL; // !!!
176                         
177                         ac->mode= saction->mode;
178                         return 1;
179                         
180                 case SACTCONT_DOPESHEET: /* DopeSheet */
181                         /* update scene-pointer (no need to check for pinning yet, as not implemented) */
182                         saction->ads.source= (ID *)ac->scene;
183                         
184                         ac->datatype= ANIMCONT_DOPESHEET;
185                         ac->data= &saction->ads;
186                         
187                         ac->mode= saction->mode;
188                         return 1;
189                 
190                 default: /* unhandled yet */
191                         ac->datatype= ANIMCONT_NONE;
192                         ac->data= NULL;
193                         
194                         ac->mode= -1;
195                         return 0;
196         }
197 }
198
199 /* ----------- Private Stuff - Graph Editor ------------- */
200
201 /* Get data being edited in Graph Editor (depending on current 'mode') */
202 static short graphedit_get_context (bAnimContext *ac, SpaceIpo *sipo)
203 {
204         /* init dopesheet data if non-existant (i.e. for old files) */
205         if (sipo->ads == NULL)
206                 sipo->ads= MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet");
207         
208         /* sync settings with current view status, then return appropriate data */
209         switch (sipo->mode) {
210                 case SIPO_MODE_ANIMATION:       /* Animation F-Curve Editor */
211                         /* update scene-pointer (no need to check for pinning yet, as not implemented) */
212                         sipo->ads->source= (ID *)ac->scene;
213                         sipo->ads->filterflag &= ~ADS_FILTER_ONLYDRIVERS;
214                         
215                         ac->datatype= ANIMCONT_FCURVES;
216                         ac->data= sipo->ads;
217                         
218                         ac->mode= sipo->mode;
219                         return 1;
220                 
221                 case SIPO_MODE_DRIVERS:         /* Driver F-Curve Editor */
222                         /* update scene-pointer (no need to check for pinning yet, as not implemented) */
223                         sipo->ads->source= (ID *)ac->scene;
224                         sipo->ads->filterflag |= ADS_FILTER_ONLYDRIVERS;
225                         
226                         ac->datatype= ANIMCONT_DRIVERS;
227                         ac->data= sipo->ads;
228                         
229                         ac->mode= sipo->mode;
230                         return 1;
231                 
232                 default: /* unhandled yet */
233                         ac->datatype= ANIMCONT_NONE;
234                         ac->data= NULL;
235                         
236                         ac->mode= -1;
237                         return 0;
238         }
239 }
240
241 /* ----------- Private Stuff - NLA Editor ------------- */
242
243 /* Get data being edited in Graph Editor (depending on current 'mode') */
244 static short nlaedit_get_context (bAnimContext *ac, SpaceNla *snla)
245 {
246         /* init dopesheet data if non-existant (i.e. for old files) */
247         if (snla->ads == NULL)
248                 snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
249         
250         /* sync settings with current view status, then return appropriate data */
251         /* update scene-pointer (no need to check for pinning yet, as not implemented) */
252         snla->ads->source= (ID *)ac->scene;
253         snla->ads->filterflag |= ADS_FILTER_ONLYNLA;
254         
255         ac->datatype= ANIMCONT_NLA;
256         ac->data= snla->ads;
257         
258         return 1;
259 }
260
261 /* ----------- Public API --------------- */
262
263 /* Obtain current anim-data context, given that context info from Blender context has already been set 
264  *      - AnimContext to write to is provided as pointer to var on stack so that we don't have
265  *        allocation/freeing costs (which are not that avoidable with channels).
266  */
267 short ANIM_animdata_context_getdata (bAnimContext *ac)
268 {
269         ScrArea *sa= ac->sa;
270         short ok= 0;
271         
272         /* context depends on editor we are currently in */
273         if (sa) {
274                 switch (sa->spacetype) {
275                         case SPACE_ACTION:
276                         {
277                                 SpaceAction *saction= (SpaceAction *)sa->spacedata.first;
278                                 ok= actedit_get_context(ac, saction);
279                         }
280                                 break;
281                                 
282                         case SPACE_IPO:
283                         {
284                                 SpaceIpo *sipo= (SpaceIpo *)sa->spacedata.first;
285                                 ok= graphedit_get_context(ac, sipo);
286                         }
287                                 break;
288                                 
289                         case SPACE_NLA:
290                         {
291                                 SpaceNla *snla= (SpaceNla *)sa->spacedata.first;
292                                 ok= nlaedit_get_context(ac, snla);
293                         }
294                                 break;
295                 }
296         }
297         
298         /* check if there's any valid data */
299         if (ok && ac->data)
300                 return 1;
301         else
302                 return 0;
303 }
304
305 /* Obtain current anim-data context from Blender Context info 
306  *      - AnimContext to write to is provided as pointer to var on stack so that we don't have
307  *        allocation/freeing costs (which are not that avoidable with channels).
308  *      - Clears data and sets the information from Blender Context which is useful
309  */
310 short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac)
311 {
312         ScrArea *sa= CTX_wm_area(C);
313         ARegion *ar= CTX_wm_region(C);
314         Scene *scene= CTX_data_scene(C);
315         
316         /* clear old context info */
317         if (ac == NULL) return 0;
318         memset(ac, 0, sizeof(bAnimContext));
319         
320         /* get useful default context settings from context */
321         ac->scene= scene;
322         if (scene) {
323                 ac->markers= &scene->markers;           
324                 ac->obact= (scene->basact)?  scene->basact->object : NULL;
325         }
326         ac->sa= sa;
327         ac->ar= ar;
328         ac->spacetype= (sa) ? sa->spacetype : 0;
329         ac->regiontype= (ar) ? ar->regiontype : 0;
330         
331         /* get data context info */
332         return ANIM_animdata_context_getdata(ac);
333 }
334
335 /* ************************************************************ */
336 /* Blender Data <-- Filter --> Channels to be operated on */
337
338 /* quick macro to test if AnimData is usable */
339 #define ANIMDATA_HAS_KEYS(id) ((id)->adt && (id)->adt->action)
340
341 /* quick macro to test if AnimData is usable for drivers */
342 #define ANIMDATA_HAS_DRIVERS(id) ((id)->adt && (id)->adt->drivers.first)
343
344 /* quick macro to test if AnimData is usable for NLA */
345 #define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first)
346
347
348 /* Quick macro to test for all three avove usability tests, performing the appropriate provided 
349  * action for each when the AnimData context is appropriate. 
350  *
351  * Priority order for this goes (most important, to least): AnimData blocks, NLA, Drivers, Keyframes.
352  *
353  * For this to work correctly, a standard set of data needs to be available within the scope that this
354  * gets called in: 
355  *      - ListBase anim_data;
356  *      - bDopeSheet *ads;
357  *      - bAnimListElem *ale;
358  *      - int items;
359  *
360  *      - id: ID block which should have an AnimData pointer following it immediately, to use
361  *      - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
362  *      - nlaOk: line or block of code to execute for NLA case
363  *      - driversOk: line or block of code to execute for Drivers case
364  *      - keysOk: line or block of code for Keyframes case
365  */
366 #define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \
367         {\
368                 if (filter_mode & ANIMFILTER_ANIMDATA) {\
369                         if ((id)->adt) {\
370                                 adtOk\
371                         }\
372                 }\
373                 else if (ads->filterflag & ADS_FILTER_ONLYNLA) {\
374                         if (ANIMDATA_HAS_NLA(id)) {\
375                                 nlaOk\
376                         }\
377                         else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) && ANIMDATA_HAS_KEYS(id)) {\
378                                 nlaOk\
379                         }\
380                 }\
381                 else if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) {\
382                         if (ANIMDATA_HAS_DRIVERS(id)) {\
383                                 driversOk\
384                         }\
385                 }\
386                 else {\
387                         if (ANIMDATA_HAS_KEYS(id)) {\
388                                 keysOk\
389                         }\
390                 }\
391         }
392
393
394 /* quick macro to add a pointer to an AnimData block as a channel */
395 #define ANIMDATA_ADD_ANIMDATA(id) \
396         {\
397                 ale= make_new_animlistelem((id)->adt, ANIMTYPE_ANIMDATA, NULL, ANIMTYPE_NONE, (ID *)id);\
398                 if (ale) {\
399                         BLI_addtail(anim_data, ale);\
400                         items++;\
401                 }\
402         }
403         
404
405
406 /* quick macro to test if a anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */
407 #define ANIMCHANNEL_SELOK(test_func) \
408                 ( !(filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) || \
409                   ((filter_mode & ANIMFILTER_SEL) && test_func) || \
410                   ((filter_mode & ANIMFILTER_UNSEL) && test_func==0) ) 
411
412 /* ----------- 'Private' Stuff --------------- */
413
414 /* this function allocates memory for a new bAnimListElem struct for the 
415  * provided animation channel-data. 
416  */
417 bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, short ownertype, ID *owner_id)
418 {
419         bAnimListElem *ale= NULL;
420         
421         /* only allocate memory if there is data to convert */
422         if (data) {
423                 /* allocate and set generic data */
424                 ale= MEM_callocN(sizeof(bAnimListElem), "bAnimListElem");
425                 
426                 ale->data= data;
427                 ale->type= datatype;
428                         // XXX what is the point of the owner data?
429                 ale->owner= owner;
430                 ale->ownertype= ownertype;
431                 
432                 ale->id= owner_id;
433                 
434                 /* do specifics */
435                 switch (datatype) {
436                         case ANIMTYPE_SCENE:
437                         {
438                                 Scene *sce= (Scene *)data;
439                                 
440                                 ale->flag= sce->flag;
441                                 
442                                 ale->key_data= sce;
443                                 ale->datatype= ALE_SCE;
444                         }
445                                 break;
446                         case ANIMTYPE_OBJECT:
447                         {
448                                 Base *base= (Base *)data;
449                                 Object *ob= base->object;
450                                 
451                                 ale->flag= ob->flag;
452                                 
453                                 ale->key_data= ob;
454                                 ale->datatype= ALE_OB;
455                         }
456                                 break;
457                         case ANIMTYPE_FILLACTD:
458                         {
459                                 bAction *act= (bAction *)data;
460                                 
461                                 ale->flag= act->flag;
462                                 
463                                 ale->key_data= act;
464                                 ale->datatype= ALE_ACT;
465                         }
466                                 break;
467                         case ANIMTYPE_FILLDRIVERS:
468                         {
469                                 AnimData *adt= (AnimData *)data;
470                                 
471                                 ale->flag= adt->flag;
472                                 
473                                         // XXX... drivers don't show summary for now
474                                 ale->key_data= NULL;
475                                 ale->datatype= ALE_NONE;
476                         }
477                                 break;
478                         case ANIMTYPE_FILLMATD:
479                         {
480                                 Object *ob= (Object *)data;
481                                 
482                                 ale->flag= FILTER_MAT_OBJC(ob);
483                                 
484                                 ale->key_data= NULL;
485                                 ale->datatype= ALE_NONE;
486                         }
487                                 break;
488                         case ANIMTYPE_FILLPARTD:
489                         {
490                                 Object *ob= (Object *)data;
491                                 
492                                 ale->flag= FILTER_PART_OBJC(ob);
493                                 
494                                 ale->key_data= NULL;
495                                 ale->datatype= ALE_NONE;
496                         }
497                                 break;
498                         
499                         case ANIMTYPE_DSMAT:
500                         {
501                                 Material *ma= (Material *)data;
502                                 AnimData *adt= ma->adt;
503                                 
504                                 ale->flag= FILTER_MAT_OBJD(ma);
505                                 
506                                 ale->key_data= (adt) ? adt->action : NULL;
507                                 ale->datatype= ALE_ACT;
508                         }
509                                 break;
510                         case ANIMTYPE_DSLAM:
511                         {
512                                 Lamp *la= (Lamp *)data;
513                                 AnimData *adt= la->adt;
514                                 
515                                 ale->flag= FILTER_LAM_OBJD(la);
516                                 
517                                 ale->key_data= (adt) ? adt->action : NULL;
518                                 ale->datatype= ALE_ACT;
519                         }
520                                 break;
521                         case ANIMTYPE_DSCAM:
522                         {
523                                 Camera *ca= (Camera *)data;
524                                 AnimData *adt= ca->adt;
525                                 
526                                 ale->flag= FILTER_CAM_OBJD(ca);
527                                 
528                                 ale->key_data= (adt) ? adt->action : NULL;
529                                 ale->datatype= ALE_ACT;
530                         }
531                                 break;
532                         case ANIMTYPE_DSCUR:
533                         {
534                                 Curve *cu= (Curve *)data;
535                                 AnimData *adt= cu->adt;
536                                 
537                                 ale->flag= FILTER_CUR_OBJD(cu);
538                                 
539                                 ale->key_data= (adt) ? adt->action : NULL;
540                                 ale->datatype= ALE_ACT;
541                         }
542                                 break;
543                         case ANIMTYPE_DSSKEY:
544                         {
545                                 Key *key= (Key *)data;
546                                 AnimData *adt= key->adt;
547                                 
548                                 ale->flag= FILTER_SKE_OBJD(key); 
549                                 
550                                 ale->key_data= (adt) ? adt->action : NULL;
551                                 ale->datatype= ALE_ACT;
552                         }
553                                 break;
554                         case ANIMTYPE_DSWOR:
555                         {
556                                 World *wo= (World *)data;
557                                 AnimData *adt= wo->adt;
558                                 
559                                 ale->flag= FILTER_WOR_SCED(wo); 
560                                 
561                                 ale->key_data= (adt) ? adt->action : NULL;
562                                 ale->datatype= ALE_ACT;
563                         }
564                                 break;
565                         case ANIMTYPE_DSPART:
566                         {
567                                 ParticleSettings *part= (ParticleSettings*)ale->data;
568                                 AnimData *adt= part->adt;
569                                 
570                                 ale->flag= FILTER_PART_OBJD(part); 
571                                 
572                                 ale->key_data= (adt) ? adt->action : NULL;
573                                 ale->datatype= ALE_ACT;
574                         }
575                                 break;
576                                 
577                         case ANIMTYPE_GROUP:
578                         {
579                                 bActionGroup *agrp= (bActionGroup *)data;
580                                 
581                                 ale->flag= agrp->flag;
582                                 
583                                 ale->key_data= NULL;
584                                 ale->datatype= ALE_GROUP;
585                         }
586                                 break;
587                         case ANIMTYPE_FCURVE:
588                         {
589                                 FCurve *fcu= (FCurve *)data;
590                                 
591                                 ale->flag= fcu->flag;
592                                 
593                                 ale->key_data= fcu;
594                                 ale->datatype= ALE_FCURVE;
595                         }
596                                 break;
597                         
598                         case ANIMTYPE_GPLAYER:
599                         {
600                                 bGPDlayer *gpl= (bGPDlayer *)data;
601                                 
602                                 ale->flag= gpl->flag;
603                                 
604                                 ale->key_data= NULL;
605                                 ale->datatype= ALE_GPFRAME;
606                         }
607                                 break;
608                                 
609                         case ANIMTYPE_NLATRACK:
610                         {
611                                 NlaTrack *nlt= (NlaTrack *)data;
612                                 
613                                 ale->flag= nlt->flag;
614                                 
615                                         // XXX or should this be done some other way?
616                                 ale->key_data= &nlt->strips;
617                                 ale->datatype= ALE_NLASTRIP;
618                         }
619                                 break;
620                         case ANIMTYPE_NLAACTION:
621                         {
622                                 /* nothing to include for now... nothing editable from NLA-perspective here */
623                                 ale->key_data= NULL;
624                                 ale->datatype= ALE_NONE;
625                         }
626                                 break;
627                 }
628         }
629         
630         /* return created datatype */
631         return ale;
632 }
633  
634 /* ----------------------------------------- */
635
636
637 static int animdata_filter_fcurves (ListBase *anim_data, FCurve *first, bActionGroup *grp, void *owner, short ownertype, int filter_mode, ID *owner_id)
638 {
639         bAnimListElem *ale = NULL;
640         FCurve *fcu;
641         int items = 0;
642         
643         /* loop over F-Curves - assume that the caller of this has already checked that these should be included 
644          * NOTE: we need to check if the F-Curves belong to the same group, as this gets called for groups too...
645          */
646         for (fcu= first; ((fcu) && (fcu->grp==grp)); fcu= fcu->next) {
647                 /* only include if visible (Graph Editor check, not channels check) */
648                 if (!(filter_mode & ANIMFILTER_CURVEVISIBLE) || (fcu->flag & FCURVE_VISIBLE)) {
649                         /* only work with this channel and its subchannels if it is editable */
650                         if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) {
651                                 /* only include this curve if selected in a way consistent with the filtering requirements */
652                                 if ( ANIMCHANNEL_SELOK(SEL_FCU(fcu)) ) {
653                                         /* only include if this curve is active */
654                                         if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
655                                                 ale= make_new_animlistelem(fcu, ANIMTYPE_FCURVE, owner, ownertype, owner_id);
656                                                 
657                                                 if (ale) {
658                                                         BLI_addtail(anim_data, ale);
659                                                         items++;
660                                                 }
661                                         }
662                                 }
663                         }
664                 }
665         }
666         
667         /* return the number of items added to the list */
668         return items;
669 }
670
671 static int animdata_filter_action (ListBase *anim_data, bAction *act, int filter_mode, void *owner, short ownertype, ID *owner_id)
672 {
673         bAnimListElem *ale=NULL;
674         bActionGroup *agrp;
675         FCurve *lastchan=NULL;
676         int items = 0;
677         
678         /* loop over groups */
679         //       XXX in future, we need to be prepared for nestled groups...
680         for (agrp= act->groups.first; agrp; agrp= agrp->next) {
681                 /* add this group as a channel first */
682                 if ((filter_mode & ANIMFILTER_CHANNELS) || !(filter_mode & ANIMFILTER_CURVESONLY)) {
683                         /* check if filtering by selection */
684                         if ( ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) ) {
685                                 ale= make_new_animlistelem(agrp, ANIMTYPE_GROUP, NULL, ANIMTYPE_NONE, owner_id);
686                                 if (ale) {
687                                         BLI_addtail(anim_data, ale);
688                                         items++;
689                                 }
690                         }
691                 }
692                 
693                 /* store reference to last channel of group */
694                 if (agrp->channels.last) 
695                         lastchan= agrp->channels.last;
696                 
697                 
698                 /* there are some situations, where only the channels of the action group should get considered */
699                 if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) {
700                         /* filters here are a bit convoulted...
701                          *      - groups show a "summary" of keyframes beside their name which must accessable for tools which handle keyframes
702                          *      - groups can be collapsed (and those tools which are only interested in channels rely on knowing that group is closed)
703                          *
704                          * cases when we should include F-Curves inside group:
705                          *      - we don't care about visibility
706                          *      - group is expanded
707                          *      - we just need the F-Curves present
708                          */
709                         if ( (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_AGRP(agrp)) || (filter_mode & ANIMFILTER_CURVESONLY) ) 
710                         {
711                                 /* for the Graph Editor, curves may be set to not be visible in the view to lessen clutter,
712                                  * but to do this, we need to check that the group doesn't have it's not-visible flag set preventing 
713                                  * all its sub-curves to be shown
714                                  */
715                                 if ( !(filter_mode & ANIMFILTER_CURVEVISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE) )
716                                 {
717                                         if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
718                                                 // XXX the 'owner' info here needs review...
719                                                 items += animdata_filter_fcurves(anim_data, agrp->channels.first, agrp, owner, ownertype, filter_mode, owner_id);
720                                                 
721                                                 /* remove group from filtered list if last element is group 
722                                                  * (i.e. only if group had channels, which were all hidden)
723                                                  */
724                                                 // XXX this is really hacky... it should be fixed in a much more elegant way!
725                                                 if ( (ale) && (anim_data->last == ale) && 
726                                                          (ale->data == agrp) && (agrp->channels.first) ) 
727                                                 {
728                                                         BLI_freelinkN(anim_data, ale);
729                                                         items--;
730                                                 }
731                                         }
732                                 }
733                         }
734                 }
735         }
736         
737         /* loop over un-grouped F-Curves (only if we're not only considering those channels in the animive group) */
738         if (!(filter_mode & ANIMFILTER_ACTGROUPED))  {
739                 // XXX the 'owner' info here needs review...
740                 items += animdata_filter_fcurves(anim_data, (lastchan)?(lastchan->next):(act->curves.first), NULL, owner, ownertype, filter_mode, owner_id);
741         }
742         
743         /* return the number of items added to the list */
744         return items;
745 }
746
747 /* Include NLA-Data for NLA-Editor:
748  *      - when ANIMFILTER_CHANNELS is used, that means we should be filtering the list for display
749  *        Although the evaluation order is from the first track to the last and then apply the Action on top,
750  *        we present this in the UI as the Active Action followed by the last track to the first so that we 
751  *        get the evaluation order presented as per a stack.
752  *      - for normal filtering (i.e. for editing), we only need the NLA-tracks but they can be in 'normal' evaluation
753  *        order, i.e. first to last. Otherwise, some tools may get screwed up.
754  */
755 static int animdata_filter_nla (ListBase *anim_data, AnimData *adt, int filter_mode, void *owner, short ownertype, ID *owner_id)
756 {
757         bAnimListElem *ale;
758         NlaTrack *nlt;
759         NlaTrack *first=NULL, *next=NULL;
760         int items = 0;
761         
762         /* if showing channels, include active action */
763         if (filter_mode & ANIMFILTER_CHANNELS) {
764                 /* there isn't really anything editable here, so skip if need editable */
765                 // TODO: currently, selection isn't checked since it doesn't matter
766                 if ((filter_mode & ANIMFILTER_FOREDIT) == 0) { 
767                         /* just add the action track now (this MUST appear for drawing)
768                          *      - as AnimData may not have an action, we pass a dummy pointer just to get the list elem created, then
769                          *        overwrite this with the real value - REVIEW THIS...
770                          */
771                         ale= make_new_animlistelem((void *)(&adt->action), ANIMTYPE_NLAACTION, owner, ownertype, owner_id);
772                         ale->data= (adt->action) ? adt->action : NULL;
773                                 
774                         if (ale) {
775                                 BLI_addtail(anim_data, ale);
776                                 items++;
777                         }
778                 }
779                 
780                 /* first track to include will be the last one if we're filtering by channels */
781                 first= adt->nla_tracks.last;
782         }
783         else {
784                 /* first track to include will the the first one (as per normal) */
785                 first= adt->nla_tracks.first;
786         }
787         
788         /* loop over NLA Tracks - assume that the caller of this has already checked that these should be included */
789         for (nlt= first; nlt; nlt= next) {
790                 /* 'next' NLA-Track to use depends on whether we're filtering for drawing or not */
791                 if (filter_mode & ANIMFILTER_CHANNELS) 
792                         next= nlt->prev;
793                 else
794                         next= nlt->next;
795                 
796                 /* if we're in NLA-tweakmode, don't show this track if it was disabled (due to tweaking) for now 
797                  *      - active track should still get shown though (even though it has disabled flag set)
798                  */
799                 // FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel
800                 if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && !(nlt->flag & NLATRACK_ACTIVE))
801                         continue;
802                 
803                 /* only work with this channel and its subchannels if it is editable */
804                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) {
805                         /* only include this track if selected in a way consistent with the filtering requirements */
806                         if ( ANIMCHANNEL_SELOK(SEL_NLT(nlt)) ) {
807                                 /* only include if this track is active */
808                                 if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
809                                         ale= make_new_animlistelem(nlt, ANIMTYPE_NLATRACK, owner, ownertype, owner_id);
810                                                 
811                                         if (ale) {
812                                                 BLI_addtail(anim_data, ale);
813                                                 items++;
814                                         }
815                                 }
816                         }
817                 }
818         }
819         
820         /* return the number of items added to the list */
821         return items;
822 }
823
824 static int animdata_filter_shapekey (ListBase *anim_data, Key *key, int filter_mode, void *owner, short ownertype, ID *owner_id)
825 {
826         bAnimListElem *ale;
827         KeyBlock *kb;
828         //FCurve *fcu;
829         int i, items=0;
830         
831         /* are we filtering for display or editing */
832         if (filter_mode & ANIMFILTER_CHANNELS) {
833                 /* for display - loop over shapekeys, adding ipo-curve references where needed */
834                 kb= key->block.first;
835                 
836                 /* loop through possible shapekeys, manually creating entries */
837                 for (i= 1; i < key->totkey; i++) {
838                         ale= MEM_callocN(sizeof(bAnimListElem), "bAnimListElem");
839                         kb = kb->next; /* do this even on the first try, as the first is 'Basis' (which doesn't get included) */
840                         
841                         ale->data= kb;
842                         ale->type= ANIMTYPE_SHAPEKEY; /* 'abused' usage of this type */
843                         ale->owner= key;
844                         ale->ownertype= ANIMTYPE_SHAPEKEY;
845                         ale->datatype= ALE_NONE;
846                         ale->index = i;
847                         
848 #if 0 // XXX fixme... old system
849                         if (key->ipo) {
850                                 for (icu= key->ipo->curve.first; icu; icu=icu->next) {
851                                         if (icu->adrcode == i) {
852                                                 ale->key_data= icu;
853                                                 ale->datatype= ALE_ICU;
854                                                 break;
855                                         }
856                                 }
857                         }
858 #endif // XXX fixme... old system
859                         
860                         ale->id= owner_id;
861                         
862                         BLI_addtail(anim_data, ale);
863                         items++;
864                 }
865         }
866         else {
867 #if 0 // XXX fixme... old system
868                 /* loop over ipo curves if present - for editing */
869                 if (key->ipo) {
870                         if (filter_mode & ANIMFILTER_IPOKEYS) {
871                                 ale= make_new_animlistelem(key->ipo, ANIMTYPE_IPO, key, ANIMTYPE_SHAPEKEY);
872                                 if (ale) {
873                                         if (owned) ale->id= owner;
874                                         BLI_addtail(anim_data, ale);
875                                         items++;
876                                 }
877                         }
878                         else {
879                                 items += animdata_filter_ipocurves(anim_data, key->ipo, filter_mode, key, ANIMTYPE_SHAPEKEY, (owned)?(owner):(NULL));
880                         }
881                 }
882 #endif // XXX fixme... old system
883         }
884         
885         /* return the number of items added to the list */
886         return items;
887 }
888  
889 #if 0
890 // FIXME: switch this to use the bDopeSheet...
891 static int animdata_filter_gpencil (ListBase *anim_data, bScreen *sc, int filter_mode)
892 {
893         bAnimListElem *ale;
894         ScrArea *sa, *curarea;
895         bGPdata *gpd;
896         bGPDlayer *gpl;
897         int items = 0;
898         
899         /* check if filtering types are appropriate */
900         {
901                 /* special hack for fullscreen area (which must be this one then):
902                  *      - we use the curarea->full as screen to get spaces from, since the
903                  *        old (pre-fullscreen) screen was stored there...
904                  *      - this is needed as all data would otherwise disappear
905                  */
906                 // XXX need to get new alternative for curarea
907                 if ((curarea->full) && (curarea->spacetype==SPACE_ACTION))
908                         sc= curarea->full;
909                 
910                 /* loop over spaces in current screen, finding gpd blocks (could be slow!) */
911                 for (sa= sc->areabase.first; sa; sa= sa->next) {
912                         /* try to get gp data */
913                         // XXX need to put back grease pencil api...
914                         gpd= gpencil_data_getactive(sa);
915                         if (gpd == NULL) continue;
916                         
917                         /* add gpd as channel too (if for drawing, and it has layers) */
918                         if ((filter_mode & ANIMFILTER_CHANNELS) && (gpd->layers.first)) {
919                                 /* add to list */
920                                 ale= make_new_animlistelem(gpd, ANIMTYPE_GPDATABLOCK, sa, ANIMTYPE_SPECIALDATA);
921                                 if (ale) {
922                                         BLI_addtail(anim_data, ale);
923                                         items++;
924                                 }
925                         }
926                         
927                         /* only add layers if they will be visible (if drawing channels) */
928                         if ( !(filter_mode & ANIMFILTER_VISIBLE) || (EXPANDED_GPD(gpd)) ) {
929                                 /* loop over layers as the conditions are acceptable */
930                                 for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
931                                         /* only if selected */
932                                         if ( ANIMCHANNEL_SELOK(SEL_GPL(gpl)) ) {
933                                                 /* only if editable */
934                                                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) {
935                                                         /* add to list */
936                                                         ale= make_new_animlistelem(gpl, ANIMTYPE_GPLAYER, gpd, ANIMTYPE_GPDATABLOCK);
937                                                         if (ale) {
938                                                                 BLI_addtail(anim_data, ale);
939                                                                 items++;
940                                                         }
941                                                 }
942                                         }
943                                 }
944                         }
945                 }
946         }
947         
948         /* return the number of items added to the list */
949         return items;
950 }
951 #endif 
952
953
954 static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
955 {
956         ListBase mats = {NULL, NULL};
957         LinkData *ld;
958         
959         bAnimListElem *ale=NULL;
960         Object *ob= base->object;
961         int items=0, a=0;
962         
963         /* firstly check that we actuallly have some materials, by gathering all materials in a temp list */
964         for (a=0; a < ob->totcol; a++) {
965                 Material *ma= give_current_material(ob, a);
966                 short ok = 0;
967                 
968                 /* for now, if no material returned, skip (this shouldn't confuse the user I hope) */
969                 if (ELEM(NULL, ma, ma->adt)) 
970                         continue;
971                 
972                 /* check if ok */
973                 ANIMDATA_FILTER_CASES(ma, 
974                         { /* AnimData blocks - do nothing... */ },
975                         ok=1;, 
976                         ok=1;, 
977                         ok=1;)
978                 if (ok == 0) continue;
979                 
980                 /* make a temp list elem for this */
981                 ld= MEM_callocN(sizeof(LinkData), "DopeSheet-MaterialCache");
982                 ld->data= ma;
983                 BLI_addtail(&mats, ld);
984         }
985         
986         /* if there were no channels found, no need to carry on */
987         if (mats.first == NULL)
988                 return 0;
989         
990         /* include materials-expand widget? */
991         if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
992                 ale= make_new_animlistelem(ob, ANIMTYPE_FILLMATD, base, ANIMTYPE_OBJECT, (ID *)ob);
993                 if (ale) {
994                         BLI_addtail(anim_data, ale);
995                         items++;
996                 }
997         }
998         
999         /* add materials? */
1000         if (FILTER_MAT_OBJC(ob) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1001                 /* for each material in cache, add channels  */
1002                 for (ld= mats.first; ld; ld= ld->next) {
1003                         Material *ma= (Material *)ld->data;
1004                         
1005                         /* include material-expand widget? */
1006                         // hmm... do we need to store the index of this material in the array anywhere?
1007                         if (filter_mode & ANIMFILTER_CHANNELS) {
1008                                 ale= make_new_animlistelem(ma, ANIMTYPE_DSMAT, base, ANIMTYPE_OBJECT, (ID *)ma);
1009                                 if (ale) {
1010                                         BLI_addtail(anim_data, ale);
1011                                         items++;
1012                                 }
1013                         }
1014                         
1015                         /* add material's animation data */
1016                         if (FILTER_MAT_OBJD(ma) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1017                                 ANIMDATA_FILTER_CASES(ma, 
1018                                         { /* AnimData blocks - do nothing... */ },
1019                                         items += animdata_filter_nla(anim_data, ma->adt, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);, 
1020                                         items += animdata_filter_fcurves(anim_data, ma->adt->drivers.first, NULL, ma, ANIMTYPE_DSMAT, filter_mode, (ID *)ma);, 
1021                                         items += animdata_filter_action(anim_data, ma->adt->action, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);)
1022                         }
1023                 }
1024         }
1025         
1026         /* free cache */
1027         BLI_freelistN(&mats);
1028         
1029         /* return the number of items added to the list */
1030         return items;
1031 }
1032
1033 static int animdata_filter_dopesheet_particles (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1034 {
1035         bAnimListElem *ale=NULL;
1036         Object *ob= base->object;
1037         ParticleSystem *psys = ob->particlesystem.first;
1038         int items= 0, first = 1;
1039
1040         for(; psys; psys=psys->next) {
1041                 short ok = 0;
1042
1043                 if(ELEM(NULL, psys->part, psys->part->adt))
1044                         continue;
1045
1046                 ANIMDATA_FILTER_CASES(psys->part,
1047                         { /* AnimData blocks - do nothing... */ },
1048                         ok=1;, 
1049                         ok=1;, 
1050                         ok=1;)
1051                 if (ok == 0) continue;
1052
1053                 /* include particles-expand widget? */
1054                 if (first && (filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1055                         ale= make_new_animlistelem(ob, ANIMTYPE_FILLPARTD, base, ANIMTYPE_OBJECT, (ID *)ob);
1056                         if (ale) {
1057                                 BLI_addtail(anim_data, ale);
1058                                 items++;
1059                         }
1060                         first = 0;
1061                 }
1062                 
1063                 /* add particle settings? */
1064                 if (FILTER_PART_OBJC(ob) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1065                         if ((filter_mode & ANIMFILTER_CHANNELS)){
1066                                 ale = make_new_animlistelem(psys->part, ANIMTYPE_DSPART, base, ANIMTYPE_OBJECT, (ID *)psys->part);
1067                                 if (ale) {
1068                                         BLI_addtail(anim_data, ale);
1069                                         items++;
1070                                 }
1071                         }
1072                         
1073                         if (FILTER_PART_OBJD(psys->part) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1074                                 ANIMDATA_FILTER_CASES(psys->part,
1075                                         { /* AnimData blocks - do nothing... */ },
1076                                         items += animdata_filter_nla(anim_data, psys->part->adt, filter_mode, psys->part, ANIMTYPE_DSPART, (ID *)psys->part);, 
1077                                         items += animdata_filter_fcurves(anim_data, psys->part->adt->drivers.first, NULL, psys->part, ANIMTYPE_DSPART, filter_mode, (ID *)psys->part);, 
1078                                         items += animdata_filter_action(anim_data, psys->part->adt->action, filter_mode, psys->part, ANIMTYPE_DSPART, (ID *)psys->part);)
1079                         }
1080                 }
1081         }
1082         
1083         /* return the number of items added to the list */
1084         return items;
1085 }
1086
1087 static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1088 {
1089         bAnimListElem *ale=NULL;
1090         Object *ob= base->object;
1091         IdAdtTemplate *iat= ob->data;
1092         AnimData *adt= iat->adt;
1093         short type=0, expanded=0;
1094         int items= 0;
1095         
1096         /* get settings based on data type */
1097         switch (ob->type) {
1098                 case OB_CAMERA: /* ------- Camera ------------ */
1099                 {
1100                         Camera *ca= (Camera *)ob->data;
1101                         
1102                         type= ANIMTYPE_DSCAM;
1103                         expanded= FILTER_CAM_OBJD(ca);
1104                 }
1105                         break;
1106                 case OB_LAMP: /* ---------- Lamp ----------- */
1107                 {
1108                         Lamp *la= (Lamp *)ob->data;
1109                         
1110                         type= ANIMTYPE_DSLAM;
1111                         expanded= FILTER_LAM_OBJD(la);
1112                 }
1113                         break;
1114                 case OB_CURVE: /* ------- Curve ---------- */
1115                 {
1116                         Curve *cu= (Curve *)ob->data;
1117                         
1118                         type= ANIMTYPE_DSCUR;
1119                         expanded= FILTER_CUR_OBJD(cu);
1120                 }
1121                         break;
1122         }
1123         
1124         /* special exception for drivers instead of action */
1125         if (ads->filterflag & ADS_FILTER_ONLYDRIVERS)
1126                 expanded= EXPANDED_DRVD(adt);
1127         
1128         /* include data-expand widget? */
1129         if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) {               
1130                 ale= make_new_animlistelem(iat, type, base, ANIMTYPE_OBJECT, (ID *)iat);
1131                 if (ale) BLI_addtail(anim_data, ale);
1132         }
1133         
1134         /* add object-data animation channels? */
1135         if ((expanded) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1136                 /* filtering for channels - nla, drivers, keyframes */
1137                 ANIMDATA_FILTER_CASES(iat, 
1138                         { /* AnimData blocks - do nothing... */ },
1139                         items+= animdata_filter_nla(anim_data, iat->adt, filter_mode, iat, type, (ID *)iat);,
1140                         items+= animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, iat, type, filter_mode, (ID *)iat);, 
1141                         items += animdata_filter_action(anim_data, iat->adt->action, filter_mode, iat, type, (ID *)iat);)
1142         }
1143         
1144         /* return the number of items added to the list */
1145         return items;
1146 }
1147
1148 static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1149 {
1150         bAnimListElem *ale=NULL;
1151         AnimData *adt = NULL;
1152         Object *ob= base->object;
1153         Key *key= ob_get_key(ob);
1154         short obdata_ok = 0;
1155         int items = 0;
1156         
1157         /* add this object as a channel first */
1158         if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) {
1159                 /* check if filtering by selection */
1160                 if ANIMCHANNEL_SELOK((base->flag & SELECT)) {
1161                         ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE, NULL);
1162                         if (ale) {
1163                                 BLI_addtail(anim_data, ale);
1164                                 items++;
1165                         }
1166                 }
1167         }
1168         
1169         /* if collapsed, don't go any further (unless adding keyframes only) */
1170         if ( (EXPANDED_OBJC(ob) == 0) && !(filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) )
1171                 return items;
1172         
1173         /* Action, Drivers, or NLA */
1174         if (ob->adt) {
1175                 adt= ob->adt;
1176                 ANIMDATA_FILTER_CASES(ob,
1177                         { /* AnimData blocks - do nothing... */ },
1178                         { /* nla */
1179                                 /* add NLA tracks */
1180                                 items += animdata_filter_nla(anim_data, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
1181                         },
1182                         { /* drivers */
1183                                 /* include drivers-expand widget? */
1184                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1185                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, base, ANIMTYPE_OBJECT, (ID *)ob);
1186                                         if (ale) {
1187                                                 BLI_addtail(anim_data, ale);
1188                                                 items++;
1189                                         }
1190                                 }
1191                                 
1192                                 /* add F-Curve channels (drivers are F-Curves) */
1193                                 if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1194                                         // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
1195                                         items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, ob, ANIMTYPE_OBJECT, filter_mode, (ID *)ob);
1196                                 }
1197                         },
1198                         { /* action (keyframes) */
1199                                 /* include action-expand widget? */
1200                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1201                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, base, ANIMTYPE_OBJECT, (ID *)ob);
1202                                         if (ale) {
1203                                                 BLI_addtail(anim_data, ale);
1204                                                 items++;
1205                                         }
1206                                 }
1207                                 
1208                                 /* add F-Curve channels? */
1209                                 if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1210                                         // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
1211                                         items += animdata_filter_action(anim_data, adt->action, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); 
1212                                 }
1213                         }
1214                 );
1215         }
1216         
1217         
1218         /* ShapeKeys? */
1219         if ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
1220                 adt= key->adt;
1221                 ANIMDATA_FILTER_CASES(key,
1222                         { /* AnimData blocks - do nothing... */ },
1223                         { /* nla */
1224                                 /* add NLA tracks */
1225                                 items += animdata_filter_nla(anim_data, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
1226                         },
1227                         { /* drivers */
1228                                 /* include shapekey-expand widget? */
1229                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1230                                         ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
1231                                         if (ale) {
1232                                                 BLI_addtail(anim_data, ale);
1233                                                 items++;
1234                                         }
1235                                 }
1236                                 
1237                                 /* add channels */
1238                                 if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1239                                         items += animdata_filter_shapekey(anim_data, key, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
1240                                 }
1241                         },
1242                         { /* action (keyframes) */
1243                                 /* include shapekey-expand widget? */
1244                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1245                                         ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
1246                                         if (ale) {
1247                                                 BLI_addtail(anim_data, ale);
1248                                                 items++;
1249                                         }
1250                                 }
1251                                 
1252                                 /* add channels */
1253                                 if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1254                                         items += animdata_filter_shapekey(anim_data, key, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
1255                                 }
1256                         }
1257                 );
1258         }
1259
1260         /* Materials? */
1261         if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT))
1262                 items += animdata_filter_dopesheet_mats(anim_data, ads, base, filter_mode);
1263         
1264         /* Object Data */
1265         switch (ob->type) {
1266                 case OB_CAMERA: /* ------- Camera ------------ */
1267                 {
1268                         Camera *ca= (Camera *)ob->data;
1269                         
1270                         if ((ads->filterflag & ADS_FILTER_NOCAM) == 0) {
1271                                 ANIMDATA_FILTER_CASES(ca,
1272                                         { /* AnimData blocks - do nothing... */ },
1273                                         obdata_ok= 1;,
1274                                         obdata_ok= 1;,
1275                                         obdata_ok= 1;)
1276                         }
1277                 }
1278                         break;
1279                 case OB_LAMP: /* ---------- Lamp ----------- */
1280                 {
1281                         Lamp *la= (Lamp *)ob->data;
1282                         
1283                         if ((ads->filterflag & ADS_FILTER_NOLAM) == 0) {
1284                                 ANIMDATA_FILTER_CASES(la,
1285                                         { /* AnimData blocks - do nothing... */ },
1286                                         obdata_ok= 1;,
1287                                         obdata_ok= 1;,
1288                                         obdata_ok= 1;)
1289                         }
1290                 }
1291                         break;
1292                 case OB_CURVE: /* ------- Curve ---------- */
1293                 {
1294                         Curve *cu= (Curve *)ob->data;
1295                         
1296                         if ((ads->filterflag & ADS_FILTER_NOCUR) == 0) {
1297                                 ANIMDATA_FILTER_CASES(cu,
1298                                         { /* AnimData blocks - do nothing... */ },
1299                                         obdata_ok= 1;,
1300                                         obdata_ok= 1;,
1301                                         obdata_ok= 1;)
1302                         }
1303                 }
1304                         break;
1305         }
1306         if (obdata_ok) 
1307                 items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode);
1308
1309         /* particles */
1310         if(ob->particlesystem.first && !(ads->filterflag & ADS_FILTER_NOPART))
1311                 items += animdata_filter_dopesheet_particles(anim_data, ads, base, filter_mode);
1312         
1313         /* return the number of items added to the list */
1314         return items;
1315 }       
1316
1317 static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
1318 {
1319         World *wo= sce->world;
1320         AnimData *adt= NULL;
1321         bAnimListElem *ale;
1322         int items = 0;
1323         
1324         /* add scene as a channel first (even if we aren't showing scenes we still need to show the scene's sub-data */
1325         if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) {
1326                 /* check if filtering by selection */
1327                 if (ANIMCHANNEL_SELOK( (sce->flag & SCE_DS_SELECTED) )) {
1328                         ale= make_new_animlistelem(sce, ANIMTYPE_SCENE, NULL, ANIMTYPE_NONE, NULL);
1329                         if (ale) {
1330                                 BLI_addtail(anim_data, ale);
1331                                 items++;
1332                         }
1333                 }
1334         }
1335         
1336         /* if collapsed, don't go any further (unless adding keyframes only) */
1337         if ( (EXPANDED_SCEC(sce) == 0) && !(filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) )
1338                 return items;
1339                 
1340         /* Action, Drivers, or NLA  for Scene */
1341         if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) {
1342                 adt= sce->adt;
1343                 ANIMDATA_FILTER_CASES(sce,
1344                         { /* AnimData blocks - do nothing... */ },
1345                         { /* nla */
1346                                 /* add NLA tracks */
1347                                 items += animdata_filter_nla(anim_data, adt, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce);
1348                         },
1349                         { /* drivers */
1350                                 /* include drivers-expand widget? */
1351                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1352                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, sce, ANIMTYPE_SCENE, (ID *)sce);
1353                                         if (ale) {
1354                                                 BLI_addtail(anim_data, ale);
1355                                                 items++;
1356                                         }
1357                                 }
1358                                 
1359                                 /* add F-Curve channels (drivers are F-Curves) */
1360                                 if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1361                                         items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, sce, ANIMTYPE_SCENE, filter_mode, (ID *)sce);
1362                                 }
1363                         },
1364                         { /* action */
1365                                 /* include action-expand widget? */
1366                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1367                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, sce, ANIMTYPE_SCENE, (ID *)sce);
1368                                         if (ale) {
1369                                                 BLI_addtail(anim_data, ale);
1370                                                 items++;
1371                                         }
1372                                 }
1373                                 
1374                                 /* add F-Curve channels? */
1375                                 if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1376                                         items += animdata_filter_action(anim_data, adt->action, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce); 
1377                                 }
1378                         }
1379                 )
1380         }
1381         
1382         /* world */
1383         if ((wo && wo->adt) && !(ads->filterflag & ADS_FILTER_NOWOR)) {
1384                 /* Action, Drivers, or NLA for World */
1385                 adt= wo->adt;
1386                 ANIMDATA_FILTER_CASES(wo,
1387                         { /* AnimData blocks - do nothing... */ },
1388                         { /* nla */
1389                                 /* add NLA tracks */
1390                                 items += animdata_filter_nla(anim_data, adt, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo);
1391                         },
1392                         { /* drivers */
1393                                 /* include world-expand widget? */
1394                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1395                                         ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)wo);
1396                                         if (ale) {
1397                                                 BLI_addtail(anim_data, ale);
1398                                                 items++;
1399                                         }
1400                                 }
1401                                 
1402                                 /* add F-Curve channels (drivers are F-Curves) */
1403                                 if (FILTER_WOR_SCED(wo)/*EXPANDED_DRVD(adt)*/ || !(filter_mode & ANIMFILTER_CHANNELS)) {
1404                                         // XXX owner info is messed up now...
1405                                         items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, wo, ANIMTYPE_DSWOR, filter_mode, (ID *)wo);
1406                                 }
1407                         },
1408                         { /* action */
1409                                 /* include world-expand widget? */
1410                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1411                                         ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)sce);
1412                                         if (ale) {
1413                                                 BLI_addtail(anim_data, ale);
1414                                                 items++;
1415                                         }
1416                                 }
1417                                 
1418                                 /* add channels */
1419                                 if (FILTER_WOR_SCED(wo) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1420                                         items += animdata_filter_action(anim_data, adt->action, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo); 
1421                                 }
1422                         }
1423                 )
1424         }
1425         
1426         /* return the number of items added to the list */
1427         return items;
1428 }
1429
1430 // 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)
1431 static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int filter_mode)
1432 {
1433         Scene *sce= (Scene *)ads->source;
1434         Base *base;
1435         bAnimListElem *ale;
1436         int items = 0;
1437         
1438         /* check that we do indeed have a scene */
1439         if ((ads->source == NULL) || (GS(ads->source->name)!=ID_SCE)) {
1440                 printf("DopeSheet Error: Not scene! \n");
1441                 return 0;
1442         }
1443         
1444         /* scene-linked animation */
1445         // TODO: sequencer, composite nodes - are we to include those here too?
1446         {
1447                 short sceOk= 0, worOk= 0;
1448                 
1449                 /* check filtering-flags if ok */
1450                 ANIMDATA_FILTER_CASES(sce, 
1451                         {
1452                                 /* for the special AnimData blocks only case, we only need to add
1453                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1454                                  */
1455                                 ANIMDATA_ADD_ANIMDATA(sce);
1456                                 sceOk=0;
1457                         },
1458                         sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, 
1459                         sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, 
1460                         sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);)
1461                 if (sce->world) {
1462                         ANIMDATA_FILTER_CASES(sce->world, 
1463                                 {
1464                                         /* for the special AnimData blocks only case, we only need to add
1465                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
1466                                          */
1467                                         ANIMDATA_ADD_ANIMDATA(sce->world);
1468                                         worOk=0;
1469                                 },
1470                                 worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, 
1471                                 worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, 
1472                                 worOk= !(ads->filterflag & ADS_FILTER_NOWOR);)
1473                 }
1474                 
1475                 /* check if not all bad (i.e. so there is something to show) */
1476                 if ( !(!sceOk && !worOk) ) {
1477                         /* add scene data to the list of filtered channels */
1478                         items += animdata_filter_dopesheet_scene(anim_data, ads, sce, filter_mode);
1479                 }
1480         }
1481         
1482         
1483         /* loop over all bases in the scene */
1484         for (base= sce->base.first; base; base= base->next) {
1485                 /* check if there's an object (all the relevant checks are done in the ob-function) */
1486                 if (base->object) {
1487                         Object *ob= base->object;
1488                         Key *key= ob_get_key(ob);
1489                         short actOk=1, keyOk=1, dataOk=1, matOk=1, partOk=1;
1490                         
1491                         /* firstly, check if object can be included, by the following fanimors:
1492                          *      - if only visible, must check for layer and also viewport visibility
1493                          *      - if only selected, must check if object is selected 
1494                          *      - there must be animation data to edit
1495                          */
1496                         // TODO: if cache is implemented, just check name here, and then 
1497                         if (filter_mode & ANIMFILTER_VISIBLE) {
1498                                 /* layer visibility - we check both object and base, since these may not be in sync yet */
1499                                 if ((sce->lay & (ob->lay|base->lay))==0) continue;
1500                                 
1501                                 /* outliner restrict-flag */
1502                                 if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
1503                         }
1504                         
1505                         /* additionally, dopesheet filtering also affects what objects to consider */
1506                         if (ads->filterflag) {
1507                                 /* check selection and object type filters */
1508                                 if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) || (base == sce->basact)) )  {
1509                                         /* only selected should be shown */
1510                                         continue;
1511                                 }
1512                                 
1513                                 /* check filters for datatypes */
1514                                         /* object */
1515                                 actOk= 0;
1516                                 keyOk= 0;
1517                                 ANIMDATA_FILTER_CASES(ob, 
1518                                         {
1519                                                 /* for the special AnimData blocks only case, we only need to add
1520                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1521                                                  */
1522                                                 ANIMDATA_ADD_ANIMDATA(ob);
1523                                                 actOk=0;
1524                                         },
1525                                         actOk= 1;, 
1526                                         actOk= 1;, 
1527                                         actOk= 1;)
1528                                 if (key) {
1529                                         /* shapekeys */
1530                                         ANIMDATA_FILTER_CASES(key, 
1531                                                 {
1532                                                         /* for the special AnimData blocks only case, we only need to add
1533                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
1534                                                          */
1535                                                         ANIMDATA_ADD_ANIMDATA(key);
1536                                                         keyOk=0;
1537                                                 },
1538                                                 keyOk= 1;, 
1539                                                 keyOk= 1;, 
1540                                                 keyOk= 1;)
1541                                 }
1542                                 
1543                                 /* materials - only for geometric types */
1544                                 matOk= 0; /* by default, not ok... */
1545                                 if ( !(ads->filterflag & ADS_FILTER_NOMAT) && (ob->totcol) && 
1546                                          ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) ) 
1547                                 {
1548                                         int a;
1549                                         
1550                                         /* firstly check that we actuallly have some materials */
1551                                         for (a=0; a < ob->totcol; a++) {
1552                                                 Material *ma= give_current_material(ob, a);
1553                                                 
1554                                                 if (ma) {
1555                                                         /* if material has relevant animation data, break */
1556                                                         ANIMDATA_FILTER_CASES(ma, 
1557                                                                 {
1558                                                                         /* for the special AnimData blocks only case, we only need to add
1559                                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
1560                                                                          */
1561                                                                         ANIMDATA_ADD_ANIMDATA(ma);
1562                                                                         matOk=0;
1563                                                                 },
1564                                                                 matOk= 1;, 
1565                                                                 matOk= 1;, 
1566                                                                 matOk= 1;)
1567                                                 }
1568                                                         
1569                                                 if (matOk) 
1570                                                         break;
1571                                         }
1572                                 }
1573                                 
1574                                 /* data */
1575                                 switch (ob->type) {
1576                                         case OB_CAMERA: /* ------- Camera ------------ */
1577                                         {
1578                                                 Camera *ca= (Camera *)ob->data;
1579                                                 dataOk= 0;
1580                                                 ANIMDATA_FILTER_CASES(ca, 
1581                                                         if ((ads->filterflag & ADS_FILTER_NOCAM)==0) {
1582                                                                 /* for the special AnimData blocks only case, we only need to add
1583                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1584                                                                  */
1585                                                                 ANIMDATA_ADD_ANIMDATA(ca);
1586                                                                 dataOk=0;
1587                                                         },
1588                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, 
1589                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, 
1590                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);)
1591                                         }
1592                                                 break;
1593                                         case OB_LAMP: /* ---------- Lamp ----------- */
1594                                         {
1595                                                 Lamp *la= (Lamp *)ob->data;
1596                                                 dataOk= 0;
1597                                                 ANIMDATA_FILTER_CASES(la, 
1598                                                         if ((ads->filterflag & ADS_FILTER_NOLAM)==0) {
1599                                                                 /* for the special AnimData blocks only case, we only need to add
1600                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1601                                                                  */
1602                                                                 ANIMDATA_ADD_ANIMDATA(la);
1603                                                                 dataOk=0;
1604                                                         },
1605                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, 
1606                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, 
1607                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);)
1608                                         }
1609                                                 break;
1610                                         case OB_CURVE: /* ------- Curve ---------- */
1611                                         {
1612                                                 Curve *cu= (Curve *)ob->data;
1613                                                 dataOk= 0;
1614                                                 ANIMDATA_FILTER_CASES(cu, 
1615                                                         if ((ads->filterflag & ADS_FILTER_NOCUR)==0) {
1616                                                                 /* for the special AnimData blocks only case, we only need to add
1617                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1618                                                                  */
1619                                                                 ANIMDATA_ADD_ANIMDATA(cu);
1620                                                                 dataOk=0;
1621                                                         },
1622                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, 
1623                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, 
1624                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);)
1625                                         }
1626                                                 break;
1627                                         default: /* --- other --- */
1628                                                 dataOk= 0;
1629                                                 break;
1630                                 }
1631
1632                                 /* particles */
1633                                 partOk = 0;
1634                                 if(!(ads->filterflag & ADS_FILTER_NOPART) && ob->particlesystem.first) {
1635                                         ParticleSystem *psys = ob->particlesystem.first;
1636                                         for(; psys; psys=psys->next) {
1637                                                 if (psys->part) {
1638                                                         /* if particlesettings has relevant animation data, break */
1639                                                         ANIMDATA_FILTER_CASES(psys->part, 
1640                                                                 {
1641                                                                         /* for the special AnimData blocks only case, we only need to add
1642                                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
1643                                                                          */
1644                                                                         ANIMDATA_ADD_ANIMDATA(psys->part);
1645                                                                         partOk=0;
1646                                                                 },
1647                                                                 partOk= 1;, 
1648                                                                 partOk= 1;, 
1649                                                                 partOk= 1;)
1650                                                 }
1651                                                         
1652                                                 if (partOk) 
1653                                                         break;
1654                                         }
1655                                 }
1656
1657                                 
1658                                 /* check if all bad (i.e. nothing to show) */
1659                                 if (!actOk && !keyOk && !dataOk && !matOk && !partOk)
1660                                         continue;
1661                         }
1662                         else {
1663                                 /* check data-types */
1664                                 actOk= ANIMDATA_HAS_KEYS(ob);
1665                                 keyOk= (key != NULL);
1666                                 
1667                                 /* materials - only for geometric types */
1668                                 matOk= 0; /* by default, not ok... */
1669                                 if (ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) && (ob->totcol)) 
1670                                 {
1671                                         int a;
1672                                         
1673                                         /* firstly check that we actuallly have some materials */
1674                                         for (a=0; a < ob->totcol; a++) {
1675                                                 Material *ma= give_current_material(ob, a);
1676                                                 
1677                                                 if ((ma) && ANIMDATA_HAS_KEYS(ma)) {
1678                                                         matOk= 1;
1679                                                         break;
1680                                                 }
1681                                         }
1682                                 }
1683                                 
1684                                 /* data */
1685                                 switch (ob->type) {
1686                                         case OB_CAMERA: /* ------- Camera ------------ */
1687                                         {
1688                                                 Camera *ca= (Camera *)ob->data;
1689                                                 dataOk= ANIMDATA_HAS_KEYS(ca);                                          
1690                                         }
1691                                                 break;
1692                                         case OB_LAMP: /* ---------- Lamp ----------- */
1693                                         {
1694                                                 Lamp *la= (Lamp *)ob->data;
1695                                                 dataOk= ANIMDATA_HAS_KEYS(la);  
1696                                         }
1697                                                 break;
1698                                         case OB_CURVE: /* -------- Curve ---------- */
1699                                         {
1700                                                 Curve *cu= (Curve *)ob->data;
1701                                                 dataOk= ANIMDATA_HAS_KEYS(cu);  
1702                                         }
1703                                                 break;
1704                                         default: /* --- other --- */
1705                                                 dataOk= 0;
1706                                                 break;
1707                                 }
1708
1709                                 /* particles */
1710                                 partOk = 0;
1711                                 if(ob->particlesystem.first) {
1712                                         ParticleSystem *psys = ob->particlesystem.first;
1713                                         for(; psys; psys=psys->next) {
1714                                                 if(psys->part && ANIMDATA_HAS_KEYS(psys->part)) {
1715                                                         partOk = 1;
1716                                                         break;
1717                                                 }
1718
1719                                         }
1720                                 }
1721                                 
1722                                 /* check if all bad (i.e. nothing to show) */
1723                                 if (!actOk && !keyOk && !dataOk && !matOk && !partOk)
1724                                         continue;
1725                         }
1726                         
1727                         /* since we're still here, this object should be usable */
1728                         items += animdata_filter_dopesheet_ob(anim_data, ads, base, filter_mode);
1729                 }
1730         }
1731         
1732         /* return the number of items in the list */
1733         return items;
1734 }
1735
1736 /* ----------- Public API --------------- */
1737
1738 /* This function filters the active data source to leave only animation channels suitable for
1739  * usage by the caller. It will return the length of the list 
1740  * 
1741  *      *anim_data: is a pointer to a ListBase, to which the filtered animation channels
1742  *              will be placed for use.
1743  *      filter_mode: how should the data be filtered - bitmapping accessed flags
1744  */
1745 int ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode, void *data, short datatype)
1746 {
1747         int items = 0;
1748         
1749         /* only filter data if there's somewhere to put it */
1750         if (data && anim_data) {
1751                 bAnimListElem *ale, *next;
1752                 Object *obact= (ac) ? ac->obact : NULL;
1753                 
1754                 /* firstly filter the data */
1755                 switch (datatype) {
1756                         case ANIMCONT_ACTION:
1757                                 items= animdata_filter_action(anim_data, data, filter_mode, NULL, ANIMTYPE_NONE, (ID *)obact);
1758                                 break;
1759                                 
1760                         case ANIMCONT_SHAPEKEY:
1761                                 items= animdata_filter_shapekey(anim_data, data, filter_mode, NULL, ANIMTYPE_NONE, (ID *)obact);
1762                                 break;
1763                                 
1764                         case ANIMCONT_GPENCIL:
1765                                 //items= animdata_filter_gpencil(anim_data, data, filter_mode);
1766                                 break;
1767                                 
1768                         case ANIMCONT_DOPESHEET:
1769                         case ANIMCONT_FCURVES:
1770                         case ANIMCONT_DRIVERS:
1771                         case ANIMCONT_NLA:
1772                                 items= animdata_filter_dopesheet(anim_data, data, filter_mode);
1773                                 break;
1774                 }
1775                         
1776                 /* remove any weedy entries */
1777                 // XXX this is weedy code!
1778                 for (ale= anim_data->first; ale; ale= next) {
1779                         next= ale->next;
1780                         
1781                         if (ale->type == ANIMTYPE_NONE) {
1782                                 items--;
1783                                 BLI_freelinkN(anim_data, ale);
1784                         }
1785                 }
1786         }
1787         
1788         /* return the number of items in the list */
1789         return items;
1790 }
1791
1792 /* ************************************************************ */