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