f631430b03e435b6ded7db89b3b5d5fe1b423b91
[blender-staging.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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
50 #include "DNA_anim_types.h"
51 #include "DNA_armature_types.h"
52 #include "DNA_constraint_types.h"
53 #include "DNA_camera_types.h"
54 #include "DNA_lamp_types.h"
55 #include "DNA_lattice_types.h"
56 #include "DNA_key_types.h"
57 #include "DNA_material_types.h"
58 #include "DNA_mesh_types.h"
59 #include "DNA_meta_types.h"
60 #include "DNA_node_types.h"
61 #include "DNA_particle_types.h"
62 #include "DNA_space_types.h"
63 #include "DNA_sequence_types.h"
64 #include "DNA_scene_types.h"
65 #include "DNA_screen_types.h"
66 #include "DNA_world_types.h"
67 #include "DNA_gpencil_types.h"
68 #include "DNA_object_types.h"
69
70 #include "MEM_guardedalloc.h"
71
72 #include "BLI_blenlib.h"
73 #include "BLI_ghash.h"
74
75 #include "BKE_animsys.h"
76 #include "BKE_action.h"
77 #include "BKE_fcurve.h"
78 #include "BKE_context.h"
79 #include "BKE_global.h"
80 #include "BKE_group.h"
81 #include "BKE_key.h"
82 #include "BKE_material.h"
83 #include "BKE_node.h"
84 #include "BKE_sequencer.h"
85 #include "BKE_utildefines.h"
86
87 #include "ED_anim_api.h"
88
89 /* ************************************************************ */
90 /* Blender Context <-> Animation Context mapping */
91
92 /* ----------- Private Stuff - Action Editor ------------- */
93
94 /* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */
95 /* Note: there's a similar function in key.c (ob_get_key) */
96 Key *actedit_get_shapekeys (bAnimContext *ac, SpaceAction *saction) 
97 {
98         Scene *scene= ac->scene;
99         Object *ob;
100         Key *key;
101         
102         ob = OBACT;
103         if (ob == NULL) 
104                 return NULL;
105         
106         /* XXX pinning is not available in 'ShapeKey' mode... */
107         //if (saction->pin) return NULL;
108         
109         /* shapekey data is stored with geometry data */
110         switch (ob->type) {
111                 case OB_MESH:
112                         key= ((Mesh *)ob->data)->key;
113                         break;
114                         
115                 case OB_LATTICE:
116                         key= ((Lattice *)ob->data)->key;
117                         break;
118                         
119                 case OB_CURVE:
120                 case OB_SURF:
121                         key= ((Curve *)ob->data)->key;
122                         break;
123                         
124                 default:
125                         return NULL;
126         }
127         
128         if (key) {
129                 if (key->type == KEY_RELATIVE)
130                         return key;
131         }
132         
133         return NULL;
134 }
135
136 /* Get data being edited in Action Editor (depending on current 'mode') */
137 static short actedit_get_context (bAnimContext *ac, SpaceAction *saction)
138 {
139         /* sync settings with current view status, then return appropriate data */
140         switch (saction->mode) {
141                 case SACTCONT_ACTION: /* 'Action Editor' */
142                         /* if not pinned, sync with active object */
143                         if (/*saction->pin == 0*/1) {
144                                 if (ac->obact && ac->obact->adt)
145                                         saction->action = ac->obact->adt->action;
146                                 else
147                                         saction->action= NULL;
148                         }
149                         
150                         ac->datatype= ANIMCONT_ACTION;
151                         ac->data= saction->action;
152                         
153                         ac->mode= saction->mode;
154                         return 1;
155                         
156                 case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */
157                         ac->datatype= ANIMCONT_SHAPEKEY;
158                         ac->data= actedit_get_shapekeys(ac, saction);
159                         
160                         ac->mode= saction->mode;
161                         return 1;
162                         
163                 case SACTCONT_GPENCIL: /* Grease Pencil */ // XXX review how this mode is handled...
164                         ac->datatype=ANIMCONT_GPENCIL;
165                         //ac->data= CTX_wm_screen(C); // FIXME: add that dopesheet type thing here!
166                         ac->data= NULL; // !!!
167                         
168                         ac->mode= saction->mode;
169                         return 1;
170                         
171                 case SACTCONT_DOPESHEET: /* DopeSheet */
172                         /* update scene-pointer (no need to check for pinning yet, as not implemented) */
173                         saction->ads.source= (ID *)ac->scene;
174                         
175                         ac->datatype= ANIMCONT_DOPESHEET;
176                         ac->data= &saction->ads;
177                         
178                         ac->mode= saction->mode;
179                         return 1;
180                 
181                 default: /* unhandled yet */
182                         ac->datatype= ANIMCONT_NONE;
183                         ac->data= NULL;
184                         
185                         ac->mode= -1;
186                         return 0;
187         }
188 }
189
190 /* ----------- Private Stuff - Graph Editor ------------- */
191
192 /* Get data being edited in Graph Editor (depending on current 'mode') */
193 static short graphedit_get_context (bAnimContext *ac, SpaceIpo *sipo)
194 {
195         /* init dopesheet data if non-existant (i.e. for old files) */
196         if (sipo->ads == NULL) {
197                 sipo->ads= MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet");
198                 sipo->ads->source= (ID *)ac->scene;
199         }
200         
201         /* set settings for Graph Editor - "Selected = Editable" */
202         if (sipo->flag & SIPO_SELCUVERTSONLY)
203                 sipo->ads->filterflag |= ADS_FILTER_SELEDIT;
204         else
205                 sipo->ads->filterflag &= ~ADS_FILTER_SELEDIT;
206         
207         /* sync settings with current view status, then return appropriate data */
208         switch (sipo->mode) {
209                 case SIPO_MODE_ANIMATION:       /* Animation F-Curve Editor */
210                         /* update scene-pointer (no need to check for pinning yet, as not implemented) */
211                         sipo->ads->source= (ID *)ac->scene;
212                         sipo->ads->filterflag &= ~ADS_FILTER_ONLYDRIVERS;
213                         
214                         ac->datatype= ANIMCONT_FCURVES;
215                         ac->data= sipo->ads;
216                         
217                         ac->mode= sipo->mode;
218                         return 1;
219                 
220                 case SIPO_MODE_DRIVERS:         /* Driver 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_DRIVERS;
226                         ac->data= sipo->ads;
227                         
228                         ac->mode= sipo->mode;
229                         return 1;
230                 
231                 default: /* unhandled yet */
232                         ac->datatype= ANIMCONT_NONE;
233                         ac->data= NULL;
234                         
235                         ac->mode= -1;
236                         return 0;
237         }
238 }
239
240 /* ----------- Private Stuff - NLA Editor ------------- */
241
242 /* Get data being edited in Graph Editor (depending on current 'mode') */
243 static short nlaedit_get_context (bAnimContext *ac, SpaceNla *snla)
244 {
245         /* init dopesheet data if non-existant (i.e. for old files) */
246         if (snla->ads == NULL)
247                 snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
248         
249         /* sync settings with current view status, then return appropriate data */
250         /* update scene-pointer (no need to check for pinning yet, as not implemented) */
251         snla->ads->source= (ID *)ac->scene;
252         snla->ads->filterflag |= ADS_FILTER_ONLYNLA;
253         
254         ac->datatype= ANIMCONT_NLA;
255         ac->data= snla->ads;
256         
257         return 1;
258 }
259
260 /* ----------- Public API --------------- */
261
262 /* Obtain current anim-data context, given that context info from Blender context has already been set 
263  *      - AnimContext to write to is provided as pointer to var on stack so that we don't have
264  *        allocation/freeing costs (which are not that avoidable with channels).
265  */
266 short ANIM_animdata_context_getdata (bAnimContext *ac)
267 {
268         ScrArea *sa= ac->sa;
269         short ok= 0;
270         
271         /* context depends on editor we are currently in */
272         if (sa) {
273                 switch (sa->spacetype) {
274                         case SPACE_ACTION:
275                         {
276                                 SpaceAction *saction= (SpaceAction *)sa->spacedata.first;
277                                 ok= actedit_get_context(ac, saction);
278                         }
279                                 break;
280                                 
281                         case SPACE_IPO:
282                         {
283                                 SpaceIpo *sipo= (SpaceIpo *)sa->spacedata.first;
284                                 ok= graphedit_get_context(ac, sipo);
285                         }
286                                 break;
287                                 
288                         case SPACE_NLA:
289                         {
290                                 SpaceNla *snla= (SpaceNla *)sa->spacedata.first;
291                                 ok= nlaedit_get_context(ac, snla);
292                         }
293                                 break;
294                 }
295         }
296         
297         /* check if there's any valid data */
298         if (ok && ac->data)
299                 return 1;
300         else
301                 return 0;
302 }
303
304 /* Obtain current anim-data context from Blender Context info 
305  *      - AnimContext to write to is provided as pointer to var on stack so that we don't have
306  *        allocation/freeing costs (which are not that avoidable with channels).
307  *      - Clears data and sets the information from Blender Context which is useful
308  */
309 short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac)
310 {
311         ScrArea *sa= CTX_wm_area(C);
312         ARegion *ar= CTX_wm_region(C);
313         Scene *scene= CTX_data_scene(C);
314         
315         /* clear old context info */
316         if (ac == NULL) return 0;
317         memset(ac, 0, sizeof(bAnimContext));
318         
319         /* get useful default context settings from context */
320         ac->scene= scene;
321         if (scene) {
322                 ac->markers= &scene->markers;           
323                 ac->obact= (scene->basact)?  scene->basact->object : NULL;
324         }
325         ac->sa= sa;
326         ac->ar= ar;
327         ac->spacetype= (sa) ? sa->spacetype : 0;
328         ac->regiontype= (ar) ? ar->regiontype : 0;
329         
330         /* get data context info */
331         return ANIM_animdata_context_getdata(ac);
332 }
333
334 /* ************************************************************ */
335 /* Blender Data <-- Filter --> Channels to be operated on */
336
337 /* quick macro to test if AnimData is usable */
338 #define ANIMDATA_HAS_KEYS(id) ((id)->adt && (id)->adt->action)
339
340 /* quick macro to test if AnimData is usable for drivers */
341 #define ANIMDATA_HAS_DRIVERS(id) ((id)->adt && (id)->adt->drivers.first)
342
343 /* quick macro to test if AnimData is usable for NLA */
344 #define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first)
345
346
347 /* Quick macro to test for all three avove usability tests, performing the appropriate provided 
348  * action for each when the AnimData context is appropriate. 
349  *
350  * Priority order for this goes (most important, to least): AnimData blocks, NLA, Drivers, Keyframes.
351  *
352  * For this to work correctly, a standard set of data needs to be available within the scope that this
353  * gets called in: 
354  *      - ListBase anim_data;
355  *      - bDopeSheet *ads;
356  *      - bAnimListElem *ale;
357  *      - int items;
358  *
359  *      - id: ID block which should have an AnimData pointer following it immediately, to use
360  *      - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
361  *      - nlaOk: line or block of code to execute for NLA tracks+strips case
362  *      - driversOk: line or block of code to execute for Drivers case
363  *      - keysOk: line or block of code for Keyframes case
364  *
365  * The checks for the various cases are as follows:
366  *      0) top level: checks for animdata and also that all the F-Curves for the block will be visible
367  *      1) animdata check: for filtering animdata blocks only
368  *      2A) nla tracks: include animdata block's data as there are NLA tracks+strips there
369  *      2B) actions to convert to nla: include animdata block's data as there is an action that can be 
370  *              converted to a new NLA strip, and the filtering options allow this
371  *      3) drivers: include drivers from animdata block (for Drivers mode in Graph Editor)
372  *      4) normal keyframes: only when there is an active action
373  */
374 #define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \
375         {\
376                 if ((id)->adt) {\
377                         if (!(filter_mode & ANIMFILTER_CURVEVISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) {\
378                                 if (filter_mode & ANIMFILTER_ANIMDATA) {\
379                                         adtOk\
380                                 }\
381                                 else if (ads->filterflag & ADS_FILTER_ONLYNLA) {\
382                                         if (ANIMDATA_HAS_NLA(id)) {\
383                                                 nlaOk\
384                                         }\
385                                         else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) && ANIMDATA_HAS_KEYS(id)) {\
386                                                 nlaOk\
387                                         }\
388                                 }\
389                                 else if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) {\
390                                         if (ANIMDATA_HAS_DRIVERS(id)) {\
391                                                 driversOk\
392                                         }\
393                                 }\
394                                 else {\
395                                         if (ANIMDATA_HAS_KEYS(id)) {\
396                                                 keysOk\
397                                         }\
398                                 }\
399                         }\
400                 }\
401         }
402
403
404 /* quick macro to add a pointer to an AnimData block as a channel */
405 #define ANIMDATA_ADD_ANIMDATA(id) \
406         {\
407                 ale= make_new_animlistelem((id)->adt, ANIMTYPE_ANIMDATA, NULL, ANIMTYPE_NONE, (ID *)id);\
408                 if (ale) {\
409                         BLI_addtail(anim_data, ale);\
410                         items++;\
411                 }\
412         }
413         
414 /* quick macro to test if an anim-channel representing an AnimData block is suitably active */
415 #define ANIMCHANNEL_ACTIVEOK(ale) \
416         ( !(filter_mode & ANIMFILTER_ACTIVE) || !(ale->adt) || (ale->adt->flag & ADT_UI_ACTIVE) )
417
418 /* quick macro to test if an anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */
419 #define ANIMCHANNEL_SELOK(test_func) \
420                 ( !(filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) || \
421                   ((filter_mode & ANIMFILTER_SEL) && test_func) || \
422                   ((filter_mode & ANIMFILTER_UNSEL) && test_func==0) ) 
423                   
424 /* quick macro to test if an anim-channel (F-Curve) is selected ok for editing purposes 
425  *      - _SELEDIT means that only selected curves will have visible+editable keyframes
426  *
427  * checks here work as follows:
428  *      1) seledit off - don't need to consider the implications of this option
429  *      2) foredit off - we're not considering editing, so channel is ok still
430  *      3) test_func (i.e. selection test) - only if selected, this test will pass
431  */
432 #define ANIMCHANNEL_SELEDITOK(test_func) \
433                 ( !(filter_mode & ANIMFILTER_SELEDIT) || \
434                   !(filter_mode & ANIMFILTER_FOREDIT) || \
435                   (test_func) )
436
437 /* ----------- 'Private' Stuff --------------- */
438
439 /* this function allocates memory for a new bAnimListElem struct for the 
440  * provided animation channel-data. 
441  */
442 bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, short ownertype, ID *owner_id)
443 {
444         bAnimListElem *ale= NULL;
445         
446         /* only allocate memory if there is data to convert */
447         if (data) {
448                 /* allocate and set generic data */
449                 ale= MEM_callocN(sizeof(bAnimListElem), "bAnimListElem");
450                 
451                 ale->data= data;
452                 ale->type= datatype;
453                         // XXX what is the point of the owner data?
454                         // xxx try and use this to simplify the problem of finding whether parent channels are working...
455                 ale->owner= owner;
456                 ale->ownertype= ownertype;
457                 
458                 ale->id= owner_id;
459                 ale->adt= BKE_animdata_from_id(owner_id);
460                 
461                 /* do specifics */
462                 switch (datatype) {
463                         case ANIMTYPE_SUMMARY:
464                         {
465                                 /* nothing to include for now... this is just a dummy wrappy around all the other channels 
466                                  * in the DopeSheet, and gets included at the start of the list
467                                  */
468                                 ale->key_data= NULL;
469                                 ale->datatype= ALE_ALL;
470                         }
471                                 break;
472                         
473                         case ANIMTYPE_SCENE:
474                         {
475                                 Scene *sce= (Scene *)data;
476                                 
477                                 ale->flag= sce->flag;
478                                 
479                                 ale->key_data= sce;
480                                 ale->datatype= ALE_SCE;
481                                 
482                                 ale->adt= BKE_animdata_from_id(data);
483                         }
484                                 break;
485                         case ANIMTYPE_OBJECT:
486                         {
487                                 Base *base= (Base *)data;
488                                 Object *ob= base->object;
489                                 
490                                 ale->flag= ob->flag;
491                                 
492                                 ale->key_data= ob;
493                                 ale->datatype= ALE_OB;
494                                 
495                                 ale->adt= BKE_animdata_from_id(&ob->id);
496                         }
497                                 break;
498                         case ANIMTYPE_FILLACTD:
499                         {
500                                 bAction *act= (bAction *)data;
501                                 
502                                 ale->flag= act->flag;
503                                 
504                                 ale->key_data= act;
505                                 ale->datatype= ALE_ACT;
506                         }
507                                 break;
508                         case ANIMTYPE_FILLDRIVERS:
509                         {
510                                 AnimData *adt= (AnimData *)data;
511                                 
512                                 ale->flag= adt->flag;
513                                 
514                                         // XXX... drivers don't show summary for now
515                                 ale->key_data= NULL;
516                                 ale->datatype= ALE_NONE;
517                         }
518                                 break;
519                         case ANIMTYPE_FILLMATD:
520                         {
521                                 Object *ob= (Object *)data;
522                                 
523                                 ale->flag= FILTER_MAT_OBJC(ob);
524                                 
525                                 ale->key_data= NULL;
526                                 ale->datatype= ALE_NONE;
527                         }
528                                 break;
529                         case ANIMTYPE_FILLPARTD:
530                         {
531                                 Object *ob= (Object *)data;
532                                 
533                                 ale->flag= FILTER_PART_OBJC(ob);
534                                 
535                                 ale->key_data= NULL;
536                                 ale->datatype= ALE_NONE;
537                         }
538                                 break;
539                         case ANIMTYPE_FILLTEXD:
540                         {
541                                 ID *id= (ID *)data;
542                                 
543                                 switch (GS(id->name)) {
544                                         case ID_MA:
545                                         {
546                                                 Material *ma= (Material *)id;
547                                                 ale->flag= FILTER_TEX_MATC(ma);
548                                         }
549                                                 break;
550                                         case ID_LA:
551                                         {
552                                                 Lamp *la= (Lamp *)id;
553                                                 ale->flag= FILTER_TEX_LAMC(la);
554                                         }
555                                                 break;
556                                         case ID_WO:
557                                         {
558                                                 World *wo= (World *)id;
559                                                 ale->flag= FILTER_TEX_WORC(wo);
560                                         }
561                                                 break;
562                                 }
563                                 
564                                 ale->key_data= NULL;
565                                 ale->datatype= ALE_NONE;
566                         }
567                                 break;
568                         
569                         case ANIMTYPE_DSMAT:
570                         {
571                                 Material *ma= (Material *)data;
572                                 AnimData *adt= ma->adt;
573                                 
574                                 ale->flag= FILTER_MAT_OBJD(ma);
575                                 
576                                 ale->key_data= (adt) ? adt->action : NULL;
577                                 ale->datatype= ALE_ACT;
578                                 
579                                 ale->adt= BKE_animdata_from_id(data);
580                         }
581                                 break;
582                         case ANIMTYPE_DSLAM:
583                         {
584                                 Lamp *la= (Lamp *)data;
585                                 AnimData *adt= la->adt;
586                                 
587                                 ale->flag= FILTER_LAM_OBJD(la);
588                                 
589                                 ale->key_data= (adt) ? adt->action : NULL;
590                                 ale->datatype= ALE_ACT;
591                                 
592                                 ale->adt= BKE_animdata_from_id(data);
593                         }
594                                 break;
595                         case ANIMTYPE_DSCAM:
596                         {
597                                 Camera *ca= (Camera *)data;
598                                 AnimData *adt= ca->adt;
599                                 
600                                 ale->flag= FILTER_CAM_OBJD(ca);
601                                 
602                                 ale->key_data= (adt) ? adt->action : NULL;
603                                 ale->datatype= ALE_ACT;
604                                 
605                                 ale->adt= BKE_animdata_from_id(data);
606                         }
607                                 break;
608                         case ANIMTYPE_DSCUR:
609                         {
610                                 Curve *cu= (Curve *)data;
611                                 AnimData *adt= cu->adt;
612                                 
613                                 ale->flag= FILTER_CUR_OBJD(cu);
614                                 
615                                 ale->key_data= (adt) ? adt->action : NULL;
616                                 ale->datatype= ALE_ACT;
617                                 
618                                 ale->adt= BKE_animdata_from_id(data);
619                         }
620                                 break;
621                         case ANIMTYPE_DSARM:
622                         {
623                                 bArmature *arm= (bArmature *)data;
624                                 AnimData *adt= arm->adt;
625                                 
626                                 ale->flag= FILTER_ARM_OBJD(arm);
627                                 
628                                 ale->key_data= (adt) ? adt->action : NULL;
629                                 ale->datatype= ALE_ACT;
630                                 
631                                 ale->adt= BKE_animdata_from_id(data);
632                         }
633                                 break;
634                         case ANIMTYPE_DSMESH:
635                         {
636                                 Mesh *me= (Mesh *)data;
637                                 AnimData *adt= me->adt;
638                                 
639                                 ale->flag= FILTER_MESH_OBJD(me);
640                                 
641                                 ale->key_data= (adt) ? adt->action : NULL;
642                                 ale->datatype= ALE_ACT;
643                                 
644                                 ale->adt= BKE_animdata_from_id(data);
645                         }
646                                 break;
647                         case ANIMTYPE_DSSKEY:
648                         {
649                                 Key *key= (Key *)data;
650                                 AnimData *adt= key->adt;
651                                 
652                                 ale->flag= FILTER_SKE_OBJD(key); 
653                                 
654                                 ale->key_data= (adt) ? adt->action : NULL;
655                                 ale->datatype= ALE_ACT;
656                                 
657                                 ale->adt= BKE_animdata_from_id(data);
658                         }
659                                 break;
660                         case ANIMTYPE_DSWOR:
661                         {
662                                 World *wo= (World *)data;
663                                 AnimData *adt= wo->adt;
664                                 
665                                 ale->flag= FILTER_WOR_SCED(wo); 
666                                 
667                                 ale->key_data= (adt) ? adt->action : NULL;
668                                 ale->datatype= ALE_ACT;
669                                 
670                                 ale->adt= BKE_animdata_from_id(data);
671                         }
672                                 break;
673                         case ANIMTYPE_DSNTREE:
674                         {
675                                 bNodeTree *ntree= (bNodeTree *)data;
676                                 AnimData *adt= ntree->adt;
677                                 
678                                 ale->flag= FILTER_NTREE_SCED(ntree); 
679                                 
680                                 ale->key_data= (adt) ? adt->action : NULL;
681                                 ale->datatype= ALE_ACT;
682                                 
683                                 ale->adt= BKE_animdata_from_id(data);
684                         }
685                                 break;
686                         case ANIMTYPE_DSPART:
687                         {
688                                 ParticleSettings *part= (ParticleSettings*)ale->data;
689                                 AnimData *adt= part->adt;
690                                 
691                                 ale->flag= FILTER_PART_OBJD(part); 
692                                 
693                                 ale->key_data= (adt) ? adt->action : NULL;
694                                 ale->datatype= ALE_ACT;
695                                 
696                                 ale->adt= BKE_animdata_from_id(data);
697                         }
698                                 break;
699                         case ANIMTYPE_DSTEX:
700                         {
701                                 Tex *tex= (Tex *)data;
702                                 AnimData *adt= tex->adt;
703                                 
704                                 ale->flag= FILTER_TEX_DATA(tex); 
705                                 
706                                 ale->key_data= (adt) ? adt->action : NULL;
707                                 ale->datatype= ALE_ACT;
708                                 
709                                 ale->adt= BKE_animdata_from_id(data);
710                         }
711                                 break;
712                                 
713                         case ANIMTYPE_GROUP:
714                         {
715                                 bActionGroup *agrp= (bActionGroup *)data;
716                                 
717                                 ale->flag= agrp->flag;
718                                 
719                                 ale->key_data= NULL;
720                                 ale->datatype= ALE_GROUP;
721                         }
722                                 break;
723                         case ANIMTYPE_FCURVE:
724                         {
725                                 FCurve *fcu= (FCurve *)data;
726                                 
727                                 ale->flag= fcu->flag;
728                                 
729                                 ale->key_data= fcu;
730                                 ale->datatype= ALE_FCURVE;
731                         }
732                                 break;
733                                 
734                         case ANIMTYPE_SHAPEKEY:
735                         {
736                                 KeyBlock *kb= (KeyBlock *)data;
737                                 Key *key= (Key *)ale->id;
738                                 
739                                 ale->flag= kb->flag;
740                                 
741                                 /* whether we have keyframes depends on whether there is a Key block to find it from */
742                                 if (key) {
743                                         /* index of shapekey is defined by place in key's list */
744                                         ale->index= BLI_findindex(&key->block, kb);
745                                         
746                                         /* the corresponding keyframes are from the animdata */
747                                         if (ale->adt && ale->adt->action) {
748                                                 bAction *act= ale->adt->action;
749                                                 char *rna_path = key_get_curValue_rnaPath(key, kb);
750                                                 
751                                                 /* try to find the F-Curve which corresponds to this exactly,
752                                                  * then free the MEM_alloc'd string
753                                                  */
754                                                 if (rna_path) {
755                                                         ale->key_data= (void *)list_find_fcurve(&act->curves, rna_path, 0);
756                                                         MEM_freeN(rna_path);
757                                                 }
758                                         }
759                                         ale->datatype= (ale->key_data)? ALE_FCURVE : ALE_NONE;
760                                 }
761                         }       
762                                 break;
763                         
764                         case ANIMTYPE_GPLAYER:
765                         {
766                                 bGPDlayer *gpl= (bGPDlayer *)data;
767                                 
768                                 ale->flag= gpl->flag;
769                                 
770                                 ale->key_data= NULL;
771                                 ale->datatype= ALE_GPFRAME;
772                         }
773                                 break;
774                                 
775                         case ANIMTYPE_NLATRACK:
776                         {
777                                 NlaTrack *nlt= (NlaTrack *)data;
778                                 
779                                 ale->flag= nlt->flag;
780                                 
781                                 ale->key_data= &nlt->strips;
782                                 ale->datatype= ALE_NLASTRIP;
783                         }
784                                 break;
785                         case ANIMTYPE_NLAACTION:
786                         {
787                                 /* nothing to include for now... nothing editable from NLA-perspective here */
788                                 ale->key_data= NULL;
789                                 ale->datatype= ALE_NONE;
790                         }
791                                 break;
792                 }
793         }
794         
795         /* return created datatype */
796         return ale;
797 }
798  
799 /* ----------------------------------------- */
800
801 /* NOTE: when this function returns true, the F-Curve is to be skipped */
802 static int skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode)
803 {
804         if (GS(owner_id->name) == ID_OB) {
805                 Object *ob= (Object *)owner_id;
806                 
807                 /* only consider if F-Curve involves pose.bones */
808                 if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) {
809                         bPoseChannel *pchan;
810                         char *bone_name;
811                         
812                         /* get bone-name, and check if this bone is selected */
813                         bone_name= BLI_getQuotedStr(fcu->rna_path, "pose.bones[");
814                         pchan= get_pose_channel(ob->pose, bone_name);
815                         if (bone_name) MEM_freeN(bone_name);
816                         
817                         /* check whether to continue or skip */
818                         if ((pchan) && (pchan->bone)) {
819                                 /* if only visible channels, skip if bone not visible unless user wants channels from hidden data too */
820                                 if ((filter_mode & ANIMFILTER_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
821                                         bArmature *arm= (bArmature *)ob->data;
822                                         
823                                         if ((arm->layer & pchan->bone->layer) == 0)
824                                                 return 1;
825                                 }
826                                 
827                                 /* can only add this F-Curve if it is selected */
828                                 if ((pchan->bone->flag & BONE_SELECTED) == 0)
829                                         return 1;
830                         }
831                 }
832         }
833         else if (GS(owner_id->name) == ID_SCE) {
834                 Scene *scene = (Scene *)owner_id;
835                 
836                 /* only consider if F-Curve involves sequence_editor.sequences */
837                 if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
838                         Editing *ed= seq_give_editing(scene, FALSE);
839                         Sequence *seq;
840                         char *seq_name;
841                         
842                         /* get strip name, and check if this strip is selected */
843                         seq_name= BLI_getQuotedStr(fcu->rna_path, "sequences_all[");
844                         seq = get_seq_by_name(ed->seqbasep, seq_name, FALSE);
845                         if (seq_name) MEM_freeN(seq_name);
846                         
847                         /* can only add this F-Curve if it is selected */
848                         if (seq==NULL || (seq->flag & SELECT)==0)
849                                 return 1;
850                 }
851         }
852         else if (GS(owner_id->name) == ID_NT) {
853                 bNodeTree *ntree = (bNodeTree *)owner_id;
854                 
855                 /* check for selected  nodes */
856                 if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) {
857                         bNode *node;
858                         char *node_name;
859                         
860                         /* get strip name, and check if this strip is selected */
861                         node_name= BLI_getQuotedStr(fcu->rna_path, "nodes[");
862                         node = nodeFindNodebyName(ntree, node_name);
863                         if (node_name) MEM_freeN(node_name);
864                         
865                         /* can only add this F-Curve if it is selected */
866                         if ((node) && (node->flag & NODE_SELECT)==0)
867                                 return 1;
868                 }
869         }
870         return 0;
871 }
872
873 /* find the next F-Curve that is usable for inclusion */
874 static FCurve *animdata_filter_fcurve_next (bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id)
875 {
876         FCurve *fcu = NULL;
877         
878         /* loop over F-Curves - assume that the caller of this has already checked that these should be included 
879          * NOTE: we need to check if the F-Curves belong to the same group, as this gets called for groups too...
880          */
881         for (fcu= first; ((fcu) && (fcu->grp==grp)); fcu= fcu->next) {
882                 /* special exception for Pose-Channel Based F-Curves:
883                  *      - the 'Only Selected' data filter should be applied to Pose-Channel data too, but those are
884                  *        represented as F-Curves. The way the filter for objects worked was to be the first check
885                  *        after 'normal' visibility, so this is done first here too...
886                  *      - we currently use an 'approximate' method for getting these F-Curves that doesn't require
887                  *        carefully checking the entire path
888                  *      - this will also affect things like Drivers, and also works for Bone Constraints
889                  */
890                 if ( ((ads) && (ads->filterflag & ADS_FILTER_ONLYSEL)) && (owner_id) ) {
891                         if (skip_fcurve_selected_data(ads, fcu, owner_id, filter_mode))
892                                 continue;
893                 }
894                         
895                 /* only include if visible (Graph Editor check, not channels check) */
896                 if (!(filter_mode & ANIMFILTER_CURVEVISIBLE) || (fcu->flag & FCURVE_VISIBLE)) {
897                         /* only work with this channel and its subchannels if it is editable */
898                         if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) {
899                                 /* only include this curve if selected in a way consistent with the filtering requirements */
900                                 if ( ANIMCHANNEL_SELOK(SEL_FCU(fcu)) && ANIMCHANNEL_SELEDITOK(SEL_FCU(fcu)) ) {
901                                         /* only include if this curve is active */
902                                         if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
903                                                 /* this F-Curve can be used, so return it */
904                                                 return fcu;
905                                         }
906                                 }
907                         }
908                 }
909         }
910         
911         /* no (more) F-Curves from the list are suitable... */
912         return NULL;
913 }
914
915 static int animdata_filter_fcurves (ListBase *anim_data, bDopeSheet *ads, FCurve *first, bActionGroup *grp, void *owner, short ownertype, int filter_mode, ID *owner_id)
916 {
917         FCurve *fcu;
918         int items = 0;
919         
920         /* loop over every F-Curve able to be included 
921          *      - this for-loop works like this: 
922          *              1) the starting F-Curve is assigned to the fcu pointer so that we have a starting point to search from
923          *              2) the first valid F-Curve to start from (which may include the one given as 'first') in the remaining 
924          *                 list of F-Curves is found, and verified to be non-null
925          *              3) the F-Curve referenced by fcu pointer is added to the list
926          *              4) the fcu pointer is set to the F-Curve after the one we just added, so that we can keep going through 
927          *                 the rest of the F-Curve list without an eternal loop. Back to step 2 :)
928          */
929         for (fcu=first; ( (fcu = animdata_filter_fcurve_next(ads, fcu, grp, filter_mode, owner_id)) ); fcu=fcu->next)
930         {
931                 bAnimListElem *ale = make_new_animlistelem(fcu, ANIMTYPE_FCURVE, owner, ownertype, owner_id);
932                 
933                 if (ale) {
934                         BLI_addtail(anim_data, ale);
935                         items++;
936                 }
937         }
938         
939         /* return the number of items added to the list */
940         return items;
941 }
942
943 static int animdata_filter_action (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAction *act, int filter_mode, void *owner, short ownertype, ID *owner_id)
944 {
945         bAnimListElem *ale=NULL;
946         bActionGroup *agrp;
947         FCurve *lastchan=NULL;
948         int items = 0;
949         
950         /* don't include anything from this action if it is linked in from another file,
951          * and we're getting stuff for editing...
952          */
953         // TODO: need a way of tagging other channels that may also be affected...
954         if ((filter_mode & ANIMFILTER_FOREDIT) && (act->id.lib))
955                 return 0;
956         
957         /* loop over groups */
958         // TODO: in future, should we expect to need nested groups?
959         for (agrp= act->groups.first; agrp; agrp= agrp->next) {
960                 FCurve *first_fcu;
961                 int filter_gmode;
962                 
963                 /* store reference to last channel of group */
964                 if (agrp->channels.last) 
965                         lastchan= agrp->channels.last;
966                 
967                 
968                 /* make a copy of filtering flags for use by the sub-channels of this group */
969                 filter_gmode= filter_mode;
970                 
971                 /* if we care about the selection status of the channels, 
972                  * but the group isn't expanded...
973                  */
974                 if ( (filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) &&       /* care about selection status */
975                          (EXPANDED_AGRP(agrp)==0) )                                                             /* group isn't expanded */
976                 {
977                         /* if the group itself isn't selected appropriately, we shouldn't consider it's children either */
978                         if (ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) == 0)
979                                 continue;
980                         
981                         /* if we're still here, then the selection status of the curves within this group should not matter,
982                          * since this creates too much overhead for animators (i.e. making a slow workflow)
983                          *
984                          * Tools affected by this at time of coding (2010 Feb 09):
985                          *      - inserting keyframes on selected channels only
986                          *      - pasting keyframes
987                          *      - creating ghost curves in Graph Editor
988                          */
989                         filter_gmode &= ~(ANIMFILTER_SEL|ANIMFILTER_UNSEL);
990                 }
991                 
992                 
993                 /* get the first F-Curve in this group we can start to use, and if there isn't any F-Curve to start from,  
994                  * then don't use this group at all...
995                  *
996                  * NOTE: use filter_gmode here not filter_mode, since there may be some flags we shouldn't consider under certain circumstances
997                  */
998                 first_fcu = animdata_filter_fcurve_next(ads, agrp->channels.first, agrp, filter_gmode, owner_id);
999                 
1000                 /* Bug note: 
1001                  *      Selecting open group to toggle visbility of the group, where the F-Curves of the group are not suitable 
1002                  *      for inclusion due to their selection status (vs visibility status of bones/etc., as is usually the case),
1003                  *      will not work, since the group gets skipped. However, fixing this can easily reintroduce the bugs whereby
1004                  *      hidden groups (due to visibility status of bones/etc.) that were selected before becoming invisible, can
1005                  *      easily get deleted accidentally as they'd be included in the list filtered for that purpose.
1006                  *
1007                  *      So, for now, best solution is to just leave this note here, and hope to find a solution at a later date.
1008                  *      -- Joshua Leung, 2010 Feb 10
1009                  */
1010                 if (first_fcu) {
1011                         /* add this group as a channel first */
1012                         if ((filter_mode & ANIMFILTER_CHANNELS) || !(filter_mode & ANIMFILTER_CURVESONLY)) {
1013                                 /* filter selection of channel specially here again, since may be open and not subject to previous test */
1014                                 if ( ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) ) {
1015                                         ale= make_new_animlistelem(agrp, ANIMTYPE_GROUP, NULL, ANIMTYPE_NONE, owner_id);
1016                                         if (ale) {
1017                                                 BLI_addtail(anim_data, ale);
1018                                                 items++;
1019                                         }
1020                                 }
1021                         }
1022                         
1023                         /* there are some situations, where only the channels of the action group should get considered */
1024                         if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) {
1025                                 /* filters here are a bit convoulted...
1026                                  *      - groups show a "summary" of keyframes beside their name which must accessable for tools which handle keyframes
1027                                  *      - groups can be collapsed (and those tools which are only interested in channels rely on knowing that group is closed)
1028                                  *
1029                                  * cases when we should include F-Curves inside group:
1030                                  *      - we don't care about visibility
1031                                  *      - group is expanded
1032                                  *      - we just need the F-Curves present
1033                                  */
1034                                 if ( (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_AGRP(agrp)) || (filter_mode & ANIMFILTER_CURVESONLY) ) 
1035                                 {
1036                                         /* for the Graph Editor, curves may be set to not be visible in the view to lessen clutter,
1037                                          * but to do this, we need to check that the group doesn't have it's not-visible flag set preventing 
1038                                          * all its sub-curves to be shown
1039                                          */
1040                                         if ( !(filter_mode & ANIMFILTER_CURVEVISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE) )
1041                                         {
1042                                                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
1043                                                         /* NOTE: filter_gmode is used here, not standard filter_mode, since there may be some flags that shouldn't apply */
1044                                                         items += animdata_filter_fcurves(anim_data, ads, first_fcu, agrp, owner, ownertype, filter_gmode, owner_id);
1045                                                 }
1046                                         }
1047                                 }
1048                         }
1049                 }
1050         }
1051         
1052         /* loop over un-grouped F-Curves (only if we're not only considering those channels in the animive group) */
1053         if (!(filter_mode & ANIMFILTER_ACTGROUPED))  {
1054                 // XXX the 'owner' info here needs review...
1055                 items += animdata_filter_fcurves(anim_data, ads, (lastchan)?(lastchan->next):(act->curves.first), NULL, owner, ownertype, filter_mode, owner_id);
1056         }
1057         
1058         /* return the number of items added to the list */
1059         return items;
1060 }
1061
1062 /* Include NLA-Data for NLA-Editor:
1063  *      - when ANIMFILTER_CHANNELS is used, that means we should be filtering the list for display
1064  *        Although the evaluation order is from the first track to the last and then apply the Action on top,
1065  *        we present this in the UI as the Active Action followed by the last track to the first so that we 
1066  *        get the evaluation order presented as per a stack.
1067  *      - for normal filtering (i.e. for editing), we only need the NLA-tracks but they can be in 'normal' evaluation
1068  *        order, i.e. first to last. Otherwise, some tools may get screwed up.
1069  */
1070 static int animdata_filter_nla (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, void *owner, short ownertype, ID *owner_id)
1071 {
1072         bAnimListElem *ale;
1073         NlaTrack *nlt;
1074         NlaTrack *first=NULL, *next=NULL;
1075         int items = 0;
1076         
1077         /* if showing channels, include active action */
1078         if (filter_mode & ANIMFILTER_CHANNELS) {
1079                 /* there isn't really anything editable here, so skip if need editable */
1080                 // TODO: currently, selection isn't checked since it doesn't matter
1081                 if ((filter_mode & ANIMFILTER_FOREDIT) == 0) { 
1082                         /* just add the action track now (this MUST appear for drawing)
1083                          *      - as AnimData may not have an action, we pass a dummy pointer just to get the list elem created, then
1084                          *        overwrite this with the real value - REVIEW THIS...
1085                          */
1086                         ale= make_new_animlistelem((void *)(&adt->action), ANIMTYPE_NLAACTION, owner, ownertype, owner_id);
1087                         ale->data= (adt->action) ? adt->action : NULL;
1088                                 
1089                         if (ale) {
1090                                 BLI_addtail(anim_data, ale);
1091                                 items++;
1092                         }
1093                 }
1094                 
1095                 /* first track to include will be the last one if we're filtering by channels */
1096                 first= adt->nla_tracks.last;
1097         }
1098         else {
1099                 /* first track to include will the the first one (as per normal) */
1100                 first= adt->nla_tracks.first;
1101         }
1102         
1103         /* loop over NLA Tracks - assume that the caller of this has already checked that these should be included */
1104         for (nlt= first; nlt; nlt= next) {
1105                 /* 'next' NLA-Track to use depends on whether we're filtering for drawing or not */
1106                 if (filter_mode & ANIMFILTER_CHANNELS) 
1107                         next= nlt->prev;
1108                 else
1109                         next= nlt->next;
1110                 
1111                 /* if we're in NLA-tweakmode, don't show this track if it was disabled (due to tweaking) for now 
1112                  *      - active track should still get shown though (even though it has disabled flag set)
1113                  */
1114                 // FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel
1115                 if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && !(nlt->flag & NLATRACK_ACTIVE))
1116                         continue;
1117                 
1118                 /* only work with this channel and its subchannels if it is editable */
1119                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) {
1120                         /* only include this track if selected in a way consistent with the filtering requirements */
1121                         if ( ANIMCHANNEL_SELOK(SEL_NLT(nlt)) ) {
1122                                 /* only include if this track is active */
1123                                 if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
1124                                         ale= make_new_animlistelem(nlt, ANIMTYPE_NLATRACK, owner, ownertype, owner_id);
1125                                                 
1126                                         if (ale) {
1127                                                 BLI_addtail(anim_data, ale);
1128                                                 items++;
1129                                         }
1130                                 }
1131                         }
1132                 }
1133         }
1134         
1135         /* return the number of items added to the list */
1136         return items;
1137 }
1138
1139 /* Include ShapeKey Data for ShapeKey Editor */
1140 static int animdata_filter_shapekey (bAnimContext *ac, ListBase *anim_data, Key *key, int filter_mode)
1141 {
1142         bAnimListElem *ale;
1143         int items = 0;
1144         
1145         /* check if channels or only F-Curves */
1146         if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) {
1147                 KeyBlock *kb;
1148                 
1149                 /* loop through the channels adding ShapeKeys as appropriate */
1150                 for (kb= key->block.first; kb; kb= kb->next) {
1151                         /* skip the first one, since that's the non-animateable basis */
1152                         // XXX maybe in future this may become handy?
1153                         if (kb == key->block.first) continue;
1154                         
1155                         /* only work with this channel and its subchannels if it is editable */
1156                         if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_SHAPEKEY(kb)) {
1157                                 /* only include this track if selected in a way consistent with the filtering requirements */
1158                                 if ( ANIMCHANNEL_SELOK(SEL_SHAPEKEY(kb)) ) {
1159                                         // TODO: consider 'active' too?
1160                                         
1161                                         /* owner-id here must be key so that the F-Curve can be resolved... */
1162                                         ale= make_new_animlistelem(kb, ANIMTYPE_SHAPEKEY, NULL, ANIMTYPE_NONE, (ID *)key);
1163                                         
1164                                         if (ale) {
1165                                                 BLI_addtail(anim_data, ale);
1166                                                 items++;
1167                                         }
1168                                 }
1169                         }
1170                 }
1171         }
1172         else {
1173                 /* just use the action associated with the shapekey */
1174                 // FIXME: is owner-id and having no owner/dopesheet really fine?
1175                 if (key->adt) {
1176                         if (filter_mode & ANIMFILTER_ANIMDATA)
1177                                 ANIMDATA_ADD_ANIMDATA(key)
1178                         else if (key->adt->action)
1179                                 items= animdata_filter_action(ac, anim_data, NULL, key->adt->action, filter_mode, NULL, ANIMTYPE_NONE, (ID *)key);
1180                 }
1181         }
1182         
1183         /* return the number of items added to the list */
1184         return items;
1185 }
1186
1187 #if 0
1188 // FIXME: switch this to use the bDopeSheet...
1189 static int animdata_filter_gpencil (ListBase *anim_data, bScreen *sc, int filter_mode)
1190 {
1191         bAnimListElem *ale;
1192         ScrArea *sa, *curarea;
1193         bGPdata *gpd;
1194         bGPDlayer *gpl;
1195         int items = 0;
1196         
1197         /* check if filtering types are appropriate */
1198         {
1199                 /* special hack for fullscreen area (which must be this one then):
1200                  *      - we use the curarea->full as screen to get spaces from, since the
1201                  *        old (pre-fullscreen) screen was stored there...
1202                  *      - this is needed as all data would otherwise disappear
1203                  */
1204                 // XXX need to get new alternative for curarea
1205                 if ((curarea->full) && (curarea->spacetype==SPACE_ACTION))
1206                         sc= curarea->full;
1207                 
1208                 /* loop over spaces in current screen, finding gpd blocks (could be slow!) */
1209                 for (sa= sc->areabase.first; sa; sa= sa->next) {
1210                         /* try to get gp data */
1211                         // XXX need to put back grease pencil api...
1212                         gpd= gpencil_data_get_active(sa);
1213                         if (gpd == NULL) continue;
1214                         
1215                         /* add gpd as channel too (if for drawing, and it has layers) */
1216                         if ((filter_mode & ANIMFILTER_CHANNELS) && (gpd->layers.first)) {
1217                                 /* add to list */
1218                                 ale= make_new_animlistelem(gpd, ANIMTYPE_GPDATABLOCK, sa, ANIMTYPE_SPECIALDATA);
1219                                 if (ale) {
1220                                         BLI_addtail(anim_data, ale);
1221                                         items++;
1222                                 }
1223                         }
1224                         
1225                         /* only add layers if they will be visible (if drawing channels) */
1226                         if ( !(filter_mode & ANIMFILTER_VISIBLE) || (EXPANDED_GPD(gpd)) ) {
1227                                 /* loop over layers as the conditions are acceptable */
1228                                 for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
1229                                         /* only if selected */
1230                                         if ( ANIMCHANNEL_SELOK(SEL_GPL(gpl)) ) {
1231                                                 /* only if editable */
1232                                                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) {
1233                                                         /* add to list */
1234                                                         ale= make_new_animlistelem(gpl, ANIMTYPE_GPLAYER, gpd, ANIMTYPE_GPDATABLOCK);
1235                                                         if (ale) {
1236                                                                 BLI_addtail(anim_data, ale);
1237                                                                 items++;
1238                                                         }
1239                                                 }
1240                                         }
1241                                 }
1242                         }
1243                 }
1244         }
1245         
1246         /* return the number of items added to the list */
1247         return items;
1248 }
1249 #endif 
1250
1251 /* NOTE: owner_id is either material, lamp, or world block, which is the direct owner of the texture stack in question */
1252 static int animdata_filter_dopesheet_texs (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, int filter_mode)
1253 {
1254         ListBase texs = {NULL, NULL};
1255         LinkData *ld;
1256         MTex **mtex = NULL;
1257         short expanded=0;
1258         int ownertype = ANIMTYPE_NONE;
1259         
1260         bAnimListElem *ale=NULL;
1261         int items=0, a=0;
1262         
1263         /* get datatype specific data first */
1264         if (owner_id == NULL)
1265                 return 0;
1266         
1267         switch (GS(owner_id->name)) {
1268                 case ID_MA:
1269                 {
1270                         Material *ma= (Material *)owner_id;
1271                         
1272                         mtex= (MTex**)(&ma->mtex);
1273                         expanded= FILTER_TEX_MATC(ma);
1274                         ownertype= ANIMTYPE_DSMAT;
1275                 }
1276                         break;
1277                 case ID_LA:
1278                 {
1279                         Lamp *la= (Lamp *)owner_id;
1280                         
1281                         mtex= (MTex**)(&la->mtex);
1282                         expanded= FILTER_TEX_LAMC(la);
1283                         ownertype= ANIMTYPE_DSLAM;
1284                 }
1285                         break;
1286                 case ID_WO:
1287                 {
1288                         World *wo= (World *)owner_id;
1289                         
1290                         mtex= (MTex**)(&wo->mtex);
1291                         expanded= FILTER_TEX_WORC(wo);
1292                         ownertype= ANIMTYPE_DSWOR;
1293                 }
1294                         break;
1295                 default: 
1296                 {
1297                         /* invalid/unsupported option */
1298                         if (G.f & G_DEBUG)
1299                                 printf("ERROR: unsupported owner_id (i.e. texture stack) for filter textures - %s \n", owner_id->name);
1300                         return 0;
1301                 }
1302         }
1303         
1304         /* firstly check that we actuallly have some textures, by gathering all textures in a temp list */
1305         for (a=0; a < MAX_MTEX; a++) {
1306                 Tex *tex= (mtex[a]) ? mtex[a]->tex : NULL;
1307                 short ok = 0;
1308                 
1309                 /* for now, if no texture returned, skip (this shouldn't confuse the user I hope) */
1310                 if (ELEM(NULL, tex, tex->adt)) 
1311                         continue;
1312                 
1313                 /* check if ok */
1314                 ANIMDATA_FILTER_CASES(tex, 
1315                         { /* AnimData blocks - do nothing... */ },
1316                         ok=1;, 
1317                         ok=1;, 
1318                         ok=1;)
1319                 if (ok == 0) continue;
1320                 
1321                 /* make a temp list elem for this */
1322                 ld= MEM_callocN(sizeof(LinkData), "DopeSheet-TextureCache");
1323                 ld->data= tex;
1324                 BLI_addtail(&texs, ld);
1325         }
1326         
1327         /* if there were no channels found, no need to carry on */
1328         if (texs.first == NULL)
1329                 return 0;
1330         
1331         /* include textures-expand widget? */
1332         if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1333                 ale= make_new_animlistelem(owner_id, ANIMTYPE_FILLTEXD, owner_id, ownertype, owner_id);
1334                 if (ale) {
1335                         BLI_addtail(anim_data, ale);
1336                         items++;
1337                 }
1338         }
1339         
1340         /* add textures */
1341         if ((expanded) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1342                 /* for each texture in cache, add channels  */
1343                 for (ld= texs.first; ld; ld= ld->next) {
1344                         Tex *tex= (Tex *)ld->data;
1345                         
1346                         /* include texture-expand widget? */
1347                         if (filter_mode & ANIMFILTER_CHANNELS) {
1348                                 /* check if filtering by active status */
1349                                 if ANIMCHANNEL_ACTIVEOK(tex) {
1350                                         ale= make_new_animlistelem(tex, ANIMTYPE_DSTEX, owner_id, ownertype, owner_id);
1351                                         if (ale) {
1352                                                 BLI_addtail(anim_data, ale);
1353                                                 items++;
1354                                         }
1355                                 }
1356                         }
1357                         
1358                         /* add texture's animation data
1359                          * NOTE: for these, we make the owner/ownertype the material/lamp/etc. not the texture, otherwise the
1360                          * drawing code cannot resolve the indention easily
1361                          */
1362                         if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_TEX_DATA(tex) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1363                                 ANIMDATA_FILTER_CASES(tex, 
1364                                         { /* AnimData blocks - do nothing... */ },
1365                                         items += animdata_filter_nla(ac, anim_data, ads, tex->adt, filter_mode, owner_id, ownertype, (ID *)tex);, 
1366                                         items += animdata_filter_fcurves(anim_data, ads, tex->adt->drivers.first, NULL, owner_id, ownertype, filter_mode, (ID *)tex);, 
1367                                         items += animdata_filter_action(ac, anim_data, ads, tex->adt->action, filter_mode, owner_id, ownertype, (ID *)tex);)
1368                         }
1369                 }
1370         }
1371         
1372         /* free cache */
1373         BLI_freelistN(&texs);
1374         
1375         /* return the number of items added to the list */
1376         return items;
1377 }
1378
1379 static int animdata_filter_dopesheet_mats (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1380 {
1381         ListBase mats = {NULL, NULL};
1382         LinkData *ld;
1383         
1384         bAnimListElem *ale=NULL;
1385         Object *ob= base->object;
1386         int items=0, a=0;
1387         
1388         /* firstly check that we actuallly have some materials, by gathering all materials in a temp list */
1389         for (a=1; a <= ob->totcol; a++) {
1390                 Material *ma= give_current_material(ob, a);
1391                 short ok = 0;
1392                 
1393                 /* for now, if no material returned, skip (this shouldn't confuse the user I hope) */
1394                 if (ELEM(NULL, ma, ma->adt)) 
1395                         continue;
1396                 
1397                 /* check if ok */
1398                 ANIMDATA_FILTER_CASES(ma, 
1399                         { /* AnimData blocks - do nothing... */ },
1400                         ok=1;, 
1401                         ok=1;, 
1402                         ok=1;)
1403                 if (ok == 0) continue;
1404                 
1405                 /* make a temp list elem for this */
1406                 ld= MEM_callocN(sizeof(LinkData), "DopeSheet-MaterialCache");
1407                 ld->data= ma;
1408                 BLI_addtail(&mats, ld);
1409         }
1410         
1411         /* if there were no channels found, no need to carry on */
1412         // XXX: textures with no animated owner material won't work because of this...
1413         if (mats.first == NULL)
1414                 return 0;
1415         
1416         /* include materials-expand widget? */
1417         if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1418                 ale= make_new_animlistelem(ob, ANIMTYPE_FILLMATD, base, ANIMTYPE_OBJECT, (ID *)ob);
1419                 if (ale) {
1420                         BLI_addtail(anim_data, ale);
1421                         items++;
1422                 }
1423         }
1424         
1425         /* add materials? */
1426         if (FILTER_MAT_OBJC(ob) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1427                 /* for each material in cache, add channels  */
1428                 for (ld= mats.first; ld; ld= ld->next) {
1429                         Material *ma= (Material *)ld->data;
1430                         
1431                         /* include material-expand widget? */
1432                         // hmm... do we need to store the index of this material in the array anywhere?
1433                         if (filter_mode & ANIMFILTER_CHANNELS) {
1434                                 /* check if filtering by active status */
1435                                 if ANIMCHANNEL_ACTIVEOK(ma) {
1436                                         ale= make_new_animlistelem(ma, ANIMTYPE_DSMAT, base, ANIMTYPE_OBJECT, (ID *)ma);
1437                                         if (ale) {
1438                                                 BLI_addtail(anim_data, ale);
1439                                                 items++;
1440                                         }
1441                                 }
1442                         }
1443                         
1444                         /* add material's animation data */
1445                         if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_MAT_OBJD(ma) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1446                                 /* material's animation data */
1447                                 ANIMDATA_FILTER_CASES(ma, 
1448                                         { /* AnimData blocks - do nothing... */ },
1449                                         items += animdata_filter_nla(ac, anim_data, ads, ma->adt, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);, 
1450                                         items += animdata_filter_fcurves(anim_data, ads, ma->adt->drivers.first, NULL, ma, ANIMTYPE_DSMAT, filter_mode, (ID *)ma);, 
1451                                         items += animdata_filter_action(ac, anim_data, ads, ma->adt->action, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);)
1452                                         
1453                                 /* textures */
1454                                 if (!(ads->filterflag & ADS_FILTER_NOTEX))
1455                                         items += animdata_filter_dopesheet_texs(ac, anim_data, ads, (ID *)ma, filter_mode);
1456                         }
1457                 }
1458         }
1459         
1460         /* free cache */
1461         BLI_freelistN(&mats);
1462         
1463         /* return the number of items added to the list */
1464         return items;
1465 }
1466
1467 static int animdata_filter_dopesheet_particles (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1468 {
1469         bAnimListElem *ale=NULL;
1470         Object *ob= base->object;
1471         ParticleSystem *psys = ob->particlesystem.first;
1472         int items= 0, first = 1;
1473
1474         for(; psys; psys=psys->next) {
1475                 short ok = 0;
1476
1477                 if(ELEM(NULL, psys->part, psys->part->adt))
1478                         continue;
1479
1480                 ANIMDATA_FILTER_CASES(psys->part,
1481                         { /* AnimData blocks - do nothing... */ },
1482                         ok=1;, 
1483                         ok=1;, 
1484                         ok=1;)
1485                 if (ok == 0) continue;
1486
1487                 /* include particles-expand widget? */
1488                 if (first && (filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1489                         ale= make_new_animlistelem(ob, ANIMTYPE_FILLPARTD, base, ANIMTYPE_OBJECT, (ID *)ob);
1490                         if (ale) {
1491                                 BLI_addtail(anim_data, ale);
1492                                 items++;
1493                         }
1494                         first = 0;
1495                 }
1496                 
1497                 /* add particle settings? */
1498                 if (FILTER_PART_OBJC(ob) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1499                         if ((filter_mode & ANIMFILTER_CHANNELS)) {
1500                                 /* check if filtering by active status */
1501                                 if ANIMCHANNEL_ACTIVEOK(psys->part) {
1502                                         ale = make_new_animlistelem(psys->part, ANIMTYPE_DSPART, base, ANIMTYPE_OBJECT, (ID *)psys->part);
1503                                         if (ale) {
1504                                                 BLI_addtail(anim_data, ale);
1505                                                 items++;
1506                                         }
1507                                 }
1508                         }
1509                         
1510                         if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_PART_OBJD(psys->part) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1511                                 ANIMDATA_FILTER_CASES(psys->part,
1512                                         { /* AnimData blocks - do nothing... */ },
1513                                         items += animdata_filter_nla(ac, anim_data, ads, psys->part->adt, filter_mode, psys->part, ANIMTYPE_DSPART, (ID *)psys->part);, 
1514                                         items += animdata_filter_fcurves(anim_data, ads, psys->part->adt->drivers.first, NULL, psys->part, ANIMTYPE_DSPART, filter_mode, (ID *)psys->part);, 
1515                                         items += animdata_filter_action(ac, anim_data, ads, psys->part->adt->action, filter_mode, psys->part, ANIMTYPE_DSPART, (ID *)psys->part);)
1516                         }
1517                 }
1518         }
1519         
1520         /* return the number of items added to the list */
1521         return items;
1522 }
1523
1524 static int animdata_filter_dopesheet_obdata (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1525 {
1526         bAnimListElem *ale=NULL;
1527         Object *ob= base->object;
1528         IdAdtTemplate *iat= ob->data;
1529         AnimData *adt= iat->adt;
1530         short type=0, expanded=0;
1531         int items= 0;
1532         
1533         /* get settings based on data type */
1534         switch (ob->type) {
1535                 case OB_CAMERA: /* ------- Camera ------------ */
1536                 {
1537                         Camera *ca= (Camera *)ob->data;
1538                         
1539                         type= ANIMTYPE_DSCAM;
1540                         expanded= FILTER_CAM_OBJD(ca);
1541                 }
1542                         break;
1543                 case OB_LAMP: /* ---------- Lamp ----------- */
1544                 {
1545                         Lamp *la= (Lamp *)ob->data;
1546                         
1547                         type= ANIMTYPE_DSLAM;
1548                         expanded= FILTER_LAM_OBJD(la);
1549                 }
1550                         break;
1551                 case OB_CURVE: /* ------- Curve ---------- */
1552                 case OB_SURF: /* ------- Nurbs Surface ---------- */
1553                 case OB_FONT: /* ------- Text Curve ---------- */
1554                 {
1555                         Curve *cu= (Curve *)ob->data;
1556                         
1557                         type= ANIMTYPE_DSCUR;
1558                         expanded= FILTER_CUR_OBJD(cu);
1559                 }
1560                         break;
1561                 case OB_MBALL: /* ------- MetaBall ---------- */
1562                 {
1563                         MetaBall *mb= (MetaBall *)ob->data;
1564                         
1565                         type= ANIMTYPE_DSMBALL;
1566                         expanded= FILTER_MBALL_OBJD(mb);
1567                 }
1568                         break;
1569                 case OB_ARMATURE: /* ------- Armature ---------- */
1570                 {
1571                         bArmature *arm= (bArmature *)ob->data;
1572                         
1573                         type= ANIMTYPE_DSARM;
1574                         expanded= FILTER_ARM_OBJD(arm);
1575                 }
1576                         break;
1577                 case OB_MESH: /* ------- Mesh ---------- */
1578                 {
1579                         Mesh *me= (Mesh *)ob->data;
1580                         
1581                         type= ANIMTYPE_DSMESH;
1582                         expanded= FILTER_MESH_OBJD(me);
1583                 }
1584                         break;
1585         }
1586         
1587         /* special exception for drivers instead of action */
1588         if (ads->filterflag & ADS_FILTER_ONLYDRIVERS)
1589                 expanded= EXPANDED_DRVD(adt);
1590         
1591         /* include data-expand widget? */
1592         if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) {       
1593                 /* check if filtering by active status */
1594                 if ANIMCHANNEL_ACTIVEOK(iat) {
1595                         ale= make_new_animlistelem(iat, type, base, ANIMTYPE_OBJECT, (ID *)iat);
1596                         if (ale) BLI_addtail(anim_data, ale);
1597                 }
1598         }
1599         
1600         /* add object-data animation channels? */
1601         if (!(filter_mode & ANIMFILTER_VISIBLE) || (expanded) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1602                 /* filtering for channels - nla, drivers, keyframes */
1603                 ANIMDATA_FILTER_CASES(iat, 
1604                         { /* AnimData blocks - do nothing... */ },
1605                         items+= animdata_filter_nla(ac, anim_data, ads, iat->adt, filter_mode, iat, type, (ID *)iat);,
1606                         items+= animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, iat, type, filter_mode, (ID *)iat);, 
1607                         items+= animdata_filter_action(ac, anim_data, ads, iat->adt->action, filter_mode, iat, type, (ID *)iat);)
1608                         
1609                 /* sub-data filtering... */
1610                 switch (ob->type) {
1611                         case OB_LAMP:   /* lamp - textures */
1612                         {
1613                                 /* textures */
1614                                 if (!(ads->filterflag & ADS_FILTER_NOTEX))
1615                                         items += animdata_filter_dopesheet_texs(ac, anim_data, ads, ob->data, filter_mode);
1616                         }
1617                                 break;
1618                 }
1619         }
1620         
1621         /* return the number of items added to the list */
1622         return items;
1623 }
1624
1625 static int animdata_filter_dopesheet_ob (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1626 {
1627         bAnimListElem *ale=NULL;
1628         AnimData *adt = NULL;
1629         Object *ob= base->object;
1630         Key *key= ob_get_key(ob);
1631         short obdata_ok = 0;
1632         int items = 0;
1633         
1634         /* add this object as a channel first */
1635         if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) {
1636                 /* check if filtering by selection */
1637                 if ANIMCHANNEL_SELOK((base->flag & SELECT)) {
1638                         /* check if filtering by active status */
1639                         if ANIMCHANNEL_ACTIVEOK(ob) {
1640                                 ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE, (ID *)ob);
1641                                 if (ale) {
1642                                         BLI_addtail(anim_data, ale);
1643                                         items++;
1644                                 }
1645                         }
1646                 }
1647         }
1648         
1649         /* if collapsed, don't go any further (unless adding keyframes only) */
1650         if ( ((filter_mode & ANIMFILTER_VISIBLE) && EXPANDED_OBJC(ob) == 0) &&
1651                  !(filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) )
1652                 return items;
1653         
1654         /* Action, Drivers, or NLA */
1655         if (ob->adt && !(ads->filterflag & ADS_FILTER_NOOBJ)) {
1656                 adt= ob->adt;
1657                 ANIMDATA_FILTER_CASES(ob,
1658                         { /* AnimData blocks - do nothing... */ },
1659                         { /* nla */
1660                                 /* add NLA tracks */
1661                                 items += animdata_filter_nla(ac, anim_data, ads, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
1662                         },
1663                         { /* drivers */
1664                                 /* include drivers-expand widget? */
1665                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1666                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, base, ANIMTYPE_OBJECT, (ID *)ob);
1667                                         if (ale) {
1668                                                 BLI_addtail(anim_data, ale);
1669                                                 items++;
1670                                         }
1671                                 }
1672                                 
1673                                 /* add F-Curve channels (drivers are F-Curves) */
1674                                 if (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1675                                         // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
1676                                         items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, ob, ANIMTYPE_OBJECT, filter_mode, (ID *)ob);
1677                                 }
1678                         },
1679                         { /* action (keyframes) */
1680                                 /* include action-expand widget? */
1681                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1682                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, base, ANIMTYPE_OBJECT, (ID *)ob);
1683                                         if (ale) {
1684                                                 BLI_addtail(anim_data, ale);
1685                                                 items++;
1686                                         }
1687                                 }
1688                                 
1689                                 /* add F-Curve channels? */
1690                                 if (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1691                                         // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
1692                                         items += animdata_filter_action(ac, anim_data, ads, adt->action, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob); 
1693                                 }
1694                         }
1695                 );
1696         }
1697         
1698         
1699         /* ShapeKeys? */
1700         if ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
1701                 adt= key->adt;
1702                 ANIMDATA_FILTER_CASES(key,
1703                         { /* AnimData blocks - do nothing... */ },
1704                         { /* nla */
1705                                 /* include shapekey-expand widget? */
1706                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1707                                         /* check if filtering by active status */
1708                                         if ANIMCHANNEL_ACTIVEOK(key) {
1709                                                 ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
1710                                                 if (ale) {
1711                                                         BLI_addtail(anim_data, ale);
1712                                                         items++;
1713                                                 }
1714                                         }
1715                                 }
1716                                 
1717                                 /* add NLA tracks - only if expanded or so */
1718                                 if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY))
1719                                         items += animdata_filter_nla(ac, anim_data, ads, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)key);
1720                         },
1721                         { /* drivers */
1722                                 /* include shapekey-expand widget? */
1723                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1724                                         ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
1725                                         if (ale) {
1726                                                 BLI_addtail(anim_data, ale);
1727                                                 items++;
1728                                         }
1729                                 }
1730                                 
1731                                 /* add channels */
1732                                 if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1733                                         items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, key, ANIMTYPE_DSSKEY, filter_mode, (ID *)key);
1734                                 }
1735                         },
1736                         { /* action (keyframes) */
1737                                 /* include shapekey-expand widget? */
1738                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1739                                         /* check if filtering by active status */
1740                                         if ANIMCHANNEL_ACTIVEOK(key) {
1741                                                 ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
1742                                                 if (ale) {
1743                                                         BLI_addtail(anim_data, ale);
1744                                                         items++;
1745                                                 }
1746                                         }
1747                                 }
1748                                 
1749                                 /* add channels */
1750                                 if (!(filter_mode & ANIMFILTER_VISIBLE) || FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1751                                         items += animdata_filter_action(ac, anim_data, ads, adt->action, filter_mode, key, ANIMTYPE_DSSKEY, (ID *)key); 
1752                                 }
1753                         }
1754                 );
1755         }
1756
1757         /* Materials? */
1758         if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT))
1759                 items += animdata_filter_dopesheet_mats(ac, anim_data, ads, base, filter_mode);
1760         
1761         /* Object Data */
1762         switch (ob->type) {
1763                 case OB_CAMERA: /* ------- Camera ------------ */
1764                 {
1765                         Camera *ca= (Camera *)ob->data;
1766                         
1767                         if ((ads->filterflag & ADS_FILTER_NOCAM) == 0) {
1768                                 ANIMDATA_FILTER_CASES(ca,
1769                                         { /* AnimData blocks - do nothing... */ },
1770                                         obdata_ok= 1;,
1771                                         obdata_ok= 1;,
1772                                         obdata_ok= 1;)
1773                         }
1774                 }
1775                         break;
1776                 case OB_LAMP: /* ---------- Lamp ----------- */
1777                 {
1778                         Lamp *la= (Lamp *)ob->data;
1779                         
1780                         if ((ads->filterflag & ADS_FILTER_NOLAM) == 0) {
1781                                 ANIMDATA_FILTER_CASES(la,
1782                                         { /* AnimData blocks - do nothing... */ },
1783                                         obdata_ok= 1;,
1784                                         obdata_ok= 1;,
1785                                         obdata_ok= 1;)
1786                         }
1787                 }
1788                         break;
1789                 case OB_CURVE: /* ------- Curve ---------- */
1790                 case OB_SURF: /* ------- Nurbs Surface ---------- */
1791                 case OB_FONT: /* ------- Text Curve ---------- */
1792                 {
1793                         Curve *cu= (Curve *)ob->data;
1794                         
1795                         if ((ads->filterflag & ADS_FILTER_NOCUR) == 0) {
1796                                 ANIMDATA_FILTER_CASES(cu,
1797                                         { /* AnimData blocks - do nothing... */ },
1798                                         obdata_ok= 1;,
1799                                         obdata_ok= 1;,
1800                                         obdata_ok= 1;)
1801                         }
1802                 }
1803                         break;
1804                 case OB_MBALL: /* ------- MetaBall ---------- */
1805                 {
1806                         MetaBall *mb= (MetaBall *)ob->data;
1807                         
1808                         if ((ads->filterflag & ADS_FILTER_NOMBA) == 0) {
1809                                 ANIMDATA_FILTER_CASES(mb,
1810                                         { /* AnimData blocks - do nothing... */ },
1811                                         obdata_ok= 1;,
1812                                         obdata_ok= 1;,
1813                                         obdata_ok= 1;)
1814                         }
1815                 }
1816                         break;
1817                 case OB_ARMATURE: /* ------- Armature ---------- */
1818                 {
1819                         bArmature *arm= (bArmature *)ob->data;
1820                         
1821                         if ((ads->filterflag & ADS_FILTER_NOARM) == 0) {
1822                                 ANIMDATA_FILTER_CASES(arm,
1823                                         { /* AnimData blocks - do nothing... */ },
1824                                         obdata_ok= 1;,
1825                                         obdata_ok= 1;,
1826                                         obdata_ok= 1;)
1827                         }
1828                 }
1829                         break;
1830                 case OB_MESH: /* ------- Mesh ---------- */
1831                 {
1832                         Mesh *me= (Mesh *)ob->data;
1833                         
1834                         if ((ads->filterflag & ADS_FILTER_NOMESH) == 0) {
1835                                 ANIMDATA_FILTER_CASES(me,
1836                                         { /* AnimData blocks - do nothing... */ },
1837                                         obdata_ok= 1;,
1838                                         obdata_ok= 1;,
1839                                         obdata_ok= 1;)
1840                         }
1841                 }
1842                         break;
1843         }
1844         if (obdata_ok) 
1845                 items += animdata_filter_dopesheet_obdata(ac, anim_data, ads, base, filter_mode);
1846
1847         /* particles */
1848         if (ob->particlesystem.first && !(ads->filterflag & ADS_FILTER_NOPART))
1849                 items += animdata_filter_dopesheet_particles(ac, anim_data, ads, base, filter_mode);
1850         
1851         /* return the number of items added to the list */
1852         return items;
1853 }       
1854
1855 static int animdata_filter_dopesheet_scene (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
1856 {
1857         World *wo= sce->world;
1858         bNodeTree *ntree= sce->nodetree;
1859         AnimData *adt= NULL;
1860         bAnimListElem *ale;
1861         int items = 0;
1862         
1863         /* add scene as a channel first (even if we aren't showing scenes we still need to show the scene's sub-data */
1864         if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) {
1865                 /* check if filtering by selection */
1866                 if (ANIMCHANNEL_SELOK( (sce->flag & SCE_DS_SELECTED) )) {
1867                         ale= make_new_animlistelem(sce, ANIMTYPE_SCENE, NULL, ANIMTYPE_NONE, NULL);
1868                         if (ale) {
1869                                 BLI_addtail(anim_data, ale);
1870                                 items++;
1871                         }
1872                 }
1873         }
1874         
1875         /* if collapsed, don't go any further (unless adding keyframes only) */
1876         if ( (EXPANDED_SCEC(sce) == 0) && !(filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) )
1877                 return items;
1878                 
1879         /* Action, Drivers, or NLA for Scene */
1880         if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) {
1881                 adt= sce->adt;
1882                 ANIMDATA_FILTER_CASES(sce,
1883                         { /* AnimData blocks - do nothing... */ },
1884                         { /* nla */
1885                                 /* add NLA tracks */
1886                                 items += animdata_filter_nla(ac, anim_data, ads, adt, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce);
1887                         },
1888                         { /* drivers */
1889                                 /* include drivers-expand widget? */
1890                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1891                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, sce, ANIMTYPE_SCENE, (ID *)sce);
1892                                         if (ale) {
1893                                                 BLI_addtail(anim_data, ale);
1894                                                 items++;
1895                                         }
1896                                 }
1897                                 
1898                                 /* add F-Curve channels (drivers are F-Curves) */
1899                                 if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1900                                         items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, sce, ANIMTYPE_SCENE, filter_mode, (ID *)sce);
1901                                 }
1902                         },
1903                         { /* action */
1904                                 /* include action-expand widget? */
1905                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1906                                         ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, sce, ANIMTYPE_SCENE, (ID *)sce);
1907                                         if (ale) {
1908                                                 BLI_addtail(anim_data, ale);
1909                                                 items++;
1910                                         }
1911                                 }
1912                                 
1913                                 /* add F-Curve channels? */
1914                                 if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) {
1915                                         items += animdata_filter_action(ac, anim_data, ads, adt->action, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce); 
1916                                 }
1917                         }
1918                 )
1919         }
1920         
1921         /* world */
1922         if ((wo && wo->adt) && !(ads->filterflag & ADS_FILTER_NOWOR)) {
1923                 /* Action, Drivers, or NLA for World */
1924                 adt= wo->adt;
1925                 ANIMDATA_FILTER_CASES(wo,
1926                         { /* AnimData blocks - do nothing... */ },
1927                         { /* nla */
1928                                 /* add NLA tracks */
1929                                 items += animdata_filter_nla(ac, anim_data, ads, adt, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo);
1930                         },
1931                         { /* drivers */
1932                                 /* include world-expand widget? */
1933                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1934                                         ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)wo);
1935                                         if (ale) {
1936                                                 BLI_addtail(anim_data, ale);
1937                                                 items++;
1938                                         }
1939                                 }
1940                                 
1941                                 /* add F-Curve channels (drivers are F-Curves) */
1942                                 if (FILTER_WOR_SCED(wo)/*EXPANDED_DRVD(adt)*/ || !(filter_mode & ANIMFILTER_CHANNELS)) {
1943                                         // XXX owner info is messed up now...
1944                                         items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, wo, ANIMTYPE_DSWOR, filter_mode, (ID *)wo);
1945                                 }
1946                         },
1947                         { /* action */
1948                                 /* include world-expand widget? */
1949                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1950                                         ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)sce);
1951                                         if (ale) {
1952                                                 BLI_addtail(anim_data, ale);
1953                                                 items++;
1954                                         }
1955                                 }
1956                                 
1957                                 /* add channels */
1958                                 if (FILTER_WOR_SCED(wo) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1959                                         items += animdata_filter_action(ac, anim_data, ads, adt->action, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo); 
1960                                 }
1961                         }
1962                 )
1963                 
1964                 /* if expanded, check world textures too */
1965                 if (FILTER_WOR_SCED(wo) || (filter_mode & ANIMFILTER_CURVESONLY)) {
1966                         /* textures for world */
1967                         if (!(ads->filterflag & ADS_FILTER_NOTEX))
1968                                 items += animdata_filter_dopesheet_texs(ac, anim_data, ads, (ID *)wo, filter_mode);
1969                 }
1970         }
1971         /* nodetree */
1972         if ((ntree && ntree->adt) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
1973                 /* Action, Drivers, or NLA for Nodetree */
1974                 adt= ntree->adt;
1975                 ANIMDATA_FILTER_CASES(ntree,
1976                         { /* AnimData blocks - do nothing... */ },
1977                         { /* nla */
1978                                 /* add NLA tracks */
1979                                 items += animdata_filter_nla(ac, anim_data, ads, adt, filter_mode, ntree, ANIMTYPE_DSNTREE, (ID *)ntree);
1980                         },
1981                         { /* drivers */
1982                                 /* include nodetree-expand widget? */
1983                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
1984                                         ale= make_new_animlistelem(ntree, ANIMTYPE_DSNTREE, sce, ANIMTYPE_SCENE, (ID *)ntree);
1985                                         if (ale) {
1986                                                 BLI_addtail(anim_data, ale);
1987                                                 items++;
1988                                         }
1989                                 }
1990                                 
1991                                 /* add F-Curve channels (drivers are F-Curves) */
1992                                 if (FILTER_NTREE_SCED(ntree)/*EXPANDED_DRVD(adt)*/ || !(filter_mode & ANIMFILTER_CHANNELS)) {
1993                                         // XXX owner info is messed up now...
1994                                         items += animdata_filter_fcurves(anim_data, ads, adt->drivers.first, NULL, ntree, ANIMTYPE_DSNTREE, filter_mode, (ID *)ntree);
1995                                 }
1996                         },
1997                         { /* action */
1998                                 /* include nodetree-expand widget? */
1999                                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
2000                                         ale= make_new_animlistelem(ntree, ANIMTYPE_DSNTREE, sce, ANIMTYPE_SCENE, (ID *)sce);
2001                                         if (ale) {
2002                                                 BLI_addtail(anim_data, ale);
2003                                                 items++;
2004                                         }
2005                                 }
2006                                 
2007                                 /* add channels */
2008                                 if (FILTER_NTREE_SCED(ntree) || (filter_mode & ANIMFILTER_CURVESONLY)) {
2009                                         items += animdata_filter_action(ac, anim_data, ads, adt->action, filter_mode, ntree, ANIMTYPE_DSNTREE, (ID *)ntree); 
2010                                 }
2011                         }
2012                 )
2013         }
2014
2015         
2016         // TODO: scene compositing nodes (these aren't standard node-trees)
2017         
2018         /* return the number of items added to the list */
2019         return items;
2020 }
2021
2022 // 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)
2023 static int animdata_filter_dopesheet (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode)
2024 {
2025         Scene *sce= (Scene *)ads->source;
2026         Base *base;
2027         bAnimListElem *ale;
2028         int items = 0;
2029         
2030         /* check that we do indeed have a scene */
2031         if ((ads->source == NULL) || (GS(ads->source->name)!=ID_SCE)) {
2032                 printf("DopeSheet Error: Not scene!\n");
2033                 if (G.f & G_DEBUG)
2034                         printf("\tPointer = %p, Name = '%s' \n", ads->source, (ads->source)?ads->source->name:NULL);
2035                 return 0;
2036         }
2037         
2038         /* augment the filter-flags with settings based on the dopesheet filterflags 
2039          * so that some temp settings can get added automagically...
2040          */
2041         if (ads->filterflag & ADS_FILTER_SELEDIT) {
2042                 /* only selected F-Curves should get their keyframes considered for editability */
2043                 filter_mode |= ANIMFILTER_SELEDIT;
2044         }
2045         
2046         /* scene-linked animation */
2047         // TODO: sequencer, composite nodes - are we to include those here too?
2048         {
2049                 short sceOk= 0, worOk= 0, nodeOk=0;
2050                 
2051                 /* check filtering-flags if ok */
2052                 ANIMDATA_FILTER_CASES(sce, 
2053                         {
2054                                 /* for the special AnimData blocks only case, we only need to add
2055                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
2056                                  */
2057                                 ANIMDATA_ADD_ANIMDATA(sce);
2058                                 sceOk=0;
2059                         },
2060                         sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, 
2061                         sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, 
2062                         sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);)
2063                 if (sce->world) {
2064                         ANIMDATA_FILTER_CASES(sce->world, 
2065                                 {
2066                                         /* for the special AnimData blocks only case, we only need to add
2067                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
2068                                          */
2069                                         ANIMDATA_ADD_ANIMDATA(sce->world);
2070                                         worOk=0;
2071                                 },
2072                                 worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, 
2073                                 worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, 
2074                                 worOk= !(ads->filterflag & ADS_FILTER_NOWOR);)
2075                 }
2076                 if (sce->nodetree) {
2077                         ANIMDATA_FILTER_CASES(sce->nodetree, 
2078                                 {
2079                                         /* for the special AnimData blocks only case, we only need to add
2080                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
2081                                          */
2082                                         ANIMDATA_ADD_ANIMDATA(sce->nodetree);
2083                                         nodeOk=0;
2084                                 },
2085                                 nodeOk= !(ads->filterflag & ADS_FILTER_NONTREE);, 
2086                                 nodeOk= !(ads->filterflag & ADS_FILTER_NONTREE);, 
2087                                 nodeOk= !(ads->filterflag & ADS_FILTER_NONTREE);)
2088                 }
2089                 
2090                 /* if only F-Curves with visible flags set can be shown, check that 
2091                  * datablocks haven't been set to invisible 
2092                  */
2093                 if (filter_mode & ANIMFILTER_CURVEVISIBLE) {
2094                         if ((sce->adt) && (sce->adt->flag & ADT_CURVES_NOT_VISIBLE))
2095                                 sceOk= worOk= nodeOk= 0;
2096                 }
2097                 
2098                 /* check if not all bad (i.e. so there is something to show) */
2099                 if ( !(!sceOk && !worOk && !nodeOk) ) {
2100                         /* add scene data to the list of filtered channels */
2101                         items += animdata_filter_dopesheet_scene(ac, anim_data, ads, sce, filter_mode);
2102                 }
2103         }
2104         
2105         
2106         /* loop over all bases in the scene */
2107         for (base= sce->base.first; base; base= base->next) {
2108                 /* check if there's an object (all the relevant checks are done in the ob-function) */
2109                 if (base->object) {
2110                         Object *ob= base->object;
2111                         Key *key= ob_get_key(ob);
2112                         short actOk=1, keyOk=1, dataOk=1, matOk=1, partOk=1;
2113                         
2114                         /* firstly, check if object can be included, by the following factors:
2115                          *      - if only visible, must check for layer and also viewport visibility
2116                          *              --> while tools may demand only visible, user setting takes priority
2117                          *                      as user option controls whether sets of channels get included while
2118                          *                      tool-flag takes into account collapsed/open channels too
2119                          *      - if only selected, must check if object is selected 
2120                          *      - there must be animation data to edit
2121                          */
2122                         // TODO: if cache is implemented, just check name here, and then 
2123                         if ((filter_mode & ANIMFILTER_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
2124                                 /* layer visibility - we check both object and base, since these may not be in sync yet */
2125                                 if ((sce->lay & (ob->lay|base->lay))==0) continue;
2126                                 
2127                                 /* outliner restrict-flag */
2128                                 if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
2129                         }
2130                         
2131                         /* if only F-Curves with visible flags set can be shown, check that 
2132                          * datablock hasn't been set to invisible 
2133                          */
2134                         if (filter_mode & ANIMFILTER_CURVEVISIBLE) {
2135                                 if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE))
2136                                         continue;
2137                         }
2138                         
2139                         /* additionally, dopesheet filtering also affects what objects to consider */
2140                         if (ads->filterflag) {
2141                                 /* check selection and object type filters */
2142                                 if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/) )  {
2143                                         /* only selected should be shown */
2144                                         continue;
2145                                 }
2146                                 
2147                                 /* check if object belongs to the filtering group if option to filter 
2148                                  * objects by the grouped status is on
2149                                  *      - used to ease the process of doing multiple-character choreographies
2150                                  */
2151                                 if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) {
2152                                         if (object_in_group(ob, ads->filter_grp) == 0)
2153                                                 continue;
2154                                 }
2155                                 
2156                                 /* check filters for datatypes */
2157                                         /* object */
2158                                 actOk= 0;
2159                                 if (!(ads->filterflag & ADS_FILTER_NOOBJ)) {
2160                                         ANIMDATA_FILTER_CASES(ob, 
2161                                                 {
2162                                                         /* for the special AnimData blocks only case, we only need to add
2163                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
2164                                                          */
2165                                                         ANIMDATA_ADD_ANIMDATA(ob);
2166                                                         actOk=0;
2167                                                 },
2168                                                 actOk= 1;, 
2169                                                 actOk= 1;, 
2170                                                 actOk= 1;)
2171                                 }
2172                                 
2173                                 keyOk= 0;
2174                                 if ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
2175                                         /* shapekeys */
2176                                         ANIMDATA_FILTER_CASES(key, 
2177                                                 {
2178                                                         /* for the special AnimData blocks only case, we only need to add
2179                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
2180                                                          */
2181                                                         ANIMDATA_ADD_ANIMDATA(key);
2182                                                         keyOk=0;
2183                                                 },
2184                                                 keyOk= 1;, 
2185                                                 keyOk= 1;, 
2186                                                 keyOk= 1;)
2187                                 }
2188                                 
2189                                 /* materials - only for geometric types */
2190                                 matOk= 0; /* by default, not ok... */
2191                                 if ( !(ads->filterflag & ADS_FILTER_NOMAT) && (ob->totcol) && 
2192                                          ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) ) 
2193                                 {
2194                                         int a;
2195                                         
2196                                         /* firstly check that we actuallly have some materials */
2197                                         for (a=0; a < ob->totcol; a++) {
2198                                                 Material *ma= give_current_material(ob, a);
2199                                                 
2200                                                 if (ma) {
2201                                                         /* if material has relevant animation data, break */
2202                                                         ANIMDATA_FILTER_CASES(ma, 
2203                                                                 {
2204                                                                         /* for the special AnimData blocks only case, we only need to add
2205                                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
2206                                                                          */
2207                                                                         ANIMDATA_ADD_ANIMDATA(ma);
2208                                                                         matOk=0;
2209                                                                 },
2210                                                                 matOk= 1;, 
2211                                                                 matOk= 1;, 
2212                                                                 matOk= 1;)
2213                                                                 
2214                                                         if (matOk) 
2215                                                                 break;
2216                                                         
2217                                                         /* textures? */
2218                                                         // TODO: make this a macro that is used in the other checks too
2219                                                         // NOTE: this has little use on its own, since the actual filtering still ignores if no anim on the data
2220                                                         if (!(ads->filterflag & ADS_FILTER_NOTEX)) {
2221                                                                 int mtInd;
2222                                                                 
2223                                                                 for (mtInd= 0; mtInd < MAX_MTEX; mtInd++) {
2224                                                                         MTex *mtex= ma->mtex[mtInd];
2225                                                                         
2226                                                                         if (mtex && mtex->tex) {
2227                                                                                 /* if texture has relevant animation data, break */
2228                                                                                 ANIMDATA_FILTER_CASES(mtex->tex, 
2229                                                                                         {
2230                                                                                                 /* for the special AnimData blocks only case, we only need to add
2231                                                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
2232                                                                                                  */
2233                                                                                                 ANIMDATA_ADD_ANIMDATA(mtex->tex);
2234                                                                                                 matOk=0;
2235                                                                                         },
2236                                                                                         matOk= 1;, 
2237                                                                                         matOk= 1;, 
2238                                                                                         matOk= 1;)
2239                                                                                         
2240                                                                                 if (matOk) 
2241                                                                                         break;
2242                                                                         }
2243                                                                 }
2244                                                         }
2245                                                         
2246                                                 }
2247                                         }
2248                                 }
2249                                 
2250                                 /* data */
2251                                 switch (ob->type) {
2252                                         case OB_CAMERA: /* ------- Camera ------------ */
2253                                         {
2254                                                 Camera *ca= (Camera *)ob->data;
2255                                                 dataOk= 0;
2256                                                 ANIMDATA_FILTER_CASES(ca, 
2257                                                         if ((ads->filterflag & ADS_FILTER_NOCAM)==0) {
2258                                                                 /* for the special AnimData blocks only case, we only need to add
2259                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
2260                                                                  */
2261                                                                 ANIMDATA_ADD_ANIMDATA(ca);
2262                                                                 dataOk=0;
2263                                                         },
2264                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, 
2265                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, 
2266                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);)
2267                                         }
2268                                                 break;
2269                                         case OB_LAMP: /* ---------- Lamp ----------- */
2270                                         {
2271                                                 Lamp *la= (Lamp *)ob->data;
2272                                                 dataOk= 0;
2273                                                 ANIMDATA_FILTER_CASES(la, 
2274                                                         if ((ads->filterflag & ADS_FILTER_NOLAM)==0) {
2275                                                                 /* for the special AnimData blocks only case, we only need to add
2276                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
2277                                                                  */
2278                                                                 ANIMDATA_ADD_ANIMDATA(la);
2279                                                                 dataOk=0;
2280                                                         },
2281                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, 
2282                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, 
2283                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);)
2284                                         }
2285                                                 break;
2286                                         case OB_CURVE: /* ------- Curve ---------- */
2287                                         case OB_SURF: /* ------- Nurbs Surface ---------- */
2288                                         case OB_FONT: /* ------- Text Curve ---------- */
2289                                         {
2290                                                 Curve *cu= (Curve *)ob->data;
2291                                                 dataOk= 0;
2292                                                 ANIMDATA_FILTER_CASES(cu, 
2293                                                         if ((ads->filterflag & ADS_FILTER_NOCUR)==0) {
2294                                                                 /* for the special AnimData blocks only case, we only need to add
2295                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
2296                                                                  */
2297                                                                 ANIMDATA_ADD_ANIMDATA(cu);
2298                                                                 dataOk=0;
2299                                                         },
2300                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, 
2301                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, 
2302                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);)
2303                                         }
2304                                                 break;
2305                                         case OB_MBALL: /* ------- MetaBall ---------- */
2306                                         {
2307                                                 MetaBall *mb= (MetaBall *)ob->data;
2308                                                 dataOk= 0;
2309                                                 ANIMDATA_FILTER_CASES(mb, 
2310                                                         if ((ads->filterflag & ADS_FILTER_NOMBA)==0) {
2311                                                                 /* for the special AnimData blocks only case, we only need to add
2312                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
2313                                                                  */
2314                                                                 ANIMDATA_ADD_ANIMDATA(mb);
2315                                                                 dataOk=0;
2316                                                         },
2317                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);, 
2318                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);, 
2319                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOMBA);)
2320                                         }
2321                                                 break;
2322                                         case OB_ARMATURE: /* ------- Armature ---------- */
2323                                         {
2324                                                 bArmature *arm= (bArmature *)ob->data;
2325                                                 dataOk= 0;
2326                                                 ANIMDATA_FILTER_CASES(arm, 
2327                                                         if ((ads->filterflag & ADS_FILTER_NOARM)==0) {
2328                                                                 /* for the special AnimData blocks only case, we only need to add
2329                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
2330                                                                  */
2331                                                                 ANIMDATA_ADD_ANIMDATA(arm);
2332                                                                 dataOk=0;
2333                                                         },
2334                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOARM);, 
2335                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOARM);, 
2336                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOARM);)
2337                                         }
2338                                                 break;
2339                                         case OB_MESH: /* ------- Mesh ---------- */
2340                                         {
2341                                                 Mesh *me= (Mesh *)ob->data;
2342                                                 dataOk= 0;
2343                                                 ANIMDATA_FILTER_CASES(me, 
2344                                                         if ((ads->filterflag & ADS_FILTER_NOMESH)==0) {
2345                                                                 /* for the special AnimData blocks only case, we only need to add
2346                                                                  * the block if it is valid... then other cases just get skipped (hence ok=0)
2347                                                                  */
2348                                                                 ANIMDATA_ADD_ANIMDATA(me);
2349                                                                 dataOk=0;
2350                                                         },
2351                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOMESH);, 
2352                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOMESH);, 
2353                                                         dataOk= !(ads->filterflag & ADS_FILTER_NOMESH);)
2354                                         }
2355                                                 break;
2356                                         default: /* --- other --- */
2357                                                 dataOk= 0;
2358                                                 break;
2359                                 }
2360                                 
2361                                 /* particles */
2362                                 partOk = 0;
2363                                 if (!(ads->filterflag & ADS_FILTER_NOPART) && ob->particlesystem.first) {
2364                                         ParticleSystem *psys = ob->particlesystem.first;
2365                                         for(; psys; psys=psys->next) {
2366                                                 if (psys->part) {
2367                                                         /* if particlesettings has relevant animation data, break */
2368                                                         ANIMDATA_FILTER_CASES(psys->part, 
2369                                                                 {
2370                                                                         /* for the special AnimData blocks only case, we only need to add
2371                                                                          * the block if it is valid... then other cases just get skipped (hence ok=0)
2372                                                                          */
2373                                                                         ANIMDATA_ADD_ANIMDATA(psys->part);
2374                                                                         partOk=0;
2375                                                                 },
2376                                                                 partOk= 1;, 
2377                                                                 partOk= 1;, 
2378                                                                 partOk= 1;)
2379                                                 }
2380                                                         
2381                                                 if (partOk) 
2382                                                         break;
2383                                         }
2384                                 }
2385                                 
2386                                 /* check if all bad (i.e. nothing to show) */
2387                                 if (!actOk && !keyOk && !dataOk && !matOk && !partOk)
2388                                         continue;
2389                         }
2390                         else {
2391                                 /* check data-types */
2392                                 actOk= ANIMDATA_HAS_KEYS(ob);
2393                                 keyOk= (key != NULL);
2394                                 
2395                                 /* materials - only for geometric types */
2396                                 matOk= 0; /* by default, not ok... */
2397                                 if (ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) && (ob->totcol)) 
2398                                 {
2399                                         int a;
2400                                         
2401                                         /* firstly check that we actuallly have some materials */
2402                                         for (a=0; a < ob->totcol; a++) {
2403                                                 Material *ma= give_current_material(ob, a);
2404                                                 
2405                                                 if ((ma) && ANIMDATA_HAS_KEYS(ma)) {
2406                                                         matOk= 1;
2407                                                         break;
2408                                                 }
2409                                         }
2410                                 }
2411                                 
2412                                 /* data */
2413                                 switch (ob->type) {
2414                                         case OB_CAMERA: /* ------- Camera ------------ */
2415                                         {
2416                                                 Camera *ca= (Camera *)ob->data;
2417                                                 dataOk= ANIMDATA_HAS_KEYS(ca);                                          
2418                                         }
2419                                                 break;
2420                                         case OB_LAMP: /* ---------- Lamp ----------- */
2421                                         {
2422                                                 Lamp *la= (Lamp *)ob->data;
2423                                                 dataOk= ANIMDATA_HAS_KEYS(la);  
2424                                         }
2425                                                 break;
2426                                         case OB_CURVE: /* ------- Curve ---------- */
2427                                         case OB_SURF: /* ------- Nurbs Surface ---------- */
2428                                         case OB_FONT: /* ------- Text Curve ---------- */
2429                                         {
2430                                                 Curve *cu= (Curve *)ob->data;
2431                                                 dataOk= ANIMDATA_HAS_KEYS(cu);  
2432                                         }
2433                                                 break;
2434                                         case OB_MBALL: /* -------- Metas ---------- */
2435                                         {
2436                                                 MetaBall *mb= (MetaBall *)ob->data;
2437                                                 dataOk= ANIMDATA_HAS_KEYS(mb);  
2438                                         }
2439                                                 break;
2440                                         case OB_ARMATURE: /* -------- Armature ---------- */
2441                                         {
2442                                                 bArmature *arm= (bArmature *)ob->data;
2443                                                 dataOk= ANIMDATA_HAS_KEYS(arm); 
2444                                         }
2445                                                 break;
2446                                         case OB_MESH: /* -------- Mesh ---------- */
2447                                         {
2448                                                 Mesh *me= (Mesh *)ob->data;
2449                                                 dataOk= ANIMDATA_HAS_KEYS(me);  
2450                                         }
2451                                                 break;
2452                                         default: /* --- other --- */
2453                                                 dataOk= 0;
2454                                                 break;
2455                                 }
2456                                 
2457                                 /* particles */