2.5 - MetaBalls are now animateable
[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 (filter_mode & ANIMFILTER_ANIMDATA) {\
378                         if ((id)->adt) {\
379                                 adtOk\
380                         }\
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 /* quick macro to add a pointer to an AnimData block as a channel */
404 #define ANIMDATA_ADD_ANIMDATA(id) \
405         {\
406                 ale= make_new_animlistelem((id)->adt, ANIMTYPE_ANIMDATA, NULL, ANIMTYPE_NONE, (ID *)id);\
407                 if (ale) {\
408                         BLI_addtail(anim_data, ale);\
409                         items++;\
410                 }\
411         }
412         
413
414
415 /* quick macro to test if an anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */
416 #define ANIMCHANNEL_SELOK(test_func) \
417                 ( !(filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) || \
418                   ((filter_mode & ANIMFILTER_SEL) && test_func) || \
419                   ((filter_mode & ANIMFILTER_UNSEL) && test_func==0) ) 
420                   
421 /* quick macro to test if an anim-channel (F-Curve) is selected ok for editing purposes 
422  *      - _SELEDIT means that only selected curves will have visible+editable keyframes
423  */
424 // FIXME: this doesn't work cleanly yet...
425 #define ANIMCHANNEL_SELEDITOK(test_func) \
426                 ( !(filter_mode & ANIMFILTER_SELEDIT) || \
427                   (filter_mode & ANIMFILTER_CHANNELS) || \
428                   (test_func) )
429
430 /* ----------- 'Private' Stuff --------------- */
431
432 /* this function allocates memory for a new bAnimListElem struct for the 
433  * provided animation channel-data. 
434  */
435 bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, short ownertype, ID *owner_id)
436 {
437         bAnimListElem *ale= NULL;
438         
439         /* only allocate memory if there is data to convert */
440         if (data) {
441                 /* allocate and set generic data */
442                 ale= MEM_callocN(sizeof(bAnimListElem), "bAnimListElem");
443                 
444                 ale->data= data;
445                 ale->type= datatype;
446                         // XXX what is the point of the owner data?
447                 ale->owner= owner;
448                 ale->ownertype= ownertype;
449                 
450                 ale->id= owner_id;
451                 ale->adt= BKE_animdata_from_id(owner_id);
452                 
453                 /* do specifics */
454                 switch (datatype) {
455                         case ANIMTYPE_SCENE:
456                         {
457                                 Scene *sce= (Scene *)data;
458                                 
459                                 ale->flag= sce->flag;
460                                 
461                                 ale->key_data= sce;
462                                 ale->datatype= ALE_SCE;
463                                 
464                                 ale->adt= BKE_animdata_from_id(data);
465                         }
466                                 break;
467                         case ANIMTYPE_OBJECT:
468                         {
469                                 Base *base= (Base *)data;
470                                 Object *ob= base->object;
471                                 
472                                 ale->flag= ob->flag;
473                                 
474                                 ale->key_data= ob;
475                                 ale->datatype= ALE_OB;
476                                 
477                                 ale->adt= BKE_animdata_from_id(&ob->id);
478                         }
479                                 break;
480                         case ANIMTYPE_FILLACTD:
481                         {
482                                 bAction *act= (bAction *)data;
483                                 
484                                 ale->flag= act->flag;
485                                 
486                                 ale->key_data= act;
487                                 ale->datatype= ALE_ACT;
488                         }
489                                 break;
490                         case ANIMTYPE_FILLDRIVERS:
491                         {
492                                 AnimData *adt= (AnimData *)data;
493                                 
494                                 ale->flag= adt->flag;
495                                 
496                                         // XXX... drivers don't show summary for now
497                                 ale->key_data= NULL;
498                                 ale->datatype= ALE_NONE;
499                         }
500                                 break;
501                         case ANIMTYPE_FILLMATD:
502                         {
503                                 Object *ob= (Object *)data;
504                                 
505                                 ale->flag= FILTER_MAT_OBJC(ob);
506                                 
507                                 ale->key_data= NULL;
508                                 ale->datatype= ALE_NONE;
509                         }
510                                 break;
511                         case ANIMTYPE_FILLPARTD:
512                         {
513                                 Object *ob= (Object *)data;
514                                 
515                                 ale->flag= FILTER_PART_OBJC(ob);
516                                 
517                                 ale->key_data= NULL;
518                                 ale->datatype= ALE_NONE;
519                         }
520                                 break;
521                         
522                         case ANIMTYPE_DSMAT:
523                         {
524                                 Material *ma= (Material *)data;
525                                 AnimData *adt= ma->adt;
526                                 
527                                 ale->flag= FILTER_MAT_OBJD(ma);
528                                 
529                                 ale->key_data= (adt) ? adt->action : NULL;
530                                 ale->datatype= ALE_ACT;
531                                 
532                                 ale->adt= BKE_animdata_from_id(data);
533                         }
534                                 break;
535                         case ANIMTYPE_DSLAM:
536                         {
537                                 Lamp *la= (Lamp *)data;
538                                 AnimData *adt= la->adt;
539                                 
540                                 ale->flag= FILTER_LAM_OBJD(la);
541                                 
542                                 ale->key_data= (adt) ? adt->action : NULL;
543                                 ale->datatype= ALE_ACT;
544                                 
545                                 ale->adt= BKE_animdata_from_id(data);
546                         }
547                                 break;
548                         case ANIMTYPE_DSCAM:
549                         {
550                                 Camera *ca= (Camera *)data;
551                                 AnimData *adt= ca->adt;
552                                 
553                                 ale->flag= FILTER_CAM_OBJD(ca);
554                                 
555                                 ale->key_data= (adt) ? adt->action : NULL;
556                                 ale->datatype= ALE_ACT;
557                                 
558                                 ale->adt= BKE_animdata_from_id(data);
559                         }
560                                 break;
561                         case ANIMTYPE_DSCUR:
562                         {
563                                 Curve *cu= (Curve *)data;
564                                 AnimData *adt= cu->adt;
565                                 
566                                 ale->flag= FILTER_CUR_OBJD(cu);
567                                 
568                                 ale->key_data= (adt) ? adt->action : NULL;
569                                 ale->datatype= ALE_ACT;
570                                 
571                                 ale->adt= BKE_animdata_from_id(data);
572                         }
573                                 break;
574                         case ANIMTYPE_DSSKEY:
575                         {
576                                 Key *key= (Key *)data;
577                                 AnimData *adt= key->adt;
578                                 
579                                 ale->flag= FILTER_SKE_OBJD(key); 
580                                 
581                                 ale->key_data= (adt) ? adt->action : NULL;
582                                 ale->datatype= ALE_ACT;
583                                 
584                                 ale->adt= BKE_animdata_from_id(data);
585                         }
586                                 break;
587                         case ANIMTYPE_DSWOR:
588                         {
589                                 World *wo= (World *)data;
590                                 AnimData *adt= wo->adt;
591                                 
592                                 ale->flag= FILTER_WOR_SCED(wo); 
593                                 
594                                 ale->key_data= (adt) ? adt->action : NULL;
595                                 ale->datatype= ALE_ACT;
596                                 
597                                 ale->adt= BKE_animdata_from_id(data);
598                         }
599                                 break;
600                         case ANIMTYPE_DSPART:
601                         {
602                                 ParticleSettings *part= (ParticleSettings*)ale->data;
603                                 AnimData *adt= part->adt;
604                                 
605                                 ale->flag= FILTER_PART_OBJD(part); 
606                                 
607                                 ale->key_data= (adt) ? adt->action : NULL;
608                                 ale->datatype= ALE_ACT;
609                                 
610                                 ale->adt= BKE_animdata_from_id(data);
611                         }
612                                 break;
613                                 
614                         case ANIMTYPE_GROUP:
615                         {
616                                 bActionGroup *agrp= (bActionGroup *)data;
617                                 
618                                 ale->flag= agrp->flag;
619                                 
620                                 ale->key_data= NULL;
621                                 ale->datatype= ALE_GROUP;
622                         }
623                                 break;
624                         case ANIMTYPE_FCURVE:
625                         {
626                                 FCurve *fcu= (FCurve *)data;
627                                 
628                                 ale->flag= fcu->flag;
629                                 
630                                 ale->key_data= fcu;
631                                 ale->datatype= ALE_FCURVE;
632                         }
633                                 break;
634                         
635                         case ANIMTYPE_GPLAYER:
636                         {
637                                 bGPDlayer *gpl= (bGPDlayer *)data;
638                                 
639                                 ale->flag= gpl->flag;
640                                 
641                                 ale->key_data= NULL;
642                                 ale->datatype= ALE_GPFRAME;
643                         }
644                                 break;
645                                 
646                         case ANIMTYPE_NLATRACK:
647                         {
648                                 NlaTrack *nlt= (NlaTrack *)data;
649                                 
650                                 ale->flag= nlt->flag;
651                                 
652                                         // XXX or should this be done some other way?
653                                 ale->key_data= &nlt->strips;
654                                 ale->datatype= ALE_NLASTRIP;
655                         }
656                                 break;
657                         case ANIMTYPE_NLAACTION:
658                         {
659                                 /* nothing to include for now... nothing editable from NLA-perspective here */
660                                 ale->key_data= NULL;
661                                 ale->datatype= ALE_NONE;
662                         }
663                                 break;
664                 }
665         }
666         
667         /* return created datatype */
668         return ale;
669 }
670  
671 /* ----------------------------------------- */
672
673
674 static int animdata_filter_fcurves (ListBase *anim_data, FCurve *first, bActionGroup *grp, void *owner, short ownertype, int filter_mode, ID *owner_id)
675 {
676         bAnimListElem *ale = NULL;
677         FCurve *fcu;
678         int items = 0;
679         
680         /* loop over F-Curves - assume that the caller of this has already checked that these should be included 
681          * NOTE: we need to check if the F-Curves belong to the same group, as this gets called for groups too...
682          */
683         for (fcu= first; ((fcu) && (fcu->grp==grp)); fcu= fcu->next) {
684                 /* only include if visible (Graph Editor check, not channels check) */
685                 if (!(filter_mode & ANIMFILTER_CURVEVISIBLE) || (fcu->flag & FCURVE_VISIBLE)) {
686                         /* only work with this channel and its subchannels if it is editable */
687                         if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) {
688                                 /* only include this curve if selected in a way consistent with the filtering requirements */
689                                 if ( ANIMCHANNEL_SELOK(SEL_FCU(fcu)) && ANIMCHANNEL_SELEDITOK(SEL_FCU(fcu)) ) {
690                                         /* only include if this curve is active */
691                                         if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
692                                                 ale= make_new_animlistelem(fcu, ANIMTYPE_FCURVE, owner, ownertype, owner_id);
693                                                 
694                                                 if (ale) {
695                                                         BLI_addtail(anim_data, ale);
696                                                         items++;
697                                                 }
698                                         }
699                                 }
700                         }
701                 }
702         }
703         
704         /* return the number of items added to the list */
705         return items;
706 }
707
708 static int animdata_filter_action (ListBase *anim_data, bAction *act, int filter_mode, void *owner, short ownertype, ID *owner_id)
709 {
710         bAnimListElem *ale=NULL;
711         bActionGroup *agrp;
712         FCurve *lastchan=NULL;
713         int items = 0;
714         
715         /* loop over groups */
716         //       XXX in future, we need to be prepared for nestled groups...
717         for (agrp= act->groups.first; agrp; agrp= agrp->next) {
718                 /* add this group as a channel first */
719                 if ((filter_mode & ANIMFILTER_CHANNELS) || !(filter_mode & ANIMFILTER_CURVESONLY)) {
720                         /* check if filtering by selection */
721                         if ( ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) ) {
722                                 ale= make_new_animlistelem(agrp, ANIMTYPE_GROUP, NULL, ANIMTYPE_NONE, owner_id);
723                                 if (ale) {
724                                         BLI_addtail(anim_data, ale);
725                                         items++;
726                                 }
727                         }
728                 }
729                 
730                 /* store reference to last channel of group */
731                 if (agrp->channels.last) 
732                         lastchan= agrp->channels.last;
733                 
734                 
735                 /* there are some situations, where only the channels of the action group should get considered */
736                 if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) {
737                         /* filters here are a bit convoulted...
738                          *      - groups show a "summary" of keyframes beside their name which must accessable for tools which handle keyframes
739                          *      - groups can be collapsed (and those tools which are only interested in channels rely on knowing that group is closed)
740                          *
741                          * cases when we should include F-Curves inside group:
742                          *      - we don't care about visibility
743                          *      - group is expanded
744                          *      - we just need the F-Curves present
745                          */
746                         if ( (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_AGRP(agrp)) || (filter_mode & ANIMFILTER_CURVESONLY) ) 
747                         {
748                                 /* for the Graph Editor, curves may be set to not be visible in the view to lessen clutter,
749                                  * but to do this, we need to check that the group doesn't have it's not-visible flag set preventing 
750                                  * all its sub-curves to be shown
751                                  */
752                                 if ( !(filter_mode & ANIMFILTER_CURVEVISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE) )
753                                 {
754                                         if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
755                                                 // XXX the 'owner' info here needs review...
756                                                 items += animdata_filter_fcurves(anim_data, agrp->channels.first, agrp, owner, ownertype, filter_mode, owner_id);
757                                                 
758                                                 /* remove group from filtered list if last element is group 
759                                                  * (i.e. only if group had channels, which were all hidden)
760                                                  */
761                                                 // XXX this is really hacky... it should be fixed in a much more elegant way!
762                                                 if ( (ale) && (anim_data->last == ale) && 
763                                                          (ale->data == agrp) && (agrp->channels.first) ) 
764                                                 {
765                                                         BLI_freelinkN(anim_data, ale);
766                                                         items--;
767                                                 }
768                                         }
769                                 }
770                         }
771                 }
772         }
773         
774         /* loop over un-grouped F-Curves (only if we're not only considering those channels in the animive group) */
775         if (!(filter_mode & ANIMFILTER_ACTGROUPED))  {
776                 // XXX the 'owner' info here needs review...
777                 items += animdata_filter_fcurves(anim_data, (lastchan)?(lastchan->next):(act->curves.first), NULL, owner, ownertype, filter_mode, owner_id);
778         }
779         
780         /* return the number of items added to the list */
781         return items;
782 }
783
784 /* Include NLA-Data for NLA-Editor:
785  *      - when ANIMFILTER_CHANNELS is used, that means we should be filtering the list for display
786  *        Although the evaluation order is from the first track to the last and then apply the Action on top,
787  *        we present this in the UI as the Active Action followed by the last track to the first so that we 
788  *        get the evaluation order presented as per a stack.
789  *      - for normal filtering (i.e. for editing), we only need the NLA-tracks but they can be in 'normal' evaluation
790  *        order, i.e. first to last. Otherwise, some tools may get screwed up.
791  */
792 static int animdata_filter_nla (ListBase *anim_data, AnimData *adt, int filter_mode, void *owner, short ownertype, ID *owner_id)
793 {
794         bAnimListElem *ale;
795         NlaTrack *nlt;
796         NlaTrack *first=NULL, *next=NULL;
797         int items = 0;
798         
799         /* if showing channels, include active action */
800         if (filter_mode & ANIMFILTER_CHANNELS) {
801                 /* there isn't really anything editable here, so skip if need editable */
802                 // TODO: currently, selection isn't checked since it doesn't matter
803                 if ((filter_mode & ANIMFILTER_FOREDIT) == 0) { 
804                         /* just add the action track now (this MUST appear for drawing)
805                          *      - as AnimData may not have an action, we pass a dummy pointer just to get the list elem created, then
806                          *        overwrite this with the real value - REVIEW THIS...
807                          */
808                         ale= make_new_animlistelem((void *)(&adt->action), ANIMTYPE_NLAACTION, owner, ownertype, owner_id);
809                         ale->data= (adt->action) ? adt->action : NULL;
810                                 
811                         if (ale) {
812                                 BLI_addtail(anim_data, ale);
813                                 items++;
814                         }
815                 }
816                 
817                 /* first track to include will be the last one if we're filtering by channels */
818                 first= adt->nla_tracks.last;
819         }
820         else {
821                 /* first track to include will the the first one (as per normal) */
822                 first= adt->nla_tracks.first;
823         }
824         
825         /* loop over NLA Tracks - assume that the caller of this has already checked that these should be included */
826         for (nlt= first; nlt; nlt= next) {
827                 /* 'next' NLA-Track to use depends on whether we're filtering for drawing or not */
828                 if (filter_mode & ANIMFILTER_CHANNELS) 
829                         next= nlt->prev;
830                 else
831                         next= nlt->next;
832                 
833                 /* if we're in NLA-tweakmode, don't show this track if it was disabled (due to tweaking) for now 
834                  *      - active track should still get shown though (even though it has disabled flag set)
835                  */
836                 // FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel
837                 if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && !(nlt->flag & NLATRACK_ACTIVE))
838                         continue;
839                 
840                 /* only work with this channel and its subchannels if it is editable */
841                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) {
842                         /* only include this track if selected in a way consistent with the filtering requirements */
843                         if ( ANIMCHANNEL_SELOK(SEL_NLT(nlt)) ) {
844                                 /* only include if this track is active */
845                                 if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
846                                         ale= make_new_animlistelem(nlt, ANIMTYPE_NLATRACK, owner, ownertype, owner_id);
847                                                 
848                                         if (ale) {
849                                                 BLI_addtail(anim_data, ale);
850                                                 items++;
851                                         }
852                                 }
853                         }
854                 }
855         }
856         
857         /* return the number of items added to the list */
858         return items;
859 }
860  
861 #if 0
862 // FIXME: switch this to use the bDopeSheet...
863 static int animdata_filter_gpencil (ListBase *anim_data, bScreen *sc, int filter_mode)
864 {
865         bAnimListElem *ale;
866         ScrArea *sa, *curarea;
867         bGPdata *gpd;
868         bGPDlayer *gpl;
869         int items = 0;
870         
871         /* check if filtering types are appropriate */
872         {
873                 /* special hack for fullscreen area (which must be this one then):
874                  *      - we use the curarea->full as screen to get spaces from, since the
875                  *        old (pre-fullscreen) screen was stored there...
876                  *      - this is needed as all data would otherwise disappear
877                  */
878                 // XXX need to get new alternative for curarea
879                 if ((curarea->full) && (curarea->spacetype==SPACE_ACTION))
880                         sc= curarea->full;
881                 
882                 /* loop over spaces in current screen, finding gpd blocks (could be slow!) */
883                 for (sa= sc->areabase.first; sa; sa= sa->next) {
884                         /* try to get gp data */
885                         // XXX need to put back grease pencil api...
886                         gpd= gpencil_data_getactive(sa);
887                         if (gpd == NULL) continue;
888                         
889                         /* add gpd as channel too (if for drawing, and it has layers) */
890                         if ((filter_mode & ANIMFILTER_CHANNELS) && (gpd->layers.first)) {
891                                 /* add to list */
892                                 ale= make_new_animlistelem(gpd, ANIMTYPE_GPDATABLOCK, sa, ANIMTYPE_SPECIALDATA);
893                                 if (ale) {
894                                         BLI_addtail(anim_data, ale);
895                                         items++;
896                                 }
897                         }
898                         
899                         /* only add layers if they will be visible (if drawing channels) */
900                         if ( !(filter_mode & ANIMFILTER_VISIBLE) || (EXPANDED_GPD(gpd)) ) {
901                                 /* loop over layers as the conditions are acceptable */
902                                 for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
903                                         /* only if selected */
904                                         if ( ANIMCHANNEL_SELOK(SEL_GPL(gpl)) ) {
905                                                 /* only if editable */
906                                                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) {
907                                                         /* add to list */
908                                                         ale= make_new_animlistelem(gpl, ANIMTYPE_GPLAYER, gpd, ANIMTYPE_GPDATABLOCK);
909                                                         if (ale) {
910                                                                 BLI_addtail(anim_data, ale);
911                                                                 items++;
912                                                         }
913                                                 }
914                                         }
915                                 }
916                         }
917                 }
918         }
919         
920         /* return the number of items added to the list */
921         return items;
922 }
923 #endif 
924
925
926 static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
927 {
928         ListBase mats = {NULL, NULL};
929         LinkData *ld;
930         
931         bAnimListElem *ale=NULL;
932         Object *ob= base->object;
933         int items=0, a=0;
934         
935         /* firstly check that we actuallly have some materials, by gathering all materials in a temp list */
936         for (a=0; a < ob->totcol; a++) {
937                 Material *ma= give_current_material(ob, a);
938                 short ok = 0;
939                 
940                 /* for now, if no material returned, skip (this shouldn't confuse the user I hope) */
941                 if (ELEM(NULL, ma, ma->adt)) 
942                         continue;
943                 
944                 /* check if ok */
945                 ANIMDATA_FILTER_CASES(ma, 
946                         { /* AnimData blocks - do nothing... */ },
947                         ok=1;, 
948                         ok=1;, 
949                         ok=1;)
950                 if (ok == 0) continue;
951                 
952                 /* make a temp list elem for this */
953                 ld= MEM_callocN(sizeof(LinkData), "DopeSheet-MaterialCache");
954                 ld->data= ma;
955                 BLI_addtail(&mats, ld);
956         }
957         
958         /* if there were no channels found, no need to carry on */
959         if (mats.first == NULL)
960                 return 0;
961         
962         /* include materials-expand widget? */
963         if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
964                 ale= make_new_animlistelem(ob, ANIMTYPE_FILLMATD, base, ANIMTYPE_OBJECT, (ID *)ob);
965                 if (ale) {
966                         BLI_addtail(anim_data, ale);
967                         items++;
968                 }
969         }
970         
971         /* add materials? */
972         if (FILTER_MAT_OBJC(ob) || (filter_mode & ANIMFILTER_CURVESONLY)) {
973                 /* for each material in cache, add channels  */
974                 for (ld= mats.first; ld; ld= ld->next) {
975                         Material *ma= (Material *)ld->data;
976                         
977                         /* include material-expand widget? */
978                         // hmm... do we need to store the index of this material in the array anywhere?
979                         if (filter_mode & ANIMFILTER_CHANNELS) {
980                                 ale= make_new_animlistelem(ma, ANIMTYPE_DSMAT, base, ANIMTYPE_OBJECT, (ID *)ma);
981                                 if (ale) {
982                                         BLI_addtail(anim_data, ale);
983                                         items++;
984                                 }
985                         }
986                         
987                         /* add material's animation data */
988                         if (FILTER_MAT_OBJD(ma) || (filter_mode & ANIMFILTER_CURVESONLY)) {
989                                 ANIMDATA_FILTER_CASES(ma, 
990                                         { /* AnimData blocks - do nothing... */ },
991                                         items += animdata_filter_nla(anim_data, ma->adt, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);, 
992                                         items += animdata_filter_fcurves(anim_data, ma->adt->drivers.first, NULL, ma, ANIMTYPE_DSMAT, filter_mode, (ID *)ma);, 
993                                         items += animdata_filter_action(anim_data, ma->adt->action, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);)
994                         }
995                 }
996         }
997         
998         /* free cache */
999         BLI_freelistN(&mats);
1000         
1001         /* return the number of items added to the list */
1002         return items;
1003 }
1004
1005 static int animdata_filter_dopesheet_particles (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1006 {
1007         bAnimListElem *ale=NULL;
1008         Object *ob= base->object;
1009         ParticleSystem *psys = ob->particlesystem.first;
1010         int items= 0, first = 1;
1011
1012         for(; psys; psys=psys->next) {
1013                 short ok = 0;
1014
1015                 if(ELEM(NULL, psys->part, psys->part->adt))
1016                         continue;
1017
1018                 ANIMDATA_FILTER_CASES(psys->part,
1019                         { /* AnimData blocks - do nothing... */ },
1020                         ok=1;, 
1021                         ok=1;, 
1022                         ok=1;)
1023                 if (ok == 0) continue;
1024
1025                 /* include particles-expand widget? */
1026                 if (first && (filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1027                         ale= make_new_animlistelem(ob, ANIMTYPE_FILLPARTD, base, ANIMTYPE_OBJECT, (ID *)ob);
1028                         if (ale) {
1029                                 BLI_addtail(anim_data, ale);
1030                                 items++;
1031                         }
1032                         first = 0;
1033                 }
1034                 
1035                 /* add particle settings? */
1036                 if (FILTER_PART_OBJC(ob) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1037                         if ((filter_mode & ANIMFILTER_CHANNELS)){
1038                                 ale = make_new_animlistelem(psys->part, ANIMTYPE_DSPART, base, ANIMTYPE_OBJECT, (ID *)psys->part);
1039                                 if (ale) {
1040                                         BLI_addtail(anim_data, ale);
1041                                         items++;
1042                                 }
1043                         }
1044                         
1045                         if (FILTER_PART_OBJD(psys->part) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1046                                 ANIMDATA_FILTER_CASES(psys->part,
1047                                         { /* AnimData blocks - do nothing... */ },
1048                                         items += animdata_filter_nla(anim_data, psys->part->adt, filter_mode, psys->part, ANIMTYPE_DSPART, (ID *)psys->part);, 
1049                                         items += animdata_filter_fcurves(anim_data, psys->part->adt->drivers.first, NULL, psys->part, ANIMTYPE_DSPART, filter_mode, (ID *)psys->part);, 
1050                                         items += animdata_filter_action(anim_data, psys->part->adt->action, filter_mode, psys->part, ANIMTYPE_DSPART, (ID *)psys->part);)
1051                         }
1052                 }
1053         }
1054         
1055         /* return the number of items added to the list */
1056         return items;
1057 }
1058
1059 static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1060 {
1061         bAnimListElem *ale=NULL;
1062         Object *ob= base->object;
1063         IdAdtTemplate *iat= ob->data;
1064         AnimData *adt= iat->adt;
1065         short type=0, expanded=0;
1066         int items= 0;
1067         
1068         /* get settings based on data type */
1069         switch (ob->type) {
1070                 case OB_CAMERA: /* ------- Camera ------------ */
1071                 {
1072                         Camera *ca= (Camera *)ob->data;
1073                         
1074                         type= ANIMTYPE_DSCAM;
1075                         expanded= FILTER_CAM_OBJD(ca);
1076                 }
1077                         break;
1078                 case OB_LAMP: /* ---------- Lamp ----------- */
1079                 {
1080                         Lamp *la= (Lamp *)ob->data;
1081                         
1082                         type= ANIMTYPE_DSLAM;
1083                         expanded= FILTER_LAM_OBJD(la);
1084                 }
1085                         break;
1086                 case OB_CURVE: /* ------- Curve ---------- */
1087                 {
1088                         Curve *cu= (Curve *)ob->data;
1089                         
1090                         type= ANIMTYPE_DSCUR;
1091                         expanded= FILTER_CUR_OBJD(cu);
1092                 }
1093                         break;
1094                 case OB_MBALL: /* ------- MetaBall ---------- */
1095                 {
1096                         MetaBall *mb= (MetaBall *)ob->data;
1097                         
1098                         type= ANIMTYPE_DSMBALL;
1099                         expanded= FILTER_MBALL_OBJD(mb);
1100                 }
1101                         break;
1102         }
1103         
1104         /* special exception for drivers instead of action */
1105         if (ads->filterflag & ADS_FILTER_ONLYDRIVERS)
1106                 expanded= EXPANDED_DRVD(adt);
1107         
1108         /* include data-expand widget? */
1109         if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) {               
1110                 ale= make_new_animlistelem(iat, type, base, ANIMTYPE_OBJECT, (ID *)iat);
1111                 if (ale) BLI_addtail(anim_data, ale);
1112         }
1113         
1114         /* add object-data animation channels? */
1115         if ((expanded) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1116                 /* filtering for channels - nla, drivers, keyframes */
1117                 ANIMDATA_FILTER_CASES(iat, 
1118                         { /* AnimData blocks - do nothing... */ },
1119                         items+= animdata_filter_nla(anim_data, iat->adt, filter_mode, iat, type, (ID *)iat);,
1120                         items+= animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, iat, type, filter_mode, (ID *)iat);, 
1121                         items += animdata_filter_action(anim_data, iat->adt->action, filter_mode, iat, type, (ID *)iat);)
1122         }
1123         
1124         /* return the number of items added to the list */
1125         return items;
1126 }
1127
1128 static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1129 {
1130         bAnimListElem *ale=NULL;
1131         AnimData *adt = NULL;
1132         Object *ob= base->object;
1133         Key *key= ob_get_key(ob);
1134         short obdata_ok = 0;
1135         int items = 0;
1136         
1137         /* add this object as a channel first */
1138         if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) {
1139                 /* check if filtering by selection */
1140                 if ANIMCHANNEL_SELOK((base->flag & SELECT)) {
1141                         ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE, NULL);
1142                         if (ale) {
1143                                 BLI_addtail(anim_data, ale);
1144                                 items++;
1145                         }
1146                 }
1147         }
1148         
1149         /* if collapsed, don't go any further (unless adding keyframes only) */
1150         if ( (EXPANDED_OBJC(ob) == 0) && !(filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) )
1151                 return items;
1152         
1153         /* Action, Drivers, or NLA */
1154         if (ob->adt) {
1155                 adt= ob->adt;
1156                 ANIMDATA_FILTER_CASES(ob,
1157                         { /* AnimData blocks - do nothing... */ },
1158                         { /* nla */
1159                                 /* add NLA tracks */
1160                                 items += animdata_filter_nla(anim_data, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
1161                         },
1162                         { /* drivers */
1163                                 /* include drivers-expand widget? */
1164                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1165                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, base, ANIMTYPE_OBJECT, (ID *)ob);
1166                                         if (ale) {
1167                                                 BLI_addtail(anim_data, ale);
1168                                                 items++;
1169                                         }
1170                                 }
1171                                 
1172                                 /* add F-Curve channels (drivers are F-Curves) */
1173                                 if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1174                                         // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
1175                                         items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, ob, ANIMTYPE_OBJECT, filter_mode, (ID *)ob);
1176                                 }
1177                         },
1178                         { /* action (keyframes) */
1179                                 /* include action-expand widget? */
1180                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1181                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, base, ANIMTYPE_OBJECT, (ID *)ob);
1182                                         if (ale) {
1183                                                 BLI_addtail(anim_data, ale);
1184                                                 items++;
1185                                         }
1186                                 }
1187                                 
1188                                 /* add F-Curve channels? */
1189                                 if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1190                                         // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
1191                                         items += animdata_filter_action(anim_data, adt->action, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); 
1192                                 }
1193                         }
1194                 );
1195         }
1196         
1197         
1198         /* ShapeKeys? */
1199         if ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
1200                 adt= key->adt;
1201                 ANIMDATA_FILTER_CASES(key,
1202                         { /* AnimData blocks - do nothing... */ },
1203                         { /* nla */
1204                                 /* add NLA tracks */
1205                                 items += animdata_filter_nla(anim_data, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
1206                         },
1207                         { /* drivers */
1208                                 /* include shapekey-expand widget? */
1209                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1210                                         ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
1211                                         if (ale) {
1212                                                 BLI_addtail(anim_data, ale);
1213                                                 items++;
1214                                         }
1215                                 }
1216                                 
1217                                 /* add channels */
1218                                 if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1219                                         items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, key, ANIMTYPE_DSSKEY, filter_mode, (ID *)key);
1220                                 }
1221                         },
1222                         { /* action (keyframes) */
1223                                 /* include shapekey-expand widget? */
1224                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1225                                         ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
1226                                         if (ale) {
1227                                                 BLI_addtail(anim_data, ale);
1228                                                 items++;
1229                                         }
1230                                 }
1231                                 
1232                                 /* add channels */
1233                                 if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1234                                         items += animdata_filter_action(anim_data, adt->action, filter_mode, key, ANIMTYPE_DSSKEY, (ID *)key); 
1235                                 }
1236                         }
1237                 );
1238         }
1239
1240         /* Materials? */
1241         if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT))
1242                 items += animdata_filter_dopesheet_mats(anim_data, ads, base, filter_mode);
1243         
1244         /* Object Data */
1245         switch (ob->type) {
1246                 case OB_CAMERA: /* ------- Camera ------------ */
1247                 {
1248                         Camera *ca= (Camera *)ob->data;
1249                         
1250                         if ((ads->filterflag & ADS_FILTER_NOCAM) == 0) {
1251                                 ANIMDATA_FILTER_CASES(ca,
1252                                         { /* AnimData blocks - do nothing... */ },
1253                                         obdata_ok= 1;,
1254                                         obdata_ok= 1;,
1255                                         obdata_ok= 1;)
1256                         }
1257                 }
1258                         break;
1259                 case OB_LAMP: /* ---------- Lamp ----------- */
1260                 {
1261                         Lamp *la= (Lamp *)ob->data;
1262                         
1263                         if ((ads->filterflag & ADS_FILTER_NOLAM) == 0) {
1264                                 ANIMDATA_FILTER_CASES(la,
1265                                         { /* AnimData blocks - do nothing... */ },
1266                                         obdata_ok= 1;,
1267                                         obdata_ok= 1;,
1268                                         obdata_ok= 1;)
1269                         }
1270                 }
1271                         break;
1272                 case OB_CURVE: /* ------- Curve ---------- */
1273                 {
1274                         Curve *cu= (Curve *)ob->data;
1275                         
1276                         if ((ads->filterflag & ADS_FILTER_NOCUR) == 0) {
1277                                 ANIMDATA_FILTER_CASES(cu,
1278                                         { /* AnimData blocks - do nothing... */ },
1279                                         obdata_ok= 1;,
1280                                         obdata_ok= 1;,
1281                                         obdata_ok= 1;)
1282                         }
1283                 }
1284                         break;
1285                 case OB_MBALL: /* ------- MetaBall ---------- */
1286                 {
1287                         MetaBall *mb= (MetaBall *)ob->data;
1288                         
1289                         if ((ads->filterflag & ADS_FILTER_NOMBA) == 0) {
1290                                 ANIMDATA_FILTER_CASES(mb,
1291                                         { /* AnimData blocks - do nothing... */ },
1292                                         obdata_ok= 1;,
1293                                         obdata_ok= 1;,
1294                                         obdata_ok= 1;)
1295                         }
1296                 }
1297                         break;
1298         }
1299         if (obdata_ok) 
1300                 items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode);
1301
1302         /* particles */
1303         if (ob->particlesystem.first && !(ads->filterflag & ADS_FILTER_NOPART))
1304                 items += animdata_filter_dopesheet_particles(anim_data, ads, base, filter_mode);
1305         
1306         /* return the number of items added to the list */
1307         return items;
1308 }       
1309
1310 static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
1311 {
1312         World *wo= sce->world;
1313         AnimData *adt= NULL;
1314         bAnimListElem *ale;
1315         int items = 0;
1316         
1317         /* add scene as a channel first (even if we aren't showing scenes we still need to show the scene's sub-data */
1318         if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) {
1319                 /* check if filtering by selection */
1320                 if (ANIMCHANNEL_SELOK( (sce->flag & SCE_DS_SELECTED) )) {
1321                         ale= make_new_animlistelem(sce, ANIMTYPE_SCENE, NULL, ANIMTYPE_NONE, NULL);
1322                         if (ale) {
1323                                 BLI_addtail(anim_data, ale);
1324                                 items++;
1325                         }
1326                 }
1327         }
1328         
1329         /* if collapsed, don't go any further (unless adding keyframes only) */
1330         if ( (EXPANDED_SCEC(sce) == 0) && !(filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) )
1331                 return items;
1332                 
1333         /* Action, Drivers, or NLA  for Scene */
1334         if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) {
1335                 adt= sce->adt;
1336                 ANIMDATA_FILTER_CASES(sce,
1337                         { /* AnimData blocks - do nothing... */ },
1338                         { /* nla */
1339                                 /* add NLA tracks */
1340                                 items += animdata_filter_nla(anim_data, adt, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce);
1341                         },
1342                         { /* drivers */
1343                                 /* include drivers-expand widget? */
1344                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1345                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, sce, ANIMTYPE_SCENE, (ID *)sce);
1346                                         if (ale) {
1347                                                 BLI_addtail(anim_data, ale);
1348                                                 items++;
1349                                         }
1350                                 }
1351                                 
1352                                 /* add F-Curve channels (drivers are F-Curves) */
1353                                 if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1354                                         items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, sce, ANIMTYPE_SCENE, filter_mode, (ID *)sce);
1355                                 }
1356                         },
1357                         { /* action */
1358                                 /* include action-expand widget? */
1359                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1360                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, sce, ANIMTYPE_SCENE, (ID *)sce);
1361                                         if (ale) {
1362                                                 BLI_addtail(anim_data, ale);
1363                                                 items++;
1364                                         }
1365                                 }
1366                                 
1367                                 /* add F-Curve channels? */
1368                                 if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1369                                         items += animdata_filter_action(anim_data, adt->action, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce); 
1370                                 }
1371                         }
1372                 )
1373         }
1374         
1375         /* world */
1376         if ((wo && wo->adt) && !(ads->filterflag & ADS_FILTER_NOWOR)) {
1377                 /* Action, Drivers, or NLA for World */
1378                 adt= wo->adt;
1379                 ANIMDATA_FILTER_CASES(wo,
1380                         { /* AnimData blocks - do nothing... */ },
1381                         { /* nla */
1382                                 /* add NLA tracks */
1383                                 items += animdata_filter_nla(anim_data, adt, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo);
1384                         },
1385                         { /* drivers */
1386                                 /* include world-expand widget? */
1387                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1388                                         ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)wo);
1389                                         if (ale) {
1390                                                 BLI_addtail(anim_data, ale);
1391                                                 items++;
1392                                         }
1393                                 }
1394                                 
1395                                 /* add F-Curve channels (drivers are F-Curves) */
1396                                 if (FILTER_WOR_SCED(wo)/*EXPANDED_DRVD(adt)*/ || !(filter_mode & ANIMFILTER_CHANNELS)) {
1397                                         // XXX owner info is messed up now...
1398                                         items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, wo, ANIMTYPE_DSWOR, filter_mode, (ID *)wo);
1399                                 }
1400                         },
1401                         { /* action */
1402                                 /* include world-expand widget? */
1403                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1404                                         ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)sce);
1405                                         if (ale) {
1406                                                 BLI_addtail(anim_data, ale);
1407                                                 items++;
1408                                         }
1409                                 }
1410                                 
1411                                 /* add channels */
1412                                 if (FILTER_WOR_SCED(wo) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1413                                         items += animdata_filter_action(anim_data, adt->action, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo); 
1414                                 }
1415                         }
1416                 )
1417         }
1418         
1419         /* return the number of items added to the list */
1420         return items;
1421 }
1422
1423 // 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)
1424 static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int filter_mode)
1425 {
1426         Scene *sce= (Scene *)ads->source;
1427         Base *base;
1428         bAnimListElem *ale;
1429         int items = 0;
1430         
1431         /* check that we do indeed have a scene */
1432         if ((ads->source == NULL) || (GS(ads->source->name)!=ID_SCE)) {
1433                 printf("DopeSheet Error: Not scene! \n");
1434                 return 0;
1435         }
1436         
1437         /* scene-linked animation */
1438         // TODO: sequencer, composite nodes - are we to include those here too?
1439         {
1440                 short sceOk= 0, worOk= 0;
1441                 
1442                 /* check filtering-flags if ok */
1443                 ANIMDATA_FILTER_CASES(sce, 
1444                         {
1445                                 /* for the special AnimData blocks only case, we only need to add
1446                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1447                                  */
1448                                 ANIMDATA_ADD_ANIMDATA(sce);
1449                                 sceOk=0;
1450                         },
1451                         sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, 
1452                         sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, 
1453                         sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);)
1454                 if (sce->world) {
1455                         ANIMDATA_FILTER_CASES(sce->world, 
1456                                 {
1457                                         /* for the special AnimData blocks only case, we only need to add
1458                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
1459                                          */
1460                                         ANIMDATA_ADD_ANIMDATA(sce->world);
1461                                         worOk=0;
1462                                 },
1463                                 worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, 
1464                                 worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, 
1465                                 worOk= !(ads->filterflag & ADS_FILTER_NOWOR);)
1466                 }
1467                 
1468                 /* check if not all bad (i.e. so there is something to show) */
1469                 if ( !(!sceOk && !worOk) ) {
1470                         /* add scene data to the list of filtered channels */
1471                         items += animdata_filter_dopesheet_scene(anim_data, ads, sce, filter_mode);
1472                 }
1473         }
1474         
1475         
1476         /* loop over all bases in the scene */
1477         for (base= sce->base.first; base; base= base->next) {
1478                 /* check if there's an object (all the relevant checks are done in the ob-function) */
1479                 if (base->object) {
1480                         Object *ob= base->object;
1481                         Key *key= ob_get_key(ob);
1482                         short actOk=1, keyOk=1, dataOk=1, matOk=1, partOk=1;
1483                         
1484                         /* firstly, check if object can be included, by the following fanimors:
1485                          *      - if only visible, must check for layer and also viewport visibility
1486                          *      - if only selected, must check if object is selected 
1487                          *      - there must be animation data to edit
1488                          */
1489                         // TODO: if cache is implemented, just check name here, and then 
1490                         if (filter_mode & ANIMFILTER_VISIBLE) {
1491                                 /* layer visibility - we check both object and base, since these may not be in sync yet */
1492                                 if ((sce->lay & (ob->lay|base->lay))==0) continue;
1493                                 
1494                                 /* outliner restrict-flag */
1495                                 if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
1496                         }
1497                         
1498                         /* additionally, dopesheet filtering also affects what objects to consider */
1499                         if (ads->filterflag) {
1500                                 /* check selection and object type filters */
1501                                 if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) || (base == sce->basact)) )  {
1502                                         /* only selected should be shown */
1503                                         continue;
1504                                 }
1505                                 
1506                                 /* check filters for datatypes */
1507                                         /* object */
1508                                 actOk= 0;
1509                                 keyOk= 0;
1510                                 ANIMDATA_FILTER_CASES(ob, 
1511                                         {
1512                                                 /* for the special AnimData blocks only case, we only need to add
1513                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1514                                                  */
1515                                                 ANIMDATA_ADD_ANIMDATA(ob);
1516                                                 actOk=0;
1517                                         },
1518                                         actOk= 1;, 
1519                                         actOk= 1;, 
1520                                         actOk= 1;)
1521                                 if (key) {
1522                                         /* shapekeys */
1523                                         ANIMDATA_FILTER_CASES(key, 
1524                                                 {
1525                                                         /* for the special AnimData blocks only case, we only need to add
1526                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
1527                                                          */
1528                                                         ANIMDATA_ADD_ANIMDATA(key);
1529                                                         keyOk=0;
1530                                                 },
1531                                                 keyOk= 1;, 
1532                                                 keyOk= 1;, 
1533                                                 keyOk= 1;)
1534                                 }
1535                                 
1536                                 /* materials - only for geometric types */
1537                                 matOk= 0; /* by default, not ok... */
1538                                 if ( !(ads->filterflag & ADS_FILTER_NOMAT) && (ob->totcol) && 
1539                                          ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) ) 
1540                                 {
1541                                         int a;
1542                                         
1543                                         /* firstly check that we actuallly have some materials */
1544                                         for (a=0; a < ob->totcol; a++) {
1545                                                 Material *ma= give_current_material(ob, a);
1546                                                 
1547                                                 if (ma) {
1548                                                         /* if material has relevant animation data, break */
1549                                                         ANIMDATA_FILTER_CASES(ma, 
1550                                                                 {
1551                                                                         /* for the special AnimData blocks only case, we only need to add
1552                                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
1553                                                                          */
1554                                                                         ANIMDATA_ADD_ANIMDATA(ma);
1555                                                                         matOk=0;
1556                                                                 },
1557                                                                 matOk= 1;, 
1558                                                                 matOk= 1;, 
1559                                                                 matOk= 1;)
1560                                                 }
1561                                                         
1562                                                 if (matOk) 
1563                                                         break;
1564                                         }
1565                                 }
1566                                 
1567                                 /* data */
1568                                 switch (ob->type) {
1569                                         case OB_CAMERA: /* ------- Camera ------------ */
1570                                         {
1571                                                 Camera *ca= (Camera *)ob->data;
1572                                                 dataOk= 0;
1573                                                 ANIMDATA_FILTER_CASES(ca, 
1574                                                         if ((ads->filterflag & ADS_FILTER_NOCAM)==0) {
1575                                                                 /* for the special AnimData blocks only case, we only need to add
1576                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1577                                                                  */
1578                                                                 ANIMDATA_ADD_ANIMDATA(ca);
1579                                                                 dataOk=0;
1580                                                         },
1581                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, 
1582                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, 
1583                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);)
1584                                         }
1585                                                 break;
1586                                         case OB_LAMP: /* ---------- Lamp ----------- */
1587                                         {
1588                                                 Lamp *la= (Lamp *)ob->data;
1589                                                 dataOk= 0;
1590                                                 ANIMDATA_FILTER_CASES(la, 
1591                                                         if ((ads->filterflag & ADS_FILTER_NOLAM)==0) {
1592                                                                 /* for the special AnimData blocks only case, we only need to add
1593                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1594                                                                  */
1595                                                                 ANIMDATA_ADD_ANIMDATA(la);
1596                                                                 dataOk=0;
1597                                                         },
1598                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, 
1599                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, 
1600                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);)
1601                                         }
1602                                                 break;
1603                                         case OB_CURVE: /* ------- Curve ---------- */
1604                                         {
1605                                                 Curve *cu= (Curve *)ob->data;
1606                                                 dataOk= 0;
1607                                                 ANIMDATA_FILTER_CASES(cu, 
1608                                                         if ((ads->filterflag & ADS_FILTER_NOCUR)==0) {
1609                                                                 /* for the special AnimData blocks only case, we only need to add
1610                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1611                                                                  */
1612                                                                 ANIMDATA_ADD_ANIMDATA(cu);
1613                                                                 dataOk=0;
1614                                                         },
1615                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, 
1616                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, 
1617                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);)
1618                                         }
1619                                                 break;
1620                                         case OB_MBALL: /* ------- MetaBall ---------- */
1621                                         {
1622                                                 MetaBall *mb= (MetaBall *)ob->data;
1623                                                 dataOk= 0;
1624                                                 ANIMDATA_FILTER_CASES(mb, 
1625                                                         if ((ads->filterflag & ADS_FILTER_NOMBA)==0) {
1626                                                                 /* for the special AnimData blocks only case, we only need to add
1627                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
1628                                                                  */
1629                                                                 ANIMDATA_ADD_ANIMDATA(mb);
1630                                                                 dataOk=0;
1631                                                         },
1632                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);, 
1633                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);, 
1634                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);)
1635                                         }
1636                                                 break;
1637                                         default: /* --- other --- */
1638                                                 dataOk= 0;
1639                                                 break;
1640                                 }
1641                                 
1642                                 /* particles */
1643                                 partOk = 0;
1644                                 if (!(ads->filterflag & ADS_FILTER_NOPART) && ob->particlesystem.first) {
1645                                         ParticleSystem *psys = ob->particlesystem.first;
1646                                         for(; psys; psys=psys->next) {
1647                                                 if (psys->part) {
1648                                                         /* if particlesettings has relevant animation data, break */
1649                                                         ANIMDATA_FILTER_CASES(psys->part, 
1650                                                                 {
1651                                                                         /* for the special AnimData blocks only case, we only need to add
1652                                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
1653                                                                          */
1654                                                                         ANIMDATA_ADD_ANIMDATA(psys->part);
1655                                                                         partOk=0;
1656                                                                 },
1657                                                                 partOk= 1;, 
1658                                                                 partOk= 1;, 
1659                                                                 partOk= 1;)
1660                                                 }
1661                                                         
1662                                                 if (partOk) 
1663                                                         break;
1664                                         }
1665                                 }
1666                                 
1667                                 /* check if all bad (i.e. nothing to show) */
1668                                 if (!actOk && !keyOk && !dataOk && !matOk && !partOk)
1669                                         continue;
1670                         }
1671                         else {
1672                                 /* check data-types */
1673                                 actOk= ANIMDATA_HAS_KEYS(ob);
1674                                 keyOk= (key != NULL);
1675                                 
1676                                 /* materials - only for geometric types */
1677                                 matOk= 0; /* by default, not ok... */
1678                                 if (ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) && (ob->totcol)) 
1679                                 {
1680                                         int a;
1681                                         
1682                                         /* firstly check that we actuallly have some materials */
1683                                         for (a=0; a < ob->totcol; a++) {
1684                                                 Material *ma= give_current_material(ob, a);
1685                                                 
1686                                                 if ((ma) && ANIMDATA_HAS_KEYS(ma)) {
1687                                                         matOk= 1;
1688                                                         break;
1689                                                 }
1690                                         }
1691                                 }
1692                                 
1693                                 /* data */
1694                                 switch (ob->type) {
1695                                         case OB_CAMERA: /* ------- Camera ------------ */
1696                                         {
1697                                                 Camera *ca= (Camera *)ob->data;
1698                                                 dataOk= ANIMDATA_HAS_KEYS(ca);                                          
1699                                         }
1700                                                 break;
1701                                         case OB_LAMP: /* ---------- Lamp ----------- */
1702                                         {
1703                                                 Lamp *la= (Lamp *)ob->data;
1704                                                 dataOk= ANIMDATA_HAS_KEYS(la);  
1705                                         }
1706                                                 break;
1707                                         case OB_CURVE: /* -------- Curve ---------- */
1708                                         {
1709                                                 Curve *cu= (Curve *)ob->data;
1710                                                 dataOk= ANIMDATA_HAS_KEYS(cu);  
1711                                         }
1712                                                 break;
1713                                         case OB_MBALL: /* -------- Metas ---------- */
1714                                         {
1715                                                 MetaBall *mb= (MetaBall *)ob->data;
1716                                                 dataOk= ANIMDATA_HAS_KEYS(mb);  
1717                                         }
1718                                                 break;
1719                                         default: /* --- other --- */
1720                                                 dataOk= 0;
1721                                                 break;
1722                                 }
1723                                 
1724                                 /* particles */
1725                                 partOk = 0;
1726                                 if (ob->particlesystem.first) {
1727                                         ParticleSystem *psys = ob->particlesystem.first;
1728                                         for(; psys; psys=psys->next) {
1729                                                 if(psys->part && ANIMDATA_HAS_KEYS(psys->part)) {
1730                                                         partOk = 1;
1731                                                         break;
1732                                                 }
1733                                         }
1734                                 }
1735                                 
1736                                 /* check if all bad (i.e. nothing to show) */
1737                                 if (!actOk && !keyOk && !dataOk && !matOk && !partOk)
1738                                         continue;
1739                         }
1740                         
1741                         /* since we're still here, this object should be usable */
1742                         items += animdata_filter_dopesheet_ob(anim_data, ads, base, filter_mode);
1743                 }
1744         }
1745         
1746         /* return the number of items in the list */
1747         return items;
1748 }
1749
1750 /* ----------- Public API --------------- */
1751
1752 /* This function filters the active data source to leave only animation channels suitable for
1753  * usage by the caller. It will return the length of the list 
1754  * 
1755  *      *anim_data: is a pointer to a ListBase, to which the filtered animation channels
1756  *              will be placed for use.
1757  *      filter_mode: how should the data be filtered - bitmapping accessed flags
1758  */
1759 int ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode, void *data, short datatype)
1760 {
1761         int items = 0;
1762         
1763         /* only filter data if there's somewhere to put it */
1764         if (data && anim_data) {
1765                 bAnimListElem *ale, *next;
1766                 Object *obact= (ac) ? ac->obact : NULL;
1767                 
1768                 /* firstly filter the data */
1769                 switch (datatype) {
1770                         case ANIMCONT_ACTION:
1771                                 items= animdata_filter_action(anim_data, data, filter_mode, NULL, ANIMTYPE_NONE, (ID *)obact);
1772                                 break;
1773                                 
1774                         case ANIMCONT_SHAPEKEY:
1775                                 //items= animdata_filter_shapekey(anim_data, data, filter_mode, NULL, ANIMTYPE_NONE, (ID *)obact);
1776                                 break;
1777                                 
1778                         case ANIMCONT_GPENCIL:
1779                                 //items= animdata_filter_gpencil(anim_data, data, filter_mode);
1780                                 break;
1781                                 
1782                         case ANIMCONT_DOPESHEET:
1783                         case ANIMCONT_FCURVES:
1784                         case ANIMCONT_DRIVERS:
1785                         case ANIMCONT_NLA:
1786                                 items= animdata_filter_dopesheet(anim_data, data, filter_mode);
1787                                 break;
1788                 }
1789                         
1790                 /* remove any weedy entries */
1791                 // XXX this is weedy code!
1792                 for (ale= anim_data->first; ale; ale= next) {
1793                         next= ale->next;
1794                         
1795                         if (ale->type == ANIMTYPE_NONE) {
1796                                 items--;
1797                                 BLI_freelinkN(anim_data, ale);
1798                         }
1799                 }
1800         }
1801         
1802         /* return the number of items in the list */
1803         return items;
1804 }
1805
1806 /* ************************************************************ */