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