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