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