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