Merged changes in the trunk up to revision 55357.
[blender.git] / source / blender / editors / animation / anim_filter.c
index fcf424e34dc5230c3e3a408be66774490f415a16..7648d99821637fae372ccf945ede3db4f9b21482 100644 (file)
 #include "DNA_camera_types.h"
 #include "DNA_lamp_types.h"
 #include "DNA_lattice_types.h"
+#ifdef WITH_FREESTYLE
+#  include "DNA_linestyle_types.h"
+#endif
 #include "DNA_key_types.h"
+#include "DNA_mask_types.h"
 #include "DNA_material_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meta_types.h"
@@ -86,8 +90,8 @@
 #include "BKE_main.h"
 #include "BKE_material.h"
 #include "BKE_node.h"
+#include "BKE_mask.h"
 #include "BKE_sequencer.h"
-#include "BKE_utildefines.h"
 
 #include "ED_anim_api.h"
 #include "ED_markers.h"
 /* ----------- Private Stuff - Action Editor ------------- */
 
 /* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */
-/* Note: there's a similar function in key.c (ob_get_key) */
+/* Note: there's a similar function in key.c (BKE_key_from_object) */
 static Key *actedit_get_shapekeys(bAnimContext *ac)
 {
        Scene *scene = ac->scene;
@@ -113,7 +117,7 @@ static Key *actedit_get_shapekeys(bAnimContext *ac)
        //if (saction->pin) return NULL;
        
        /* shapekey data is stored with geometry data */
-       key = ob_get_key(ob);
+       key = BKE_key_from_object(ob);
        
        if (key) {
                if (key->type == KEY_RELATIVE)
@@ -162,8 +166,8 @@ static short actedit_get_context(bAnimContext *ac, SpaceAction *saction)
                        
                        ac->mode = saction->mode;
                        return 1;
-                       
-               case SACTCONT_GPENCIL: /* Grease Pencil */ // XXX review how this mode is handled...
+               
+               case SACTCONT_GPENCIL: /* Grease Pencil */ /* XXX review how this mode is handled... */
                        /* update scene-pointer (no need to check for pinning yet, as not implemented) */
                        saction->ads.source = (ID *)ac->scene;
                        
@@ -173,6 +177,22 @@ static short actedit_get_context(bAnimContext *ac, SpaceAction *saction)
                        ac->mode = saction->mode;
                        return 1;
                        
+               case SACTCONT_MASK: /* Mask */ /* XXX review how this mode is handled... */
+               {
+                       /* TODO, other methods to get the mask */
+                       // Sequence *seq = BKE_sequencer_active_get(ac->scene);
+                       //MovieClip *clip = ac->scene->clip;
+//                     struct Mask *mask = seq ? seq->mask : NULL;
+                       
+                       /* update scene-pointer (no need to check for pinning yet, as not implemented) */
+                       saction->ads.source = (ID *)ac->scene;
+                       
+                       ac->datatype = ANIMCONT_MASK;
+                       ac->data = &saction->ads;
+                       
+                       ac->mode = saction->mode;
+                       return 1;
+               }
                case SACTCONT_DOPESHEET: /* DopeSheet */
                        /* update scene-pointer (no need to check for pinning yet, as not implemented) */
                        saction->ads.source = (ID *)ac->scene;
@@ -273,7 +293,7 @@ static short nlaedit_get_context(bAnimContext *ac, SpaceNla *snla)
 short ANIM_animdata_context_getdata(bAnimContext *ac)
 {
        SpaceLink *sl = ac->sl;
-       short ok = 0;
+       short ok = FALSE;
        
        /* context depends on editor we are currently in */
        if (sl) {
@@ -302,10 +322,7 @@ short ANIM_animdata_context_getdata(bAnimContext *ac)
        }
        
        /* check if there's any valid data */
-       if (ok && ac->data)
-               return 1;
-       else
-               return 0;
+       return (ok && ac->data);
 }
 
 /* Obtain current anim-data context from Blender Context info 
@@ -337,6 +354,7 @@ short ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
        ac->regiontype = (ar) ? ar->regiontype : 0;
        
        /* get data context info */
+       // XXX: if the below fails, try to grab this info from context instead... (to allow for scripting)
        return ANIM_animdata_context_getdata(ac);
 }
 
@@ -379,7 +397,7 @@ short ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
 /* ... standard sub-channel filtering can go on here now ... */
 #define END_ANIMFILTER_SUBCHANNELS \
                filter_mode = _filter; \
-       }
+       } (void)0
 
 /* ............................... */
 
@@ -399,16 +417,16 @@ short ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
  *
  * For this to work correctly, a standard set of data needs to be available within the scope that this
  * gets called in: 
- *     - ListBase anim_data;
- *     - bDopeSheet *ads;
- *     - bAnimListElem *ale;
+ *  - ListBase anim_data;
+ *  - bDopeSheet *ads;
+ *  - bAnimListElem *ale;
  *  - size_t items;
  *
  *  - id: ID block which should have an AnimData pointer following it immediately, to use
- *     - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
- *     - nlaOk: line or block of code to execute for NLA tracks+strips case
- *     - driversOk: line or block of code to execute for Drivers case
- *     - keysOk: line or block of code for Keyframes case
+ *  - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
+ *  - nlaOk: line or block of code to execute for NLA tracks+strips case
+ *  - driversOk: line or block of code to execute for Drivers case
+ *  - keysOk: line or block of code for Keyframes case
  *
  * The checks for the various cases are as follows:
  *     0) top level: checks for animdata and also that all the F-Curves for the block will be visible
@@ -431,7 +449,7 @@ short ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
                                        if (ANIMDATA_HAS_NLA(id)) { \
                                                nlaOk \
                                        } \
-                                       else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) && ANIMDATA_HAS_KEYS(id)) { \
+                                       else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || ANIMDATA_HAS_KEYS(id)) { \
                                                nlaOk \
                                        } \
                                } \
@@ -447,7 +465,7 @@ short ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
                                } \
                        } \
                } \
-       }
+       } (void)0
 
 /* ............................... */
 
@@ -467,7 +485,7 @@ short ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
                        items ++; \
                        ale_statement \
                } \
-       }
+       } (void)0
        
 #define ANIMCHANNEL_NEW_CHANNEL(channel_data, channel_type, owner_id) \
        ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, {})
@@ -665,18 +683,18 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
                                ale->datatype = ALE_ACT;
                                
                                ale->adt = BKE_animdata_from_id(data);
-                       }       
+                       }
                        break;
                        case ANIMTYPE_DSSPK:
                        {
                                Speaker *spk = (Speaker *)data;
                                AnimData *adt = spk->adt;
-
+                               
                                ale->flag = FILTER_SPK_OBJD(spk);
-
+                               
                                ale->key_data = (adt) ? adt->action : NULL;
                                ale->datatype = ALE_ACT;
-
+                               
                                ale->adt = BKE_animdata_from_id(data);
                        }
                        break;
@@ -719,6 +737,21 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
                                ale->adt = BKE_animdata_from_id(data);
                        }
                        break;
+#ifdef WITH_FREESTYLE
+                       case ANIMTYPE_DSLINESTYLE:
+                       {
+                               FreestyleLineStyle *linestyle = (FreestyleLineStyle *)data;
+                               AnimData *adt = linestyle->adt;
+                               
+                               ale->flag = FILTER_LS_SCED(linestyle); 
+                               
+                               ale->key_data = (adt) ? adt->action : NULL;
+                               ale->datatype = ALE_ACT;
+                               
+                               ale->adt = BKE_animdata_from_id(data);
+                       }
+                               break;
+#endif
                        case ANIMTYPE_DSPART:
                        {
                                ParticleSettings *part = (ParticleSettings *)ale->data;
@@ -782,7 +815,7 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
                                        /* the corresponding keyframes are from the animdata */
                                        if (ale->adt && ale->adt->action) {
                                                bAction *act = ale->adt->action;
-                                               char *rna_path = key_get_curValue_rnaPath(key, kb);
+                                               char *rna_path = BKE_keyblock_curval_rnapath_get(key, kb);
                                                
                                                /* try to find the F-Curve which corresponds to this exactly,
                                                 * then free the MEM_alloc'd string
@@ -794,7 +827,7 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
                                        }
                                        ale->datatype = (ale->key_data) ? ALE_FCURVE : ALE_NONE;
                                }
-                       }       
+                       }
                        break;
                        
                        case ANIMTYPE_GPLAYER:
@@ -807,7 +840,18 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
                                ale->datatype = ALE_GPFRAME;
                        }
                        break;
+                       
+                       case ANIMTYPE_MASKLAYER:
+                       {
+                               MaskLayer *masklay = (MaskLayer *)data;
+                               
+                               ale->flag = masklay->flag;
                                
+                               ale->key_data = NULL;
+                               ale->datatype = ALE_MASKLAY;
+                       }
+                       break;
+                       
                        case ANIMTYPE_NLATRACK:
                        {
                                NlaTrack *nlt = (NlaTrack *)data;
@@ -851,7 +895,7 @@ static short skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_i
                        char *bone_name;
                        
                        /* get bone-name, and check if this bone is selected */
-                       bone_name = BLI_getQuotedStr(fcu->rna_path, "pose.bones[");
+                       bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
                        pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
                        if (bone_name) MEM_freeN(bone_name);
                        
@@ -883,13 +927,15 @@ static short skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_i
                /* only consider if F-Curve involves sequence_editor.sequences */
                if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
                        Editing *ed = BKE_sequencer_editing_get(scene, FALSE);
-                       Sequence *seq;
+                       Sequence *seq = NULL;
                        char *seq_name;
                        
-                       /* get strip name, and check if this strip is selected */
-                       seq_name = BLI_getQuotedStr(fcu->rna_path, "sequences_all[");
-                       seq = get_seq_by_name(ed->seqbasep, seq_name, FALSE);
-                       if (seq_name) MEM_freeN(seq_name);
+                       if (ed) {
+                               /* get strip name, and check if this strip is selected */
+                               seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all[");
+                               seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, FALSE);
+                               if (seq_name) MEM_freeN(seq_name);
+                       }
                        
                        /* can only add this F-Curve if it is selected */
                        if (ads->filterflag & ADS_FILTER_ONLYSEL) {
@@ -907,7 +953,7 @@ static short skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_i
                        char *node_name;
                        
                        /* get strip name, and check if this strip is selected */
-                       node_name = BLI_getQuotedStr(fcu->rna_path, "nodes[");
+                       node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes[");
                        node = nodeFindNodebyName(ntree, node_name);
                        if (node_name) MEM_freeN(node_name);
                        
@@ -952,6 +998,44 @@ static short skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, ID *owner_id)
        return 1;
 }
 
+/* Check if F-Curve has errors and/or is disabled 
+ * > returns: (bool) True if F-Curve has errors/is disabled
+ */
+static bool fcurve_has_errors(FCurve *fcu)
+{
+       /* F-Curve disabled - path eval error */
+       if (fcu->flag & FCURVE_DISABLED) {
+               return true;
+       }
+       
+       /* driver? */
+       if (fcu->driver) {
+               ChannelDriver *driver = fcu->driver;
+               DriverVar *dvar;
+               
+               /* error flag on driver usually means that there is an error
+                * BUT this may not hold with PyDrivers as this flag gets cleared
+                *     if no critical errors prevent the driver from working...
+                */
+               if (driver->flag & DRIVER_FLAG_INVALID)
+                       return true;
+                       
+               /* check variables for other things that need linting... */
+               // TODO: maybe it would be more efficient just to have a quick flag for this?
+               for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+                       DRIVER_TARGETS_USED_LOOPER(dvar)
+                       {
+                               if (dtar->flag & DTAR_FLAG_INVALID)
+                                       return true;
+                       }
+                       DRIVER_TARGETS_LOOPER_END
+               }
+       }
+       
+       /* no errors found */
+       return false;
+}
+
 /* find the next F-Curve that is usable for inclusion */
 static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, bActionGroup *grp, int filter_mode, ID *owner_id)
 {
@@ -974,7 +1058,7 @@ static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, bActionGro
                                if (skip_fcurve_selected_data(ads, fcu, owner_id, filter_mode))
                                        continue;
                        }
-               }       
+               }
                
                /* only include if visible (Graph Editor check, not channels check) */
                if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || (fcu->flag & FCURVE_VISIBLE)) {
@@ -990,6 +1074,13 @@ static FCurve *animfilter_fcurve_next(bDopeSheet *ads, FCurve *first, bActionGro
                                                                continue;
                                                }
                                                
+                                               /* error-based filtering... */
+                                               if ((ads) && (ads->filterflag & ADS_FILTER_ONLY_ERRORS)) {
+                                                       /* skip if no errors... */
+                                                       if (fcurve_has_errors(fcu) == false)
+                                                               continue;
+                                               }
+                                               
                                                /* this F-Curve can be used, so return it */
                                                return fcu;
                                        }
@@ -1110,7 +1201,6 @@ static size_t animfilter_action(bAnimContext *ac, ListBase *anim_data, bDopeShee
        /* don't include anything from this action if it is linked in from another file,
         * and we're getting stuff for editing...
         */
-       // TODO: need a way of tagging other channels that may also be affected...
        if ((filter_mode & ANIMFILTER_FOREDIT) && (act->id.lib))
                return 0;
                
@@ -1156,7 +1246,7 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
                 */
                if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || (adt->action)) {
                        /* there isn't really anything editable here, so skip if need editable */
-                       if ((filter_mode & ANIMFILTER_FOREDIT) == 0) { 
+                       if ((filter_mode & ANIMFILTER_FOREDIT) == 0) {
                                /* just add the action track now (this MUST appear for drawing)
                                 *      - as AnimData may not have an action, we pass a dummy pointer just to get the list elem created, then
                                 *        overwrite this with the real value - REVIEW THIS...
@@ -1212,11 +1302,11 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope
 {
        AnimData *adt = BKE_animdata_from_id(id);
        size_t items = 0;
-
+       
        /* image object datablocks have no anim-data so check for NULL */
        if (adt) {
                IdAdtTemplate *iat = (IdAdtTemplate *)id;
-
+               
                /* NOTE: this macro is used instead of inlining the logic here, since this sort of filtering is still needed
                 * in a few places in he rest of the code still - notably for the few cases where special mode-based
                 * different types of data expanders are required.
@@ -1224,7 +1314,9 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope
                ANIMDATA_FILTER_CASES(iat,
                        { /* AnimData */
                                /* specifically filter animdata block */
-                               ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id);
+                               if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(adt)) ) {
+                                       ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id);
+                               }
                        },
                        { /* NLA */
                                items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id);
@@ -1237,7 +1329,7 @@ static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, bDope
                        }
                );
        }
-
+       
        return items;
 }
 
@@ -1255,7 +1347,6 @@ static size_t animdata_filter_shapekey(bAnimContext *ac, ListBase *anim_data, Ke
                /* loop through the channels adding ShapeKeys as appropriate */
                for (kb = key->block.first; kb; kb = kb->next) {
                        /* skip the first one, since that's the non-animatable basis */
-                       // XXX maybe in future this may become handy?
                        if (kb == key->block.first) continue;
                        
                        /* only work with this channel and its subchannels if it is editable */
@@ -1275,7 +1366,9 @@ static size_t animdata_filter_shapekey(bAnimContext *ac, ListBase *anim_data, Ke
                // TODO: somehow manage to pass dopesheet info down here too?
                if (key->adt) {
                        if (filter_mode & ANIMFILTER_ANIMDATA) {
-                               ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key);
+                               if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(key->adt)) ) {
+                                       ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key);
+                               }
                        }
                        else if (key->adt->action) {
                                items = animfilter_action(ac, anim_data, NULL, key->adt->action, filter_mode, (ID *)key);
@@ -1287,6 +1380,7 @@ static size_t animdata_filter_shapekey(bAnimContext *ac, ListBase *anim_data, Ke
        return items;
 }
 
+/* Helper for Grease Pencil - layers within a datablock */
 static size_t animdata_filter_gpencil_data(ListBase *anim_data, bGPdata *gpd, int filter_mode)
 {
        bGPDlayer *gpl;
@@ -1353,6 +1447,73 @@ static size_t animdata_filter_gpencil(ListBase *anim_data, void *UNUSED(data), i
        return items;
 }
 
+/* Helper for Mask Editing - mask layers */
+static size_t animdata_filter_mask_data(ListBase *anim_data, Mask *mask, const int filter_mode)
+{
+       MaskLayer *masklay_act = BKE_mask_layer_active(mask);
+       MaskLayer *masklay;
+       size_t items = 0;
+
+       /* loop over layers as the conditions are acceptable */
+       for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+               /* only if selected */
+               if (ANIMCHANNEL_SELOK(SEL_MASKLAY(masklay)) ) {
+                       /* only if editable */
+                       if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_MASK(masklay)) {
+                               /* active... */
+                               if (!(filter_mode & ANIMFILTER_ACTIVE) || (masklay_act == masklay)) {
+                                       /* add to list */
+                                       ANIMCHANNEL_NEW_CHANNEL(masklay, ANIMTYPE_MASKLAYER, mask);
+                               }
+                       }
+               }
+       }
+
+       return items;
+}
+
+/* Grab all mask data */
+static size_t animdata_filter_mask(ListBase *anim_data, void *UNUSED(data), int filter_mode)
+{
+       Mask *mask;
+       size_t items = 0;
+       
+       /* for now, grab mask datablocks directly from main */
+       // XXX: this is not good...
+       for (mask = G.main->mask.first; mask; mask = mask->id.next) {
+               ListBase tmp_data = {NULL, NULL};
+               size_t tmp_items = 0;
+               
+               /* only show if mask is used by something... */
+               if (ID_REAL_USERS(mask) < 1)
+                       continue;
+               
+               /* add mask animation channels */
+               BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_MASK(mask))
+               {
+                       tmp_items += animdata_filter_mask_data(&tmp_data, mask, filter_mode);
+               }
+               END_ANIMFILTER_SUBCHANNELS;
+               
+               /* did we find anything? */
+               if (tmp_items) {
+                       /* include data-expand widget first */
+                       if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+                               /* add gpd as channel too (if for drawing, and it has layers) */
+                               ANIMCHANNEL_NEW_CHANNEL(mask, ANIMTYPE_MASKDATABLOCK, NULL);
+                       }
+                       
+                       /* now add the list of collected channels */
+                       BLI_movelisttolist(anim_data, &tmp_data);
+                       BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
+                       items += tmp_items;
+               }
+       }
+       
+       /* return the number of items added to the list */
+       return items;
+}
+
 /* NOTE: owner_id is scene, material, or texture block, which is the direct owner of the node tree in question */
 // TODO: how to handle group nodes is still unclear...
 static size_t animdata_filter_ds_nodetree(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, bNodeTree *ntree, int filter_mode)
@@ -1389,6 +1550,56 @@ static size_t animdata_filter_ds_nodetree(bAnimContext *ac, ListBase *anim_data,
        return items;
 }
 
+#ifdef WITH_FREESTYLE
+static size_t animdata_filter_ds_linestyle (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
+{
+       SceneRenderLayer *srl;
+       size_t items = 0;
+
+       for (srl = sce->r.layers.first; srl; srl = srl->next) {
+               FreestyleLineSet *lineset;
+
+               /* skip render layers without Freestyle enabled */
+               if (!(srl->layflag & SCE_LAY_FRS))
+                       continue;
+
+               /* loop over linesets defined in the render layer */
+               for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+                       FreestyleLineStyle *linestyle = lineset->linestyle;
+                       ListBase tmp_data = {NULL, NULL};
+                       size_t tmp_items = 0;
+
+                       /* add scene-level animation channels */
+                       BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_LS_SCED(linestyle))
+                       {
+                               /* animation data filtering */
+                               tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)linestyle, filter_mode);
+                       }
+                       END_ANIMFILTER_SUBCHANNELS;
+
+                       /* did we find anything? */
+                       if (tmp_items) {
+                               /* include anim-expand widget first */
+                               if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+                                       /* check if filtering by active status */
+                                       if ANIMCHANNEL_ACTIVEOK(linestyle) {
+                                               ANIMCHANNEL_NEW_CHANNEL(linestyle, ANIMTYPE_DSLINESTYLE, sce);
+                                       }
+                               }
+                               
+                               /* now add the list of collected channels */
+                               BLI_movelisttolist(anim_data, &tmp_data);
+                               BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
+                               items += tmp_items;
+                       }
+               }
+       }
+       
+       /* return the number of items added to the list */
+       return items;
+}
+#endif
+
 /* NOTE: owner_id is either material, lamp, or world block, which is the direct owner of the texture stack in question */
 static size_t animdata_filter_ds_textures(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, int filter_mode)
 {
@@ -1501,7 +1712,6 @@ static size_t animdata_filter_ds_material(bAnimContext *ac, ListBase *anim_data,
        /* did we find anything? */
        if (tmp_items) {
                /* include material-expand widget first */
-               // hmm... do we need to store the index of this material in the array anywhere?
                if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
                        /* check if filtering by active status */
                        if (ANIMCHANNEL_ACTIVEOK(ma)) {
@@ -1709,11 +1919,18 @@ static size_t animdata_filter_ds_obdata(bAnimContext *ac, ListBase *anim_data, b
                
                /* sub-data filtering... */
                switch (ob->type) {
-                       case OB_LAMP:  /* lamp - textures */
+                       case OB_LAMP:  /* lamp - textures + nodetree */
                        {
+                               Lamp *la = ob->data;
+                               bNodeTree *ntree = la->nodetree;
+                               
+                               /* nodetree */
+                               if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE))
+                                       tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, &la->id, ntree, filter_mode);
+                               
                                /* textures */
                                if (!(ads->filterflag & ADS_FILTER_NOTEX))
-                                       tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, ob->data, filter_mode);
+                                       tmp_items += animdata_filter_ds_textures(ac, &tmp_data, ads, &la->id, filter_mode);
                        }
                        break;
                }
@@ -1784,9 +2001,9 @@ static size_t animdata_filter_ds_obanim(bAnimContext *ac, ListBase *anim_data, b
        AnimData *adt = ob->adt;
        short type = 0, expanded = 1;
        void *cdata = NULL;
-       
+
        /* determine the type of expander channels to use */
-       // this is the best way to do this for now...
+       /* this is the best way to do this for now... */
        ANIMDATA_FILTER_CASES(ob,
                { /* AnimData - no channel, but consider data */ },
                { /* NLA - no channel, but consider data */ },
@@ -1840,7 +2057,7 @@ static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data
        /* filter data contained under object first */
        BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_OBJC(ob))
        {
-               Key *key = ob_get_key(ob);
+               Key *key = BKE_key_from_object(ob);
                
                /* object-level animation */
                if ((ob->adt) && !(ads->filterflag & ADS_FILTER_NOOBJ)) {
@@ -2017,10 +2234,17 @@ static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_d
                        tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)sce, ntree, filter_mode);
                }
                
-               // TODO: one day, when sequencer becomes its own datatype, perhaps it should be included here
+#ifdef WITH_FREESTYLE
+               /* line styles */
+               if ((ads->filterflag & ADS_FILTER_NOLINESTYLE) == 0) {
+                       tmp_items += animdata_filter_ds_linestyle(ac, &tmp_data, ads, sce, filter_mode);
+               }
+#endif
+               
+               /* TODO: one day, when sequencer becomes its own datatype, perhaps it should be included here */
        }
        END_ANIMFILTER_SUBCHANNELS;
-       
+
        /* if we collected some channels, add these to the new list... */
        if (tmp_items) {
                /* firstly add object expander if required */
@@ -2174,7 +2398,7 @@ static size_t animdata_filter_animchan(bAnimContext *ac, ListBase *anim_data, bD
        size_t items = 0;
        
        /* data to filter depends on channel type */
-       // XXX: only common channel-types have been handled for now
+       /* NOTE: only common channel-types have been handled for now. More can be added as necessary */
        switch (channel->type) {
                case ANIMTYPE_SUMMARY:
                        items += animdata_filter_dopesheet(ac, anim_data, ads, filter_mode);
@@ -2187,6 +2411,14 @@ static size_t animdata_filter_animchan(bAnimContext *ac, ListBase *anim_data, bD
                case ANIMTYPE_OBJECT:
                        items += animdata_filter_dopesheet_ob(ac, anim_data, ads, channel->data, filter_mode);
                        break;
+                       
+               case ANIMTYPE_ANIMDATA:
+                       items += animfilter_block_data(ac, anim_data, ads, channel->id, filter_mode);
+                       break;
+                       
+               default:
+                       printf("ERROR: Unsupported channel type (%d) in animdata_filter_animchan()\n", channel->type);
+                       break;
        }
        
        return items;
@@ -2280,7 +2512,7 @@ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, int filter_mo
                                        items += animfilter_action(ac, anim_data, ads, data, filter_mode, (ID *)obact);
                        }
                        break;
-                               
+                       
                        case ANIMCONT_SHAPEKEY: /* 'ShapeKey Editor' */
                        {
                                /* the check for the DopeSheet summary is included here since the summary works here too */
@@ -2291,10 +2523,18 @@ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, int filter_mo
                                
                        case ANIMCONT_GPENCIL:
                        {
-                               items = animdata_filter_gpencil(anim_data, data, filter_mode);
+                               if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
+                                       items = animdata_filter_gpencil(anim_data, data, filter_mode);
                        }
                        break;
-                               
+                       
+                       case ANIMCONT_MASK:
+                       {
+                               if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
+                                       items = animdata_filter_mask(anim_data, data, filter_mode);
+                       }
+                       break;
+                       
                        case ANIMCONT_DOPESHEET: /* 'DopeSheet Editor' */
                        {
                                /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */
@@ -2303,9 +2543,9 @@ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, int filter_mo
                        }
                        break;
                                
-                       case ANIMCONT_FCURVES: /* Graph Editor -> FCurves/Animation Editing */
+                       case ANIMCONT_FCURVES: /* Graph Editor -> F-Curves/Animation Editing */
                        case ANIMCONT_DRIVERS: /* Graph Editor -> Drivers Editing */
-                       case ANIMCONT_NLA: /* NLA Editor */
+                       case ANIMCONT_NLA:     /* NLA Editor */
                        {
                                /* all of these editors use the basic DopeSheet data for filtering options, but don't have all the same features */
                                items = animdata_filter_dopesheet(ac, anim_data, data, filter_mode);