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