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