2.5 - Transform Code for Animation Editors (Part 1)
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Joshua Leung
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /* This file contains a system used to provide a layer of abstraction between sources
30  * of animation data and tools in Animation Editors. The method used here involves 
31  * generating a list of edit structures which enable tools to naively perform the actions 
32  * they require without all the boiler-plate associated with loops within loops and checking 
33  * for cases to ignore. 
34  *
35  * While this is primarily used for the Action/Dopesheet Editor (and its accessory modes),
36  * the IPO Editor also uses this for it's channel list and for determining which curves
37  * are being edited.
38  *
39  * Note: much of the original system this was based on was built before the creation of the RNA
40  * system. In future, it would be interesting to replace some parts of this code with RNA queries,
41  * however, RNA does not eliminate some of the boiler-plate reduction benefits presented by this 
42  * system, so if any such work does occur, it should only be used for the internals used here...
43  *
44  * -- Joshua Leung, Dec 2008
45  */
46
47 #include <string.h>
48 #include <stdio.h>
49
50 #include "DNA_listBase.h"
51 #include "DNA_ID.h"
52 #include "DNA_action_types.h"
53 #include "DNA_constraint_types.h"
54 #include "DNA_camera_types.h"
55 #include "DNA_curve_types.h"
56 #include "DNA_gpencil_types.h"
57 #include "DNA_ipo_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_object_types.h"
64 #include "DNA_space_types.h"
65 #include "DNA_scene_types.h"
66 #include "DNA_screen_types.h"
67 #include "DNA_windowmanager_types.h"
68
69 #include "MEM_guardedalloc.h"
70
71 #include "BLI_blenlib.h"
72
73 #include "BKE_context.h"
74 #include "BKE_global.h"
75 #include "BKE_key.h"
76 #include "BKE_object.h"
77 #include "BKE_material.h"
78 #include "BKE_screen.h"
79 #include "BKE_utildefines.h"
80
81 #include "ED_anim_api.h"
82 #include "ED_types.h"
83 #include "ED_util.h"
84
85 #include "WM_api.h"
86 #include "WM_types.h"
87
88 #include "BIF_gl.h"
89 #include "BIF_glutil.h"
90
91 #include "UI_interface.h"
92 #include "UI_resources.h"
93 #include "UI_view2d.h"
94
95 /* ************************************************************ */
96 /* Blender Context <-> Animation Context mapping */
97
98 /* ----------- Private Stuff - Action Editor ------------- */
99
100 /* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */
101 /* Note: there's a similar function in key.c (ob_get_key) */
102 Key *actedit_get_shapekeys (bAnimContext *ac, SpaceAction *saction) 
103 {
104     Scene *scene= ac->scene;
105     Object *ob;
106     Key *key;
107         
108     ob = OBACT;
109     if (ob == NULL) 
110                 return NULL;
111         
112         /* XXX pinning is not available in 'ShapeKey' mode... */
113         //if (saction->pin) return NULL;
114         
115         /* shapekey data is stored with geometry data */
116         switch (ob->type) {
117                 case OB_MESH:
118                         key= ((Mesh *)ob->data)->key;
119                         break;
120                         
121                 case OB_LATTICE:
122                         key= ((Lattice *)ob->data)->key;
123                         break;
124                         
125                 case OB_CURVE:
126                 case OB_SURF:
127                         key= ((Curve *)ob->data)->key;
128                         break;
129                         
130                 default:
131                         return NULL;
132         }
133         
134         if (key) {
135                 if (key->type == KEY_RELATIVE)
136                         return key;
137         }
138         
139     return NULL;
140 }
141
142 /* Get data being edited in Action Editor (depending on current 'mode') */
143 static short actedit_get_context (bAnimContext *ac, SpaceAction *saction)
144 {
145         /* sync settings with current view status, then return appropriate data */
146         switch (saction->mode) {
147                 case SACTCONT_ACTION: /* 'Action Editor' */
148                         /* if not pinned, sync with active object */
149                         if (saction->pin == 0) {
150                                 if (ac->obact)
151                                         saction->action = ac->obact->action;
152                                 else
153                                         saction->action= NULL;
154                         }
155                         
156                         ac->datatype= ANIMCONT_ACTION;
157                         ac->data= saction->action;
158                         
159                         ac->mode= saction->mode;
160                         return 1;
161                         
162                 case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */
163                         ac->datatype= ANIMCONT_SHAPEKEY;
164                         ac->data= actedit_get_shapekeys(ac, saction);
165                         
166                         ac->mode= saction->mode;
167                         return 1;
168                         
169                 case SACTCONT_GPENCIL: /* Grease Pencil */ // XXX review how this mode is handled...
170                         ac->datatype=ANIMCONT_GPENCIL;
171                         //ac->data= CTX_wm_screen(C); // FIXME: add that dopesheet type thing here!
172                         ac->data= NULL; // !!!
173                         
174                         ac->mode= saction->mode;
175                         return 1;
176                         
177                 case SACTCONT_DOPESHEET: /* DopeSheet */
178                         /* update scene-pointer (no need to check for pinning yet, as not implemented) */
179                         saction->ads.source= (ID *)ac->scene;
180                         
181                         ac->datatype= ANIMCONT_DOPESHEET;
182                         ac->data= &saction->ads;
183                         
184                         ac->mode= saction->mode;
185                         return 1;
186                 
187                 default: /* unhandled yet */
188                         ac->datatype= ANIMCONT_NONE;
189                         ac->data= NULL;
190                         
191                         ac->mode= -1;
192                         return 0;
193         }
194 }
195
196 /* ----------- Private Stuff - IPO Editor ------------- */
197
198 /* Get data being edited in IPO Editor (depending on current 'mode') */
199 static short ipoedit_get_context (bAnimContext *ac, SpaceIpo *sipo)
200 {
201         // XXX FIXME...
202         return 0;
203 }
204
205 /* ----------- Public API --------------- */
206
207 /* Obtain current anim-data context, given that context info from Blender context has already been set 
208  *      - AnimContext to write to is provided as pointer to var on stack so that we don't have
209  *        allocation/freeing costs (which are not that avoidable with channels).
210  */
211 short ANIM_animdata_context_getdata (bAnimContext *ac)
212 {
213         ScrArea *sa= ac->sa;
214         short ok= 0;
215         
216         /* context depends on editor we are currently in */
217         if (sa) {
218                 switch (sa->spacetype) {
219                         case SPACE_ACTION:
220                         {
221                                 SpaceAction *saction= (SpaceAction *)sa->spacedata.first;
222                                 ok= actedit_get_context(ac, saction);
223                         }
224                                 break;
225                                 
226                         case SPACE_IPO:
227                         {
228                                 SpaceIpo *sipo= (SpaceIpo *)sa->spacedata.first;
229                                 ok= ipoedit_get_context(ac, sipo);
230                         }
231                                 break;
232                 }
233         }
234         
235         /* check if there's any valid data */
236         if (ok && ac->data)
237                 return 1;
238         else
239                 return 0;
240 }
241
242 /* Obtain current anim-data context from Blender Context info 
243  *      - AnimContext to write to is provided as pointer to var on stack so that we don't have
244  *        allocation/freeing costs (which are not that avoidable with channels).
245  *      - Clears data and sets the information from Blender Context which is useful
246  */
247 short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac)
248 {
249         ScrArea *sa= CTX_wm_area(C);
250         ARegion *ar= CTX_wm_region(C);
251         Scene *scene= CTX_data_scene(C);
252         
253         /* clear old context info */
254         if (ac == NULL) return 0;
255         memset(ac, 0, sizeof(bAnimContext));
256         
257         /* get useful default context settings from context */
258         ac->scene= scene;
259         ac->obact= (scene && scene->basact)?  scene->basact->object : NULL;
260         ac->sa= sa;
261         ac->ar= ar;
262         ac->spacetype= (sa) ? sa->spacetype : 0;
263         ac->regiontype= (ar) ? ar->regiontype : 0;
264         
265         /* get data context info */
266         return ANIM_animdata_context_getdata(ac);
267 }
268
269 /* ************************************************************ */
270 /* Blender Data <-- Filter --> Channels to be operated on */
271
272 /* ----------- 'Private' Stuff --------------- */
273
274 /* this function allocates memory for a new bAnimListElem struct for the 
275  * provided animation channel-data. 
276  */
277 bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, short ownertype)
278 {
279         bAnimListElem *ale= NULL;
280         
281         /* only allocate memory if there is data to convert */
282         if (data) {
283                 /* allocate and set generic data */
284                 ale= MEM_callocN(sizeof(bAnimListElem), "bAnimListElem");
285                 
286                 ale->data= data;
287                 ale->type= datatype;
288                 ale->owner= owner;
289                 ale->ownertype= ownertype;
290                 
291                 if ((owner) && (ownertype == ANIMTYPE_ACHAN)) {
292                         bActionChannel *ochan= (bActionChannel *)owner;
293                         ale->grp= ochan->grp;
294                 }
295                 else 
296                         ale->grp= NULL;
297                 
298                 /* do specifics */
299                 switch (datatype) {
300                         case ANIMTYPE_OBJECT:
301                         {
302                                 Base *base= (Base *)data;
303                                 Object *ob= base->object;
304                                 
305                                 ale->flag= ob->flag;
306                                 
307                                 ale->key_data= ob;
308                                 ale->datatype= ALE_OB;
309                         }
310                                 break;
311                         case ANIMTYPE_FILLACTD:
312                         {
313                                 bAction *act= (bAction *)data;
314                                 
315                                 ale->flag= act->flag;
316                                 
317                                 ale->key_data= act;
318                                 ale->datatype= ALE_ACT;
319                         }
320                                 break;
321                         case ANIMTYPE_FILLIPOD:
322                         {
323                                 Object *ob= (Object *)data;
324                                 
325                                 ale->flag= FILTER_IPO_OBJC(ob);
326                                 
327                                 ale->key_data= ob->ipo;
328                                 ale->datatype= ALE_IPO;
329                         }
330                                 break;
331                         case ANIMTYPE_FILLCOND:
332                         {
333                                 Object *ob= (Object *)data;
334                                 
335                                 ale->flag= FILTER_CON_OBJC(ob);
336                                 
337                                 ale->key_data= NULL;
338                                 ale->datatype= ALE_NONE;
339                         }
340                                 break;
341                         case ANIMTYPE_FILLMATD:
342                         {
343                                 Object *ob= (Object *)data;
344                                 
345                                 ale->flag= FILTER_MAT_OBJC(ob);
346                                 
347                                 ale->key_data= NULL;
348                                 ale->datatype= ALE_NONE;
349                         }
350                                 break;
351                         
352                         case ANIMTYPE_DSMAT:
353                         {
354                                 Material *ma= (Material *)data;
355                                 
356                                 ale->flag= FILTER_MAT_OBJD(ma);
357                                 
358                                 ale->key_data= ma->ipo;
359                                 ale->datatype= ALE_IPO;
360                         }
361                                 break;
362                         case ANIMTYPE_DSLAM:
363                         {
364                                 Lamp *la= (Lamp *)data;
365                                 
366                                 ale->flag= FILTER_LAM_OBJD(la);
367                                 
368                                 ale->key_data= la->ipo;
369                                 ale->datatype= ALE_IPO;
370                         }
371                                 break;
372                         case ANIMTYPE_DSCAM:
373                         {
374                                 Camera *ca= (Camera *)data;
375                                 
376                                 ale->flag= FILTER_CAM_OBJD(ca);
377                                 
378                                 ale->key_data= ca->ipo;
379                                 ale->datatype= ALE_IPO;
380                         }
381                                 break;
382                         case ANIMTYPE_DSCUR:
383                         {
384                                 Curve *cu= (Curve *)data;
385                                 
386                                 ale->flag= FILTER_CUR_OBJD(cu);
387                                 
388                                 ale->key_data= cu->ipo;
389                                 ale->datatype= ALE_IPO;
390                         }
391                                 break;
392                         case ANIMTYPE_DSSKEY:
393                         {
394                                 Key *key= (Key *)data;
395                                 
396                                 ale->flag= FILTER_SKE_OBJD(key);
397                                 
398                                 ale->key_data= key->ipo;
399                                 ale->datatype= ALE_IPO;
400                         }
401                                 break;
402                                 
403                         case ANIMTYPE_GROUP:
404                         {
405                                 bActionGroup *agrp= (bActionGroup *)data;
406                                 
407                                 ale->flag= agrp->flag;
408                                 
409                                 ale->key_data= NULL;
410                                 ale->datatype= ALE_GROUP;
411                         }
412                                 break;
413                         case ANIMTYPE_ACHAN:
414                         {
415                                 bActionChannel *achan= (bActionChannel *)data;
416                                 
417                                 ale->flag= achan->flag;
418                                 
419                                 if (achan->ipo) {
420                                         ale->key_data= achan->ipo;
421                                         ale->datatype= ALE_IPO;
422                                 }
423                                 else {
424                                         ale->key_data= NULL;
425                                         ale->datatype= ALE_NONE;
426                                 }
427                         }       
428                                 break;
429                         case ANIMTYPE_CONCHAN:
430                         case ANIMTYPE_CONCHAN2:
431                         {
432                                 bConstraintChannel *conchan= (bConstraintChannel *)data;
433                                 
434                                 ale->flag= conchan->flag;
435                                 
436                                 if (datatype == ANIMTYPE_CONCHAN2) {
437                                         /* CONCHAN2 is a hack so that constraint-channels keyframes can be edited */
438                                         if (conchan->ipo) {
439                                                 ale->key_data= conchan->ipo;
440                                                 ale->datatype= ALE_IPO;
441                                         }
442                                         else {
443                                                 ale->key_data= NULL;
444                                                 ale->datatype= ALE_NONE;
445                                         }
446                                 }
447                                 else {
448                                         if ((conchan->ipo) && (conchan->ipo->curve.first)) {
449                                                 /* we assume that constraint ipo blocks only have 1 curve:
450                                                  * INFLUENCE, so we pretend that a constraint channel is 
451                                                  * really just a Ipo-Curve channel instead.
452                                                  */
453                                                 ale->key_data= conchan->ipo->curve.first;
454                                                 ale->datatype= ALE_ICU;
455                                         }
456                                         else {
457                                                 ale->key_data= NULL;
458                                                 ale->datatype= ALE_NONE;
459                                         }
460                                 }
461                         }
462                                 break;
463                         case ANIMTYPE_ICU:
464                         {
465                                 IpoCurve *icu= (IpoCurve *)data;
466                                 
467                                 ale->flag= icu->flag;
468                                 ale->key_data= icu;
469                                 ale->datatype= ALE_ICU;
470                         }
471                                 break;
472                         case ANIMTYPE_FILLIPO:
473                         case ANIMTYPE_FILLCON:
474                         {
475                                 bActionChannel *achan= (bActionChannel *)data;
476                                 
477                                 if (datatype == ANIMTYPE_FILLIPO)
478                                         ale->flag= FILTER_IPO_ACHAN(achan);
479                                 else
480                                         ale->flag= FILTER_CON_ACHAN(achan);
481                                         
482                                 ale->key_data= NULL;
483                                 ale->datatype= ALE_NONE;
484                         }
485                                 break;
486                         case ANIMTYPE_IPO:
487                         {
488                                 ale->flag= 0;
489                                 ale->key_data= data;
490                                 ale->datatype= ALE_IPO;
491                         }
492                                 break;
493                         
494                         case ANIMTYPE_GPLAYER:
495                         {
496                                 bGPDlayer *gpl= (bGPDlayer *)data;
497                                 
498                                 ale->flag= gpl->flag;
499                                 
500                                 ale->key_data= NULL;
501                                 ale->datatype= ALE_GPFRAME;
502                         }
503                                 break;
504                 }
505         }
506         
507         /* return created datatype */
508         return ale;
509 }
510  
511 /* ----------------------------------------- */
512
513 static int animdata_filter_actionchannel (ListBase *anim_data, bActionChannel *achan, int filter_mode, void *owner, short ownertype)
514 {
515         bAnimListElem *ale = NULL;
516         bConstraintChannel *conchan;
517         IpoCurve *icu;
518         short owned= (owner && ownertype)? 1 : 0;
519         int items = 0;
520         
521         /* only work with this channel and its subchannels if it is visible */
522         if (!(filter_mode & ANIMFILTER_VISIBLE) || VISIBLE_ACHAN(achan)) {
523                 /* only work with this channel and its subchannels if it is editable */
524                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_ACHAN(achan)) {
525                         /* check if this achan should only be included if it is selected */
526                         if (!(filter_mode & ANIMFILTER_SEL) || SEL_ACHAN(achan)) {
527                                 /* are we only interested in the ipo-curves? */
528                                 if ((filter_mode & ANIMFILTER_ONLYICU)==0) {
529                                         ale= make_new_animlistelem(achan, ANIMTYPE_ACHAN, achan, ANIMTYPE_ACHAN);
530                                         
531                                         if (ale) {
532                                                 if (owned) ale->id= owner;
533                                                 BLI_addtail(anim_data, ale);
534                                                 items++;
535                                         }
536                                 }
537                         }
538                         else {
539                                 /* for insert key... this check could be improved */
540                                 //return;  // FIXME...
541                         }
542                         
543                         /* check if expanded - if not, continue on to next animion channel */
544                         if (EXPANDED_ACHAN(achan) == 0 && (filter_mode & ANIMFILTER_ONLYICU)==0) {
545                                 /* only exit if we don't need to include constraint channels for group-channel keyframes */
546                                 if ( !(filter_mode & ANIMFILTER_IPOKEYS) || (achan->grp == NULL) || (EXPANDED_AGRP(achan->grp)==0) )
547                                         return items;
548                         }
549                                 
550                         /* ipo channels */
551                         if ((achan->ipo) && (filter_mode & ANIMFILTER_IPOKEYS)==0) {
552                                 /* include ipo-expand widget? */
553                                 if ((filter_mode & ANIMFILTER_CHANNELS) && (filter_mode & ANIMFILTER_ONLYICU)==0) {
554                                         ale= make_new_animlistelem(achan, ANIMTYPE_FILLIPO, achan, ANIMTYPE_ACHAN);
555                                         
556                                         if (ale) {
557                                                 if (owned) ale->id= owner;
558                                                 BLI_addtail(anim_data, ale);
559                                                 items++;
560                                         }
561                                 }
562                                 
563                                 /* add ipo-curve channels? */
564                                 if (FILTER_IPO_ACHAN(achan) || (filter_mode & ANIMFILTER_ONLYICU)) {
565                                         /* loop through ipo-curve channels, adding them */
566                                         for (icu= achan->ipo->curve.first; icu; icu=icu->next) {
567                                                 ale= make_new_animlistelem(icu, ANIMTYPE_ICU, achan, ANIMTYPE_ACHAN);
568                                                 
569                                                 if (ale) {
570                                                         if (owned) ale->id= owner;
571                                                         BLI_addtail(anim_data, ale); 
572                                                         items++;
573                                                 }
574                                         }
575                                 }
576                         }
577                         
578                         /* constraint channels */
579                         if (achan->constraintChannels.first) {
580                                 /* include constraint-expand widget? */
581                                 if ( (filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_ONLYICU)
582                                          && !(filter_mode & ANIMFILTER_IPOKEYS) ) 
583                                 {
584                                         ale= make_new_animlistelem(achan, ANIMTYPE_FILLCON, achan, ANIMTYPE_ACHAN);
585                                         
586                                         if (ale) {
587                                                 if (owned) ale->id= owner;
588                                                 BLI_addtail(anim_data, ale);
589                                                 items++;
590                                         }
591                                 }
592                                 
593                                 /* add constraint channels? */
594                                 if (FILTER_CON_ACHAN(achan) || (filter_mode & ANIMFILTER_IPOKEYS) || (filter_mode & ANIMFILTER_ONLYICU)) {
595                                         /* loop through constraint channels, checking and adding them */
596                                         for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
597                                                 /* only work with this channel and its subchannels if it is editable */
598                                                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_CONCHAN(conchan)) {
599                                                         /* check if this conchan should only be included if it is selected */
600                                                         if (!(filter_mode & ANIMFILTER_SEL) || SEL_CONCHAN(conchan)) {
601                                                                 if (filter_mode & ANIMFILTER_IPOKEYS) {
602                                                                         ale= make_new_animlistelem(conchan, ANIMTYPE_CONCHAN2, achan, ANIMTYPE_ACHAN);
603                                                                         
604                                                                         if (ale) {
605                                                                                 if (owned) ale->id= owner;
606                                                                                 BLI_addtail(anim_data, ale);
607                                                                                 items++;
608                                                                         }
609                                                                 }
610                                                                 else {
611                                                                         ale= make_new_animlistelem(conchan, ANIMTYPE_CONCHAN, achan, ANIMTYPE_ACHAN);
612                                                                         
613                                                                         if (ale) {
614                                                                                 if (owned) ale->id= owner;
615                                                                                 BLI_addtail(anim_data, ale);
616                                                                                 items++;
617                                                                         }
618                                                                 }
619                                                         }
620                                                 }
621                                         }
622                                 }
623                         }
624                 }               
625         }
626         
627         /* return the number of items added to the list */
628         return items;
629 }
630
631 static int animdata_filter_action (ListBase *anim_data, bAction *act, int filter_mode, void *owner, short ownertype)
632 {
633         bAnimListElem *ale=NULL;
634         bActionGroup *agrp;
635         bActionChannel *achan, *lastchan=NULL;
636         short owned= (owner && ownertype) ? 1 : 0;
637         int items = 0;
638         
639         /* loop over groups */
640         for (agrp= act->groups.first; agrp; agrp= agrp->next) {
641                 /* add this group as a channel first */
642                 if (!(filter_mode & ANIMFILTER_ONLYICU) && !(filter_mode & ANIMFILTER_IPOKEYS)) {
643                         /* check if filtering by selection */
644                         if ( !(filter_mode & ANIMFILTER_SEL) || SEL_AGRP(agrp) ) {
645                                 ale= make_new_animlistelem(agrp, ANIMTYPE_GROUP, NULL, ANIMTYPE_NONE);
646                                 if (ale) {
647                                         if (owned) ale->id= owner;
648                                         BLI_addtail(anim_data, ale);
649                                         items++;
650                                 }
651                         }
652                 }
653                 
654                 /* store reference to last channel of group */
655                 if (agrp->channels.last) 
656                         lastchan= agrp->channels.last;
657                 
658                 
659                 /* there are some situations, where only the channels of the animive group should get considered */
660                 if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) {
661                         /* filters here are a bit convoulted...
662                          *      - groups show a "summary" of keyframes beside their name which must accessable for tools which handle keyframes
663                          *      - groups can be collapsed (and those tools which are only interested in channels rely on knowing that group is closed)
664                          *
665                          * cases when we should include animion-channels and so-forth inside group:
666                          *      - we don't care about visibility
667                          *      - group is expanded
668                          *      - we're interested in keyframes, but not if they appear in selected channels
669                          */
670                         if ( (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_AGRP(agrp)) || 
671                                  ( ((filter_mode & ANIMFILTER_IPOKEYS) || (filter_mode & ANIMFILTER_ONLYICU)) && 
672                                    (!(filter_mode & ANIMFILTER_SEL) || (SEL_AGRP(agrp))) ) ) 
673                         {
674                                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {                                       
675                                         for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
676                                                 items += animdata_filter_actionchannel(anim_data, achan, filter_mode, owner, ownertype);
677                                         }
678                                         
679                                         /* remove group from filtered list if last element is group 
680                                          * (i.e. only if group had channels, which were all hidden)
681                                          */
682                                         // XXX this is really hacky... it should be fixed in a much more elegant way!
683                                         if ( (ale) && (anim_data->last == ale) && 
684                                                  (ale->data == agrp) && (agrp->channels.first) ) 
685                                         {
686                                                 BLI_freelinkN(anim_data, ale);
687                                                 items--;
688                                         }
689                                 }
690                         }
691                 }
692         }
693         
694         /* loop over un-grouped animion channels (only if we're not only considering those channels in the animive group) */
695         if (!(filter_mode & ANIMFILTER_ACTGROUPED))  {
696                 for (achan=(lastchan)?(lastchan->next):(act->chanbase.first); achan; achan=achan->next) {
697                         items += animdata_filter_actionchannel(anim_data, achan, filter_mode, owner, ownertype);
698                 }
699         }
700         
701         /* return the number of items added to the list */
702         return items;
703 }
704
705 static int animdata_filter_shapekey (ListBase *anim_data, Key *key, int filter_mode, void *owner, short ownertype)
706 {
707         bAnimListElem *ale;
708         KeyBlock *kb;
709         IpoCurve *icu;
710         short owned= (owner && ownertype)? 1 : 0;
711         int i, items=0;
712         
713         /* are we filtering for display or editing */
714         if (filter_mode & ANIMFILTER_FORDRAWING) {
715                 /* for display - loop over shapekeys, adding ipo-curve references where needed */
716                 kb= key->block.first;
717                 
718                 /* loop through possible shapekeys, manually creating entries */
719                 for (i= 1; i < key->totkey; i++) {
720                         ale= MEM_callocN(sizeof(bAnimListElem), "bAnimListElem");
721                         kb = kb->next; /* do this even on the first try, as the first is 'Basis' (which doesn't get included) */
722                         
723                         ale->data= kb;
724                         ale->type= ANIMTYPE_SHAPEKEY; /* 'abused' usage of this type */
725                         ale->owner= key;
726                         ale->ownertype= ANIMTYPE_SHAPEKEY;
727                         ale->datatype= ALE_NONE;
728                         ale->index = i;
729                         
730                         if (key->ipo) {
731                                 for (icu= key->ipo->curve.first; icu; icu=icu->next) {
732                                         if (icu->adrcode == i) {
733                                                 ale->key_data= icu;
734                                                 ale->datatype= ALE_ICU;
735                                                 break;
736                                         }
737                                 }
738                         }
739                         
740                         if (owned) ale->id= owner;
741                         
742                         BLI_addtail(anim_data, ale);
743                         items++;
744                 }
745         }
746         else {
747                 /* loop over ipo curves if present - for editing */
748                 if (key->ipo) {
749                         if (filter_mode & ANIMFILTER_IPOKEYS) {
750                                 ale= make_new_animlistelem(key->ipo, ANIMTYPE_IPO, key, ANIMTYPE_SHAPEKEY);
751                                 if (ale) {
752                                         if (owned) ale->id= owner;
753                                         BLI_addtail(anim_data, ale);
754                                         items++;
755                                 }
756                         }
757                         else {
758                                 for (icu= key->ipo->curve.first; icu; icu=icu->next) {
759                                         ale= make_new_animlistelem(icu, ANIMTYPE_ICU, key, ANIMTYPE_SHAPEKEY);
760                                         if (ale) {
761                                                 if (owned) ale->id= owner;
762                                                 BLI_addtail(anim_data, ale);
763                                                 items++;
764                                         }
765                                 }
766                         }
767                 }
768         }
769         
770         /* return the number of items added to the list */
771         return items;
772 }
773  
774 #if 0
775 // FIXME: switch this to use the bDopeSheet...
776 static int animdata_filter_gpencil (ListBase *anim_data, bScreen *sc, int filter_mode)
777 {
778         bAnimListElem *ale;
779         ScrArea *sa, *curarea;
780         bGPdata *gpd;
781         bGPDlayer *gpl;
782         int items = 0;
783         
784         /* check if filtering types are appropriate */
785         if ( !(filter_mode & (ANIMFILTER_IPOKEYS|ANIMFILTER_ONLYICU|ANIMFILTER_ACTGROUPED)) ) 
786         {
787                 /* special hack for fullscreen area (which must be this one then):
788                  *      - we use the curarea->full as screen to get spaces from, since the
789                  *        old (pre-fullscreen) screen was stored there...
790                  *      - this is needed as all data would otherwise disappear
791                  */
792                 // XXX need to get new alternative for curarea
793                 if ((curarea->full) && (curarea->spacetype==SPACE_ACTION))
794                         sc= curarea->full;
795                 
796                 /* loop over spaces in current screen, finding gpd blocks (could be slow!) */
797                 for (sa= sc->areabase.first; sa; sa= sa->next) {
798                         /* try to get gp data */
799                         // XXX need to put back grease pencil api...
800                         gpd= gpencil_data_getactive(sa);
801                         if (gpd == NULL) continue;
802                         
803                         /* add gpd as channel too (if for drawing, and it has layers) */
804                         if ((filter_mode & ANIMFILTER_FORDRAWING) && (gpd->layers.first)) {
805                                 /* add to list */
806                                 ale= make_new_animlistelem(gpd, ANIMTYPE_GPDATABLOCK, sa, ANIMTYPE_SPECIALDATA);
807                                 if (ale) {
808                                         BLI_addtail(anim_data, ale);
809                                         items++;
810                                 }
811                         }
812                         
813                         /* only add layers if they will be visible (if drawing channels) */
814                         if ( !(filter_mode & ANIMFILTER_VISIBLE) || (EXPANDED_GPD(gpd)) ) {
815                                 /* loop over layers as the conditions are acceptable */
816                                 for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
817                                         /* only if selected */
818                                         if (!(filter_mode & ANIMFILTER_SEL) || SEL_GPL(gpl)) {
819                                                 /* only if editable */
820                                                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) {
821                                                         /* add to list */
822                                                         ale= make_new_animlistelem(gpl, ANIMTYPE_GPLAYER, gpd, ANIMTYPE_GPDATABLOCK);
823                                                         if (ale) {
824                                                                 BLI_addtail(anim_data, ale);
825                                                                 items++;
826                                                         }
827                                                 }
828                                         }
829                                 }
830                         }
831                 }
832         }
833         
834         /* return the number of items added to the list */
835         return items;
836 }
837 #endif 
838
839 static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
840 {
841         bAnimListElem *ale=NULL;
842         Object *ob= base->object;
843         IpoCurve *icu;
844         int items = 0;
845         
846         /* include materials-expand widget? */
847         if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & (ANIMFILTER_IPOKEYS|ANIMFILTER_ONLYICU))) {
848                 ale= make_new_animlistelem(ob, ANIMTYPE_FILLMATD, base, ANIMTYPE_OBJECT);
849                 if (ale) {
850                         BLI_addtail(anim_data, ale);
851                         items++;
852                 }
853         }
854         
855         /* add materials? */
856         if (FILTER_MAT_OBJC(ob) || (filter_mode & ANIMFILTER_IPOKEYS) || (filter_mode & ANIMFILTER_ONLYICU)) {
857                 short a;
858                 
859                 /* for each material, either add channels separately, or as ipo-block */
860                 for (a=0; a<ob->totcol; a++) {
861                         Material *ma= give_current_material(ob, a);
862                         
863                         /* for now, if no material returned, skip (this shouldn't confuse the user I hope) */
864                         if (ELEM(NULL, ma, ma->ipo)) continue;
865                         
866                         /* include material-expand widget? */
867                         // hmm... do we need to store the index of this material in the array anywhere?
868                         if (filter_mode & (ANIMFILTER_CHANNELS|ANIMFILTER_IPOKEYS)) {
869                                 ale= make_new_animlistelem(ma, ANIMTYPE_DSMAT, base, ANIMTYPE_OBJECT);
870                                 if (ale) {
871                                         BLI_addtail(anim_data, ale);
872                                         items++;
873                                 }
874                         }
875                         
876                         /* add material's ipo-curve channels? */
877                         if ( (FILTER_MAT_OBJD(ma) || (filter_mode & ANIMFILTER_ONLYICU)) && 
878                                   !(filter_mode & ANIMFILTER_IPOKEYS) ) 
879                         {
880                                 /* loop through ipo-curve channels, adding them */
881                                 for (icu= ma->ipo->curve.first; icu; icu=icu->next) {
882                                         /* only if selected (if checking for selection) */
883                                         if ( !(filter_mode & ANIMFILTER_SEL) || (SEL_ICU(icu)) ) {
884                                                 ale= make_new_animlistelem(icu, ANIMTYPE_ICU, base, ANIMTYPE_OBJECT);
885                                                 if (ale) {
886                                                         /* make owner the material not object, so that indent is not just object level */
887                                                         ale->id= (ID *)ma;
888                                                         BLI_addtail(anim_data, ale);
889                                                         items++;
890                                                 }
891                                         }
892                                 }
893                         }
894                 }
895         }
896         
897         /* return the number of items added to the list */
898         return items;
899 }
900
901 static int animdata_filter_dopesheet_cam (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
902 {
903         bAnimListElem *ale=NULL;
904         Object *ob= base->object;
905         Camera *ca= (Camera *)ob->data;
906         IpoCurve *icu;
907         int items = 0;
908         
909         /* include camera-expand widget? */
910         if (filter_mode & (ANIMFILTER_CHANNELS|ANIMFILTER_IPOKEYS)) {
911                 ale= make_new_animlistelem(ca, ANIMTYPE_DSCAM, base, ANIMTYPE_OBJECT);
912                 if (ale) {
913                         BLI_addtail(anim_data, ale);
914                         items++;
915                 }
916         }
917         
918         /* add camera ipo-curve channels? */
919         if ( (FILTER_CAM_OBJD(ca) || (filter_mode & ANIMFILTER_ONLYICU)) && 
920                   !(filter_mode & ANIMFILTER_IPOKEYS) ) 
921         {
922                 /* loop through ipo-curve channels, adding them */
923                 for (icu= ca->ipo->curve.first; icu; icu=icu->next) {
924                         /* only if selected (if checking for selection) */
925                         if ( !(filter_mode & ANIMFILTER_SEL) || (SEL_ICU(icu)) ) {
926                                 ale= make_new_animlistelem(icu, ANIMTYPE_ICU, base, ANIMTYPE_OBJECT);
927                                 if (ale) {
928                                         /* make owner the material not object, so that indent is not just object level */
929                                         ale->id= (ID *)ca;
930                                         BLI_addtail(anim_data, ale);
931                                         items++;
932                                 }
933                         }
934                 }
935         }
936         
937         /* return the number of items added to the list */
938         return items;
939 }
940
941 static int animdata_filter_dopesheet_lamp (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
942 {
943         bAnimListElem *ale=NULL;
944         Object *ob= base->object;
945         Lamp *la= (Lamp *)ob->data;
946         IpoCurve *icu;
947         int items = 0;
948         
949         /* include lamp-expand widget? */
950         if (filter_mode & (ANIMFILTER_CHANNELS|ANIMFILTER_IPOKEYS)) {
951                 ale= make_new_animlistelem(la, ANIMTYPE_DSLAM, base, ANIMTYPE_OBJECT);
952                 if (ale) {
953                         BLI_addtail(anim_data, ale);
954                         items++;
955                 }
956         }
957         
958         /* add lamp ipo-curve channels? */
959         if ( (FILTER_LAM_OBJD(la) || (filter_mode & ANIMFILTER_ONLYICU)) && 
960                   !(filter_mode & ANIMFILTER_IPOKEYS) ) 
961         {
962                 /* loop through ipo-curve channels, adding them */
963                 for (icu= la->ipo->curve.first; icu; icu=icu->next) {
964                         /* only if selected (if checking for selection) */
965                         if ( !(filter_mode & ANIMFILTER_SEL) || (SEL_ICU(icu)) ) {
966                                 ale= make_new_animlistelem(icu, ANIMTYPE_ICU, base, ANIMTYPE_OBJECT);
967                                 if (ale) {
968                                         /* make owner the material not object, so that indent is not just object level */
969                                         ale->id= (ID *)la;
970                                         BLI_addtail(anim_data, ale);
971                                         items++;
972                                 }
973                         }
974                 }
975         }
976         
977         /* return the number of items added to the list */
978         return items;
979 }
980
981 static int animdata_filter_dopesheet_curve (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
982 {
983         bAnimListElem *ale=NULL;
984         Object *ob= base->object;
985         Curve *cu= (Curve *)ob->data;
986         IpoCurve *icu;
987         int items = 0;
988         
989         /* include curve-expand widget? */
990         if (filter_mode & (ANIMFILTER_CHANNELS|ANIMFILTER_IPOKEYS)) {
991                 ale= make_new_animlistelem(cu, ANIMTYPE_DSCUR, base, ANIMTYPE_OBJECT);
992                 if (ale) {
993                         BLI_addtail(anim_data, ale);
994                         items++;
995                 }
996         }
997         
998         /* add curve ipo-curve channels? */
999         if ( (FILTER_CUR_OBJD(cu) || (filter_mode & ANIMFILTER_ONLYICU)) && 
1000                   !(filter_mode & ANIMFILTER_IPOKEYS) ) 
1001         {
1002                 /* loop through ipo-curve channels, adding them */
1003                 for (icu= cu->ipo->curve.first; icu; icu=icu->next) {
1004                         /* only if selected (if checking for selection) */
1005                         if ( !(filter_mode & ANIMFILTER_SEL) || (SEL_ICU(icu)) ) {
1006                                 ale= make_new_animlistelem(icu, ANIMTYPE_ICU, base, ANIMTYPE_OBJECT);
1007                                 if (ale) {
1008                                         /* make owner the material not object, so that indent is not just object level */
1009                                         ale->id= (ID *)cu;
1010                                         BLI_addtail(anim_data, ale);
1011                                         items++;
1012                                 }
1013                         }
1014                 }
1015         }
1016         
1017         /* return the number of items added to the list */
1018         return items;
1019 }
1020
1021 static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
1022 {
1023         bAnimListElem *ale=NULL;
1024         Scene *sce= (Scene *)ads->source;
1025         Object *ob= base->object;
1026         Key *key= ob_get_key(ob);
1027         IpoCurve *icu;
1028         int items = 0;
1029         
1030         /* add this object as a channel first */
1031         if (!(filter_mode & ANIMFILTER_ONLYICU) && !(filter_mode & ANIMFILTER_IPOKEYS)) {
1032                 /* check if filtering by selection */
1033                 if ( !(filter_mode & ANIMFILTER_SEL) || ((base->flag & SELECT) || (base == sce->basact)) ) {
1034                         ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE);
1035                         if (ale) {
1036                                 BLI_addtail(anim_data, ale);
1037                                 items++;
1038                         }
1039                 }
1040         }
1041         
1042         /* if collapsed, don't go any further (unless adding keyframes only) */
1043         if ( (EXPANDED_OBJC(ob) == 0) && !(filter_mode & (ANIMFILTER_IPOKEYS|ANIMFILTER_ONLYICU)) )
1044                 return items;
1045         
1046         /* IPO? */
1047         if ((ob->ipo) && !(ads->filterflag & ADS_FILTER_NOIPOS)) {              
1048                 /* include ipo-expand widget? */
1049                 if (filter_mode & (ANIMFILTER_CHANNELS|ANIMFILTER_IPOKEYS)) {
1050                         ale= make_new_animlistelem(ob, ANIMTYPE_FILLIPOD, base, ANIMTYPE_OBJECT);
1051                         if (ale) {
1052                                 BLI_addtail(anim_data, ale);
1053                                 items++;
1054                         }
1055                 }
1056                 
1057                 /* add ipo-curve channels? */
1058                 if ( (FILTER_IPO_OBJC(ob) || (filter_mode & ANIMFILTER_ONLYICU)) && 
1059                           !(filter_mode & ANIMFILTER_IPOKEYS) ) 
1060                 {
1061                         /* loop through ipo-curve channels, adding them */
1062                         for (icu= ob->ipo->curve.first; icu; icu=icu->next) {
1063                                 /* only if selected (if checking for selection) */
1064                                 if ( !(filter_mode & ANIMFILTER_SEL) || (SEL_ICU(icu)) ) {
1065                                         ale= make_new_animlistelem(icu, ANIMTYPE_ICU, base, ANIMTYPE_OBJECT);
1066                                         if (ale) {
1067                                                 BLI_addtail(anim_data, ale); 
1068                                                 items++;
1069                                         }
1070                                 }
1071                         }
1072                 }
1073         }
1074         
1075         /* Action? */
1076         if ((ob->action) && !(ads->filterflag & ADS_FILTER_NOACTS)) {
1077                 /* include animion-expand widget? */
1078                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & (ANIMFILTER_IPOKEYS|ANIMFILTER_ONLYICU))) {
1079                         ale= make_new_animlistelem(ob->action, ANIMTYPE_FILLACTD, base, ANIMTYPE_OBJECT);
1080                         if (ale) {
1081                                 ale->id= (ID *)ob; // err.... is this a good idea?
1082                                 BLI_addtail(anim_data, ale);
1083                                 items++;
1084                         }
1085                 }
1086                 
1087                 /* add ipo-curve channels? */
1088                 if (EXPANDED_ACTC(ob->action) || !(filter_mode & (ANIMFILTER_CHANNELS|ANIMFILTER_FORDRAWING))) {
1089                         // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
1090                         items += animdata_filter_action(anim_data, ob->action, filter_mode, ob, ANIMTYPE_OBJECT); 
1091                 }
1092         }
1093         
1094         /* ShapeKeys? */
1095         if ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
1096                 /* include shapekey-expand widget? */
1097                 if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & (ANIMFILTER_IPOKEYS|ANIMFILTER_ONLYICU))) {
1098                         ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT);
1099                         if (ale) {
1100                                 BLI_addtail(anim_data, ale);
1101                                 items++;
1102                         }
1103                 }
1104                 
1105                 /* add channels */
1106                 if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_IPOKEYS) || (filter_mode & ANIMFILTER_ONLYICU)) {
1107                         items += animdata_filter_shapekey (anim_data, key, filter_mode, ob, ANIMTYPE_OBJECT);
1108                 }
1109         }
1110         
1111         /* Materials? */
1112         if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT))
1113                 items += animdata_filter_dopesheet_mats(anim_data, ads, base, filter_mode);
1114         
1115         /* Object Data */
1116         switch (ob->type) {
1117                 case OB_CAMERA: /* ------- Camera ------------ */
1118                 {
1119                         Camera *ca= (Camera *)ob->data;
1120                         if ((ca->ipo) && !(ads->filterflag & ADS_FILTER_NOCAM))
1121                                 items += animdata_filter_dopesheet_cam(anim_data, ads, base, filter_mode);
1122                 }
1123                         break;
1124                 case OB_LAMP: /* ---------- Lamp ----------- */
1125                 {
1126                         Lamp *la= (Lamp *)ob->data;
1127                         if ((la->ipo) && !(ads->filterflag & ADS_FILTER_NOLAM))
1128                                 items += animdata_filter_dopesheet_lamp(anim_data, ads, base, filter_mode);
1129                 }
1130                         break;
1131                 case OB_CURVE: /* ------- Curve ---------- */
1132                 {
1133                         Curve *cu= (Curve *)ob->data;
1134                         if ((cu->ipo) && !(ads->filterflag & ADS_FILTER_NOCUR))
1135                                 items += animdata_filter_dopesheet_curve(anim_data, ads, base, filter_mode);
1136                 }
1137                         break;
1138         }
1139         
1140         /* Constraint Channels? */
1141         if ((ob->constraintChannels.first) && !(ads->filterflag & ADS_FILTER_NOCONSTRAINTS)) {
1142                 bConstraintChannel *conchan;
1143                 
1144                 /* include constraint-expand widget? */
1145                 if ( (filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_ONLYICU)
1146                          && !(filter_mode & ANIMFILTER_IPOKEYS) ) 
1147                 {
1148                         ale= make_new_animlistelem(ob, ANIMTYPE_FILLCOND, base, ANIMTYPE_OBJECT);
1149                         if (ale) {
1150                                 BLI_addtail(anim_data, ale);
1151                                 items++;
1152                         }
1153                 }
1154                 
1155                 /* add constraint channels? */
1156                 if (FILTER_CON_OBJC(ob) || (filter_mode & ANIMFILTER_IPOKEYS) || (filter_mode & ANIMFILTER_ONLYICU)) {
1157                         /* loop through constraint channels, checking and adding them */
1158                         for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next) {
1159                                 /* only work with this channel and its subchannels if it is editable */
1160                                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_CONCHAN(conchan)) {
1161                                         /* check if this conchan should only be included if it is selected */
1162                                         if (!(filter_mode & ANIMFILTER_SEL) || SEL_CONCHAN(conchan)) {
1163                                                 if (filter_mode & ANIMFILTER_IPOKEYS) {
1164                                                         ale= make_new_animlistelem(conchan, ANIMTYPE_CONCHAN2, base, ANIMTYPE_OBJECT);
1165                                                         if (ale) {
1166                                                                 ale->id= (ID *)ob;
1167                                                                 BLI_addtail(anim_data, ale);
1168                                                                 items++;
1169                                                         }
1170                                                 }
1171                                                 else {
1172                                                         ale= make_new_animlistelem(conchan, ANIMTYPE_CONCHAN, base, ANIMTYPE_OBJECT);
1173                                                         if (ale) {
1174                                                                 ale->id= (ID *)ob;
1175                                                                 BLI_addtail(anim_data, ale);
1176                                                                 items++;
1177                                                         }
1178                                                 }
1179                                         }
1180                                 }
1181                         }
1182                 }
1183         }
1184         
1185         /* return the number of items added to the list */
1186         return items;
1187 }       
1188
1189 // 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)
1190 static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int filter_mode)
1191 {
1192         Scene *sce= (Scene *)ads->source;
1193         Base *base;
1194         int items = 0;
1195         
1196         /* check that we do indeed have a scene */
1197         if ((ads->source == NULL) || (GS(ads->source->name)!=ID_SCE)) {
1198                 printf("DopeSheet Error: Not scene! \n");
1199                 return 0;
1200         }
1201         
1202         /* loop over all bases in the scene */
1203         for (base= sce->base.first; base; base= base->next) {
1204                 /* check if there's an object (all the relevant checks are done in the ob-function) */
1205                 if (base->object) {
1206                         Object *ob= base->object;
1207                         Key *key= ob_get_key(ob);
1208                         short ipoOk, actOk, constsOk, keyOk, dataOk;
1209                         
1210                         /* firstly, check if object can be included, by the following fanimors:
1211                          *      - if only visible, must check for layer and also viewport visibility
1212                          *      - if only selected, must check if object is selected 
1213                          *      - there must be animation data to edit
1214                          */
1215                         // TODO: if cache is implemented, just check name here, and then 
1216                         if (filter_mode & ANIMFILTER_VISIBLE) {
1217                                 /* layer visibility */
1218                                 if ((ob->lay & sce->lay)==0) continue;
1219                                 
1220                                 /* outliner restrict-flag */
1221                                 if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
1222                         }
1223                         
1224                         /* additionally, dopesheet filtering also affects what objects to consider */
1225                         if (ads->filterflag) {
1226                                 /* check selection and object type filters */
1227                                 if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) || (base == sce->basact)) )  {
1228                                         /* only selected should be shown */
1229                                         continue;
1230                                 }
1231                                 if ((ads->filterflag & ADS_FILTER_NOARM) && (ob->type == OB_ARMATURE)) {
1232                                         /* not showing armatures  */
1233                                         continue;
1234                                 }
1235                                 if ((ads->filterflag & ADS_FILTER_NOOBJ) && (ob->type != OB_ARMATURE)) {
1236                                         /* not showing objects that aren't armatures */
1237                                         continue;
1238                                 }
1239                                 
1240                                 /* check filters for datatypes */
1241                                 ipoOk= ((ob->ipo) && !(ads->filterflag & ADS_FILTER_NOIPOS));
1242                                 actOk= ((ob->action) && !(ads->filterflag & ADS_FILTER_NOACTS));
1243                                 constsOk= ((ob->constraintChannels.first) && !(ads->filterflag & ADS_FILTER_NOCONSTRAINTS));
1244                                 keyOk= ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS));
1245                                 
1246                                 switch (ob->type) {
1247                                         case OB_CAMERA: /* ------- Camera ------------ */
1248                                         {
1249                                                 Camera *ca= (Camera *)ob->data;
1250                                                 dataOk= ((ca->ipo) && !(ads->filterflag & ADS_FILTER_NOCAM));                                           
1251                                         }
1252                                                 break;
1253                                         case OB_LAMP: /* ---------- Lamp ----------- */
1254                                         {
1255                                                 Lamp *la= (Lamp *)ob->data;
1256                                                 dataOk= ((la->ipo) && !(ads->filterflag & ADS_FILTER_NOLAM));
1257                                         }
1258                                                 break;
1259                                         case OB_CURVE: /* -------- Curve ---------- */
1260                                         {
1261                                                 Curve *cu= (Curve *)ob->data;
1262                                                 dataOk= ((cu->ipo) && !(ads->filterflag & ADS_FILTER_NOCUR));
1263                                         }
1264                                                 break;
1265                                         default: /* --- other --- */
1266                                                 dataOk= 0;
1267                                                 break;
1268                                 }
1269                                 
1270                                 /* check if all bad (i.e. nothing to show) */
1271                                 if (!ipoOk && !actOk && !constsOk && !keyOk && !dataOk)
1272                                         continue;
1273                         }
1274                         else {
1275                                 /* check data-types */
1276                                 ipoOk= (ob->ipo != NULL);
1277                                 actOk= (ob->action != NULL);
1278                                 constsOk= (ob->constraintChannels.first != NULL);
1279                                 keyOk= (key != NULL);
1280                                 
1281                                 switch (ob->type) {
1282                                         case OB_CAMERA: /* ------- Camera ------------ */
1283                                         {
1284                                                 Camera *ca= (Camera *)ob->data;
1285                                                 dataOk= (ca->ipo != NULL);                                              
1286                                         }
1287                                                 break;
1288                                         case OB_LAMP: /* ---------- Lamp ----------- */
1289                                         {
1290                                                 Lamp *la= (Lamp *)ob->data;
1291                                                 dataOk= (la->ipo != NULL);
1292                                         }
1293                                                 break;
1294                                         case OB_CURVE: /* -------- Curve ---------- */
1295                                         {
1296                                                 Curve *cu= (Curve *)ob->data;
1297                                                 dataOk= (cu->ipo != NULL);
1298                                         }
1299                                                 break;
1300                                         default: /* --- other --- */
1301                                                 dataOk= 0;
1302                                                 break;
1303                                 }
1304                                 
1305                                 /* check if all bad (i.e. nothing to show) */
1306                                 if (!ipoOk && !actOk && !constsOk && !keyOk && !dataOk)
1307                                         continue;
1308                         }
1309                         
1310                         /* since we're still here, this object should be usable */
1311                         items += animdata_filter_dopesheet_ob(anim_data, ads, base, filter_mode);
1312                 }
1313         }
1314         
1315         /* return the number of items in the list */
1316         return items;
1317 }
1318
1319 /* ----------- Public API --------------- */
1320
1321 /* This function filters the active data source to leave only animation channels suitable for
1322  * usage by the caller. It will return the length of the list 
1323  * 
1324  *      *act_data: is a pointer to a ListBase, to which the filtered animation channels
1325  *              will be placed for use.
1326  *      filter_mode: how should the data be filtered - bitmapping accessed flags
1327  */
1328 int ANIM_animdata_filter (ListBase *anim_data, int filter_mode, void *data, short datatype)
1329 {
1330         int items = 0;
1331         
1332         /* only filter data if there's somewhere to put it */
1333         if (data && anim_data) {
1334                 bAnimListElem *ale, *next;
1335                 
1336                 /* firstly filter the data */
1337                 switch (datatype) {
1338                         case ANIMCONT_ACTION:
1339                                 items= animdata_filter_action(anim_data, data, filter_mode, NULL, ANIMTYPE_NONE);
1340                                 break;
1341                         case ANIMCONT_SHAPEKEY:
1342                                 items= animdata_filter_shapekey(anim_data, data, filter_mode, NULL, ANIMTYPE_NONE);
1343                                 break;
1344                         case ANIMCONT_GPENCIL:
1345                                 //items= animdata_filter_gpencil(anim_data, data, filter_mode);
1346                                 break;
1347                         case ANIMCONT_DOPESHEET:
1348                                 items= animdata_filter_dopesheet(anim_data, data, filter_mode);
1349                                 break;
1350                                 
1351                         case ANIMCONT_IPO:
1352                                 // FIXME: this will be used for showing a single IPO-block (not too useful from animator perspective though!)
1353                                 //items= 0;
1354                                 break;
1355                 }
1356                         
1357                 /* remove any weedy entries */
1358                 // XXX this is weedy code!
1359                 for (ale= anim_data->first; ale; ale= next) {
1360                         next= ale->next;
1361                         
1362                         if (ale->type == ANIMTYPE_NONE) {
1363                                 items--;
1364                                 BLI_freelinkN(anim_data, ale);
1365                         }
1366                         
1367                         if (filter_mode & ANIMFILTER_IPOKEYS) {
1368                                 if (ale->datatype != ALE_IPO) {
1369                                         items--;
1370                                         BLI_freelinkN(anim_data, ale);
1371                                 }
1372                                 else if (ale->key_data == NULL) {
1373                                         items--;
1374                                         BLI_freelinkN(anim_data, ale);
1375                                 }
1376                         }
1377                 }
1378         }
1379         
1380         /* return the number of items in the list */
1381         return items;
1382 }
1383
1384 /* ************************************************************ */