2.5 - Action Editor: All Keyframe Selection Tools Ported
authorJoshua Leung <aligorith@gmail.com>
Fri, 26 Dec 2008 10:55:07 +0000 (10:55 +0000)
committerJoshua Leung <aligorith@gmail.com>
Fri, 26 Dec 2008 10:55:07 +0000 (10:55 +0000)
User Notes (for using tools whose behaviour has changed):
* Mouse Selection Tools:
1) Click on keyframe to modify its selection. Holding the 'Shift' modifier when doing so, will result in keyframe selection being toggled instead of replacing existing selections.
2) Click on either side of the current frame indicator while holding the 'Alt' modifier. This will select only all the keyframes on the relevant side of the current frame indicator.
3) Click on a keyframe while holding the 'Ctrl' modifier. This will select all the keyframes that fall on that frame.

* Borderselect Tools
1) BKEY selects all the keyframes within the specified range (as per normal)
2) ALT-BKEY will select either all the keyframes in the frame-range specified or the channel range specified, depending on which axis of the select region was larger. This method is prejudiced towards frame-range selection.

Code Notes:
* Finished porting over all of the remaining keyframe selection tools, and recoded the ported ones to make them easier to use (after running into some technical limitations)

* Simplified the way to check if 'animation context' is valid by moving a necessary check into that function.

* Refactored internal keyframe-looping tools to reduce the amount of code needed per tool to edit keyframes, removing a lot of the unnecessary bulk. Now, the ipo/icu_keys_bezier_loop functions recieve a few more arguments (1st arg is pointer to generic customdata, and another defines a validation callback which makes it easier to reuse some of the select callbacks).

* Added 'totrect' adjustment for number of channels being shown in Action Editor, so that scrolling will be limited to where there is data (and also so that scroller displays more relevant context info).
For this to work, filtering channels now returns the number of channels extracted. This may come into use for other tools if there's such a need.

* I still need to port over some code for markers, which is required for some of the tools which use them. For now, those tools do nothing.

* Grease-Pencil editing mode in Action Editor is currently non-functional (code is commented out due to missing dependencies). This is currently pending the re-implementation of Grease Pencil in 2.5

source/blender/editors/animation/anim_filter.c
source/blender/editors/animation/keyframes_edit.c
source/blender/editors/include/ED_anim_api.h
source/blender/editors/include/ED_keyframes_edit.h
source/blender/editors/space_action/action_draw.c
source/blender/editors/space_action/action_intern.h
source/blender/editors/space_action/action_ops.c
source/blender/editors/space_action/action_select.c
source/blender/editors/space_action/space_action.c
source/blender/editors/space_ipo/space_ipo.c

index d21340782e6e037acc738f6a420e8064866fce27..6283f2dd0c68d9de0314ad0b92a566cb48c86a85 100644 (file)
@@ -210,9 +210,10 @@ static short ipoedit_get_context (const bContext *C, bAnimContext *ac, SpaceIpo
  */
 short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac)
 {
-       ScrArea *sa= CTX_wm_area(C); // XXX it is assumed that this will always be valid
+       ScrArea *sa= CTX_wm_area(C);
        ARegion *ar= CTX_wm_region(C);
        Scene *scene= CTX_data_scene(C);
+       short ok= 0;
        
        /* clear old context info */
        if (ac == NULL) return 0;
@@ -231,20 +232,23 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac)
                case SPACE_ACTION:
                {
                        SpaceAction *saction= (SpaceAction *)CTX_wm_space_data(C);
-                       return actedit_get_context(C, ac, saction);
+                       ok= actedit_get_context(C, ac, saction);
                }
                        break;
                        
                case SPACE_IPO:
                {
                        SpaceIpo *sipo= (SpaceIpo *)CTX_wm_space_data(C);
-                       return ipoedit_get_context(C, ac, sipo);
+                       ok= ipoedit_get_context(C, ac, sipo);
                }
                        break;
        }
        
-       /* nothing appropriate */
-       return 0;
+       /* check if there's any valid data */
+       if (ok && ac->data)
+               return 1;
+       else
+               return 0;
 }
 
 /* ************************************************************ */
index 278e216535bd1c3bb330853dcc8ab9535963360b..a3a0490153349080526602694ed705be38277805 100644 (file)
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include <float.h>
 
 #include "BLI_blenlib.h"
 #include "BLI_arithb.h"
  * appropriate bezier-modify function to set. These functions (ANIM_editkeyframes_*) will need
  * to be called before getting any channels.
  * 
+ * A set of 'validation' callbacks are provided for checking if a BezTriple should be operated on.
+ * These should only be used when using a 'general' BezTriple editor (i.e. selection setters which 
+ * don't check existing selection status).
+ * 
  * - Joshua Leung, Dec 2008
  */
 
 /* This function is used to loop over BezTriples in the given IpoCurve, applying a given 
  * operation on them, and optionally applies an IPO-curve validate function afterwards.
  */
-short icu_keys_bezier_loop(Scene *scene, IpoCurve *icu, BeztEditFunc bezt_cb, IcuEditFunc icu_cb) 
+short icu_keys_bezier_loop(BeztEditData *bed, IpoCurve *icu, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, IcuEditFunc icu_cb) 
 {
     BezTriple *bezt;
        int b;
        
        /* if function to apply to bezier curves is set, then loop through executing it on beztriples */
     if (bezt_cb) {
-               for (b=0, bezt=icu->bezt; b < icu->totvert; b++, bezt++) {
-                       /* Exit with return-code '1' if function returns positive
-                        * This is useful if finding if some BezTriple satisfies a condition.
-                        */
-               if (bezt_cb(scene, bezt)) return 1;
+               /* if there's a validation func, include that check in the loop 
+                * (this is should be more efficient than checking for it in every loop)
+                */
+               if (bezt_ok) {
+                       for (b=0, bezt=icu->bezt; b < icu->totvert; b++, bezt++) {
+                               /* Only operate on this BezTriple if it fullfills the criteria of the validation func */
+                               if (bezt_ok(bed, bezt)) {
+                                       /* Exit with return-code '1' if function returns positive
+                                        * This is useful if finding if some BezTriple satisfies a condition.
+                                        */
+                               if (bezt_cb(bed, bezt)) return 1;
+                               }
+                       }
+               }
+               else {
+                       for (b=0, bezt=icu->bezt; b < icu->totvert; b++, bezt++) {
+                               /* Exit with return-code '1' if function returns positive
+                                * This is useful if finding if some BezTriple satisfies a condition.
+                                */
+                       if (bezt_cb(bed, bezt)) return 1;
+                       }
                }
     }
 
@@ -98,7 +119,7 @@ short icu_keys_bezier_loop(Scene *scene, IpoCurve *icu, BeztEditFunc bezt_cb, Ic
 }
 
 /* This function is used to loop over the IPO curves (and subsequently the keyframes in them) */
-short ipo_keys_bezier_loop(Scene *scene, Ipo *ipo, BeztEditFunc bezt_cb, IcuEditFunc icu_cb)
+short ipo_keys_bezier_loop(BeztEditData *bed, Ipo *ipo, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, IcuEditFunc icu_cb)
 {
     IpoCurve *icu;
        
@@ -108,54 +129,98 @@ short ipo_keys_bezier_loop(Scene *scene, Ipo *ipo, BeztEditFunc bezt_cb, IcuEdit
        
     /* Loop through each curve in the Ipo */
     for (icu= ipo->curve.first; icu; icu=icu->next) {
-        if (icu_keys_bezier_loop(scene, icu, bezt_cb, icu_cb))
+        if (icu_keys_bezier_loop(bed, icu, bezt_ok, bezt_cb, icu_cb))
             return 1;
     }
 
     return 0;
 }
 
-/* This function is used to loop over the channels in an Action Group to modify the IPO blocks within them */
-short actgroup_keys_bezier_loop(Scene *scene, bActionGroup *agrp, BeztEditFunc bezt_cb, IcuEditFunc icu_cb)
+/* -------------------------------- Further Abstracted ----------------------------- */
+
+/* This function is used to apply operation to all keyframes, regardless of the type */
+short animchannel_keys_bezier_loop(BeztEditData *bed, bAnimListElem *ale, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, IcuEditFunc icu_cb)
 {
-       
+       return 0;
 }
 
-/* -------------------------------- Further Abstracted ----------------------------- */
+/* ************************************************************************** */
+/* BezTriple Validation Callbacks */
 
-/* this function is called to apply the same operation to all types of channels */
-short animchannel_keys_bezier_loop(Scene *scene, bAnimListElem *ale, BeztEditFunc bezt_cb, IcuEditFunc icu_cb)
+static short ok_bezier_frame(BeztEditData *bed, BezTriple *bezt)
 {
+       /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */
+       return IS_EQ(bezt->vec[1][0], bed->f1);
+}
 
+static short ok_bezier_framerange(BeztEditData *bed, BezTriple *bezt)
+{
+       /* frame range is stored in float properties */
+       return ((bezt->vec[1][0] > bed->f1) && (bezt->vec[1][0] < bed->f2));
 }
 
+static short ok_bezier_selected(BeztEditData *bed, BezTriple *bezt)
+{
+       /* this macro checks all beztriple handles for selection... */
+       return BEZSELECTED(bezt);
+}
+
+static short ok_bezier_value(BeztEditData *bed, BezTriple *bezt)
+{
+       /* value is stored in f1 property 
+        *      - this float accuracy check may need to be dropped?
+        *      - should value be stored in f2 instead so that we won't have conflicts when using f1 for frames too?
+        */
+       return IS_EQ(bezt->vec[1][1], bed->f1);
+}
+
+
+BeztEditFunc ANIM_editkeyframes_ok(short mode)
+{
+       /* eEditKeyframes_Validate */
+       switch (mode) {
+               case BEZT_OK_FRAME: /* only if bezt falls on the right frame (float) */
+                       return ok_bezier_frame;
+               case BEZT_OK_FRAMERANGE: /* only if bezt falls within the specified frame range (floats) */
+                       return ok_bezier_framerange;
+               case BEZT_OK_SELECTED:  /* only if bezt is selected */
+                       return ok_bezier_selected;
+               case BEZT_OK_VALUE: /* only if bezt value matches (float) */
+                       return ok_bezier_value;
+               default: /* nothing was ok */
+                       return NULL;
+       }
+}
 
 /* ******************************************* */
 /* Transform */
 
-static short snap_bezier_nearest(Scene *scene, BezTriple *bezt)
+static short snap_bezier_nearest(BeztEditData *bed, BezTriple *bezt)
 {
        if (bezt->f2 & SELECT)
                bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
        return 0;
 }
 
-static short snap_bezier_nearestsec(Scene *scene, BezTriple *bezt)
+static short snap_bezier_nearestsec(BeztEditData *bed, BezTriple *bezt)
 {
-       float secf = FPS;
+       const Scene *scene= bed->scene;
+       const float secf = FPS;
+       
        if (bezt->f2 & SELECT)
                bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]/secf + 0.5f) * secf);
        return 0;
 }
 
-static short snap_bezier_cframe(Scene *scene, BezTriple *bezt)
+static short snap_bezier_cframe(BeztEditData *bed, BezTriple *bezt)
 {
+       const Scene *scene= bed->scene;
        if (bezt->f2 & SELECT)
                bezt->vec[1][0]= (float)CFRA;
        return 0;
 }
 
-static short snap_bezier_nearmarker(Scene *scene, BezTriple *bezt)
+static short snap_bezier_nearmarker(BeztEditData *bed, BezTriple *bezt)
 {
        //if (bezt->f2 & SELECT)
        //      bezt->vec[1][0]= (float)find_nearest_marker_time(bezt->vec[1][0]);  // XXX missing function!
@@ -163,8 +228,9 @@ static short snap_bezier_nearmarker(Scene *scene, BezTriple *bezt)
 }
 
 // calchandles_ipocurve
-BeztEditFunc ANIM_editkeys_snap(short type)
+BeztEditFunc ANIM_editkeyframes_snap(short type)
 {
+       /* eEditKeyframes_Snap */
        switch (type) {
                case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
                        return snap_bezier_nearest;
@@ -181,8 +247,9 @@ BeztEditFunc ANIM_editkeys_snap(short type)
 
 /* --------- */
 
-static short mirror_bezier_cframe(Scene *scene, BezTriple *bezt)
+static short mirror_bezier_cframe(BeztEditData *bed, BezTriple *bezt)
 {
+       const Scene *scene= bed->scene;
        float diff;
        
        if (bezt->f2 & SELECT) {
@@ -193,7 +260,7 @@ static short mirror_bezier_cframe(Scene *scene, BezTriple *bezt)
        return 0;
 }
 
-static short mirror_bezier_yaxis(Scene *scene, BezTriple *bezt)
+static short mirror_bezier_yaxis(BeztEditData *bed, BezTriple *bezt)
 {
        float diff;
        
@@ -205,7 +272,7 @@ static short mirror_bezier_yaxis(Scene *scene, BezTriple *bezt)
        return 0;
 }
 
-static short mirror_bezier_xaxis(Scene *scene, BezTriple *bezt)
+static short mirror_bezier_xaxis(BeztEditData *bed, BezTriple *bezt)
 {
        float diff;
        
@@ -217,10 +284,11 @@ static short mirror_bezier_xaxis(Scene *scene, BezTriple *bezt)
        return 0;
 }
 
-static short mirror_bezier_marker(Scene *scene, BezTriple *bezt)
+static short mirror_bezier_marker(BeztEditData *bed, BezTriple *bezt)
 {
        static TimeMarker *marker;
        static short initialised = 0;
+       const Scene *scene= bed->scene;
        
        /* In order for this mirror function to work without
         * any extra arguments being added, we use the case
@@ -288,11 +356,13 @@ BeztEditFunc ANIM_editkeyframes_mirror(short type)
  *     for (ipo...) snap_cfra_ipo_keys(scene, ipo, 0); // sum up keyframe times
  *     snap_cfra_ipo_keys(scene, NULL, 1); // set current frame after taking average
  */
-void snap_cfra_ipo_keys(Scene *scene, Ipo *ipo, short mode)
+// XXX this thing needs to be refactored!
+void snap_cfra_ipo_keys(BeztEditData *bed, Ipo *ipo, short mode)
 {
        static int cfra;
        static int tot;
        
+       Scene *scene= bed->scene;
        IpoCurve *icu;
        BezTriple *bezt;
        int a;
@@ -330,7 +400,7 @@ void snap_cfra_ipo_keys(Scene *scene, Ipo *ipo, short mode)
 /* Settings */
 
 /* Sets the selected bezier handles to type 'auto' */
-static short set_bezier_auto(Scene *scene, BezTriple *bezt) 
+static short set_bezier_auto(BeztEditData *bed, BezTriple *bezt) 
 {
        /* is a handle selected? If so set it to type auto */
        if((bezt->f1  & SELECT) || (bezt->f3 & SELECT)) {
@@ -349,7 +419,7 @@ static short set_bezier_auto(Scene *scene, BezTriple *bezt)
 }
 
 /* Sets the selected bezier handles to type 'vector'  */
-static short set_bezier_vector(Scene *scene, BezTriple *bezt) 
+static short set_bezier_vector(BeztEditData *bed, BezTriple *bezt) 
 {
        /* is a handle selected? If so set it to type vector */
        if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
@@ -368,7 +438,7 @@ static short set_bezier_vector(Scene *scene, BezTriple *bezt)
 }
 
 #if 0 // xxx currently not used (only used by old code as a check)
-static short bezier_isfree(Scene *scene, BezTriple *bezt) 
+static short bezier_isfree(BeztEditData *bed, BezTriple *bezt) 
 {
        /* queries whether the handle should be set
         * to type 'free' or 'align'
@@ -378,7 +448,7 @@ static short bezier_isfree(Scene *scene, BezTriple *bezt)
        return 0;
 }
 
-static short set_bezier_align(Scene *scene, BezTriple *bezt) 
+static short set_bezier_align(BeztEditData *bed, BezTriple *bezt) 
 {
        /* Sets selected bezier handles to type 'align' */
        if (bezt->f1 & SELECT) bezt->h1= HD_ALIGN;
@@ -387,7 +457,7 @@ static short set_bezier_align(Scene *scene, BezTriple *bezt)
 }
 #endif // xxx currently not used (only used by old code as a check, but can't replicate that now)
 
-static short set_bezier_free(Scene *scene, BezTriple *bezt) 
+static short set_bezier_free(BeztEditData *bed, BezTriple *bezt) 
 {
        /* Sets selected bezier handles to type 'free'  */
        if (bezt->f1 & SELECT) bezt->h1= HD_FREE;
@@ -452,21 +522,21 @@ void set_ipocurve_mixed(IpoCurve *icu)
        calchandles_ipocurve(icu);
 }
 
-static short set_bezt_constant(Scene *scene, BezTriple *bezt) 
+static short set_bezt_constant(BeztEditData *bed, BezTriple *bezt) 
 {
        if (bezt->f2 & SELECT) 
                bezt->ipo= IPO_CONST;
        return 0;
 }
 
-static short set_bezt_linear(Scene *scene, BezTriple *bezt) 
+static short set_bezt_linear(BeztEditData *bed, BezTriple *bezt) 
 {
        if (bezt->f2 & SELECT) 
                bezt->ipo= IPO_LIN;
        return 0;
 }
 
-static short set_bezt_bezier(Scene *scene, BezTriple *bezt) 
+static short set_bezt_bezier(BeztEditData *bed, BezTriple *bezt) 
 {
        if (bezt->f2 & SELECT) 
                bezt->ipo= IPO_BEZ;
@@ -520,21 +590,21 @@ void setexprap_ipoloop(Ipo *ipo, int code)
 /* ******************************************* */
 /* Selection */
 
-static short select_bezier_add(Scene *scene, BezTriple *bezt) 
+static short select_bezier_add(BeztEditData *bed, BezTriple *bezt) 
 {
        /* Select the bezier triple */
        BEZ_SEL(bezt);
        return 0;
 }
 
-static short select_bezier_subtract(Scene *scene, BezTriple *bezt) 
+static short select_bezier_subtract(BeztEditData *bed, BezTriple *bezt) 
 {
        /* Deselect the bezier triple */
        BEZ_DESEL(bezt);
        return 0;
 }
 
-static short select_bezier_invert(Scene *scene, BezTriple *bezt) 
+static short select_bezier_invert(BeztEditData *bed, BezTriple *bezt) 
 {
        /* Invert the selection for the bezier triple */
        bezt->f2 ^= SELECT;
@@ -684,48 +754,7 @@ void borderselect_ipo_key(Ipo *ipo, float xmin, float xmax, short selectmode)
        }
 }
 
-
-#if 0
-void select_ipo_bezier_keys(Ipo *ipo, int selectmode)
-{
-       /* Select all of the beziers in all
-       * of the Ipo curves belonging to the
-       * Ipo, using the selection mode.
-       */
-       switch (selectmode) {
-               case SELECT_ADD:
-                       ipo_keys_bezier_loop(ipo, select_bezier_add, NULL);
-                       break;
-               case SELECT_SUBTRACT:
-                       ipo_keys_bezier_loop(ipo, select_bezier_subtract, NULL);
-                       break;
-               case SELECT_INVERT:
-                       ipo_keys_bezier_loop(ipo, select_bezier_invert, NULL);
-                       break;
-       }
-}
-
-void select_icu_bezier_keys(IpoCurve *icu, int selectmode)
-{
-       /* Select all of the beziers in all
-       * of the Ipo curves belonging to the
-       * Ipo, using the selection mode.
-       */
-       switch (selectmode) {
-               case SELECT_ADD:
-                       icu_keys_bezier_loop(icu, select_bezier_add, NULL);
-                       break;
-               case SELECT_SUBTRACT:
-                       icu_keys_bezier_loop(icu, select_bezier_subtract, NULL);
-                       break;
-               case SELECT_INVERT:
-                       icu_keys_bezier_loop(icu, select_bezier_invert, NULL);
-                       break;
-       }
-}
-#endif
-
-void select_icu_key(Scene *scene, IpoCurve *icu, float selx, short selectmode)
+void select_icu_key(BeztEditData *bed, IpoCurve *icu, float selx, short selectmode)
 {
     /* Selects all bezier triples in the Ipocurve
         * at time selx, using the selection mode.
@@ -762,12 +791,12 @@ void select_icu_key(Scene *scene, IpoCurve *icu, float selx, short selectmode)
         */
     for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) {
         if (bezt->vec[1][0] == selx) {
-            select_cb(scene, bezt);
+            select_cb(bed, bezt);
         }
     }
 }
 
-void select_ipo_key(Scene *scene, Ipo *ipo, float selx, short selectmode)
+void select_ipo_key(BeztEditData *bed, Ipo *ipo, float selx, short selectmode)
 {
        /* Selects all bezier triples in each Ipocurve of the
         * Ipo at time selx, using the selection mode.
@@ -796,7 +825,7 @@ void select_ipo_key(Scene *scene, Ipo *ipo, float selx, short selectmode)
        for (icu=ipo->curve.first; icu; icu=icu->next) {
                for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) {
                        if (bezt->vec[1][0] == selx) {
-                               select_cb(scene, bezt);
+                               select_cb(bed, bezt);
                        }
                }
        }
index d840747797062be9acb8fadf4d210395222aed07..adc2f3a8c4cee9c2fbdd0c744e2f5c0672542d71 100644 (file)
@@ -218,14 +218,13 @@ typedef enum eAnimFilter_Flags {
 
 /* ---------------- API  -------------------- */
 
-/* Obtain list of filtered Animation channels to operate on */
-int ANIM_animdata_filter(struct ListBase *anim_data, int filter_mode, void *data, short datatype);
-
-/* Obtain current anim-data context from Blender Context info */
-/** Example usage (example to be removed...):
-       // get editor data
-       if ((ANIM_animdata_get_context(C, &ac) == 0) || (ac.data == NULL))
-               return;
+/* Obtain list of filtered Animation channels to operate on.
+ * Returns the number of channels in the list
+ */
+int ANIM_animdata_filter(ListBase *anim_data, int filter_mode, void *data, short datatype);
+
+/* Obtain current anim-data context from Blender Context info.
+ * Returns whether the operation was successful. 
  */
 short ANIM_animdata_get_context(const struct bContext *C, bAnimContext *ac);
 
index 1015de2e9e490302f1b719bb47c3493b642e8a11..56a4cb6089c78b06b5cc179ae53c36ac2470d15a 100644 (file)
@@ -47,6 +47,16 @@ struct Scene;
 
 /* --------- Tool Flags ------------ */
 
+/* bezt validation */
+typedef enum eEditKeyframes_Validate {
+       BEZT_OK_FRAME   = 1,
+       BEZT_OK_FRAMERANGE,
+       BEZT_OK_SELECTED,
+       BEZT_OK_VALUE,
+} eEditKeyframes_Validate;
+
+/* ------------ */
+
 /* select tools */
 typedef enum eEditKeyframes_Select {
        SELECT_REPLACE  =       (1<<0),
@@ -71,32 +81,47 @@ typedef enum eEditKeyframes_Snap {
 /* ************************************************ */
 /* Editing API */
 
+/* --- Generic Properties for Bezier Edit Tools ----- */
+
+// XXX maybe a union would be more compact?
+typedef struct BeztEditData {
+       ListBase list;                          /* temp list for storing custom list of data to check */
+       struct Scene *scene;            /* pointer to current scene - many tools need access to cfra/etc.  */
+       void *data;                                     /* pointer to custom data - not that useful? */
+       float f1, f2;                           /* storage of times/values as 'decimals' */
+       int i1, i2;                                     /* storage of times/values as 'whole' numbers */
+} BeztEditData;
+
 /* ------- Function Pointer Typedefs --------------- */
 
        /* callback function that refreshes the IPO curve after use */
 typedef void (*IcuEditFunc)(struct IpoCurve *icu);
-typedef short (*BeztEditFunc)(struct Scene *scene, struct BezTriple *bezt);
+       /* callback function that operates on the given BezTriple */
+typedef short (*BeztEditFunc)(BeztEditData *bed, struct BezTriple *bezt);
 
 /* ------------- Looping API ------------------- */
 
-short icu_keys_bezier_loop(struct Scene *scene, struct IpoCurve *icu, BeztEditFunc bezt_cb, IcuEditFunc icu_cb);
-short ipo_keys_bezier_loop(struct Scene *scene, struct Ipo *ipo, BeztEditFunc bezt_cb, IcuEditFunc icu_cb);
+short icu_keys_bezier_loop(BeztEditData *bed, struct IpoCurve *icu, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, IcuEditFunc icu_cb);
+short ipo_keys_bezier_loop(BeztEditData *bed, struct Ipo *ipo, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, IcuEditFunc icu_cb);
 
 /* ------------ BezTriple Callback Getters --------------- */
 
+/* accessories */
+BeztEditFunc ANIM_editkeyframes_ok(short mode);
+
+/* edit */
 BeztEditFunc ANIM_editkeyframes_snap(short mode);
 BeztEditFunc ANIM_editkeyframes_mirror(short mode);
 BeztEditFunc ANIM_editkeyframes_select(short mode);
 BeztEditFunc ANIM_editkeyframes_handles(short mode);
 BeztEditFunc ANIM_editkeyframes_ipo(short mode);
 
-/* ------------ Helper Funcs -------------- */
-// XXX will these be needed to set globals for some funcs?
-
 /* ************************************************ */
 
-void select_ipo_key(struct Scene *scene, struct Ipo *ipo, float selx, short selectmode);
-void select_icu_key(struct Scene *scene, struct IpoCurve *icu, float selx, short selectmode);
+// XXX all of these funcs will be depreceated!
+
+void select_ipo_key(BeztEditData *bed, struct Ipo *ipo, float selx, short selectmode);
+void select_icu_key(BeztEditData *bed, struct IpoCurve *icu, float selx, short selectmode);
 
 short is_ipo_key_selected(struct Ipo *ipo);
 void set_ipo_key_selection(struct Ipo *ipo, short sel);
index 7a99b1511485dc089f71509d986359ce6e688f44..0b63cad4712bf9dc450df49d5212c713300b5f96 100644 (file)
@@ -404,10 +404,25 @@ void draw_channel_names(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
        int filter;
        View2D *v2d= &ar->v2d;
        float x= 0.0f, y= 0.0f;
+       int items, height;
        
        /* build list of channels to draw */
        filter= (ANIMFILTER_FORDRAWING|ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
-       ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+       items= ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+       
+       /* Update max-extent of channels here (taking into account scrollers):
+        *      - this is done to allow the channel list to be scrollable, but must be done here
+        *        to avoid regenerating the list again and/or also because channels list is drawn first
+        *      - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
+        *        start of list offset, and the second is as a correction for the scrollers.
+        */
+       height= ((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
+       if (height > (v2d->mask.ymax - v2d->mask.ymin)) {
+               /* don't use totrect set, as the width stays the same 
+                * (NOTE: this is ok here, the configuration is pretty straightforward) 
+                */
+               v2d->tot.ymin= -height;
+       }
        
        /* loop through channels, and set up drawing depending on their type  */        
        y= (float)(-ACHANNEL_HEIGHT);
@@ -728,6 +743,11 @@ void draw_channel_names(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
                                                mute = ICON_MUTE_IPO_ON;
                                        else    
                                                mute = ICON_MUTE_IPO_OFF;
+                                               
+                                       if (icu->flag & IPO_PROTECT)
+                                               protect = ICON_UNLOCKED;
+                                       else
+                                               protect = ICON_LOCKED;
                                        
                                        sel = SEL_ICU(icu);
                                        if (saction->pin)
@@ -1076,6 +1096,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
        rcti scr_rct;
        
        int act_start, act_end, dummy;
+       int height, items;
        float y, sta, end;
        
        char col1[3], col2[3];
@@ -1117,7 +1138,21 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
        
        /* build list of channels to draw */
        filter= (ANIMFILTER_FORDRAWING|ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS);
-       ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+       items= ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+       
+       /* Update max-extent of channels here (taking into account scrollers):
+        *      - this is done to allow the channel list to be scrollable, but must be done here
+        *        to avoid regenerating the list again and/or also because channels list is drawn first
+        *      - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
+        *        start of list offset, and the second is as a correction for the scrollers.
+        */
+       height= ((items*ACHANNEL_STEP) + (ACHANNEL_HEIGHT*2));
+       if (height > (v2d->mask.ymax - v2d->mask.ymin)) {
+               /* don't use totrect set, as the width stays the same 
+                * (NOTE: this is ok here, the configuration is pretty straightforward) 
+                */
+               v2d->tot.ymin= -height;
+       }
        
        /* first backdrop strips */
        y= (float)(-ACHANNEL_HEIGHT);
index 788e5df2d13628b16938722de6f009c037668d91..51c6c3c7a1d87397295b6a11963f0607e4773626 100644 (file)
@@ -37,18 +37,39 @@ struct wmOperatorType;
 
 /* internal exports only */
 
+/* ***************************************** */
 /* action_draw.c */
 void draw_channel_names(struct bAnimContext *ac, struct SpaceAction *saction, struct ARegion *ar); 
 void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, struct ARegion *ar);
 
+/* ***************************************** */
 /* action_header.c */
 void action_header_buttons(const struct bContext *C, struct ARegion *ar);
 
+/* ***************************************** */
 /* action_select.c */
 void ED_ACT_OT_keyframes_deselectall(struct wmOperatorType *ot);
 void ED_ACT_OT_keyframes_borderselect(struct wmOperatorType *ot);
+void ED_ACT_OT_keyframes_columnselect(struct wmOperatorType *ot);
 void ED_ACT_OT_keyframes_clickselect(struct wmOperatorType *ot);
 
+/* defines for left-right select tool */
+enum {
+       ACTKEYS_LRSEL_TEST      = -1,
+       ACTKEYS_LRSEL_NONE,
+       ACTKEYS_LRSEL_LEFT,
+       ACTKEYS_LRSEL_RIGHT,
+} eActKeys_LeftRightSelect_Mode;
+
+/* defines for column-select mode */
+enum {
+       ACTKEYS_COLUMNSEL_KEYS  = 0,
+       ACTKEYS_COLUMNSEL_CFRA,
+       ACTKEYS_COLUMNSEL_MARKERS_COLUMN,
+       ACTKEYS_COLUMNSEL_MARKERS_BETWEEN,
+} eActKeys_ColumnSelect_Mode;
+
+/* ***************************************** */
 /* action_ops.c */
 void action_operatortypes(void);
 void action_keymap(struct wmWindowManager *wm);
index 6d6bee90171468dce8de061a051d1c9751794224..ceaa8117de71652b10bec5f0d84baabb828b17e0 100644 (file)
@@ -65,16 +65,20 @@ void action_operatortypes(void)
        WM_operatortype_append(ED_ACT_OT_keyframes_clickselect);
        WM_operatortype_append(ED_ACT_OT_keyframes_deselectall);
        WM_operatortype_append(ED_ACT_OT_keyframes_borderselect);
+       WM_operatortype_append(ED_ACT_OT_keyframes_columnselect);
 }
 
 /* ************************** registration - keymaps **********************************/
 
 static void action_keymap_keyframes (ListBase *keymap)
 {
+       /* action_select.c - selection tools */
                /* click-select */
        WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "column_select", 1);
        RNA_boolean_set(WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend_select", 1);
-       RNA_boolean_set(WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "left_right", 1);
+       RNA_enum_set(WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "left_right", ACTKEYS_LRSEL_TEST);
+       
        
                /* deselect all */
        WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_deselectall", AKEY, KM_PRESS, 0, 0);
@@ -82,6 +86,13 @@ static void action_keymap_keyframes (ListBase *keymap)
        
                /* borderselect */
        WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_borderselect", BKEY, KM_PRESS, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_borderselect", BKEY, KM_PRESS, KM_ALT, 0)->ptr, "axis_range", 1);
+       
+               /* column select */
+       RNA_enum_set(WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_columnselect", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS);
+       RNA_enum_set(WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_columnselect", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA);
+       RNA_enum_set(WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_columnselect", KKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_MARKERS_COLUMN);
+       RNA_enum_set(WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_columnselect", KKEY, KM_PRESS, KM_ALT, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_MARKERS_BETWEEN);
 }
 
 /* --------------- */
index 100024fc0d180d5e66cdb327222b8a53d8b823f0..cd454388a57ae9fb066253bf254dcbd9623c23e2 100644 (file)
@@ -83,6 +83,8 @@
 #include "WM_api.h"
 #include "WM_types.h"
 
+#include "action_intern.h"
+
 /* ************************************************************************** */
 /* GENERAL STUFF */
 
@@ -384,7 +386,7 @@ static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
        bAnimContext ac;
        
        /* get editor data */
-       if ((ANIM_animdata_get_context(C, &ac) == 0) || (ac.data == NULL))
+       if (ANIM_animdata_get_context(C, &ac) == 0)
                return OPERATOR_CANCELLED;
                
        /* 'standard' behaviour - check if selected, then apply relevant selection */
@@ -414,23 +416,34 @@ void ED_ACT_OT_keyframes_deselectall (wmOperatorType *ot)
 }
 
 /* ******************** Border Select Operator **************************** */
-/* This operator works in one of three ways:
- *     1) borderselect over keys (BKEY) - mouse over main area when initialised; will select keys in region
- *     2) borderselect over horizontal scroller - mouse over horizontal scroller when initialised; will select keys in frame range
- *     3) borderselect over vertical scroller - mouse over vertical scroller when initialised; will select keys in row range
+/* This operator currently works in one of three ways:
+ *     -> BKEY         - 1) all keyframes within region are selected (ACTKEYS_BORDERSEL_ALLKEYS)
+ *     -> ALT-BKEY - depending on which axis of the region was larger...
+ *             -> 2) x-axis, so select all frames within frame range (ACTKEYS_BORDERSEL_FRAMERANGE)
+ *             -> 3) y-axis, so select all frames within channels that region included (ACTKEYS_BORDERSEL_CHANNELS)
  */
 
-static void borderselect_action (bAnimContext *ac, rcti rect, short in_scroller, short selectmode)
+/* defines for borderselect mode */
+enum {
+       ACTKEYS_BORDERSEL_ALLKEYS       = 0,
+       ACTKEYS_BORDERSEL_FRAMERANGE,
+       ACTKEYS_BORDERSEL_CHANNELS,
+} eActKeys_BorderSelect_Mode;
+
+
+static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short selectmode)
 {
        ListBase anim_data = {NULL, NULL};
        bAnimListElem *ale;
        int filter;
        
+       BeztEditData bed;
+       BeztEditFunc ok_cb, select_cb;
        View2D *v2d= &ac->ar->v2d;
-       BeztEditFunc select_cb;
        rctf rectf;
-       float ymin=0, ymax=ACHANNEL_HEIGHT;
+       float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT);
        
+       /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
        UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin+2, &rectf.xmin, &rectf.ymin);
        UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax-2, &rectf.xmax, &rectf.ymax);
        
@@ -438,29 +451,47 @@ static void borderselect_action (bAnimContext *ac, rcti rect, short in_scroller,
        filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
        ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
        
-       /* get selection editing func */
+       /* get beztriple editing/validation funcs  */
        select_cb= ANIM_editkeyframes_select(selectmode);
        
+       if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS))
+               ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
+       else
+               ok_cb= NULL;
+               
+       /* init editing data */
+       memset(&bed, 0, sizeof(BeztEditData));
+       
        /* loop over data, doing border select */
        for (ale= anim_data.first; ale; ale= ale->next) {
                Object *nob= ANIM_nla_mapping_get(ac, ale);
                
+               /* get new vertical minimum extent of channel */
                ymin= ymax - ACHANNEL_STEP;
                
-               /* if action is mapped in NLA, it returns a correction */
-               if (nob) {
-                       rectf.xmin= get_action_frame(nob, rectf.xmin);
-                       rectf.xmax= get_action_frame(nob, rectf.xmax);
+               /* set horizontal range (if applicable) */
+               if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
+                       /* if channel is mapped in NLA, apply correction */
+                       if (nob) {
+                               bed.f1= get_action_frame(nob, rectf.xmin);
+                               bed.f2= get_action_frame(nob, rectf.xmax);
+                       }
+                       else {
+                               bed.f1= rectf.xmin;
+                               bed.f2= rectf.xmax;
+                       }
                }
                
-               /* what gets selected depends on the mode (based on initial position of cursor) */
-               switch (in_scroller) {
-               case 'h': /* all in frame(s) (option 3) */
+               /* perform vertical suitability check (if applicable) */
+               if ( (mode == ACTKEYS_BORDERSEL_FRAMERANGE) || 
+                       !((ymax < rectf.ymin) || (ymin > rectf.ymax)) )
+               {
+                       /* loop over data selecting */
                        if (ale->key_data) {
                                if (ale->datatype == ALE_IPO)
-                                       borderselect_ipo_key(ale->key_data, rectf.xmin, rectf.xmax, selectmode);
+                                       ipo_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
                                else if (ale->datatype == ALE_ICU)
-                                       borderselect_icu_key(ale->key_data, rectf.xmin, rectf.xmax, select_cb);
+                                       icu_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
                        }
                        else if (ale->type == ANIMTYPE_GROUP) {
                                bActionGroup *agrp= ale->data;
@@ -468,74 +499,18 @@ static void borderselect_action (bAnimContext *ac, rcti rect, short in_scroller,
                                bConstraintChannel *conchan;
                                
                                for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
-                                       borderselect_ipo_key(achan->ipo, rectf.xmin, rectf.xmax, selectmode);
+                                       ipo_keys_bezier_loop(&bed, achan->ipo, ok_cb, select_cb, NULL);
                                        
                                        for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
-                                               borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, selectmode);
+                                               ipo_keys_bezier_loop(&bed, conchan->ipo, ok_cb, select_cb, NULL);
                                }
                        }
                        //else if (ale->type == ANIMTYPE_GPLAYER) {
                        //      borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode);
                        //}
-                       break;
-               case 'v': /* all in channel(s) (option 2) */
-                       if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
-                               if (ale->key_data) {
-                                       if (ale->datatype == ALE_IPO)
-                                               ipo_keys_bezier_loop(ac->scene, ale->key_data, select_cb, NULL);
-                                       else if (ale->datatype == ALE_ICU)
-                                               icu_keys_bezier_loop(ac->scene, ale->key_data, select_cb, NULL);
-                               }
-                               else if (ale->type == ANIMTYPE_GROUP) {
-                                       bActionGroup *agrp= ale->data;
-                                       bActionChannel *achan;
-                                       bConstraintChannel *conchan;
-                                       
-                                       for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
-                                               ipo_keys_bezier_loop(ac->scene, achan->ipo, select_cb, NULL);
-                                               
-                                               for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
-                                                       ipo_keys_bezier_loop(ac->scene, conchan->ipo, select_cb, NULL);
-                                       }
-                               }
-                               //else if (ale->type == ANIMTYPE_GPLAYER) {
-                               //      select_gpencil_frames(ale->data, selectmode);
-                               //}
-                       }
-                       break;
-               default: /* any keyframe inside region defined by region (option 1) */
-                       if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
-                               if (ale->key_data) {
-                                       if (ale->datatype == ALE_IPO)
-                                               borderselect_ipo_key(ale->key_data, rectf.xmin, rectf.xmax, selectmode);
-                                       else if (ale->datatype == ALE_ICU)
-                                               borderselect_icu_key(ale->key_data, rectf.xmin, rectf.xmax, select_cb);
-                               }
-                               else if (ale->type == ANIMTYPE_GROUP) {
-                                       // fixme: need a nicer way of dealing with summaries!
-                                       bActionGroup *agrp= ale->data;
-                                       bActionChannel *achan;
-                                       bConstraintChannel *conchan;
-                                       
-                                       for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
-                                               borderselect_ipo_key(achan->ipo, rectf.xmin, rectf.xmax, selectmode);
-                                               
-                                               for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
-                                                       borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, selectmode);
-                                       }
-                               }
-                               //else if (ale->type == ANIMTYPE_GPLAYER) {
-                               ////    borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode);
-                               //}
-                       }
-               }
-               
-               /* if action is mapped in NLA, unapply correction */
-               if (nob) {
-                       rectf.xmin= get_action_frame_inv(nob, rectf.xmin);
-                       rectf.xmax= get_action_frame_inv(nob, rectf.xmax);
                }
                
+               /* set minimum extent to be the maximum of the next channel */
                ymax=ymin;
        }
        
@@ -549,11 +524,11 @@ static int actkeys_borderselect_exec(bContext *C, wmOperator *op)
 {
        bAnimContext ac;
        rcti rect;
-       short in_scroller, selectmode;
+       short mode=0, selectmode=0;
        int event;
        
        /* get editor data */
-       if ((ANIM_animdata_get_context(C, &ac) == 0) || (ac.data == NULL))
+       if (ANIM_animdata_get_context(C, &ac) == 0)
                return OPERATOR_CANCELLED;
        
        /* get settings from operator */
@@ -561,37 +536,33 @@ static int actkeys_borderselect_exec(bContext *C, wmOperator *op)
        rect.ymin= RNA_int_get(op->ptr, "ymin");
        rect.xmax= RNA_int_get(op->ptr, "xmax");
        rect.ymax= RNA_int_get(op->ptr, "ymax");
-       
-       in_scroller= RNA_int_get(op->ptr, "in_scroller");
-       
+               
        event= RNA_int_get(op->ptr, "event_type");
        if (event == LEFTMOUSE) // FIXME... hardcoded
                selectmode = SELECT_ADD;
        else
                selectmode = SELECT_SUBTRACT;
-               
-       borderselect_action(&ac, rect, in_scroller, selectmode);
        
-       return OPERATOR_FINISHED;
-} 
-
-static int actkeys_borderselect_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
-       bAnimContext ac;
-       ARegion *ar;
+       /* selection 'mode' depends on whether borderselect region only matters on one axis */
+       if (RNA_boolean_get(op->ptr, "axis_range")) {
+               /* mode depends on which axis of the range is larger to determine which axis to use 
+                *      - checking this in region-space is fine, as it's fundamentally still going to be a different rect size
+                *      - the frame-range select option is favoured over the channel one (x over y), as frame-range one is often
+                *        used for tweaking timing when "blocking", while channels is not that useful...
+                */
+               if ((rect.xmax - rect.xmin) >= (rect.ymax - rect.ymin))
+                       mode= ACTKEYS_BORDERSEL_FRAMERANGE;
+               else
+                       mode= ACTKEYS_BORDERSEL_CHANNELS;
+       }
+       else 
+               mode= ACTKEYS_BORDERSEL_ALLKEYS;
        
-       /* get editor data */
-       if ((ANIM_animdata_get_context(C, &ac) == 0) || (ac.data == NULL))
-               return OPERATOR_CANCELLED;
-       ar= ac.ar;
-               
-       /* check if mouse is in a scroller */
-       // XXX move this to keymap level thing (boundbox checking)?
-       RNA_enum_set(op->ptr, "in_scroller", UI_view2d_mouse_in_scrollers(C, &ar->v2d, event->x, event->y));
+       /* apply borderselect action */
+       borderselect_action(&ac, rect, mode, selectmode);
        
-       /* now init borderselect operator to handle borderselect as per normal */
-       return WM_border_select_invoke(C, op, event);
-}
+       return OPERATOR_FINISHED;
+} 
 
 void ED_ACT_OT_keyframes_borderselect(wmOperatorType *ot)
 {
@@ -600,34 +571,270 @@ void ED_ACT_OT_keyframes_borderselect(wmOperatorType *ot)
        ot->idname= "ED_ACT_OT_keyframes_borderselect";
        
        /* api callbacks */
-       ot->invoke= actkeys_borderselect_invoke;//WM_border_select_invoke;
+       ot->invoke= WM_border_select_invoke;
        ot->exec= actkeys_borderselect_exec;
        ot->modal= WM_border_select_modal;
        
        ot->poll= ED_operator_areaactive;
        
        /* rna */
-       RNA_def_property(ot->srna, "in_scroller", PROP_INT, PROP_NONE); // as enum instead?
        RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
        RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
        RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
        RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
        RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
+       
+       RNA_def_property(ot->srna, "axis_range", PROP_BOOLEAN, PROP_NONE);
 }
 
 /* ******************** Column Select Operator **************************** */
+/* This operator works in one of four ways:
+ *     - 1) select all keyframes in the same frame as a selected one  (KKEY)
+ *     - 2) select all keyframes in the same frame as the current frame marker (CTRL-KKEY)
+ *     - 3) select all keyframes in the same frame as a selected markers (SHIFT-KKEY)
+ *     - 4) select all keyframes that occur between selected markers (ALT-KKEY)
+ */
+
+/* defines for column-select mode */
+EnumPropertyItem prop_column_select_types[] = {
+       {ACTKEYS_COLUMNSEL_KEYS, "KEYS", "On Selected Keyframes", ""},
+       {ACTKEYS_COLUMNSEL_CFRA, "CFRA", "On Current Frame", ""},
+       {ACTKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", "On Selected Markers", ""},
+       {ACTKEYS_COLUMNSEL_MARKERS_BETWEEN, "MARKERS_BETWEEN", "Between Min/Max Selected Markers", ""},
+       {0, NULL, NULL, NULL}
+};
+
+/* ------------------- */ 
+
+/* Selects all visible keyframes between the specified markers */
+static void markers_selectkeys_between (bAnimContext *ac)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       BeztEditFunc select_cb;
+       BeztEditData bed;
+       float min, max;
+       
+       /* get extreme markers */
+       //get_minmax_markers(1, &min, &max); // FIXME... add back markers api!
+       min= ac->scene->r.sfra; // xxx temp code
+       max= ac->scene->r.efra; // xxx temp code
+       
+       if (min==max) return;
+       min -= 0.5f;
+       max += 0.5f;
+       
+       /* get editing funcs + data */
+       select_cb= ANIM_editkeyframes_select(SELECT_ADD);
+       memset(&bed, 0, sizeof(BeztEditData));
+       bed.f1= min; 
+       bed.f2= max;
+       
+       /* filter data */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_IPOKEYS);
+       ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+       
+       /* select keys in-between */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               Object *nob= ANIM_nla_mapping_get(ac, ale);
+               
+               if (nob) {      
+                       ANIM_nla_mapping_apply(nob, ale->key_data, 0, 1);
+                       ipo_keys_bezier_loop(&bed, ale->key_data, NULL, select_cb, NULL);
+                       ANIM_nla_mapping_apply(nob, ale->key_data, 1, 1);
+               }
+               else {
+                       ipo_keys_bezier_loop(&bed, ale->key_data, NULL, select_cb, NULL);
+               }
+       }
+       
+       /* Cleanup */
+       BLI_freelistN(&anim_data);
+}
+
+
+/* helper callback for columnselect_action_keys() -> populate list CfraElems with frame numbers from selected beztriples */
+// TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!!
+static short bezt_to_cfraelem(BeztEditData *bed, BezTriple *bezt)
+{
+       /* only if selected */
+       if (bezt->f2 & SELECT) {
+               CfraElem *ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
+               BLI_addtail(&bed->list, ce);
+               
+               ce->cfra= bezt->vec[1][0];
+       }
+       
+       return 0;
+}
+
+/* Selects all visible keyframes in the same frames as the specified elements */
+static void columnselect_action_keys (bAnimContext *ac, short mode)
+{
+       ListBase anim_data= {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       Scene *scene= ac->scene;
+       CfraElem *ce;
+       BeztEditFunc select_cb, ok_cb;
+       BeztEditData bed;
+       
+       /* initialise keyframe editing data */
+       memset(&bed, 0, sizeof(BeztEditData));
+       
+       /* build list of columns */
+       switch (mode) {
+               case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */
+                       if (ac->datatype == ANIMCONT_GPENCIL) {
+                               filter= (ANIMFILTER_VISIBLE);
+                               ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+                               
+                               //for (ale= anim_data.first; ale; ale= ale->next)
+                               //      gplayer_make_cfra_list(ale->data, &elems, 1);
+                       }
+                       else {
+                               filter= (ANIMFILTER_VISIBLE | ANIMFILTER_IPOKEYS);
+                               ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+                               
+                               for (ale= anim_data.first; ale; ale= ale->next)
+                                       ipo_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_to_cfraelem, NULL);
+                       }
+                       BLI_freelistN(&anim_data);
+                       break;
+                       
+               case ACTKEYS_COLUMNSEL_CFRA: /* current frame */
+                       /* make a single CfraElem for storing this */
+                       ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
+                       BLI_addtail(&bed.list, ce);
+                       
+                       ce->cfra= (float)CFRA;
+                       break;
+                       
+               case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
+                       // FIXME: markers api needs to be improved for this first!
+                       //make_marker_cfra_list(&elems, 1);
+                       return; // XXX currently, this does nothing!
+                       break;
+                       
+               default: /* invalid option */
+                       return;
+       }
+       
+       /* set up BezTriple edit callbacks */
+       select_cb= ANIM_editkeyframes_select(SELECT_ADD);
+       ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME);
+       
+       /* loop through all of the keys and select additional keyframes
+        * based on the keys found to be selected above
+        */
+       if (ac->datatype == ANIMCONT_GPENCIL)
+               filter= (ANIMFILTER_VISIBLE);
+       else
+               filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ONLYICU);
+       ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+       
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               Object *nob= ANIM_nla_mapping_get(ac, ale);
+               
+               /* loop over cfraelems (stored in the BeztEditData->list)
+                *      - we need to do this here, as we can apply fewer NLA-mapping conversions
+                */
+               for (ce= bed.list.first; ce; ce= ce->next) {
+                       /* set frame for validation callback to refer to */
+                       if (nob)
+                               bed.f1= get_action_frame(nob, ce->cfra);
+                       else
+                               bed.f1= ce->cfra;
+                       
+                       /* select elements with frame number matching cfraelem */
+                       icu_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
+                       
+#if 0 // XXX reenable when Grease Pencil stuff is back
+                       if (ale->type == ANIMTYPE_GPLAYER) {
+                               bGPDlayer *gpl= (bGPDlayer *)ale->data;
+                               bGPDframe *gpf;
+                               
+                               for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+                                       if (ecfra == gpf->framenum) 
+                                               gpf->flag |= GP_FRAME_SELECT;
+                               }
+                       }
+                       //else... 
+#endif // XXX reenable when Grease Pencil stuff is back
+               }
+       }
+       
+       /* free elements */
+       BLI_freelistN(&bed.list);
+       BLI_freelistN(&anim_data);
+}
+
+/* ------------------- */
+
+static int actkeys_columnselect_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       short mode;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* action to take depends on the mode */
+       mode= RNA_enum_get(op->ptr, "mode");
+       
+       if (mode == ACTKEYS_COLUMNSEL_MARKERS_BETWEEN)
+               markers_selectkeys_between(&ac);
+       else
+               columnselect_action_keys(&ac, mode);
+       
+       /* set notifier tha things have changed */
+       ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
+       
+       return OPERATOR_FINISHED;
+}
+void ED_ACT_OT_keyframes_columnselect (wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+       
+       /* identifiers */
+       ot->name= "Select All";
+       ot->idname= "ED_ACT_OT_keyframes_columnselect";
+       
+       /* api callbacks */
+       ot->exec= actkeys_columnselect_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* props */
+       prop= RNA_def_property(ot->srna, "mode", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_items(prop, prop_column_select_types);
+}
 
 /* ******************** Mouse-Click Select Operator *********************** */
-/* This operator works in one of four ways:
- *     - main area
- *             -> 1) without alt-key - selects keyframe that was under mouse position
- *             -> 2) with alt-key - only those keyframes on same side of current frame
- *     - 3) horizontal scroller (*) - select all keyframes in frame (err... maybe integrate this with column select only)?
- *     - 4) vertical scroller (*) - select all keyframes in channel
+/* This operator works in one of three ways:
+ *     - 1) keyframe under mouse - no special modifiers
+ *     - 2) all keyframes on the same side of current frame indicator as mouse - ALT modifier
+ *     - 3) column select all keyframes in frame under mouse - CTRL modifier
  *
- *     (*) - these are not obviously presented in UI. We need to find a new way to showcase them.
+ * In addition to these basic options, the SHIFT modifier can be used to toggle the 
+ * selection mode between replacing the selection (without) and inverting the selection (with).
  */
 
+/* defines for left-right select tool */
+EnumPropertyItem prop_leftright_select_types[] = {
+       {ACTKEYS_LRSEL_TEST, "CHECK", "Check if Select Left or Right", ""},
+       {ACTKEYS_LRSEL_NONE, "OFF", "Don't select", ""},
+       {ACTKEYS_LRSEL_LEFT, "LEFT", "Before current frame", ""},
+       {ACTKEYS_LRSEL_RIGHT, "RIGHT", "After current frame", ""},
+       {0, NULL, NULL, NULL}
+};
+
+/* ------------------- */
 /* option 1) select keyframe directly under mouse */
 static void mouse_action_keys (bAnimContext *ac, int mval[2], short selectmode)
 {
@@ -642,6 +849,8 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short selectmode)
        bGPdata *gpd = NULL;
        bGPDlayer *gpl = NULL;
        
+       BeztEditData bed;
+       BeztEditFunc select_cb, ok_cb;
        void *anim_channel;
        short sel, chan_type = 0;
        float selx = 0.0f, selxa;
@@ -653,127 +862,143 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short selectmode)
                ads= (bDopeSheet *)ac->data;
        else if (ac->datatype == ANIMCONT_GPENCIL) 
                gpd= (bGPdata *)ac->data;
-
+       
+       /* get channel and selection info */
        anim_channel= get_nearest_action_key(ac, mval, &selx, &sel, &chan_type, &achan);
-       if (anim_channel) {
-               /* must have been a channel */
-               switch (chan_type) {
-                       case ANIMTYPE_ICU:
-                               icu= (IpoCurve *)anim_channel;
-                               break;
-                       case ANIMTYPE_CONCHAN:
-                               conchan= (bConstraintChannel *)anim_channel;
-                               break;
-                       case ANIMTYPE_ACHAN:
-                               achan= (bActionChannel *)anim_channel;
-                               break;
-                       case ANIMTYPE_GROUP:
-                               agrp= (bActionGroup *)anim_channel;
-                               break;
-                       case ANIMTYPE_DSMAT:
-                               ipo= ((Material *)anim_channel)->ipo;
-                               break;
-                       case ANIMTYPE_DSLAM:
-                               ipo= ((Lamp *)anim_channel)->ipo;
-                               break;
-                       case ANIMTYPE_DSCAM:
-                               ipo= ((Camera *)anim_channel)->ipo;
-                               break;
-                       case ANIMTYPE_DSCUR:
-                               ipo= ((Curve *)anim_channel)->ipo;
-                               break;
-                       case ANIMTYPE_DSSKEY:
-                               ipo= ((Key *)anim_channel)->ipo;
-                               break;
-                       case ANIMTYPE_FILLACTD:
-                               act= (bAction *)anim_channel;
-                               break;
-                       case ANIMTYPE_FILLIPOD:
-                               ipo= ((Object *)anim_channel)->ipo;
-                               break;
-                       case ANIMTYPE_OBJECT:
-                               ob= ((Base *)anim_channel)->object;
-                               break;
-                       case ANIMTYPE_GPLAYER:
-                               gpl= (bGPDlayer *)anim_channel;
-                               break;
-                       default:
-                               return;
-               }
+       if (anim_channel == NULL) 
+               return;
+       
+       switch (chan_type) {
+               case ANIMTYPE_ICU:
+                       icu= (IpoCurve *)anim_channel;
+                       break;
+               case ANIMTYPE_CONCHAN:
+                       conchan= (bConstraintChannel *)anim_channel;
+                       break;
+               case ANIMTYPE_ACHAN:
+                       achan= (bActionChannel *)anim_channel;
+                       break;
+               case ANIMTYPE_GROUP:
+                       agrp= (bActionGroup *)anim_channel;
+                       break;
+               case ANIMTYPE_DSMAT:
+                       ipo= ((Material *)anim_channel)->ipo;
+                       break;
+               case ANIMTYPE_DSLAM:
+                       ipo= ((Lamp *)anim_channel)->ipo;
+                       break;
+               case ANIMTYPE_DSCAM:
+                       ipo= ((Camera *)anim_channel)->ipo;
+                       break;
+               case ANIMTYPE_DSCUR:
+                       ipo= ((Curve *)anim_channel)->ipo;
+                       break;
+               case ANIMTYPE_DSSKEY:
+                       ipo= ((Key *)anim_channel)->ipo;
+                       break;
+               case ANIMTYPE_FILLACTD:
+                       act= (bAction *)anim_channel;
+                       break;
+               case ANIMTYPE_FILLIPOD:
+                       ipo= ((Object *)anim_channel)->ipo;
+                       break;
+               case ANIMTYPE_OBJECT:
+                       ob= ((Base *)anim_channel)->object;
+                       break;
+               case ANIMTYPE_GPLAYER:
+                       gpl= (bGPDlayer *)anim_channel;
+                       break;
+               default:
+                       return;
+       }
+       
+       /* for replacing selection, firstly need to clear existing selection */
+       if (selectmode == SELECT_REPLACE) {
+               selectmode = SELECT_ADD;
                
-               if (selectmode == SELECT_REPLACE) {
-                       selectmode = SELECT_ADD;
-                       
-                       deselect_action_keys(ac, 0, 0);
+               deselect_action_keys(ac, 0, 0);
+               
+               if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) {
+                       //deselect_action_channels(0);
                        
-                       if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) {
-                               //deselect_action_channels(0);
-                               
-                               /* Highlight either an Action-Channel or Action-Group */
-                               if (achan) {
-                                       achan->flag |= ACHAN_SELECTED;
-                                       //hilight_channel(act, achan, 1);
-                                       //select_poseelement_by_name(achan->name, 2);   /* 2 is activate */
-                               }
-                               else if (agrp) {
-                                       agrp->flag |= AGRP_SELECTED;
-                                       //set_active_actiongroup(act, agrp, 1);
-                               }
+                       /* Highlight either an Action-Channel or Action-Group */
+                       if (achan) {
+                               achan->flag |= ACHAN_SELECTED;
+                               //hilight_channel(act, achan, 1);
+                               //select_poseelement_by_name(achan->name, 2);   /* 2 is activate */
                        }
-                       else if (ac->datatype == ANIMCONT_GPENCIL) {
-                               //deselect_action_channels(0);
-                               
-                               /* Highlight gpencil layer */
-                               gpl->flag |= GP_LAYER_SELECT;
-                               //gpencil_layer_setactive(gpd, gpl);
+                       else if (agrp) {
+                               agrp->flag |= AGRP_SELECTED;
+                               //set_active_actiongroup(act, agrp, 1);
                        }
                }
-               
-               if (icu)
-                       select_icu_key(ac->scene, icu, selx, selectmode);
-               else if (ipo)
-                       select_ipo_key(ac->scene, ipo, selx, selectmode);
-               else if (conchan)
-                       select_ipo_key(ac->scene, conchan->ipo, selx, selectmode);
-               else if (achan)
-                       select_ipo_key(ac->scene, achan->ipo, selx, selectmode);
-               else if (agrp) {
-                       for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
-                               select_ipo_key(ac->scene, achan->ipo, selx, selectmode);
-                               
-                               for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
-                                       select_ipo_key(ac->scene, conchan->ipo, selx, selectmode);
-                       }
+               else if (ac->datatype == ANIMCONT_GPENCIL) {
+                       //deselect_action_channels(0);
+                       
+                       /* Highlight gpencil layer */
+                       gpl->flag |= GP_LAYER_SELECT;
+                       //gpencil_layer_setactive(gpd, gpl);
                }
-               else if (act) {
-                       for (achan= act->chanbase.first; achan; achan= achan->next) {
-                               select_ipo_key(ac->scene, achan->ipo, selx, selectmode);
-                               
-                               for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
-                                       select_ipo_key(ac->scene, conchan->ipo, selx, selectmode);
-                       }
+       }
+       
+       /* get functions for selecting keyframes */
+       select_cb= ANIM_editkeyframes_select(selectmode);
+       ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME);
+       memset(&bed, 0, sizeof(BeztEditData)); 
+       bed.f1= selx;
+       
+       /* apply selection to keyframes */
+       if (icu)
+               icu_keys_bezier_loop(&bed, icu, ok_cb, select_cb, NULL);
+       else if (ipo)
+               ipo_keys_bezier_loop(&bed, ipo, ok_cb, select_cb, NULL);
+       else if (conchan)
+               ipo_keys_bezier_loop(&bed, conchan->ipo, ok_cb, select_cb, NULL);
+       else if (achan)
+               ipo_keys_bezier_loop(&bed, achan->ipo, ok_cb, select_cb, NULL);
+       else if (agrp) {
+               for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
+                       ipo_keys_bezier_loop(&bed, achan->ipo, ok_cb, select_cb, NULL);
+                       
+                       for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
+                               ipo_keys_bezier_loop(&bed, conchan->ipo, ok_cb, select_cb, NULL);
+               }
+       }
+       else if (act) {
+               for (achan= act->chanbase.first; achan; achan= achan->next) {
+                       ipo_keys_bezier_loop(&bed, achan->ipo, ok_cb, select_cb, NULL);
+                       
+                       for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
+                               ipo_keys_bezier_loop(&bed, conchan->ipo, ok_cb, select_cb, NULL);
+               }
+       }
+       else if (ob) {
+               if (ob->ipo) {
+                       bed.f1= selx;
+                       ipo_keys_bezier_loop(&bed, ob->ipo, ok_cb, select_cb, NULL);
                }
-               else if (ob) {
-                       if (ob->ipo) 
-                               select_ipo_key(ac->scene, ob->ipo, selx, selectmode);
+               
+               if (ob->action) {
+                       selxa= get_action_frame(ob, selx);
+                       bed.f1= selxa;
                        
-                       if (ob->action) {
-                               selxa= get_action_frame(ob, selx);
+                       for (achan= ob->action->chanbase.first; achan; achan= achan->next) {
+                               ipo_keys_bezier_loop(&bed, achan->ipo, ok_cb, select_cb, NULL);
                                
-                               for (achan= ob->action->chanbase.first; achan; achan= achan->next) {
-                                       select_ipo_key(ac->scene, achan->ipo, selxa, selectmode);
-                                       
-                                       for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
-                                               select_ipo_key(ac->scene, conchan->ipo, selxa, selectmode);
-                               }
+                               for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
+                                       ipo_keys_bezier_loop(&bed, conchan->ipo, ok_cb, select_cb, NULL);
                        }
+               }
+               
+               if (ob->constraintChannels.first) {
+                       bed.f1= selx;
                        
                        for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next)
-                               select_ipo_key(ac->scene, conchan->ipo, selx, selectmode);
+                               ipo_keys_bezier_loop(&bed, conchan->ipo, ok_cb, select_cb, NULL);
                }
-               //else if (gpl)
-               //      select_gpencil_frame(gpl, (int)selx, selectmode);
        }
+       //else if (gpl)
+       //      select_gpencil_frame(gpl, (int)selx, selectmode);
 }
 
 /* Option 2) Selects all the keyframes on either side of the current frame (depends on which side the mouse is on) */
@@ -790,7 +1015,7 @@ static void selectkeys_leftright (bAnimContext *ac, short leftright, short selec
                deselect_action_keys(ac, 0, 0);
        }
        
-       if (leftright == 1) {
+       if (leftright == ACTKEYS_LRSEL_LEFT) {
                min = -MAXFRAMEF;
                max = (float)(CFRA + 0.1f);
        } 
@@ -824,50 +1049,116 @@ static void selectkeys_leftright (bAnimContext *ac, short leftright, short selec
        /* Cleanup */
        BLI_freelistN(&anim_data);
 }
+
+/* Option 3) Selects all visible keyframes in the same frame as the mouse click */
+static void mouse_columnselect_action_keys (bAnimContext *ac, float selx)
+{
+       ListBase anim_data= {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       BeztEditFunc select_cb, ok_cb;
+       BeztEditData bed;
+       
+       /* initialise keyframe editing data */
+       memset(&bed, 0, sizeof(BeztEditData));
+       
+       /* set up BezTriple edit callbacks */
+       select_cb= ANIM_editkeyframes_select(SELECT_ADD);
+       ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME);
+       
+       /* loop through all of the keys and select additional keyframes
+        * based on the keys found to be selected above
+        */
+       if (ac->datatype == ANIMCONT_GPENCIL)
+               filter= (ANIMFILTER_VISIBLE);
+       else
+               filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ONLYICU);
+       ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+       
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               Object *nob= ANIM_nla_mapping_get(ac, ale);
+               
+               /* set frame for validation callback to refer to */
+               if (nob)
+                       bed.f1= get_action_frame(nob, selx);
+               else
+                       bed.f1= selx;
+               
+               /* select elements with frame number matching cfraelem */
+               icu_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
+                       
+#if 0 // XXX reenable when Grease Pencil stuff is back
+                       if (ale->type == ANIMTYPE_GPLAYER) {
+                               bGPDlayer *gpl= (bGPDlayer *)ale->data;
+                               bGPDframe *gpf;
+                               
+                               for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
+                                       if (ecfra == gpf->framenum) 
+                                               gpf->flag |= GP_FRAME_SELECT;
+                               }
+                       }
+                       //else... 
+#endif // XXX reenable when Grease Pencil stuff is back
+       }
+       
+       /* free elements */
+       BLI_freelistN(&bed.list);
+       BLI_freelistN(&anim_data);
+}
  
 /* ------------------- */
 
+/* handle clicking */
 static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        bAnimContext ac;
        Scene *scene;
        ARegion *ar;
-       short in_scroller, selectmode;
+       View2D *v2d;
+       short selectmode;
        int mval[2];
        
        /* get editor data */
-       if ((ANIM_animdata_get_context(C, &ac) == 0) || (ac.data == NULL))
+       if (ANIM_animdata_get_context(C, &ac) == 0)
                return OPERATOR_CANCELLED;
                
        /* get useful pointers from animation context data */
        scene= ac.scene;
        ar= ac.ar;
+       v2d= &ar->v2d;
        
        /* get mouse coordinates (in region coordinates) */
        mval[0]= (event->x - ar->winrct.xmin);
        mval[1]= (event->y - ar->winrct.ymin);
        
-       /* check where in view mouse is */
-       in_scroller = UI_view2d_mouse_in_scrollers(C, &ar->v2d, event->x, event->y);
-       
        /* select mode is either replace (deselect all, then add) or add/extend */
+       // XXX this is currently only available for normal select only
        if (RNA_boolean_get(op->ptr, "extend_select"))
-               selectmode= SELECT_ADD;
+               selectmode= SELECT_INVERT;
        else
                selectmode= SELECT_REPLACE;
        
-       /* check which scroller mouse is in, and figure out how to handle this */
-       if (in_scroller == 'h') {
-               /* horizontal - column select in current frame */
-               // FIXME.... todo
-       }
-       else if (in_scroller == 'v') {
-               /* vertical - row select in current channel */
-               // FIXME... 
-       }
-       else if (RNA_boolean_get(op->ptr, "left_right")) {
+       /* figure out action to take */
+       if (RNA_enum_get(op->ptr, "left_right")) {
                /* select all keys on same side of current frame as mouse */
-               selectkeys_leftright(&ac, (mval[0] < CFRA), selectmode);
+               float x;
+               
+               UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, NULL);
+               if (x < CFRA)
+                       RNA_int_set(op->ptr, "left_right", ACTKEYS_LRSEL_LEFT);
+               else    
+                       RNA_int_set(op->ptr, "left_right", ACTKEYS_LRSEL_RIGHT);
+               
+               selectkeys_leftright(&ac, RNA_enum_get(op->ptr, "left_right"), selectmode);
+       }
+       else if (RNA_boolean_get(op->ptr, "column_select")) {
+               /* select all the keyframes that occur on the same frame as where the mouse clicked */
+               float x;
+               
+               /* figure out where (the frame) the mouse clicked, and set all keyframes in that frame */
+               UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, NULL);
+               mouse_columnselect_action_keys(&ac, x);
        }
        else {
                /* select keyframe under mouse */
@@ -883,17 +1174,21 @@ static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *even
  
 void ED_ACT_OT_keyframes_clickselect (wmOperatorType *ot)
 {
+       PropertyRNA *prop;
+       
        /* identifiers */
        ot->name= "Mouse Select Keys";
        ot->idname= "ED_ACT_OT_keyframes_clickselect";
        
        /* api callbacks */
        ot->invoke= actkeys_clickselect_invoke;
-       //ot->poll= ED_operator_areaactive;
+       ot->poll= ED_operator_areaactive;
        
        /* id-props */
-       RNA_def_property(ot->srna, "left_right", PROP_BOOLEAN, PROP_NONE); // ALTKEY
-       RNA_def_property(ot->srna, "extend_select", PROP_BOOLEAN, PROP_NONE); // SHIFTKEY
+       prop= RNA_def_property(ot->srna, "left_right", PROP_ENUM, PROP_NONE); // ALTKEY
+               //RNA_def_property_enum_items(prop, prop_actkeys_clickselect_items);
+       prop= RNA_def_property(ot->srna, "extend_select", PROP_BOOLEAN, PROP_NONE); // SHIFTKEY
+       prop= RNA_def_property(ot->srna, "column_select", PROP_BOOLEAN, PROP_NONE); // CTRLKEY
 }
 
 /* ************************************************************************** */
index 7c56af533972776aa85e5bdc561fa3fb58449894..fec2e28fa0e6b9a8a4a62bb9d4e11ac29a612aff 100644 (file)
@@ -188,7 +188,7 @@ static void action_main_area_draw(const bContext *C, ARegion *ar)
        UI_view2d_grid_free(grid);
        
        /* data */
-       if ((ANIM_animdata_get_context(C, &ac)) && (ac.data)) {
+       if (ANIM_animdata_get_context(C, &ac)) {
                draw_channel_strips(&ac, saction, ar);
        }
        
@@ -243,7 +243,7 @@ static void action_channel_area_draw(const bContext *C, ARegion *ar)
        UI_view2d_view_ortho(C, v2d);
        
        /* data */
-       if ((ANIM_animdata_get_context(C, &ac)) && (ac.data)) {
+       if (ANIM_animdata_get_context(C, &ac)) {
                draw_channel_names(&ac, saction, ar);
        }
        
index 99b0ebcf03c2b1a7bd18e43bbfd6ad8ce7373983..00e446c65a9d3d87c6de8b90e9e5761cf59ee152 100644 (file)
@@ -88,8 +88,6 @@ static SpaceLink *ipo_new(const bContext *C)
        
        ar->v2d.scroll = (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM);
        
-       /* XXX view2d init for channels */
-       
        /* main area */
        ar= MEM_callocN(sizeof(ARegion), "main area for ipo");