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