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