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