Blender V2.61 - r43446

anim_filter.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2008 Blender Foundation, Joshua Leung
00019  * All rights reserved.
00020  *
00021  * 
00022  * Contributor(s): Joshua Leung (original author)
00023  *
00024  * ***** END GPL LICENSE BLOCK *****
00025  */
00026 
00032 /* This file contains a system used to provide a layer of abstraction between sources
00033  * of animation data and tools in Animation Editors. The method used here involves 
00034  * generating a list of edit structures which enable tools to naively perform the actions 
00035  * they require without all the boiler-plate associated with loops within loops and checking 
00036  * for cases to ignore. 
00037  *
00038  * While this is primarily used for the Action/Dopesheet Editor (and its accessory modes),
00039  * the Graph Editor also uses this for its channel list and for determining which curves
00040  * are being edited. Likewise, the NLA Editor also uses this for its channel list and in
00041  * its operators.
00042  *
00043  * Note: much of the original system this was based on was built before the creation of the RNA
00044  * system. In future, it would be interesting to replace some parts of this code with RNA queries,
00045  * however, RNA does not eliminate some of the boiler-plate reduction benefits presented by this 
00046  * system, so if any such work does occur, it should only be used for the internals used here...
00047  *
00048  * -- Joshua Leung, Dec 2008 (Last revision July 2009)
00049  */
00050 
00051 #include <string.h>
00052 
00053 #include "DNA_anim_types.h"
00054 #include "DNA_armature_types.h"
00055 #include "DNA_camera_types.h"
00056 #include "DNA_lamp_types.h"
00057 #include "DNA_lattice_types.h"
00058 #include "DNA_key_types.h"
00059 #include "DNA_material_types.h"
00060 #include "DNA_mesh_types.h"
00061 #include "DNA_meta_types.h"
00062 #include "DNA_node_types.h"
00063 #include "DNA_particle_types.h"
00064 #include "DNA_space_types.h"
00065 #include "DNA_sequence_types.h"
00066 #include "DNA_scene_types.h"
00067 #include "DNA_screen_types.h"
00068 #include "DNA_speaker_types.h"
00069 #include "DNA_world_types.h"
00070 #include "DNA_gpencil_types.h"
00071 #include "DNA_object_types.h"
00072 
00073 #include "MEM_guardedalloc.h"
00074 
00075 #include "BLI_blenlib.h"
00076 #include "BLI_utildefines.h"
00077 #include "BLI_ghash.h"
00078 
00079 #include "BKE_animsys.h"
00080 #include "BKE_action.h"
00081 #include "BKE_fcurve.h"
00082 #include "BKE_context.h"
00083 #include "BKE_global.h"
00084 #include "BKE_group.h"
00085 #include "BKE_key.h"
00086 #include "BKE_main.h"
00087 #include "BKE_material.h"
00088 #include "BKE_node.h"
00089 #include "BKE_sequencer.h"
00090 #include "BKE_utildefines.h"
00091 
00092 #include "ED_anim_api.h"
00093 #include "ED_markers.h"
00094 
00095 /* ************************************************************ */
00096 /* Blender Context <-> Animation Context mapping */
00097 
00098 /* ----------- Private Stuff - Action Editor ------------- */
00099 
00100 /* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */
00101 /* Note: there's a similar function in key.c (ob_get_key) */
00102 static Key *actedit_get_shapekeys (bAnimContext *ac) 
00103 {
00104     Scene *scene= ac->scene;
00105     Object *ob;
00106     Key *key;
00107     
00108     ob = OBACT;
00109     if (ob == NULL) 
00110         return NULL;
00111     
00112     /* XXX pinning is not available in 'ShapeKey' mode... */
00113     //if (saction->pin) return NULL;
00114     
00115     /* shapekey data is stored with geometry data */
00116     key= ob_get_key(ob);
00117     
00118     if (key) {
00119         if (key->type == KEY_RELATIVE)
00120             return key;
00121     }
00122     
00123     return NULL;
00124 }
00125 
00126 /* Get data being edited in Action Editor (depending on current 'mode') */
00127 static short actedit_get_context (bAnimContext *ac, SpaceAction *saction)
00128 {
00129     /* get dopesheet */
00130     ac->ads = &saction->ads;
00131     
00132     /* sync settings with current view status, then return appropriate data */
00133     switch (saction->mode) {
00134         case SACTCONT_ACTION: /* 'Action Editor' */
00135             /* if not pinned, sync with active object */
00136             if (/*saction->pin == 0*/1) {
00137                 if (ac->obact && ac->obact->adt)
00138                     saction->action = ac->obact->adt->action;
00139                 else
00140                     saction->action= NULL;
00141             }
00142             
00143             ac->datatype= ANIMCONT_ACTION;
00144             ac->data= saction->action;
00145             
00146             ac->mode= saction->mode;
00147             return 1;
00148             
00149         case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */
00150             ac->datatype= ANIMCONT_SHAPEKEY;
00151             ac->data= actedit_get_shapekeys(ac);
00152             
00153             ac->mode= saction->mode;
00154             return 1;
00155             
00156         case SACTCONT_GPENCIL: /* Grease Pencil */ // XXX review how this mode is handled...
00157             /* update scene-pointer (no need to check for pinning yet, as not implemented) */
00158             saction->ads.source= (ID *)ac->scene;
00159             
00160             ac->datatype= ANIMCONT_GPENCIL;
00161             ac->data= &saction->ads;
00162             
00163             ac->mode= saction->mode;
00164             return 1;
00165             
00166         case SACTCONT_DOPESHEET: /* DopeSheet */
00167             /* update scene-pointer (no need to check for pinning yet, as not implemented) */
00168             saction->ads.source= (ID *)ac->scene;
00169             
00170             ac->datatype= ANIMCONT_DOPESHEET;
00171             ac->data= &saction->ads;
00172             
00173             ac->mode= saction->mode;
00174             return 1;
00175         
00176         default: /* unhandled yet */
00177             ac->datatype= ANIMCONT_NONE;
00178             ac->data= NULL;
00179             
00180             ac->mode= -1;
00181             return 0;
00182     }
00183 }
00184 
00185 /* ----------- Private Stuff - Graph Editor ------------- */
00186 
00187 /* Get data being edited in Graph Editor (depending on current 'mode') */
00188 static short graphedit_get_context (bAnimContext *ac, SpaceIpo *sipo)
00189 {
00190     /* init dopesheet data if non-existant (i.e. for old files) */
00191     if (sipo->ads == NULL) {
00192         sipo->ads= MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet");
00193         sipo->ads->source= (ID *)ac->scene;
00194     }
00195     ac->ads = sipo->ads;
00196     
00197     /* set settings for Graph Editor - "Selected = Editable" */
00198     if (sipo->flag & SIPO_SELCUVERTSONLY)
00199         sipo->ads->filterflag |= ADS_FILTER_SELEDIT;
00200     else
00201         sipo->ads->filterflag &= ~ADS_FILTER_SELEDIT;
00202     
00203     /* sync settings with current view status, then return appropriate data */
00204     switch (sipo->mode) {
00205         case SIPO_MODE_ANIMATION:   /* Animation F-Curve Editor */
00206             /* update scene-pointer (no need to check for pinning yet, as not implemented) */
00207             sipo->ads->source= (ID *)ac->scene;
00208             sipo->ads->filterflag &= ~ADS_FILTER_ONLYDRIVERS;
00209             
00210             ac->datatype= ANIMCONT_FCURVES;
00211             ac->data= sipo->ads;
00212             
00213             ac->mode= sipo->mode;
00214             return 1;
00215         
00216         case SIPO_MODE_DRIVERS:     /* Driver F-Curve Editor */
00217             /* update scene-pointer (no need to check for pinning yet, as not implemented) */
00218             sipo->ads->source= (ID *)ac->scene;
00219             sipo->ads->filterflag |= ADS_FILTER_ONLYDRIVERS;
00220             
00221             ac->datatype= ANIMCONT_DRIVERS;
00222             ac->data= sipo->ads;
00223             
00224             ac->mode= sipo->mode;
00225             return 1;
00226         
00227         default: /* unhandled yet */
00228             ac->datatype= ANIMCONT_NONE;
00229             ac->data= NULL;
00230             
00231             ac->mode= -1;
00232             return 0;
00233     }
00234 }
00235 
00236 /* ----------- Private Stuff - NLA Editor ------------- */
00237 
00238 /* Get data being edited in Graph Editor (depending on current 'mode') */
00239 static short nlaedit_get_context (bAnimContext *ac, SpaceNla *snla)
00240 {
00241     /* init dopesheet data if non-existant (i.e. for old files) */
00242     if (snla->ads == NULL)
00243         snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
00244     ac->ads = snla->ads;
00245     
00246     /* sync settings with current view status, then return appropriate data */
00247     /* update scene-pointer (no need to check for pinning yet, as not implemented) */
00248     snla->ads->source= (ID *)ac->scene;
00249     snla->ads->filterflag |= ADS_FILTER_ONLYNLA;
00250     
00251     ac->datatype= ANIMCONT_NLA;
00252     ac->data= snla->ads;
00253     
00254     return 1;
00255 }
00256 
00257 /* ----------- Public API --------------- */
00258 
00259 /* Obtain current anim-data context, given that context info from Blender context has already been set 
00260  *  - AnimContext to write to is provided as pointer to var on stack so that we don't have
00261  *    allocation/freeing costs (which are not that avoidable with channels).
00262  */
00263 short ANIM_animdata_context_getdata (bAnimContext *ac)
00264 {
00265     SpaceLink *sl = ac->sl;
00266     short ok= 0;
00267     
00268     /* context depends on editor we are currently in */
00269     if (sl) {
00270         switch (ac->spacetype) {
00271             case SPACE_ACTION:
00272             {
00273                 SpaceAction *saction= (SpaceAction *)sl;
00274                 ok= actedit_get_context(ac, saction);
00275             }
00276                 break;
00277                 
00278             case SPACE_IPO:
00279             {
00280                 SpaceIpo *sipo= (SpaceIpo *)sl;
00281                 ok= graphedit_get_context(ac, sipo);
00282             }
00283                 break;
00284                 
00285             case SPACE_NLA:
00286             {
00287                 SpaceNla *snla= (SpaceNla *)sl;
00288                 ok= nlaedit_get_context(ac, snla);
00289             }
00290                 break;
00291         }
00292     }
00293     
00294     /* check if there's any valid data */
00295     if (ok && ac->data)
00296         return 1;
00297     else
00298         return 0;
00299 }
00300 
00301 /* Obtain current anim-data context from Blender Context info 
00302  *  - AnimContext to write to is provided as pointer to var on stack so that we don't have
00303  *    allocation/freeing costs (which are not that avoidable with channels).
00304  *  - Clears data and sets the information from Blender Context which is useful
00305  */
00306 short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac)
00307 {
00308     ScrArea *sa= CTX_wm_area(C);
00309     ARegion *ar= CTX_wm_region(C);
00310     SpaceLink *sl= CTX_wm_space_data(C);
00311     Scene *scene= CTX_data_scene(C);
00312     
00313     /* clear old context info */
00314     if (ac == NULL) return 0;
00315     memset(ac, 0, sizeof(bAnimContext));
00316     
00317     /* get useful default context settings from context */
00318     ac->scene= scene;
00319     if (scene) {
00320         ac->markers= ED_context_get_markers(C);     
00321         ac->obact= (scene->basact)?  scene->basact->object : NULL;
00322     }
00323     ac->sa= sa;
00324     ac->ar= ar;
00325     ac->sl= sl;
00326     ac->spacetype= (sa) ? sa->spacetype : 0;
00327     ac->regiontype= (ar) ? ar->regiontype : 0;
00328     
00329     /* get data context info */
00330     return ANIM_animdata_context_getdata(ac);
00331 }
00332 
00333 /* ************************************************************ */
00334 /* Blender Data <-- Filter --> Channels to be operated on */
00335 
00336 /* macros to use before/after getting the sub-channels of some channel,
00337  * to abstract away some of the tricky logic involved
00338  *
00339  * cases:
00340  *  1) Graph Edit main area (just data) OR channels visible in Channel List
00341  *  2) If not showing channels, we're only interested in the data (Action Editor's editing)
00342  *  3) We don't care what data, we just care there is some (so that a collapsed 
00343  *     channel can be kept around). No need to clear channels-flag in order to 
00344  *     keep expander channels with no sub-data out, as those cases should get
00345  *     dealt with by the recursive detection idiom in place.
00346  *
00347  * Implementation Note:
00348  *  YES the _doSubChannels variable is NOT read anywhere. BUT, this is NOT an excuse
00349  *  to go steamrolling the logic into a single-line expression as from experience,
00350  *  those are notoriously difficult to read + debug when extending later on. The code
00351  *  below is purposefully laid out so that each case noted above corresponds clearly to
00352  *  one case below.
00353  */
00354 #define BEGIN_ANIMFILTER_SUBCHANNELS(expanded_check) \
00355     { \
00356         int _filter = filter_mode; \
00357         short _doSubChannels = 0; \
00358         if (!(filter_mode & ANIMFILTER_LIST_VISIBLE) || (expanded_check)) \
00359             _doSubChannels=1; \
00360         else if (!(filter_mode & ANIMFILTER_LIST_CHANNELS)) \
00361             _doSubChannels=2; \
00362         else {\
00363             filter_mode |= ANIMFILTER_TMP_PEEK; \
00364         } \
00365         (void) _doSubChannels;
00366         /* ... standard sub-channel filtering can go on here now ... */
00367 #define END_ANIMFILTER_SUBCHANNELS \
00368         filter_mode = _filter; \
00369     }
00370 
00371 /* ............................... */
00372 
00373 /* quick macro to test if AnimData is usable */
00374 #define ANIMDATA_HAS_KEYS(id) ((id)->adt && (id)->adt->action)
00375 
00376 /* quick macro to test if AnimData is usable for drivers */
00377 #define ANIMDATA_HAS_DRIVERS(id) ((id)->adt && (id)->adt->drivers.first)
00378 
00379 /* quick macro to test if AnimData is usable for NLA */
00380 #define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first)
00381 
00382 /* Quick macro to test for all three above usability tests, performing the appropriate provided 
00383  * action for each when the AnimData context is appropriate. 
00384  *
00385  * Priority order for this goes (most important, to least): AnimData blocks, NLA, Drivers, Keyframes.
00386  *
00387  * For this to work correctly, a standard set of data needs to be available within the scope that this
00388  * gets called in: 
00389  *  - ListBase anim_data;
00390  *  - bDopeSheet *ads;
00391  *  - bAnimListElem *ale;
00392  *  - size_t items;
00393  *
00394  *  - id: ID block which should have an AnimData pointer following it immediately, to use
00395  *  - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
00396  *  - nlaOk: line or block of code to execute for NLA tracks+strips case
00397  *  - driversOk: line or block of code to execute for Drivers case
00398  *  - keysOk: line or block of code for Keyframes case
00399  *
00400  * The checks for the various cases are as follows:
00401  *  0) top level: checks for animdata and also that all the F-Curves for the block will be visible
00402  *  1) animdata check: for filtering animdata blocks only
00403  *  2A) nla tracks: include animdata block's data as there are NLA tracks+strips there
00404  *  2B) actions to convert to nla: include animdata block's data as there is an action that can be 
00405  *      converted to a new NLA strip, and the filtering options allow this
00406  *  2C) allow non-animated datablocks to be included so that datablocks can be added
00407  *  3) drivers: include drivers from animdata block (for Drivers mode in Graph Editor)
00408  *  4) normal keyframes: only when there is an active action
00409  */
00410 #define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \
00411     {\
00412         if ((id)->adt) {\
00413             if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) {\
00414                 if (filter_mode & ANIMFILTER_ANIMDATA) {\
00415                     adtOk\
00416                 }\
00417                 else if (ads->filterflag & ADS_FILTER_ONLYNLA) {\
00418                     if (ANIMDATA_HAS_NLA(id)) {\
00419                         nlaOk\
00420                     }\
00421                     else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) && ANIMDATA_HAS_KEYS(id)) {\
00422                         nlaOk\
00423                     }\
00424                 }\
00425                 else if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) {\
00426                     if (ANIMDATA_HAS_DRIVERS(id)) {\
00427                         driversOk\
00428                     }\
00429                 }\
00430                 else {\
00431                     if (ANIMDATA_HAS_KEYS(id)) {\
00432                         keysOk\
00433                     }\
00434                 }\
00435             }\
00436         }\
00437     }
00438 
00439 /* ............................... */
00440 
00441 /* Add a new animation channel, taking into account the "peek" flag, which is used to just check 
00442  * whether any channels will be added (but without needing them to actually get created).
00443  *
00444  * ! This causes the calling function to return early if we're only "peeking" for channels
00445  */
00446 // XXX: ale_statement stuff is really a hack for one special case. It shouldn't really be needed...
00447 #define ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, ale_statement) \
00448     if (filter_mode & ANIMFILTER_TMP_PEEK) \
00449         return 1; \
00450     else { \
00451         bAnimListElem *ale= make_new_animlistelem(channel_data, channel_type, (ID *)owner_id); \
00452         if (ale) {\
00453             BLI_addtail(anim_data, ale); \
00454             items++; \
00455             ale_statement \
00456         } \
00457     }
00458     
00459 #define ANIMCHANNEL_NEW_CHANNEL(channel_data, channel_type, owner_id) \
00460     ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, {})
00461     
00462 /* ............................... */
00463     
00464 /* quick macro to test if an anim-channel representing an AnimData block is suitably active */
00465 #define ANIMCHANNEL_ACTIVEOK(ale) \
00466     ( !(filter_mode & ANIMFILTER_ACTIVE) || !(ale->adt) || (ale->adt->flag & ADT_UI_ACTIVE) )
00467 
00468 /* quick macro to test if an anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */
00469 #define ANIMCHANNEL_SELOK(test_func) \
00470         ( !(filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) || \
00471           ((filter_mode & ANIMFILTER_SEL) && test_func) || \
00472           ((filter_mode & ANIMFILTER_UNSEL) && test_func==0) ) 
00473           
00474 /* quick macro to test if an anim-channel (F-Curve) is selected ok for editing purposes 
00475  *  - _SELEDIT means that only selected curves will have visible+editable keyframes
00476  *
00477  * checks here work as follows:
00478  *  1) seledit off - don't need to consider the implications of this option
00479  *  2) foredit off - we're not considering editing, so channel is ok still
00480  *  3) test_func (i.e. selection test) - only if selected, this test will pass
00481  */
00482 #define ANIMCHANNEL_SELEDITOK(test_func) \
00483         ( !(filter_mode & ANIMFILTER_SELEDIT) || \
00484           !(filter_mode & ANIMFILTER_FOREDIT) || \
00485           (test_func) )
00486 
00487 /* ----------- 'Private' Stuff --------------- */
00488 
00489 /* this function allocates memory for a new bAnimListElem struct for the 
00490  * provided animation channel-data. 
00491  */
00492 static bAnimListElem *make_new_animlistelem (void *data, short datatype, ID *owner_id)
00493 {
00494     bAnimListElem *ale= NULL;
00495     
00496     /* only allocate memory if there is data to convert */
00497     if (data) {
00498         /* allocate and set generic data */
00499         ale= MEM_callocN(sizeof(bAnimListElem), "bAnimListElem");
00500         
00501         ale->data= data;
00502         ale->type= datatype;
00503         
00504         ale->id= owner_id;
00505         ale->adt= BKE_animdata_from_id(owner_id);
00506         
00507         /* do specifics */
00508         switch (datatype) {
00509             case ANIMTYPE_SUMMARY:
00510             {
00511                 /* nothing to include for now... this is just a dummy wrappy around all the other channels 
00512                  * in the DopeSheet, and gets included at the start of the list
00513                  */
00514                 ale->key_data= NULL;
00515                 ale->datatype= ALE_ALL;
00516             }
00517                 break;
00518             
00519             case ANIMTYPE_SCENE:
00520             {
00521                 Scene *sce= (Scene *)data;
00522                 
00523                 ale->flag= sce->flag;
00524                 
00525                 ale->key_data= sce;
00526                 ale->datatype= ALE_SCE;
00527                 
00528                 ale->adt= BKE_animdata_from_id(data);
00529             }
00530                 break;
00531             case ANIMTYPE_OBJECT:
00532             {
00533                 Base *base= (Base *)data;
00534                 Object *ob= base->object;
00535                 
00536                 ale->flag= ob->flag;
00537                 
00538                 ale->key_data= ob;
00539                 ale->datatype= ALE_OB;
00540                 
00541                 ale->adt= BKE_animdata_from_id(&ob->id);
00542             }
00543                 break;
00544             case ANIMTYPE_FILLACTD:
00545             {
00546                 bAction *act= (bAction *)data;
00547                 
00548                 ale->flag= act->flag;
00549                 
00550                 ale->key_data= act;
00551                 ale->datatype= ALE_ACT;
00552             }
00553                 break;
00554             case ANIMTYPE_FILLDRIVERS:
00555             {
00556                 AnimData *adt= (AnimData *)data;
00557                 
00558                 ale->flag= adt->flag;
00559                 
00560                     // XXX... drivers don't show summary for now
00561                 ale->key_data= NULL;
00562                 ale->datatype= ALE_NONE;
00563             }
00564                 break;
00565             
00566             case ANIMTYPE_DSMAT:
00567             {
00568                 Material *ma= (Material *)data;
00569                 AnimData *adt= ma->adt;
00570                 
00571                 ale->flag= FILTER_MAT_OBJD(ma);
00572                 
00573                 ale->key_data= (adt) ? adt->action : NULL;
00574                 ale->datatype= ALE_ACT;
00575                 
00576                 ale->adt= BKE_animdata_from_id(data);
00577             }
00578                 break;
00579             case ANIMTYPE_DSLAM:
00580             {
00581                 Lamp *la= (Lamp *)data;
00582                 AnimData *adt= la->adt;
00583                 
00584                 ale->flag= FILTER_LAM_OBJD(la);
00585                 
00586                 ale->key_data= (adt) ? adt->action : NULL;
00587                 ale->datatype= ALE_ACT;
00588                 
00589                 ale->adt= BKE_animdata_from_id(data);
00590             }
00591                 break;
00592             case ANIMTYPE_DSCAM:
00593             {
00594                 Camera *ca= (Camera *)data;
00595                 AnimData *adt= ca->adt;
00596                 
00597                 ale->flag= FILTER_CAM_OBJD(ca);
00598                 
00599                 ale->key_data= (adt) ? adt->action : NULL;
00600                 ale->datatype= ALE_ACT;
00601                 
00602                 ale->adt= BKE_animdata_from_id(data);
00603             }
00604                 break;
00605             case ANIMTYPE_DSCUR:
00606             {
00607                 Curve *cu= (Curve *)data;
00608                 AnimData *adt= cu->adt;
00609                 
00610                 ale->flag= FILTER_CUR_OBJD(cu);
00611                 
00612                 ale->key_data= (adt) ? adt->action : NULL;
00613                 ale->datatype= ALE_ACT;
00614                 
00615                 ale->adt= BKE_animdata_from_id(data);
00616             }
00617                 break;
00618             case ANIMTYPE_DSARM:
00619             {
00620                 bArmature *arm= (bArmature *)data;
00621                 AnimData *adt= arm->adt;
00622                 
00623                 ale->flag= FILTER_ARM_OBJD(arm);
00624                 
00625                 ale->key_data= (adt) ? adt->action : NULL;
00626                 ale->datatype= ALE_ACT;
00627                 
00628                 ale->adt= BKE_animdata_from_id(data);
00629             }
00630                 break;
00631             case ANIMTYPE_DSMESH:
00632             {
00633                 Mesh *me= (Mesh *)data;
00634                 AnimData *adt= me->adt;
00635                 
00636                 ale->flag= FILTER_MESH_OBJD(me);
00637                 
00638                 ale->key_data= (adt) ? adt->action : NULL;
00639                 ale->datatype= ALE_ACT;
00640                 
00641                 ale->adt= BKE_animdata_from_id(data);
00642             }
00643                 break;
00644             case ANIMTYPE_DSLAT:
00645             {
00646                 Lattice *lt= (Lattice *)data;
00647                 AnimData *adt= lt->adt;
00648                 
00649                 ale->flag= FILTER_LATTICE_OBJD(lt);
00650                 
00651                 ale->key_data= (adt) ? adt->action : NULL;
00652                 ale->datatype= ALE_ACT;
00653                 
00654                 ale->adt= BKE_animdata_from_id(data);
00655             }   
00656                 break;
00657             case ANIMTYPE_DSSPK:
00658             {
00659                 Speaker *spk= (Speaker *)data;
00660                 AnimData *adt= spk->adt;
00661 
00662                 ale->flag= FILTER_SPK_OBJD(spk);
00663 
00664                 ale->key_data= (adt) ? adt->action : NULL;
00665                 ale->datatype= ALE_ACT;
00666 
00667                 ale->adt= BKE_animdata_from_id(data);
00668             }
00669                 break;
00670             case ANIMTYPE_DSSKEY:
00671             {
00672                 Key *key= (Key *)data;
00673                 AnimData *adt= key->adt;
00674                 
00675                 ale->flag= FILTER_SKE_OBJD(key); 
00676                 
00677                 ale->key_data= (adt) ? adt->action : NULL;
00678                 ale->datatype= ALE_ACT;
00679                 
00680                 ale->adt= BKE_animdata_from_id(data);
00681             }
00682                 break;
00683             case ANIMTYPE_DSWOR:
00684             {
00685                 World *wo= (World *)data;
00686                 AnimData *adt= wo->adt;
00687                 
00688                 ale->flag= FILTER_WOR_SCED(wo); 
00689                 
00690                 ale->key_data= (adt) ? adt->action : NULL;
00691                 ale->datatype= ALE_ACT;
00692                 
00693                 ale->adt= BKE_animdata_from_id(data);
00694             }
00695                 break;
00696             case ANIMTYPE_DSNTREE:
00697             {
00698                 bNodeTree *ntree= (bNodeTree *)data;
00699                 AnimData *adt= ntree->adt;
00700                 
00701                 ale->flag= FILTER_NTREE_DATA(ntree); 
00702                 
00703                 ale->key_data= (adt) ? adt->action : NULL;
00704                 ale->datatype= ALE_ACT;
00705                 
00706                 ale->adt= BKE_animdata_from_id(data);
00707             }
00708                 break;
00709             case ANIMTYPE_DSPART:
00710             {
00711                 ParticleSettings *part= (ParticleSettings*)ale->data;
00712                 AnimData *adt= part->adt;
00713                 
00714                 ale->flag= FILTER_PART_OBJD(part); 
00715                 
00716                 ale->key_data= (adt) ? adt->action : NULL;
00717                 ale->datatype= ALE_ACT;
00718                 
00719                 ale->adt= BKE_animdata_from_id(data);
00720             }
00721                 break;
00722             case ANIMTYPE_DSTEX:
00723             {
00724                 Tex *tex= (Tex *)data;
00725                 AnimData *adt= tex->adt;
00726                 
00727                 ale->flag= FILTER_TEX_DATA(tex); 
00728                 
00729                 ale->key_data= (adt) ? adt->action : NULL;
00730                 ale->datatype= ALE_ACT;
00731                 
00732                 ale->adt= BKE_animdata_from_id(data);
00733             }
00734                 break;
00735                 
00736             case ANIMTYPE_GROUP:
00737             {
00738                 bActionGroup *agrp= (bActionGroup *)data;
00739                 
00740                 ale->flag= agrp->flag;
00741                 
00742                 ale->key_data= NULL;
00743                 ale->datatype= ALE_GROUP;
00744             }
00745                 break;
00746             case ANIMTYPE_FCURVE:
00747             {
00748                 FCurve *fcu= (FCurve *)data;
00749                 
00750                 ale->flag= fcu->flag;
00751                 
00752                 ale->key_data= fcu;
00753                 ale->datatype= ALE_FCURVE;
00754             }
00755                 break;
00756                 
00757             case ANIMTYPE_SHAPEKEY:
00758             {
00759                 KeyBlock *kb= (KeyBlock *)data;
00760                 Key *key= (Key *)ale->id;
00761                 
00762                 ale->flag= kb->flag;
00763                 
00764                 /* whether we have keyframes depends on whether there is a Key block to find it from */
00765                 if (key) {
00766                     /* index of shapekey is defined by place in key's list */
00767                     ale->index= BLI_findindex(&key->block, kb);
00768                     
00769                     /* the corresponding keyframes are from the animdata */
00770                     if (ale->adt && ale->adt->action) {
00771                         bAction *act= ale->adt->action;
00772                         char *rna_path = key_get_curValue_rnaPath(key, kb);
00773                         
00774                         /* try to find the F-Curve which corresponds to this exactly,
00775                          * then free the MEM_alloc'd string
00776                          */
00777                         if (rna_path) {
00778                             ale->key_data= (void *)list_find_fcurve(&act->curves, rna_path, 0);
00779                             MEM_freeN(rna_path);
00780                         }
00781                     }
00782                     ale->datatype= (ale->key_data)? ALE_FCURVE : ALE_NONE;
00783                 }
00784             }   
00785                 break;
00786             
00787             case ANIMTYPE_GPLAYER:
00788             {
00789                 bGPDlayer *gpl= (bGPDlayer *)data;
00790                 
00791                 ale->flag= gpl->flag;
00792                 
00793                 ale->key_data= NULL;
00794                 ale->datatype= ALE_GPFRAME;
00795             }
00796                 break;
00797                 
00798             case ANIMTYPE_NLATRACK:
00799             {
00800                 NlaTrack *nlt= (NlaTrack *)data;
00801                 
00802                 ale->flag= nlt->flag;
00803                 
00804                 ale->key_data= &nlt->strips;
00805                 ale->datatype= ALE_NLASTRIP;
00806             }
00807                 break;
00808             case ANIMTYPE_NLAACTION:
00809             {
00810                 /* nothing to include for now... nothing editable from NLA-perspective here */
00811                 ale->key_data= NULL;
00812                 ale->datatype= ALE_NONE;
00813             }
00814                 break;
00815         }
00816     }
00817     
00818     /* return created datatype */
00819     return ale;
00820 }
00821  
00822 /* ----------------------------------------- */
00823 
00824 /* 'Only Selected' selected data filtering
00825  * NOTE: when this function returns true, the F-Curve is to be skipped 
00826  */
00827 static size_t skip_fcurve_selected_data (bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode)
00828 {
00829     if (GS(owner_id->name) == ID_OB) {
00830         Object *ob= (Object *)owner_id;
00831         
00832         /* only consider if F-Curve involves pose.bones */
00833         if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) {
00834             bPoseChannel *pchan;
00835             char *bone_name;
00836             
00837             /* get bone-name, and check if this bone is selected */
00838             bone_name= BLI_getQuotedStr(fcu->rna_path, "pose.bones[");
00839             pchan= get_pose_channel(ob->pose, bone_name);
00840             if (bone_name) MEM_freeN(bone_name);
00841             
00842             /* check whether to continue or skip */
00843             if ((pchan) && (pchan->bone)) {
00844                 /* if only visible channels, skip if bone not visible unless user wants channels from hidden data too */
00845                 if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
00846                     bArmature *arm= (bArmature *)ob->data;
00847                     
00848                     if ((arm->layer & pchan->bone->layer) == 0)
00849                         return 1;
00850                     // TODO: manually hidden using flags
00851                 }
00852                 
00853                 /* can only add this F-Curve if it is selected */
00854                 if ((pchan->bone->flag & BONE_SELECTED) == 0)
00855                     return 1;
00856             }
00857         }
00858     }
00859     else if (GS(owner_id->name) == ID_SCE) {
00860         Scene *scene = (Scene *)owner_id;
00861         
00862         /* only consider if F-Curve involves sequence_editor.sequences */
00863         if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
00864             Editing *ed= seq_give_editing(scene, FALSE);
00865             Sequence *seq;
00866             char *seq_name;
00867             
00868             /* get strip name, and check if this strip is selected */
00869             seq_name= BLI_getQuotedStr(fcu->rna_path, "sequences_all[");
00870             seq = get_seq_by_name(ed->seqbasep, seq_name, FALSE);
00871             if (seq_name) MEM_freeN(seq_name);
00872             
00873             /* can only add this F-Curve if it is selected */
00874             if (seq==NULL || (seq->flag & SELECT)==0)
00875                 return 1;
00876         }
00877     }
00878     else if (GS(owner_id->name) == ID_NT) {
00879         bNodeTree *ntree = (bNodeTree *)owner_id;
00880         
00881         /* check for selected  nodes */
00882         if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) {
00883             bNode *node;
00884             char *node_name;
00885             
00886             /* get strip name, and check if this strip is selected */
00887             node_name= BLI_getQuotedStr(fcu->rna_path, "nodes[");
00888             node = nodeFindNodebyName(ntree, node_name);
00889             if (node_name) MEM_freeN(node_name);
00890             
00891             /* can only add this F-Curve if it is selected */
00892             if ((node) && (node->flag & NODE_SELECT)==0)
00893                 return 1;
00894         }
00895     }
00896     return 0;
00897 }
00898 
00899 /* (Display-)Name-based F-Curve filtering
00900  * NOTE: when this function returns true, the F-Curve is to be skipped 
00901  */
00902 static short skip_fcurve_with_name (bDopeSheet *ads, FCurve *fcu, ID *owner_id)
00903 {
00904     bAnimListElem ale_dummy = {NULL};
00905     bAnimChannelType *acf;
00906     
00907     /* create a dummy wrapper for the F-Curve */
00908     ale_dummy.type = ANIMTYPE_FCURVE;
00909     ale_dummy.id = owner_id;
00910     ale_dummy.data = fcu;
00911     
00912     /* get type info for channel */
00913     acf = ANIM_channel_get_typeinfo(&ale_dummy);
00914     if (acf && acf->name) {
00915         char name[256]; /* hopefully this will be enough! */
00916         
00917         /* get name */
00918         acf->name(&ale_dummy, name);
00919         
00920         /* check for partial match with the match string, assuming case insensitive filtering 
00921          * if match, this channel shouldn't be ignored!
00922          */
00923         return BLI_strcasestr(name, ads->searchstr) == NULL;
00924     }
00925     
00926     /* just let this go... */
00927     return 1;
00928 }
00929 
00930 /* find the next F-Curve that is usable for inclusion */
00931 static FCurve *animfilter_fcurve_next (bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id)
00932 {
00933     FCurve *fcu = NULL;
00934     
00935     /* loop over F-Curves - assume that the caller of this has already checked that these should be included 
00936      * NOTE: we need to check if the F-Curves belong to the same group, as this gets called for groups too...
00937      */
00938     for (fcu= first; ((fcu) && (fcu->grp==grp)); fcu= fcu->next) {
00939         /* special exception for Pose-Channel/Sequence-Strip/Node Based F-Curves:
00940          *  - the 'Only Selected' data filter should be applied to Pose-Channel data too, but those are
00941          *    represented as F-Curves. The way the filter for objects worked was to be the first check
00942          *    after 'normal' visibility, so this is done first here too...
00943          *  - we currently use an 'approximate' method for getting these F-Curves that doesn't require
00944          *    carefully checking the entire path
00945          *  - this will also affect things like Drivers, and also works for Bone Constraints
00946          */
00947         if ( ((ads) && (ads->filterflag & ADS_FILTER_ONLYSEL)) && (owner_id) ) {
00948             if (skip_fcurve_selected_data(ads, fcu, owner_id, filter_mode))
00949                 continue;
00950         }
00951         
00952         /* only include if visible (Graph Editor check, not channels check) */
00953         if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || (fcu->flag & FCURVE_VISIBLE)) {
00954             /* only work with this channel and its subchannels if it is editable */
00955             if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) {
00956                 /* only include this curve if selected in a way consistent with the filtering requirements */
00957                 if ( ANIMCHANNEL_SELOK(SEL_FCU(fcu)) && ANIMCHANNEL_SELEDITOK(SEL_FCU(fcu)) ) {
00958                     /* only include if this curve is active */
00959                     if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
00960                         /* name based filtering... */
00961                         if ( ((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) && (owner_id) ) {
00962                             if (skip_fcurve_with_name(ads, fcu, owner_id))
00963                                 continue;
00964                         }
00965                         
00966                         /* this F-Curve can be used, so return it */
00967                         return fcu;
00968                     }
00969                 }
00970             }
00971         }
00972     }
00973     
00974     /* no (more) F-Curves from the list are suitable... */
00975     return NULL;
00976 }
00977 
00978 static size_t animfilter_fcurves (ListBase *anim_data, bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id)
00979 {
00980     FCurve *fcu;
00981     size_t items = 0;
00982     
00983     /* loop over every F-Curve able to be included 
00984      *  - this for-loop works like this: 
00985      *      1) the starting F-Curve is assigned to the fcu pointer so that we have a starting point to search from
00986      *      2) the first valid F-Curve to start from (which may include the one given as 'first') in the remaining 
00987      *         list of F-Curves is found, and verified to be non-null
00988      *      3) the F-Curve referenced by fcu pointer is added to the list
00989      *      4) the fcu pointer is set to the F-Curve after the one we just added, so that we can keep going through 
00990      *         the rest of the F-Curve list without an eternal loop. Back to step 2 :)
00991      */
00992     for (fcu=first; ( (fcu = animfilter_fcurve_next(ads, fcu, grp, filter_mode, owner_id)) ); fcu=fcu->next)
00993     {
00994         ANIMCHANNEL_NEW_CHANNEL(fcu, ANIMTYPE_FCURVE, owner_id);
00995     }
00996     
00997     /* return the number of items added to the list */
00998     return items;
00999 }
01000 
01001 static size_t animfilter_act_group (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAction *UNUSED(act), bActionGroup *agrp, int filter_mode, ID *owner_id)
01002 {
01003     ListBase tmp_data = {NULL, NULL};
01004     size_t tmp_items = 0;
01005     size_t items = 0;
01006     //int ofilter = filter_mode;
01007     
01008     /* if we care about the selection status of the channels, 
01009      * but the group isn't expanded (1)...
01010      *  (1) this only matters if we actually care about the hierarchy though.
01011      *      - Hierarchy matters: this hack should be applied
01012      *      - Hierarchy ignored: cases like [#21276] won't work properly, unless we skip this hack
01013      */
01014     if ( ((filter_mode & ANIMFILTER_LIST_VISIBLE) && EXPANDED_AGRP(ac, agrp)==0) &&     /* care about hierarchy but group isn't expanded */
01015           (filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) )                           /* care about selection status */    
01016     {
01017         /* if the group itself isn't selected appropriately, we shouldn't consider it's children either */
01018         if (ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) == 0)
01019             return 0;
01020         
01021         /* if we're still here, then the selection status of the curves within this group should not matter,
01022          * since this creates too much overhead for animators (i.e. making a slow workflow)
01023          *
01024          * Tools affected by this at time of coding (2010 Feb 09):
01025          *  - inserting keyframes on selected channels only
01026          *  - pasting keyframes
01027          *  - creating ghost curves in Graph Editor
01028          */
01029         filter_mode &= ~(ANIMFILTER_SEL|ANIMFILTER_UNSEL|ANIMFILTER_LIST_VISIBLE);
01030     }
01031     
01032     /* add grouped F-Curves */
01033     BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_AGRP(ac, agrp))
01034     {
01035         /* special filter so that we can get just the F-Curves within the active group */
01036         if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) {
01037             /* for the Graph Editor, curves may be set to not be visible in the view to lessen clutter,
01038              * but to do this, we need to check that the group doesn't have it's not-visible flag set preventing 
01039              * all its sub-curves to be shown
01040              */
01041             if ( !(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE) )
01042             {
01043                 /* group must be editable for its children to be editable (if we care about this) */
01044                 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
01045                     /* get first F-Curve which can be used here */
01046                     FCurve *first_fcu = animfilter_fcurve_next(ads, agrp->channels.first, agrp, filter_mode, owner_id);
01047                     
01048                     /* filter list, starting from this F-Curve */
01049                     tmp_items += animfilter_fcurves(&tmp_data, ads, first_fcu, agrp, filter_mode, owner_id);
01050                 }
01051             }
01052         }
01053     }
01054     END_ANIMFILTER_SUBCHANNELS;
01055     
01056     /* did we find anything? */
01057     if (tmp_items) {
01058         /* add this group as a channel first */
01059         if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01060             /* restore original filter mode so that this next step works ok... */
01061             //filter_mode = ofilter;
01062             
01063             /* filter selection of channel specially here again, since may be open and not subject to previous test */
01064             if ( ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) ) {
01065                 ANIMCHANNEL_NEW_CHANNEL(agrp, ANIMTYPE_GROUP, owner_id);
01066             }
01067         }
01068         
01069         /* now add the list of collected channels */
01070         BLI_movelisttolist(anim_data, &tmp_data);
01071         BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01072         items += tmp_items;
01073     }
01074     
01075     /* return the number of items added to the list */
01076     return items;
01077 }
01078 
01079 static size_t animfilter_action (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAction *act, int filter_mode, ID *owner_id)
01080 {
01081     bActionGroup *agrp;
01082     FCurve *lastchan = NULL;
01083     size_t items = 0;
01084     
01085     /* don't include anything from this action if it is linked in from another file,
01086      * and we're getting stuff for editing...
01087      */
01088     // TODO: need a way of tagging other channels that may also be affected...
01089     if ((filter_mode & ANIMFILTER_FOREDIT) && (act->id.lib))
01090         return 0;
01091         
01092     /* do groups */
01093     // TODO: do nested groups?
01094     for (agrp = act->groups.first; agrp; agrp = agrp->next) {
01095         /* store reference to last channel of group */
01096         if (agrp->channels.last) 
01097             lastchan= agrp->channels.last;
01098             
01099         /* action group's channels */
01100         items += animfilter_act_group(ac, anim_data, ads, act, agrp, filter_mode, owner_id);
01101     }
01102     
01103     /* un-grouped F-Curves (only if we're not only considering those channels in the active group) */
01104     if (!(filter_mode & ANIMFILTER_ACTGROUPED))  {
01105         FCurve *firstfcu = (lastchan)? (lastchan->next) : (act->curves.first);
01106         items += animfilter_fcurves(anim_data, ads, firstfcu, NULL, filter_mode, owner_id);
01107     }
01108     
01109     /* return the number of items added to the list */
01110     return items;
01111 }
01112 
01113 /* Include NLA-Data for NLA-Editor:
01114  *  - when ANIMFILTER_LIST_CHANNELS is used, that means we should be filtering the list for display
01115  *    Although the evaluation order is from the first track to the last and then apply the Action on top,
01116  *    we present this in the UI as the Active Action followed by the last track to the first so that we 
01117  *    get the evaluation order presented as per a stack.
01118  *  - for normal filtering (i.e. for editing), we only need the NLA-tracks but they can be in 'normal' evaluation
01119  *    order, i.e. first to last. Otherwise, some tools may get screwed up.
01120  */
01121 static size_t animfilter_nla (bAnimContext *UNUSED(ac), ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id)
01122 {
01123     NlaTrack *nlt;
01124     NlaTrack *first=NULL, *next=NULL;
01125     size_t items = 0;
01126     
01127     /* if showing channels, include active action */
01128     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01129         /* if NLA action-line filtering is off, don't show unless there are keyframes, 
01130          * in order to keep things more compact for doing transforms
01131          */
01132         if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || (adt->action)) {
01133             /* there isn't really anything editable here, so skip if need editable */
01134             if ((filter_mode & ANIMFILTER_FOREDIT) == 0) { 
01135                 /* just add the action track now (this MUST appear for drawing)
01136                  *  - as AnimData may not have an action, we pass a dummy pointer just to get the list elem created, then
01137                  *    overwrite this with the real value - REVIEW THIS...
01138                  */
01139                 ANIMCHANNEL_NEW_CHANNEL_FULL((void *)(&adt->action), ANIMTYPE_NLAACTION, owner_id, 
01140                     {
01141                         ale->data= adt->action ? adt->action : NULL; 
01142                     });
01143             }
01144         }
01145         
01146         /* first track to include will be the last one if we're filtering by channels */
01147         first= adt->nla_tracks.last;
01148     }
01149     else {
01150         /* first track to include will the the first one (as per normal) */
01151         first= adt->nla_tracks.first;
01152     }
01153     
01154     /* loop over NLA Tracks - assume that the caller of this has already checked that these should be included */
01155     for (nlt= first; nlt; nlt= next) {
01156         /* 'next' NLA-Track to use depends on whether we're filtering for drawing or not */
01157         if (filter_mode & ANIMFILTER_LIST_CHANNELS) 
01158             next= nlt->prev;
01159         else
01160             next= nlt->next;
01161         
01162         /* if we're in NLA-tweakmode, don't show this track if it was disabled (due to tweaking) for now 
01163          *  - active track should still get shown though (even though it has disabled flag set)
01164          */
01165         // FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel
01166         if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && !(nlt->flag & NLATRACK_ACTIVE))
01167             continue;
01168         
01169         /* only work with this channel and its subchannels if it is editable */
01170         if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) {
01171             /* only include this track if selected in a way consistent with the filtering requirements */
01172             if ( ANIMCHANNEL_SELOK(SEL_NLT(nlt)) ) {
01173                 /* only include if this track is active */
01174                 if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
01175                     ANIMCHANNEL_NEW_CHANNEL(nlt, ANIMTYPE_NLATRACK, owner_id);
01176                 }
01177             }
01178         }
01179     }
01180     
01181     /* return the number of items added to the list */
01182     return items;
01183 }
01184 
01185 /* determine what animation data from AnimData block should get displayed */
01186 static size_t animfilter_block_data (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *id, int filter_mode)
01187 {
01188     AnimData *adt = BKE_animdata_from_id(id);
01189     size_t items = 0;
01190 
01191     /* image object datablocks have no anim-data so check for NULL */
01192     if(adt) {
01193         IdAdtTemplate *iat = (IdAdtTemplate*)id;
01194 
01195         /* NOTE: this macro is used instead of inlining the logic here, since this sort of filtering is still needed
01196          * in a few places in he rest of the code still - notably for the few cases where special mode-based
01197          * different types of data expanders are required.
01198          */
01199         ANIMDATA_FILTER_CASES(iat,
01200             { /* AnimData */
01201                 /* specifically filter animdata block */
01202                 ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id);
01203             },
01204             { /* NLA */
01205                 items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id);
01206             },
01207             { /* Drivers */
01208                 items += animfilter_fcurves(anim_data, ads, adt->drivers.first, NULL, filter_mode, id);
01209             },
01210             { /* Keyframes */
01211                 items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id);
01212             }
01213         );
01214     }
01215 
01216     return items;
01217 }
01218 
01219 
01220 
01221 /* Include ShapeKey Data for ShapeKey Editor */
01222 static size_t animdata_filter_shapekey (bAnimContext *ac, ListBase *anim_data, Key *key, int filter_mode)
01223 {
01224     size_t items = 0;
01225     
01226     /* check if channels or only F-Curves */
01227     if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01228         KeyBlock *kb;
01229         
01230         /* loop through the channels adding ShapeKeys as appropriate */
01231         for (kb= key->block.first; kb; kb= kb->next) {
01232             /* skip the first one, since that's the non-animateable basis */
01233             // XXX maybe in future this may become handy?
01234             if (kb == key->block.first) continue;
01235             
01236             /* only work with this channel and its subchannels if it is editable */
01237             if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_SHAPEKEY(kb)) {
01238                 /* only include this track if selected in a way consistent with the filtering requirements */
01239                 if ( ANIMCHANNEL_SELOK(SEL_SHAPEKEY(kb)) ) {
01240                     // TODO: consider 'active' too?
01241                     
01242                     /* owner-id here must be key so that the F-Curve can be resolved... */
01243                     ANIMCHANNEL_NEW_CHANNEL(kb, ANIMTYPE_SHAPEKEY, key);
01244                 }
01245             }
01246         }
01247     }
01248     else {
01249         /* just use the action associated with the shapekey */
01250         // TODO: somehow manage to pass dopesheet info down here too?
01251         if (key->adt) {
01252             if (filter_mode & ANIMFILTER_ANIMDATA) {
01253                 ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key);
01254             }
01255             else if (key->adt->action) {
01256                 items= animfilter_action(ac, anim_data, NULL, key->adt->action, filter_mode, (ID *)key);
01257             }
01258         }
01259     }
01260     
01261     /* return the number of items added to the list */
01262     return items;
01263 }
01264 
01265 static size_t animdata_filter_gpencil_data (ListBase *anim_data, bGPdata *gpd, int filter_mode)
01266 {
01267     bGPDlayer *gpl;
01268     size_t items = 0;
01269     
01270     /* loop over layers as the conditions are acceptable */
01271     for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
01272         /* only if selected */
01273         if ( ANIMCHANNEL_SELOK(SEL_GPL(gpl)) ) {
01274             /* only if editable */
01275             if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) {
01276                 /* active... */
01277                 if (!(filter_mode & ANIMFILTER_ACTIVE) || (gpl->flag & GP_LAYER_ACTIVE)) {
01278                     /* add to list */
01279                     ANIMCHANNEL_NEW_CHANNEL(gpl, ANIMTYPE_GPLAYER, gpd);
01280                 }
01281             }
01282         }
01283     }
01284     
01285     return items;
01286 }
01287 
01288 /* Grab all Grase Pencil datablocks in file */
01289 // TODO: should this be amalgamated with the dopesheet filtering code?
01290 static size_t animdata_filter_gpencil (ListBase *anim_data, void *UNUSED(data), int filter_mode)
01291 {
01292     bGPdata *gpd;
01293     size_t items = 0;
01294     
01295     /* for now, grab grease pencil datablocks directly from main */
01296     // XXX: this is not good...
01297     for (gpd = G.main->gpencil.first; gpd; gpd = gpd->id.next) {
01298         ListBase tmp_data = {NULL, NULL};
01299         size_t tmp_items = 0;
01300         
01301         /* only show if gpd is used by something... */
01302         if (ID_REAL_USERS(gpd) < 1)
01303             continue;
01304             
01305         /* add gpencil animation channels */
01306         BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd))
01307         {
01308             tmp_items += animdata_filter_gpencil_data(&tmp_data, gpd, filter_mode);
01309         }
01310         END_ANIMFILTER_SUBCHANNELS;
01311         
01312         /* did we find anything? */
01313         if (tmp_items) {
01314             /* include data-expand widget first */
01315             if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01316                 /* add gpd as channel too (if for drawing, and it has layers) */
01317                 ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
01318             }
01319             
01320             /* now add the list of collected channels */
01321             BLI_movelisttolist(anim_data, &tmp_data);
01322             BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01323             items += tmp_items;
01324         }
01325     }
01326     
01327     /* return the number of items added to the list */
01328     return items;
01329 }
01330 
01331 /* NOTE: owner_id is scene, material, or texture block, which is the direct owner of the node tree in question */
01332 // TODO: how to handle group nodes is still unclear...
01333 static size_t animdata_filter_ds_nodetree (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, bNodeTree *ntree, int filter_mode)
01334 {
01335     ListBase tmp_data = {NULL, NULL};
01336     size_t tmp_items = 0;
01337     size_t items = 0;
01338     
01339     /* add nodetree animation channels */
01340     BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_NTREE_DATA(ntree))
01341     {
01342         /* animation data filtering */
01343         tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ntree, filter_mode);
01344     }
01345     END_ANIMFILTER_SUBCHANNELS;
01346     
01347     /* did we find anything? */
01348     if (tmp_items) {
01349         /* include data-expand widget first */
01350         if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01351             /* check if filtering by active status */
01352             if ANIMCHANNEL_ACTIVEOK(ntree) {
01353                 ANIMCHANNEL_NEW_CHANNEL(ntree, ANIMTYPE_DSNTREE, owner_id);
01354             }
01355         }
01356         
01357         /* now add the list of collected channels */
01358         BLI_movelisttolist(anim_data, &tmp_data);
01359         BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01360         items += tmp_items;
01361     }
01362     
01363     /* return the number of items added to the list */
01364     return items;
01365 }
01366 
01367 /* NOTE: owner_id is either material, lamp, or world block, which is the direct owner of the texture stack in question */
01368 static size_t animdata_filter_ds_textures (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, int filter_mode)
01369 {
01370     MTex **mtex = NULL;
01371     size_t items=0;
01372     int a=0;
01373     
01374     /* get datatype specific data first */
01375     if (owner_id == NULL)
01376         return 0;
01377     
01378     switch (GS(owner_id->name)) {
01379         case ID_MA:
01380         {
01381             Material *ma= (Material *)owner_id;
01382             mtex= (MTex**)(&ma->mtex);
01383         }
01384             break;
01385         case ID_LA:
01386         {
01387             Lamp *la= (Lamp *)owner_id;
01388             mtex= (MTex**)(&la->mtex);
01389         }
01390             break;
01391         case ID_WO:
01392         {
01393             World *wo= (World *)owner_id;
01394             mtex= (MTex**)(&wo->mtex);
01395         }
01396             break;
01397         default: 
01398         {
01399             /* invalid/unsupported option */
01400             if (G.f & G_DEBUG)
01401                 printf("ERROR: unsupported owner_id (i.e. texture stack) for filter textures - %s \n", owner_id->name);
01402             return 0;
01403         }
01404     }
01405     
01406     /* firstly check that we actuallly have some textures, by gathering all textures in a temp list */
01407     for (a=0; a < MAX_MTEX; a++) {
01408         Tex *tex= (mtex[a]) ? mtex[a]->tex : NULL;
01409         ListBase tmp_data = {NULL, NULL};
01410         size_t tmp_items = 0;
01411         
01412         /* for now, if no texture returned, skip (this shouldn't confuse the user I hope) */
01413         if (tex == NULL) 
01414             continue;
01415         
01416         /* add texture's animation data to temp collection */
01417         BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_TEX_DATA(tex)) 
01418         {
01419             /* texture animdata */
01420             tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)tex, filter_mode);
01421             
01422             /* nodes */
01423             if ((tex->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
01424                 /* owner_id as id instead of texture, since it'll otherwise be impossible to track the depth */
01425                 // FIXME: perhaps as a result, textures should NOT be included under materials, but under their own section instead
01426                 // so that free-floating textures can also be animated
01427                 tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)tex, tex->nodetree, filter_mode);
01428             }
01429         }
01430         END_ANIMFILTER_SUBCHANNELS;
01431         
01432         /* did we find anything? */
01433         if (tmp_items) {
01434             /* include texture-expand widget? */
01435             if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01436                 /* check if filtering by active status */
01437                 if ANIMCHANNEL_ACTIVEOK(tex) {
01438                     ANIMCHANNEL_NEW_CHANNEL(tex, ANIMTYPE_DSTEX, owner_id);
01439                 }
01440             }
01441             
01442             /* now add the list of collected channels */
01443             BLI_movelisttolist(anim_data, &tmp_data);
01444             BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01445             items += tmp_items;
01446         }
01447     }
01448     
01449     /* return the number of items added to the list */
01450     return items;
01451 }
01452 
01453 static size_t animdata_filter_ds_materials (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
01454 {
01455     size_t items=0;
01456     int a=0;
01457     
01458     /* firstly check that we actuallly have some materials, by gathering all materials in a temp list */
01459     for (a=1; a <= ob->totcol; a++) {
01460         Material *ma= give_current_material(ob, a);
01461         ListBase tmp_data = {NULL, NULL};
01462         size_t tmp_items = 0;
01463         
01464         /* if no material returned, skip - so that we don't get weird blank entries... */
01465         if (ma == NULL) continue;
01466         
01467         /* add material's animation data to temp collection */
01468         BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_MAT_OBJD(ma))
01469         {
01470             /* material's animation data */
01471             tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ma, filter_mode);
01472                 
01473             /* textures */
01474             if (!(ads->filterflag & ADS_FILTER_NOTEX))
01475                 tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)ma, filter_mode);
01476                 
01477             /* nodes */
01478             if ((ma->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) 
01479                 tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)ma, ma->nodetree, filter_mode);
01480         }
01481         END_ANIMFILTER_SUBCHANNELS;
01482         
01483         /* did we find anything? */
01484         if (tmp_items) {
01485             /* include material-expand widget first */
01486             // hmm... do we need to store the index of this material in the array anywhere?
01487             if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01488                 /* check if filtering by active status */
01489                 if ANIMCHANNEL_ACTIVEOK(ma) {
01490                     ANIMCHANNEL_NEW_CHANNEL(ma, ANIMTYPE_DSMAT, ma);
01491                 }
01492             }
01493             
01494             /* now add the list of collected channels */
01495             BLI_movelisttolist(anim_data, &tmp_data);
01496             BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01497             items += tmp_items;
01498         }
01499     }
01500     
01501     /* return the number of items added to the list */
01502     return items;
01503 }
01504 
01505 static size_t animdata_filter_ds_particles (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
01506 {
01507     ParticleSystem *psys;
01508     size_t items= 0;
01509 
01510     for (psys = ob->particlesystem.first; psys; psys=psys->next) {
01511         ListBase tmp_data = {NULL, NULL};
01512         size_t tmp_items = 0;
01513         
01514         /* if no material returned, skip - so that we don't get weird blank entries... */
01515         if (ELEM(NULL, psys->part, psys->part->adt))
01516             continue;
01517         
01518         /* add particle-system's animation data to temp collection */
01519         BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_PART_OBJD(psys->part))
01520         {
01521             /* material's animation data */
01522             tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)psys->part, filter_mode);
01523         }
01524         END_ANIMFILTER_SUBCHANNELS;
01525         
01526         /* did we find anything? */
01527         if (tmp_items) {
01528             /* include particle-expand widget first */
01529             if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01530                 /* check if filtering by active status */
01531                 if ANIMCHANNEL_ACTIVEOK(psys->part) {
01532                     ANIMCHANNEL_NEW_CHANNEL(psys->part, ANIMTYPE_DSPART, psys->part);
01533                 }
01534             }
01535             
01536             /* now add the list of collected channels */
01537             BLI_movelisttolist(anim_data, &tmp_data);
01538             BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01539             items += tmp_items;
01540         }
01541     }
01542     
01543     /* return the number of items added to the list */
01544     return items;
01545 }
01546 
01547 static size_t animdata_filter_ds_obdata (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
01548 {
01549     ListBase tmp_data = {NULL, NULL};
01550     size_t tmp_items = 0;
01551     size_t items= 0;
01552     
01553     IdAdtTemplate *iat= ob->data;
01554     short type=0, expanded=0;
01555     
01556     /* get settings based on data type */
01557     switch (ob->type) {
01558         case OB_CAMERA: /* ------- Camera ------------ */
01559         {
01560             Camera *ca= (Camera *)ob->data;
01561             
01562             if (ads->filterflag & ADS_FILTER_NOCAM)
01563                 return 0;
01564             
01565             type= ANIMTYPE_DSCAM;
01566             expanded= FILTER_CAM_OBJD(ca);
01567         }
01568             break;
01569         case OB_LAMP: /* ---------- Lamp ----------- */
01570         {
01571             Lamp *la= (Lamp *)ob->data;
01572             
01573             if (ads->filterflag & ADS_FILTER_NOLAM)
01574                 return 0;
01575             
01576             type= ANIMTYPE_DSLAM;
01577             expanded= FILTER_LAM_OBJD(la);
01578         }
01579             break;
01580         case OB_CURVE: /* ------- Curve ---------- */
01581         case OB_SURF: /* ------- Nurbs Surface ---------- */
01582         case OB_FONT: /* ------- Text Curve ---------- */
01583         {
01584             Curve *cu= (Curve *)ob->data;
01585             
01586             if (ads->filterflag & ADS_FILTER_NOCUR)
01587                 return 0;
01588             
01589             type= ANIMTYPE_DSCUR;
01590             expanded= FILTER_CUR_OBJD(cu);
01591         }
01592             break;
01593         case OB_MBALL: /* ------- MetaBall ---------- */
01594         {
01595             MetaBall *mb= (MetaBall *)ob->data;
01596             
01597             if (ads->filterflag & ADS_FILTER_NOMBA)
01598                 return 0;
01599             
01600             type= ANIMTYPE_DSMBALL;
01601             expanded= FILTER_MBALL_OBJD(mb);
01602         }
01603             break;
01604         case OB_ARMATURE: /* ------- Armature ---------- */
01605         {
01606             bArmature *arm= (bArmature *)ob->data;
01607             
01608             if (ads->filterflag & ADS_FILTER_NOARM)
01609                 return 0;
01610             
01611             type= ANIMTYPE_DSARM;
01612             expanded= FILTER_ARM_OBJD(arm);
01613         }
01614             break;
01615         case OB_MESH: /* ------- Mesh ---------- */
01616         {
01617             Mesh *me= (Mesh *)ob->data;
01618             
01619             if (ads->filterflag & ADS_FILTER_NOMESH)
01620                 return 0;
01621             
01622             type= ANIMTYPE_DSMESH;
01623             expanded= FILTER_MESH_OBJD(me);
01624         }
01625             break;
01626         case OB_LATTICE: /* ---- Lattice ---- */
01627         {
01628             Lattice *lt = (Lattice *)ob->data;
01629             
01630             if (ads->filterflag & ADS_FILTER_NOLAT)
01631                 return 0;
01632             
01633             type= ANIMTYPE_DSLAT;
01634             expanded= FILTER_LATTICE_OBJD(lt);
01635         }
01636             break;
01637         case OB_SPEAKER: /* ---------- Speaker ----------- */
01638         {
01639             Speaker *spk= (Speaker *)ob->data;
01640             
01641             type= ANIMTYPE_DSSPK;
01642             expanded= FILTER_SPK_OBJD(spk);
01643         }
01644             break;
01645     }
01646     
01647     /* add object data animation channels */
01648     BEGIN_ANIMFILTER_SUBCHANNELS(expanded)
01649     {
01650         /* animation data filtering */
01651         tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)iat, filter_mode);
01652         
01653         /* sub-data filtering... */
01654         switch (ob->type) {
01655             case OB_LAMP:   /* lamp - textures */
01656             {
01657                 /* textures */
01658                 if (!(ads->filterflag & ADS_FILTER_NOTEX))
01659                     tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, ob->data, filter_mode);
01660             }
01661                 break;
01662         }
01663     }
01664     END_ANIMFILTER_SUBCHANNELS;
01665     
01666     /* did we find anything? */
01667     if (tmp_items) {
01668         /* include data-expand widget first */
01669         if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01670             /* check if filtering by active status */
01671             if ANIMCHANNEL_ACTIVEOK(iat) {
01672                 ANIMCHANNEL_NEW_CHANNEL(iat, type, iat);
01673             }
01674         }
01675         
01676         /* now add the list of collected channels */
01677         BLI_movelisttolist(anim_data, &tmp_data);
01678         BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01679         items += tmp_items;
01680     }
01681     
01682     /* return the number of items added to the list */
01683     return items;
01684 }
01685 
01686 /* shapekey-level animation */
01687 static size_t animdata_filter_ds_keyanim (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, Key *key, int filter_mode)
01688 {
01689     ListBase tmp_data = {NULL, NULL};
01690     size_t tmp_items = 0;
01691     size_t items = 0;
01692     
01693     /* add shapekey-level animation channels */
01694     BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_SKE_OBJD(key))
01695     {
01696         /* animation data filtering */
01697         tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)key, filter_mode);
01698     }
01699     END_ANIMFILTER_SUBCHANNELS;
01700     
01701     /* did we find anything? */
01702     if (tmp_items) {
01703         /* include key-expand widget first */
01704         if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01705             if ANIMCHANNEL_ACTIVEOK(key) {
01706                 ANIMCHANNEL_NEW_CHANNEL(key, ANIMTYPE_DSSKEY, ob);
01707             }
01708         }
01709         
01710         /* now add the list of collected channels */
01711         BLI_movelisttolist(anim_data, &tmp_data);
01712         BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01713         items += tmp_items;
01714     }
01715     
01716     /* return the number of items added to the list */
01717     return items;
01718 }
01719 
01720 /* object-level animation */
01721 static size_t animdata_filter_ds_obanim (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
01722 {
01723     ListBase tmp_data = {NULL, NULL};
01724     size_t tmp_items = 0;
01725     size_t items = 0;
01726     
01727     AnimData *adt = ob->adt;
01728     short type=0, expanded=1;
01729     void *cdata = NULL;
01730     
01731     /* determine the type of expander channels to use */
01732     // this is the best way to do this for now...
01733     ANIMDATA_FILTER_CASES(ob,
01734         {/* AnimData - no channel, but consider data */},
01735         {/* NLA - no channel, but consider data */},
01736         {/* Drivers */
01737             type = ANIMTYPE_FILLDRIVERS;
01738             cdata = adt;
01739             expanded = EXPANDED_DRVD(adt);
01740         },
01741         {/* Keyframes */
01742             type = ANIMTYPE_FILLACTD;
01743             cdata = adt->action;
01744             expanded = EXPANDED_ACTC(adt->action);
01745         });
01746         
01747     /* add object-level animation channels */
01748     BEGIN_ANIMFILTER_SUBCHANNELS(expanded)
01749     {
01750         /* animation data filtering */
01751         tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ob, filter_mode);
01752     }
01753     END_ANIMFILTER_SUBCHANNELS;
01754     
01755     /* did we find anything? */
01756     if (tmp_items) {
01757         /* include anim-expand widget first */
01758         if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01759             if (type != ANIMTYPE_NONE) {
01760                 /* NOTE: active-status (and the associated checks) don't apply here... */
01761                 ANIMCHANNEL_NEW_CHANNEL(cdata, type, ob);
01762             }
01763         }
01764         
01765         /* now add the list of collected channels */
01766         BLI_movelisttolist(anim_data, &tmp_data);
01767         BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01768         items += tmp_items;
01769     }
01770     
01771     /* return the number of items added to the list */
01772     return items;
01773 }
01774 
01775 /* get animation channels from object2 */
01776 static size_t animdata_filter_dopesheet_ob (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
01777 {
01778     ListBase tmp_data = {NULL, NULL};
01779     Object *ob= base->object;
01780     size_t tmp_items = 0;
01781     size_t items = 0;
01782     
01783     /* filter data contained under object first */
01784     BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_OBJC(ob))
01785     {
01786         Key *key= ob_get_key(ob);
01787         
01788         /* object-level animation */
01789         if ((ob->adt) && !(ads->filterflag & ADS_FILTER_NOOBJ)) {
01790             tmp_items += animdata_filter_ds_obanim(ac, &tmp_data, ads, ob, filter_mode);
01791         }
01792         
01793         /* shape-key */
01794         if ((key && key->adt) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
01795             tmp_items += animdata_filter_ds_keyanim(ac, &tmp_data, ads, ob, key, filter_mode);
01796         }
01797         
01798         /* materials */
01799         if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT)) {
01800             tmp_items += animdata_filter_ds_materials(ac, &tmp_data, ads, ob, filter_mode);
01801         }
01802         
01803         /* object data */
01804         if (ob->data) {
01805             tmp_items += animdata_filter_ds_obdata(ac, &tmp_data, ads, ob, filter_mode);
01806         }
01807         
01808         /* particles */
01809         if ((ob->particlesystem.first) && !(ads->filterflag & ADS_FILTER_NOPART)) {
01810             tmp_items += animdata_filter_ds_particles(ac, &tmp_data, ads, ob, filter_mode);
01811         }
01812     }
01813     END_ANIMFILTER_SUBCHANNELS;
01814     
01815     
01816     /* if we collected some channels, add these to the new list... */
01817     if (tmp_items) {
01818         /* firstly add object expander if required */
01819         if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01820             /* check if filtering by selection */
01821             // XXX: double-check on this - most of the time, a lot of tools need to filter out these channels!
01822             if ANIMCHANNEL_SELOK((base->flag & SELECT)) {
01823                 /* check if filtering by active status */
01824                 if (ANIMCHANNEL_ACTIVEOK(ob)) {
01825                     ANIMCHANNEL_NEW_CHANNEL(base, ANIMTYPE_OBJECT, ob);
01826                 }
01827             }
01828         }
01829         
01830         /* now add the list of collected channels */
01831         BLI_movelisttolist(anim_data, &tmp_data);
01832         BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01833         items += tmp_items;
01834     }
01835     
01836     /* return the number of items added */
01837     return items;
01838 }
01839 
01840 static size_t animdata_filter_ds_world (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, World *wo, int filter_mode)
01841 {
01842     ListBase tmp_data = {NULL, NULL};
01843     size_t tmp_items = 0;
01844     size_t items = 0;
01845     
01846     /* add world animation channels */
01847     BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_WOR_SCED(wo))
01848     {
01849         /* animation data filtering */
01850         tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)wo, filter_mode);
01851         
01852         /* textures for world */
01853         if (!(ads->filterflag & ADS_FILTER_NOTEX))
01854             items += animdata_filter_ds_textures(ac, &tmp_data, ads, (ID *)wo, filter_mode);
01855             
01856         /* nodes */
01857         if ((wo->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) 
01858             tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)wo, wo->nodetree, filter_mode);
01859     }
01860     END_ANIMFILTER_SUBCHANNELS;
01861     
01862     /* did we find anything? */
01863     if (tmp_items) {
01864         /* include data-expand widget first */
01865         if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01866             /* check if filtering by active status */
01867             if ANIMCHANNEL_ACTIVEOK(wo) {
01868                 ANIMCHANNEL_NEW_CHANNEL(wo, ANIMTYPE_DSWOR, sce);
01869             }
01870         }
01871         
01872         /* now add the list of collected channels */
01873         BLI_movelisttolist(anim_data, &tmp_data);
01874         BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01875         items += tmp_items;
01876     }
01877     
01878     /* return the number of items added to the list */
01879     return items;
01880 }
01881 
01882 static size_t animdata_filter_ds_scene (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
01883 {
01884     ListBase tmp_data = {NULL, NULL};
01885     size_t tmp_items = 0;
01886     size_t items = 0;
01887     
01888     AnimData *adt = sce->adt;
01889     short type=0, expanded=1;
01890     void *cdata = NULL;
01891     
01892     /* determine the type of expander channels to use */
01893     // this is the best way to do this for now...
01894     ANIMDATA_FILTER_CASES(sce,
01895         {/* AnimData - no channel, but consider data */},
01896         {/* NLA - no channel, but consider data */},
01897         {/* Drivers */
01898             type = ANIMTYPE_FILLDRIVERS;
01899             cdata = adt;
01900             expanded = EXPANDED_DRVD(adt);
01901         },
01902         {/* Keyframes */
01903             type = ANIMTYPE_FILLACTD;
01904             cdata = adt->action;
01905             expanded = EXPANDED_ACTC(adt->action);
01906         });
01907         
01908     /* add scene-level animation channels */
01909     BEGIN_ANIMFILTER_SUBCHANNELS(expanded)
01910     {
01911         /* animation data filtering */
01912         tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)sce, filter_mode);
01913     }
01914     END_ANIMFILTER_SUBCHANNELS;
01915     
01916     /* did we find anything? */
01917     if (tmp_items) {
01918         /* include anim-expand widget first */
01919         if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01920             if (type != ANIMTYPE_NONE) {
01921                 /* NOTE: active-status (and the associated checks) don't apply here... */
01922                 ANIMCHANNEL_NEW_CHANNEL(cdata, type, sce);
01923             }
01924         }
01925         
01926         /* now add the list of collected channels */
01927         BLI_movelisttolist(anim_data, &tmp_data);
01928         BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01929         items += tmp_items;
01930     }
01931     
01932     /* return the number of items added to the list */
01933     return items;
01934 }
01935 
01936 static size_t animdata_filter_dopesheet_scene (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
01937 {
01938     ListBase tmp_data = {NULL, NULL};
01939     size_t tmp_items = 0;
01940     size_t items = 0;
01941     
01942     /* filter data contained under object first */
01943     BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_SCEC(sce))
01944     {
01945         bNodeTree *ntree= sce->nodetree;
01946         World *wo= sce->world;
01947         
01948         /* Action, Drivers, or NLA for Scene */
01949         if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) {
01950             tmp_items += animdata_filter_ds_scene(ac, &tmp_data, ads, sce, filter_mode);
01951         }
01952         
01953         /* world */
01954         if ((wo) && !(ads->filterflag & ADS_FILTER_NOWOR)) {
01955             tmp_items += animdata_filter_ds_world(ac, &tmp_data, ads, sce, wo, filter_mode);
01956         }
01957         
01958         /* nodetree */
01959         if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
01960             tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)sce, ntree, filter_mode);
01961         }
01962         
01963         // TODO: one day, when sequencer becomes its own datatype, perhaps it should be included here
01964     }
01965     END_ANIMFILTER_SUBCHANNELS;
01966     
01967     /* if we collected some channels, add these to the new list... */
01968     if (tmp_items) {
01969         /* firstly add object expander if required */
01970         if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
01971             /* check if filtering by selection */
01972             if ANIMCHANNEL_SELOK((sce->flag & SCE_DS_SELECTED)) {
01973                 /* NOTE: active-status doesn't matter for this! */
01974                 ANIMCHANNEL_NEW_CHANNEL(sce, ANIMTYPE_SCENE, sce);
01975             }
01976         }
01977         
01978         /* now add the list of collected channels */
01979         BLI_movelisttolist(anim_data, &tmp_data);
01980         BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
01981         items += tmp_items;
01982     }
01983     
01984     /* return the number of items added */
01985     return items;
01986 }
01987 
01988 // 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)
01989 static size_t animdata_filter_dopesheet (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode)
01990 {
01991     Scene *sce= (Scene *)ads->source;
01992     Base *base;
01993     size_t items = 0;
01994     
01995     /* check that we do indeed have a scene */
01996     if ((ads->source == NULL) || (GS(ads->source->name)!=ID_SCE)) {
01997         printf("DopeSheet Error: Not scene!\n");
01998         if (G.f & G_DEBUG)
01999             printf("\tPointer = %p, Name = '%s' \n", (void *)ads->source, (ads->source)?ads->source->name:NULL);
02000         return 0;
02001     }
02002     
02003     /* augment the filter-flags with settings based on the dopesheet filterflags 
02004      * so that some temp settings can get added automagically...
02005      */
02006     if (ads->filterflag & ADS_FILTER_SELEDIT) {
02007         /* only selected F-Curves should get their keyframes considered for editability */
02008         filter_mode |= ANIMFILTER_SELEDIT;
02009     }
02010     
02011     /* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */
02012     items += animdata_filter_dopesheet_scene(ac, anim_data, ads, sce, filter_mode);
02013     
02014     /* loop over all bases (i.e.objects) in the scene */
02015     for (base= sce->base.first; base; base= base->next) {
02016         /* check if there's an object (all the relevant checks are done in the ob-function) */
02017         if (base->object) {
02018             Object *ob= base->object;
02019             
02020             /* firstly, check if object can be included, by the following factors:
02021              *  - if only visible, must check for layer and also viewport visibility
02022              *      --> while tools may demand only visible, user setting takes priority
02023              *          as user option controls whether sets of channels get included while
02024              *          tool-flag takes into account collapsed/open channels too
02025              *  - if only selected, must check if object is selected 
02026              *  - there must be animation data to edit (this is done recursively as we 
02027              *    try to add the channels)
02028              */
02029             if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
02030                 /* layer visibility - we check both object and base, since these may not be in sync yet */
02031                 if ((sce->lay & (ob->lay|base->lay))==0) continue;
02032                 
02033                 /* outliner restrict-flag */
02034                 if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
02035             }
02036             
02037             /* if only F-Curves with visible flags set can be shown, check that 
02038              * datablock hasn't been set to invisible 
02039              */
02040             if (filter_mode & ANIMFILTER_CURVE_VISIBLE) {
02041                 if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE))
02042                     continue;
02043             }
02044             
02045             /* check selection and object type filters */
02046             if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/) )  {
02047                 /* only selected should be shown */
02048                 continue;
02049             }
02050             
02051             /* check if object belongs to the filtering group if option to filter 
02052              * objects by the grouped status is on
02053              *  - used to ease the process of doing multiple-character choreographies
02054              */
02055             if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) {
02056                 if (object_in_group(ob, ads->filter_grp) == 0)
02057                     continue;
02058             }
02059                 
02060             /* since we're still here, this object should be usable */
02061             items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode);
02062         }
02063     }
02064     
02065     /* return the number of items in the list */
02066     return items;
02067 }
02068 
02069 /* Summary track for DopeSheet/Action Editor 
02070  *  - return code is whether the summary lets the other channels get drawn
02071  */
02072 static short animdata_filter_dopesheet_summary (bAnimContext *ac, ListBase *anim_data, int filter_mode, size_t *items)
02073 {
02074     bDopeSheet *ads = NULL;
02075     
02076     /* get the DopeSheet information to use 
02077      *  - we should only need to deal with the DopeSheet/Action Editor, 
02078      *    since all the other Animation Editors won't have this concept
02079      *    being applicable.
02080      */
02081     if ((ac && ac->sl) && (ac->spacetype == SPACE_ACTION)) {
02082         SpaceAction *saction= (SpaceAction *)ac->sl;
02083         ads= &saction->ads;
02084     }
02085     else {
02086         /* invalid space type - skip this summary channels */
02087         return 1;
02088     }
02089     
02090     /* dopesheet summary 
02091      *  - only for drawing and/or selecting keyframes in channels, but not for real editing 
02092      *  - only useful for DopeSheet/Action/etc. editors where it is actually useful
02093      */
02094     if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && (ads->filterflag & ADS_FILTER_SUMMARY)) {
02095         bAnimListElem *ale= make_new_animlistelem(ac, ANIMTYPE_SUMMARY, NULL);
02096         if (ale) {
02097             BLI_addtail(anim_data, ale);
02098             (*items)++;
02099         }
02100         
02101         /* if summary is collapsed, don't show other channels beneath this 
02102          *  - this check is put inside the summary check so that it doesn't interfere with normal operation
02103          */ 
02104         if (ads->flag & ADS_FLAG_SUMMARY_COLLAPSED)
02105             return 0;
02106     }
02107     
02108     /* the other channels beneath this can be shown */
02109     return 1;
02110 }  
02111 
02112 /* ......................... */
02113 
02114 /* filter data associated with a channel - usually for handling summary-channels in DopeSheet */
02115 static size_t animdata_filter_animchan (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bAnimListElem *channel, int filter_mode)
02116 {
02117     size_t items = 0;
02118     
02119     /* data to filter depends on channel type */
02120     // XXX: only common channel-types have been handled for now
02121     switch (channel->type) {
02122         case ANIMTYPE_SUMMARY:
02123             items += animdata_filter_dopesheet(ac, anim_data, ads, filter_mode);
02124             break;
02125             
02126         case ANIMTYPE_SCENE:
02127             items += animdata_filter_dopesheet_scene(ac, anim_data, ads, channel->data, filter_mode);
02128             break;
02129         
02130         case ANIMTYPE_OBJECT:
02131             items += animdata_filter_dopesheet_ob(ac, anim_data, ads, channel->data, filter_mode);
02132             break;
02133     }
02134     
02135     return items;
02136 }
02137 
02138 /* ----------- Cleanup API --------------- */
02139 
02140 /* Remove entries with invalid types in animation channel list */
02141 static size_t animdata_filter_remove_invalid (ListBase *anim_data)
02142 {
02143     bAnimListElem *ale, *next;
02144     size_t items = 0;
02145     
02146     /* only keep entries with valid types */
02147     for (ale= anim_data->first; ale; ale= next) {
02148         next= ale->next;
02149         
02150         if (ale->type == ANIMTYPE_NONE)
02151             BLI_freelinkN(anim_data, ale);
02152         else
02153             items++;
02154     }
02155     
02156     return items;
02157 }
02158 
02159 /* Remove duplicate entries in animation channel list */
02160 static size_t animdata_filter_remove_duplis (ListBase *anim_data)
02161 {
02162     bAnimListElem *ale, *next;
02163     GHash *gh;
02164     size_t items = 0;
02165     
02166     /* build new hashtable to efficiently store and retrieve which entries have been 
02167      * encountered already while searching
02168      */
02169     gh= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "animdata_filter_duplis_remove gh");
02170     
02171     /* loop through items, removing them from the list if a similar item occurs already */
02172     for (ale = anim_data->first; ale; ale = next) {
02173         next = ale->next;
02174         
02175         /* check if hash has any record of an entry like this 
02176          *  - just use ale->data for now, though it would be nicer to involve 
02177          *    ale->type in combination too to capture corner cases (where same data performs differently)
02178          */
02179         if (BLI_ghash_haskey(gh, ale->data) == 0) {
02180             /* this entry is 'unique' and can be kept */
02181             BLI_ghash_insert(gh, ale->data, NULL);
02182             items++;
02183         }
02184         else {
02185             /* this entry isn't needed anymore */
02186             BLI_freelinkN(anim_data, ale);
02187         }
02188     }
02189     
02190     /* free the hash... */
02191     BLI_ghash_free(gh, NULL, NULL);
02192     
02193     /* return the number of items still in the list */
02194     return items;
02195 }
02196 
02197 /* ----------- Public API --------------- */
02198 
02199 /* This function filters the active data source to leave only animation channels suitable for
02200  * usage by the caller. It will return the length of the list 
02201  * 
02202  *  *anim_data: is a pointer to a ListBase, to which the filtered animation channels
02203  *      will be placed for use.
02204  *  filter_mode: how should the data be filtered - bitmapping accessed flags
02205  */
02206 size_t ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode, void *data, short datatype)
02207 {
02208     size_t items = 0;
02209     
02210     /* only filter data if there's somewhere to put it */
02211     if (data && anim_data) {
02212         
02213         /* firstly filter the data */
02214         switch (datatype) {
02215             case ANIMCONT_ACTION:   /* 'Action Editor' */
02216             {
02217                 Object *obact= ac->obact;
02218                 SpaceAction *saction = (SpaceAction *)ac->sl;
02219                 bDopeSheet *ads = (saction)? &saction->ads : NULL;
02220                 
02221                 /* the check for the DopeSheet summary is included here since the summary works here too */
02222                 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
02223                     items += animfilter_action(ac, anim_data, ads, data, filter_mode, (ID *)obact);
02224             }
02225                 break;
02226                 
02227             case ANIMCONT_SHAPEKEY: /* 'ShapeKey Editor' */
02228             {
02229                 /* the check for the DopeSheet summary is included here since the summary works here too */
02230                 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
02231                     items= animdata_filter_shapekey(ac, anim_data, data, filter_mode);
02232             }
02233                 break;
02234                 
02235             case ANIMCONT_GPENCIL:
02236             {
02237                 items= animdata_filter_gpencil(anim_data, data, filter_mode);
02238             }
02239                 break;
02240                 
02241             case ANIMCONT_DOPESHEET: /* 'DopeSheet Editor' */
02242             {
02243                 /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */
02244                 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
02245                     items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode);
02246             }
02247                 break;
02248                 
02249             case ANIMCONT_FCURVES: /* Graph Editor -> FCurves/Animation Editing */
02250             case ANIMCONT_DRIVERS: /* Graph Editor -> Drivers Editing */
02251             case ANIMCONT_NLA: /* NLA Editor */
02252             {
02253                 /* all of these editors use the basic DopeSheet data for filtering options, but don't have all the same features */
02254                 items = animdata_filter_dopesheet(ac, anim_data, data, filter_mode);
02255             }
02256                 break;
02257             
02258             case ANIMCONT_CHANNEL: /* animation channel */
02259             {
02260                 bDopeSheet *ads = ac->ads;
02261                 
02262                 /* based on the channel type, filter relevant data for this */
02263                 items = animdata_filter_animchan(ac, anim_data, ads, data, filter_mode);
02264             }
02265                 break;
02266         }
02267             
02268         /* remove any 'weedy' entries */
02269         items = animdata_filter_remove_invalid(anim_data);
02270         
02271         /* remove duplicates (if required) */
02272         if (filter_mode & ANIMFILTER_NODUPLIS)
02273             items = animdata_filter_remove_duplis(anim_data);
02274     }
02275     
02276     /* return the number of items in the list */
02277     return items;
02278 }
02279 
02280 /* ************************************************************ */