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