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