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