diff options
-rw-r--r-- | source/blender/editors/animation/anim_filter.c | 14 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframes_edit.c | 191 | ||||
-rw-r--r-- | source/blender/editors/include/ED_anim_api.h | 15 | ||||
-rw-r--r-- | source/blender/editors/include/ED_keyframes_edit.h | 41 | ||||
-rw-r--r-- | source/blender/editors/space_action/action_draw.c | 39 | ||||
-rw-r--r-- | source/blender/editors/space_action/action_intern.h | 21 | ||||
-rw-r--r-- | source/blender/editors/space_action/action_ops.c | 13 | ||||
-rw-r--r-- | source/blender/editors/space_action/action_select.c | 771 | ||||
-rw-r--r-- | source/blender/editors/space_action/space_action.c | 4 | ||||
-rw-r--r-- | source/blender/editors/space_ipo/space_ipo.c | 2 |
10 files changed, 764 insertions, 347 deletions
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index d21340782e6..6283f2dd0c6 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -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; } /* ************************************************************ */ diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 278e216535b..a3a04901533 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -28,6 +28,7 @@ #include <stdlib.h> #include <string.h> #include <math.h> +#include <float.h> #include "BLI_blenlib.h" #include "BLI_arithb.h" @@ -60,6 +61,10 @@ * 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 */ @@ -74,18 +79,34 @@ /* 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); } } } diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index d8407477970..adc2f3a8c4c 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -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); diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index 1015de2e9e4..56a4cb6089c 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -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); diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 7a99b151148..0b63cad4712 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -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); diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index 788e5df2d13..51c6c3c7a1d 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -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); diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index 6d6bee90171..ceaa8117de7 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -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); } /* --------------- */ diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 100024fc0d1..cd454388a57 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -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 } /* ************************************************************************** */ diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 7c56af53397..fec2e28fa0e 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -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); } diff --git a/source/blender/editors/space_ipo/space_ipo.c b/source/blender/editors/space_ipo/space_ipo.c index 99b0ebcf03c..00e446c65a9 100644 --- a/source/blender/editors/space_ipo/space_ipo.c +++ b/source/blender/editors/space_ipo/space_ipo.c @@ -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"); |