Compare commits

...

2 Commits

Author SHA1 Message Date
eb0a3c3b0c Fix T87160: DSE Keyframe Selection Now Selects Channels
Select All/Box/Circle/Lasso/MouseClick of keyframes now add channels to selection if any keydata was added to the selection.

Changed box/region select to sync channel selection instead of only ever adding channel to selection. Seems more intuitive

make tmp comments obvious (prefixed //)

Differential Revision: https://developer.blender.org/D11317
2021-05-19 19:19:00 -04:00
8694b428c7 Fix T87160: DSE Keyframe Selection Now Selects Channels
Select All/Box/Circle/Lasso/MouseClick of keyframes now add channels to selection if any keydata was added to the selection.
2021-05-19 19:14:10 -04:00
7 changed files with 445 additions and 51 deletions

View File

@@ -745,6 +745,11 @@ static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
static short ok_bezier_channel_all_are_valid(KeyframeEditData *ked, BezTriple *bezt)
{
return KEYFRAME_OK_KEY;
}
KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
{
/* eEditKeyframes_Validate */
@@ -779,6 +784,8 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
case BEZT_OK_CHANNEL_CIRCLE:
/* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */
return ok_bezier_channel_circle;
case BEZT_OK_ALL_ARE_VALID:
return ok_bezier_channel_all_are_valid;
default: /* nothing was ok */
return NULL;
}

View File

@@ -146,17 +146,19 @@ static void gpencil_frame_select(bGPDframe *gpf, short select_mode)
}
/* set all/none/invert select (like above, but with SELECT_* modes) */
void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
bool ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
{
/* error checking */
if (gpl == NULL) {
return;
return false;
}
/* handle according to mode */
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
gpencil_frame_select(gpf, select_mode);
}
return !BLI_listbase_is_empty(&gpl->frames);
}
/* set all/none/invert select */
@@ -172,46 +174,56 @@ void ED_gpencil_layer_frame_select_set(bGPDlayer *gpl, short mode)
}
/* select the frame in this layer that occurs on this frame (there should only be one at most) */
void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
bool ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
{
bGPDframe *gpf;
if (gpl == NULL) {
return;
return false;
}
gpf = BKE_gpencil_layer_frame_find(gpl, selx);
if (gpf) {
gpencil_frame_select(gpf, select_mode);
return true;
}
return false;
}
/* select the frames in this layer that occur within the bounds specified */
void ED_gpencil_layer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode)
bool ED_gpencil_layer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode)
{
if (gpl == NULL) {
return;
return false;
}
bool any_in_region = false;
/* only select those frames which are in bounds */
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
if (IN_RANGE(gpf->framenum, min, max)) {
any_in_region = true;
gpencil_frame_select(gpf, select_mode);
}
}
return any_in_region;
}
/* select the frames in this layer that occur within the lasso/circle region specified */
void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked,
bool ED_gpencil_layer_frames_select_region(KeyframeEditData *ked,
bGPDlayer *gpl,
short tool,
short select_mode)
{
if (gpl == NULL) {
return;
return false;
}
bool any_in_region = false;
/* only select frames which are within the region */
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* construct a dummy point coordinate to do this testing with */
@@ -224,16 +236,36 @@ void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked,
if (tool == BEZT_OK_CHANNEL_LASSO) {
/* Lasso */
if (keyframe_region_lasso_test(ked->data, pt)) {
any_in_region = true;
gpencil_frame_select(gpf, select_mode);
}
}
else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
/* Circle */
if (keyframe_region_circle_test(ked->data, pt)) {
any_in_region = true;
gpencil_frame_select(gpf, select_mode);
}
}
}
return any_in_region;
}
bool ED_gpencil_select_layer_based_on_frames(bGPDlayer *layer)
{
if (layer == NULL) {
return false;
}
if (ED_gpencil_layer_frame_select_check(layer)) {
layer->flag |= GP_LAYER_SELECT;
return true;
}
else {
layer->flag &= ~GP_LAYER_SELECT;
return false;
}
}
/* ***************************************** */

View File

@@ -191,16 +191,17 @@ void ED_gpencil_layer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, boo
bool ED_gpencil_layer_frame_select_check(struct bGPDlayer *gpl);
void ED_gpencil_layer_frame_select_set(struct bGPDlayer *gpl, short mode);
void ED_gpencil_layer_frames_select_box(struct bGPDlayer *gpl,
bool ED_gpencil_layer_frames_select_box(struct bGPDlayer *gpl,
float min,
float max,
short select_mode);
void ED_gpencil_layer_frames_select_region(struct KeyframeEditData *ked,
bool ED_gpencil_layer_frames_select_region(struct KeyframeEditData *ked,
struct bGPDlayer *gpl,
short tool,
short select_mode);
void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
bool ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
bool ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
bool ED_gpencil_select_layer_based_on_frames(struct bGPDlayer *layer);
bool ED_gpencil_layer_frames_delete(struct bGPDlayer *gpl);
void ED_gpencil_layer_frames_duplicate(struct bGPDlayer *gpl);

View File

@@ -58,6 +58,7 @@ typedef enum eEditKeyframes_Validate {
/* Only for keyframes a certain Dopesheet channel */
BEZT_OK_CHANNEL_LASSO,
BEZT_OK_CHANNEL_CIRCLE,
BEZT_OK_ALL_ARE_VALID,
} eEditKeyframes_Validate;
/* ------------ */

View File

@@ -102,16 +102,17 @@ void ED_masklayer_make_cfra_list(struct MaskLayer *mask_layer, ListBase *elems,
bool ED_masklayer_frame_select_check(struct MaskLayer *mask_layer);
void ED_masklayer_frame_select_set(struct MaskLayer *mask_layer, short mode);
void ED_masklayer_frames_select_box(struct MaskLayer *mask_layer,
bool ED_masklayer_frames_select_box(struct MaskLayer *mask_layer,
float min,
float max,
short select_mode);
void ED_masklayer_frames_select_region(struct KeyframeEditData *ked,
bool ED_masklayer_frames_select_region(struct KeyframeEditData *ked,
struct MaskLayer *mask_layer,
short tool,
short select_mode);
void ED_mask_select_frames(struct MaskLayer *mask_layer, short select_mode);
void ED_mask_select_frame(struct MaskLayer *mask_layer, int selx, short select_mode);
bool ED_mask_select_frames(struct MaskLayer *mask_layer, short select_mode);
bool ED_mask_select_frame(struct MaskLayer *mask_layer, int selx, short select_mode);
bool ED_mask_select_layer_based_on_frames(struct MaskLayer *mask_layer);
bool ED_masklayer_frames_delete(struct MaskLayer *mask_layer);
void ED_masklayer_frames_duplicate(struct MaskLayer *mask_layer);

View File

@@ -151,13 +151,13 @@ static void mask_layer_shape_select(MaskLayerShape *mask_layer_shape, short sele
}
/* set all/none/invert select (like above, but with SELECT_* modes) */
void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
bool ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
{
MaskLayerShape *mask_layer_shape;
/* error checking */
if (mask_layer == NULL) {
return;
return false;
}
/* handle according to mode */
@@ -165,6 +165,7 @@ void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
mask_layer_shape = mask_layer_shape->next) {
mask_layer_shape_select(mask_layer_shape, select_mode);
}
return !BLI_listbase_is_empty(&mask_layer->splines_shapes);
}
/* set all/none/invert select */
@@ -180,41 +181,65 @@ void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
}
/* select the frame in this layer that occurs on this frame (there should only be one at most) */
void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
bool ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
{
MaskLayerShape *mask_layer_shape;
if (mask_layer == NULL) {
return;
return false;
}
mask_layer_shape = BKE_mask_layer_shape_find_frame(mask_layer, selx);
if (mask_layer_shape) {
mask_layer_shape_select(mask_layer_shape, select_mode);
return true;
}
return false;
}
bool ED_mask_select_layer_based_on_frames(struct MaskLayer *mask_layer)
{
if (mask_layer == NULL) {
return false;
}
if (ED_masklayer_frame_select_check(mask_layer)) {
mask_layer->flag |= MASK_LAYERFLAG_SELECT;
return true;
}
else {
mask_layer->flag &= ~MASK_LAYERFLAG_SELECT;
return false;
}
}
/* select the frames in this layer that occur within the bounds specified */
void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max, short select_mode)
bool ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max, short select_mode)
{
MaskLayerShape *mask_layer_shape;
if (mask_layer == NULL) {
return;
return false;
}
bool any_in_region = false;
/* only select those frames which are in bounds */
for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
mask_layer_shape = mask_layer_shape->next) {
if (IN_RANGE(mask_layer_shape->frame, min, max)) {
any_in_region = true;
mask_layer_shape_select(mask_layer_shape, select_mode);
}
}
return any_in_region;
}
/* select the frames in this layer that occur within the lasso/circle region specified */
void ED_masklayer_frames_select_region(KeyframeEditData *ked,
bool ED_masklayer_frames_select_region(KeyframeEditData *ked,
MaskLayer *mask_layer,
short tool,
short select_mode)
@@ -222,9 +247,11 @@ void ED_masklayer_frames_select_region(KeyframeEditData *ked,
MaskLayerShape *mask_layer_shape;
if (mask_layer == NULL) {
return;
return false;
}
bool any_in_region = false;
/* only select frames which are within the region */
for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
mask_layer_shape = mask_layer_shape->next) {
@@ -238,16 +265,20 @@ void ED_masklayer_frames_select_region(KeyframeEditData *ked,
if (tool == BEZT_OK_CHANNEL_LASSO) {
/* Lasso */
if (keyframe_region_lasso_test(ked->data, pt)) {
any_in_region = true;
mask_layer_shape_select(mask_layer_shape, select_mode);
}
}
else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
/* Circle */
if (keyframe_region_circle_test(ked->data, pt)) {
any_in_region = true;
mask_layer_shape_select(mask_layer_shape, select_mode);
}
}
}
return any_in_region;
}
/* ***************************************** */

View File

@@ -66,6 +66,156 @@
/* ************************************************************************** */
/* KEYFRAMES STUFF */
static void actkeys_select_channel_based_on_keys(FCurve *fcu, short select_mode)
{
bool any_selected = false;
BezTriple *cur_bezt = fcu->bezt;
int i = 0;
for (; i < fcu->totvert; cur_bezt++, i++) {
if (BEZT_ISSEL_ANY(cur_bezt)) {
any_selected = true;
break;
}
}
if (any_selected) {
fcu->flag |= FCURVE_SELECTED;
}
else {
fcu->flag &= ~FCURVE_SELECTED;
}
}
static void actkeys_channel_set_active(bAnimListElem *ale)
{
switch (ale->datatype) {
case ALE_FCURVE:
((FCurve *)ale->key_data)->flag |= FCURVE_ACTIVE;
break;
case ALE_GPFRAME:
((bGPDlayer *)ale->data)->flag |= GP_LAYER_ACTIVE;
break;
case ALE_MASKLAY:
/* Mask layers don't have an active flag. Do nothing. */
break;
}
}
static void actkeys_channel_unset_active(bAnimListElem *ale)
{
switch (ale->datatype) {
case ALE_FCURVE:
((FCurve *)ale->key_data)->flag &= ~FCURVE_ACTIVE;
break;
case ALE_GPFRAME:
((bGPDlayer *)ale->data)->flag &= ~GP_LAYER_ACTIVE;
ale->update |= ANIM_UPDATE_DEPS;
break;
case ALE_MASKLAY:
/* Mask layers don't have an active flag. Do nothing. */
break;
}
}
static void actkeys_channel_select(bAnimListElem *ale, const eEditKeyframes_Select select_mode)
{
// GG:TODO: Is this function necessary when (anim_channels_edit.c) anim_channels_select_set()
// exists?
switch (select_mode) {
case SELECT_SUBTRACT: {
switch (ale->datatype) {
case ALE_FCURVE:
((FCurve *)ale->key_data)->flag &= ~FCURVE_SELECTED;
break;
case ALE_GPFRAME:
((bGPDlayer *)ale->data)->flag &= ~GP_LAYER_SELECT;
ale->update |= ANIM_UPDATE_DEPS;
break;
case ALE_MASKLAY:
((MaskLayer *)ale->data)->flag &= ~MASK_LAYERFLAG_SELECT;
break;
}
break;
}
case SELECT_ADD: {
switch (ale->datatype) {
case ALE_FCURVE:
((FCurve *)ale->key_data)->flag |= FCURVE_SELECTED;
break;
case ALE_GPFRAME:
((bGPDlayer *)ale->data)->flag |= GP_LAYER_SELECT;
ale->update |= ANIM_UPDATE_DEPS;
break;
case ALE_MASKLAY:
((MaskLayer *)ale->data)->flag |= MASK_LAYERFLAG_SELECT;
break;
}
break;
}
case SELECT_INVERT: {
switch (ale->datatype) {
case ALE_FCURVE:
((FCurve *)ale->key_data)->flag ^= FCURVE_SELECTED;
break;
case ALE_GPFRAME:
((bGPDlayer *)ale->data)->flag ^= GP_LAYER_SELECT;
ale->update |= ANIM_UPDATE_DEPS;
break;
case ALE_MASKLAY:
((MaskLayer *)ale->data)->flag ^= MASK_LAYERFLAG_SELECT;
break;
}
break;
}
case SELECT_REPLACE: {
/* Caller must handle this manually, as SELECT_REPLACE depends more on the situation. */
break;
}
}
}
static void actkeys_channel_set_active_selected_and_update(bAnimContext *ac, bAnimListElem *ale)
{
if (ale == NULL) {
return;
}
actkeys_channel_set_active(ale);
actkeys_channel_select(ale, SELECT_ADD);
ListBase anim_data = {NULL, NULL};
BLI_addtail(&anim_data, ale);
/* GreasePencil Layer might need updated. */
ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
static void actkeys_keyframes_loop_and_select_channel(const short select_mode,
KeyframeEditData *ked,
bDopeSheet *ads,
bAnimListElem *ale,
KeyframeEditFunc key_ok,
KeyframeEditFunc key_cb,
FcuEditFunc fcu_cb)
{
/* Firstly, check if any keyframes will be hit by this. */
if (!ANIM_animchannel_keyframes_loop(ked, ads, ale, NULL, key_ok, fcu_cb)) {
return;
}
ANIM_animchannel_keyframes_loop(ked, ads, ale, key_ok, key_cb, fcu_cb);
switch (ale->datatype) {
case ALE_FCURVE: /* F-Curve */
{
FCurve *fcu = (FCurve *)ale->key_data;
actkeys_select_channel_based_on_keys(fcu, select_mode);
break;
}
}
}
static bAnimListElem *actkeys_find_list_element_at_position(bAnimContext *ac,
int filter,
float region_x,
@@ -229,6 +379,39 @@ static bool actkeys_is_key_at_position(bAnimContext *ac, float region_x, float r
return found;
}
// GG:TODO: exact C+P from graph_utils.c which is from graph_intern.h.....
/**
* Find 'active' F-Curve.
* It must be editable, since that's the purpose of these buttons (subject to change).
* We return the 'wrapper' since it contains valuable context info (about hierarchy),
* which will need to be freed when the caller is done with it.
*
* \note curve-visible flag isn't included,
* otherwise selecting a curve via list to edit is too cumbersome.
*/
static bAnimListElem *get_active_channel(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ACTIVE);
size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* We take the first channel only, since some other ones may have had 'active' flag set
* if they were from linked data.
*/
if (items) {
bAnimListElem *ale = (bAnimListElem *)anim_data.first;
/* remove first item from list, then free the rest of the list and return the stored one */
BLI_remlink(&anim_data, ale);
ANIM_animdata_freelist(&anim_data);
return ale;
}
/* no active channel */
return NULL;
}
/* ******************** Deselect All Operator ***************************** */
/* This operator works in one of three ways:
* 1) (de)select all (AKEY) - test if select all or deselect all
@@ -242,7 +425,7 @@ static bool actkeys_is_key_at_position(bAnimContext *ac, float region_x, float r
* - test: check if select or deselect all
* - sel: how to select keyframes (SELECT_*)
*/
static void deselect_action_keys(bAnimContext *ac, short test, short sel)
static void deselect_action_keys(bAnimContext *ac, short test, short sel, const bool do_channels)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -305,6 +488,16 @@ static void deselect_action_keys(bAnimContext *ac, short test, short sel)
else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, sel_cb, NULL);
}
/* affect channel selection status? */
if (do_channels) {
/* deactivate the F-Curve, and deselect if deselecting keyframes.
* otherwise select the F-Curve too since we've selected all the keyframes
*/
actkeys_channel_select(ale, sel);
/* always deactivate all F-Curves if we perform batch ops for selection */
actkeys_channel_unset_active(ale);
}
}
/* Cleanup */
@@ -323,26 +516,35 @@ static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* find active F-Curve, and preserve this for later
* or else it becomes annoying with the current active
* curve keeps fading out even while you're editing it
*/
bAnimListElem *ale_active = get_active_channel(&ac);
/* 'standard' behavior - check if selected, then apply relevant selection */
const int action = RNA_enum_get(op->ptr, "action");
switch (action) {
case SEL_TOGGLE:
deselect_action_keys(&ac, 1, SELECT_ADD);
deselect_action_keys(&ac, 1, SELECT_ADD, true);
break;
case SEL_SELECT:
deselect_action_keys(&ac, 0, SELECT_ADD);
deselect_action_keys(&ac, 0, SELECT_ADD, true);
break;
case SEL_DESELECT:
deselect_action_keys(&ac, 0, SELECT_SUBTRACT);
deselect_action_keys(&ac, 0, SELECT_SUBTRACT, true);
break;
case SEL_INVERT:
deselect_action_keys(&ac, 0, SELECT_INVERT);
deselect_action_keys(&ac, 0, SELECT_INVERT, true);
break;
default:
BLI_assert(0);
break;
}
/* Restore active channel selection. */
actkeys_channel_set_active_selected_and_update(&ac, ale_active);
ale_active = NULL;
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
if (ac.datatype == ANIMCONT_GPENCIL) {
@@ -388,7 +590,8 @@ enum {
typedef struct BoxSelectData {
bAnimContext *ac;
short selectmode;
short box_selectmode;
short key_selectmode;
KeyframeEditData ked;
KeyframeEditFunc ok_cb, select_cb;
@@ -405,14 +608,27 @@ static void box_select_elem(
bGPdata *gpd = ale->data;
bGPDlayer *gpl;
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
ED_gpencil_layer_frames_select_box(gpl, xmin, xmax, data->selectmode);
ED_gpencil_layer_frames_select_box(gpl, xmin, xmax, data->key_selectmode);
}
ale->update |= ANIM_UPDATE_DEPS;
break;
}
#endif
case ANIMTYPE_GPLAYER: {
ED_gpencil_layer_frames_select_box(ale->data, xmin, xmax, sel_data->selectmode);
if (ELEM(
sel_data->box_selectmode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
ED_gpencil_layer_frames_select_box(ale->data, xmin, xmax, sel_data->key_selectmode);
}
else if (ELEM(sel_data->box_selectmode, ACTKEYS_BORDERSEL_CHANNELS)) {
ED_gpencil_select_frames(ale->data, sel_data->key_selectmode);
}
else {
BLI_assert(!"Unknown Box select mode not implemented");
}
if (!summary) {
ED_gpencil_select_layer_based_on_frames(ale->data);
}
ale->update |= ANIM_UPDATE_DEPS;
break;
}
@@ -420,12 +636,38 @@ static void box_select_elem(
Mask *mask = ale->data;
MaskLayer *masklay;
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
ED_masklayer_frames_select_box(masklay, xmin, xmax, sel_data->selectmode);
if (ELEM(sel_data->box_selectmode,
ACTKEYS_BORDERSEL_FRAMERANGE,
ACTKEYS_BORDERSEL_ALLKEYS)) {
ED_masklayer_frames_select_box(masklay, xmin, xmax, sel_data->key_selectmode);
}
else if (ELEM(sel_data->box_selectmode, ACTKEYS_BORDERSEL_CHANNELS)) {
ED_mask_select_frames(masklay, sel_data->key_selectmode);
}
else {
BLI_assert(!"Unknown Box select mode not implemented");
}
if (!summary) {
ED_mask_select_layer_based_on_frames(masklay);
}
}
break;
}
case ANIMTYPE_MASKLAYER: {
ED_masklayer_frames_select_box(ale->data, xmin, xmax, sel_data->selectmode);
if (ELEM(
sel_data->box_selectmode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
ED_masklayer_frames_select_box(ale->data, xmin, xmax, sel_data->key_selectmode);
}
else if (ELEM(sel_data->box_selectmode, ACTKEYS_BORDERSEL_CHANNELS)) {
ED_mask_select_frames(ale->data, sel_data->key_selectmode);
}
else {
BLI_assert(!"Unknown Box select mode not implemented");
}
if (!summary) {
ED_mask_select_layer_based_on_frames(ale->data);
}
break;
}
default: {
@@ -445,19 +687,28 @@ static void box_select_elem(
ANIM_animdata_freelist(&anim_data);
}
ANIM_animchannel_keyframes_loop(
&sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, NULL);
actkeys_keyframes_loop_and_select_channel(sel_data->key_selectmode,
&sel_data->ked,
ac->ads,
ale,
sel_data->ok_cb,
sel_data->select_cb,
NULL);
}
}
}
static void box_select_action(bAnimContext *ac, const rcti rect, short mode, short selectmode)
static void box_select_action(bAnimContext *ac,
const rcti rect,
short box_selectmode,
short key_selectmode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
BoxSelectData sel_data = {.ac = ac, .selectmode = selectmode};
BoxSelectData sel_data = {
.ac = ac, .key_selectmode = key_selectmode, .box_selectmode = box_selectmode};
View2D *v2d = &ac->region->v2d;
rctf rectf;
@@ -471,13 +722,14 @@ static void box_select_action(bAnimContext *ac, const rcti rect, short mode, sho
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* get beztriple editing/validation funcs */
sel_data.select_cb = ANIM_editkeyframes_select(selectmode);
sel_data.select_cb = ANIM_editkeyframes_select(key_selectmode);
if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
if (ELEM(box_selectmode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
sel_data.ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
}
else {
sel_data.ok_cb = NULL;
/* ACTKEYS_BORDERSEL_CHANNELS */
sel_data.ok_cb = ANIM_editkeyframes_ok(BEZT_OK_ALL_ARE_VALID);
}
/* init editing data */
@@ -493,7 +745,7 @@ static void box_select_action(bAnimContext *ac, const rcti rect, short mode, sho
float ymin = ymax - ACHANNEL_STEP(ac);
/* set horizontal range (if applicable) */
if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
if (ELEM(box_selectmode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
/* if channel is mapped in NLA, apply correction */
if (adt) {
sel_data.ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP);
@@ -508,7 +760,8 @@ static void box_select_action(bAnimContext *ac, const rcti rect, short mode, sho
}
/* perform vertical suitability check (if applicable) */
if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || !((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
if ((box_selectmode == ACTKEYS_BORDERSEL_FRAMERANGE) ||
!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
box_select_elem(&sel_data, ale, rectf.xmin, rectf.xmax, false);
}
}
@@ -546,10 +799,11 @@ static int actkeys_box_select_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
bAnimListElem *ale_active = get_active_channel(&ac);
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const int selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
deselect_action_keys(&ac, 1, SELECT_SUBTRACT);
deselect_action_keys(&ac, 1, SELECT_SUBTRACT, true);
}
/* get settings from operator */
@@ -578,6 +832,10 @@ static int actkeys_box_select_exec(bContext *C, wmOperator *op)
/* apply box_select action */
box_select_action(&ac, rect, mode, selectmode);
/* Restore active channel selection. */
actkeys_channel_set_active_selected_and_update(&ac, ale_active);
ale_active = NULL;
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
if (ac.datatype == ANIMCONT_GPENCIL) {
@@ -641,7 +899,7 @@ static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, b
bGPdata *gpd = ale->data;
bGPDlayer *gpl;
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
ED_gpencil_layer_frames_select_region(&rdata->ked, ale->data, rdata->mode, rdata->selectmode);
ED_gpencil_layer_frames_select_region(&rdata->ked, ale->data, rdata->mode, rdata->key_selectmode);
}
break;
}
@@ -649,6 +907,11 @@ static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, b
case ANIMTYPE_GPLAYER: {
ED_gpencil_layer_frames_select_region(
&sel_data->ked, ale->data, sel_data->mode, sel_data->selectmode);
if (!summary) {
ED_gpencil_select_layer_based_on_frames(ale->data);
}
ale->update |= ANIM_UPDATE_DEPS;
break;
}
@@ -658,12 +921,18 @@ static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, b
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
ED_masklayer_frames_select_region(
&sel_data->ked, masklay, sel_data->mode, sel_data->selectmode);
if (!summary) {
ED_mask_select_layer_based_on_frames(masklay);
}
}
break;
}
case ANIMTYPE_MASKLAYER: {
ED_masklayer_frames_select_region(
&sel_data->ked, ale->data, sel_data->mode, sel_data->selectmode);
if (!summary) {
ED_mask_select_layer_based_on_frames(ale->data);
}
break;
}
default: {
@@ -683,8 +952,13 @@ static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, b
ANIM_animdata_freelist(&anim_data);
}
ANIM_animchannel_keyframes_loop(
&sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, NULL);
actkeys_keyframes_loop_and_select_channel(sel_data->selectmode,
&sel_data->ked,
ac->ads,
ale,
sel_data->ok_cb,
sel_data->select_cb,
NULL);
}
}
}
@@ -798,10 +1072,12 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
bAnimListElem *ale_active = get_active_channel(&ac);
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const int selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
deselect_action_keys(&ac, 1, SELECT_SUBTRACT);
deselect_action_keys(&ac, 1, SELECT_SUBTRACT, true);
}
/* get settings from operator */
@@ -813,6 +1089,10 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
MEM_freeN((void *)data_lasso.mcoords);
/* Restore active channel selection. */
actkeys_channel_set_active_selected_and_update(&ac, ale_active);
ale_active = NULL;
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
if (ac.datatype == ANIMCONT_GPENCIL) {
@@ -865,7 +1145,7 @@ static int action_circle_select_exec(bContext *C, wmOperator *op)
WM_gesture_is_modal_first(op->customdata));
const short selectmode = (sel_op != SEL_OP_SUB) ? SELECT_ADD : SELECT_SUBTRACT;
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
deselect_action_keys(&ac, 0, SELECT_SUBTRACT);
deselect_action_keys(&ac, 0, SELECT_SUBTRACT, true);
}
data.mval[0] = x;
@@ -1349,7 +1629,7 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se
/* - deselect all other keyframes, so that just the newly selected remain
* - channels aren't deselected, since we don't re-select any as a consequence
*/
deselect_action_keys(ac, 0, SELECT_SUBTRACT);
deselect_action_keys(ac, 0, SELECT_SUBTRACT, false);
}
/* set callbacks and editing data */
@@ -1545,10 +1825,12 @@ static void actkeys_mselect_single(bAnimContext *ac,
/* select the nominated keyframe on the given frame */
if (ale->type == ANIMTYPE_GPLAYER) {
ED_gpencil_select_frame(ale->data, selx, select_mode);
ED_gpencil_select_layer_based_on_frames(ale->data);
ale->update |= ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
ED_mask_select_frame(ale->data, selx, select_mode);
ED_mask_select_layer_based_on_frames(ale->data);
}
else {
if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK) && (ale->type == ANIMTYPE_SUMMARY) &&
@@ -1574,7 +1856,46 @@ static void actkeys_mselect_single(bAnimContext *ac,
ANIM_animdata_freelist(&anim_data);
}
else {
// Question: Wayde Moss : Which block to use?
#if 1
// This block is inconsistent with how the graph editor does channel selection but feels
// better.
ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
switch (ale->datatype) {
case ALE_FCURVE: /* F-Curve */
{
FCurve *fcu = (FCurve *)ale->key_data;
actkeys_select_channel_based_on_keys(fcu, select_mode);
break;
}
}
#else
// This block is consistent with how the graph editor does channel selection but feels wrong.
if (!ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, NULL, ok_cb, NULL)) {
return;
}
const int selected_index = ked.curIndex;
ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
switch (ale->datatype) {
case ALE_FCURVE: /* F-Curve */
{
FCurve *fcu = (FCurve *)ale->key_data;
BezTriple *selected_bezt = fcu->bezt + selected_index;
if (BEZT_ISSEL_ANY(selected_bezt)) {
fcu->flag |= FCURVE_SELECTED;
}
else {
fcu->flag &= ~FCURVE_SELECTED;
}
}
}
#endif
}
}
}
@@ -1725,7 +2046,7 @@ static int mouse_action_keys(bAnimContext *ac,
}
else {
/* deselect all keyframes */
deselect_action_keys(ac, 0, SELECT_SUBTRACT);
deselect_action_keys(ac, 0, SELECT_SUBTRACT, true);
/* highlight channel clicked on */
if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) {