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