From b02bfb716f06e89f07dde97569d613042cff3fa1 Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Fri, 10 Feb 2023 17:29:54 +0530 Subject: [PATCH 01/18] Allow select range in animation editor Patch will allow range selection similar to outliner. New function ANIM_animchannel_select_range created for range selection. Similar to outliner, active fcurve remains unchanged when this operation is called. New keymap is created to separate extend and extend range functionality. Old Differential revision: https://archive.blender.org/developer/D17079 --- .../keyconfig/keymap_data/blender_default.py | 4 +- .../editors/animation/anim_channels_edit.c | 64 ++++++++++++++++++- .../editors/include/ED_keyframes_edit.h | 1 + 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 63a68507a5d..910a810e358 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -3462,7 +3462,9 @@ def km_animation_channels(params): items.extend([ # Click select. ("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), - ("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + ("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True}, + {"properties": [("extend_range", True)]}), + ("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True}, {"properties": [("extend", True)]}), ("anim.channels_click", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, {"properties": [("children_only", True)]}), diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index e1dc46a8a72..ca93627f268 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3189,6 +3189,55 @@ static int click_select_channel_group(bAnimContext *ac, return (ND_ANIMCHAN | NA_SELECTED); } +static void animchannel_clear_selection(bAnimContext *ac) +{ + ListBase anim_data = anim_channels_for_selection(ac); + + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + if (ale->type != ANIMTYPE_FCURVE) { + continue; + } + + FCurve *fcu = (FCurve *)ale->data; + fcu->flag &= ~FCURVE_SELECTED; + } + + ANIM_animdata_freelist(&anim_data); +} + +static void animchannel_select_range(bAnimContext *ac, FCurve *cursor) +{ + ListBase anim_data = anim_channels_for_selection(ac); + bool selected = false; + + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + + if (ale->type != ANIMTYPE_FCURVE) { + continue; + } + + FCurve *fcu = (FCurve *)ale->data; + + if (cursor->flag & FCURVE_ACTIVE) { + cursor->flag |= FCURVE_SELECTED; + return; + } + + /* Select first and last element from the range. Reverse selection status on extremes. */ + if ((fcu->flag & FCURVE_ACTIVE) || fcu == cursor) { + fcu->flag |= FCURVE_SELECTED; + selected = !selected; + } + + /* Select elements between the range. */ + if (selected) { + fcu->flag |= FCURVE_SELECTED; + } + } + + ANIM_animdata_freelist(&anim_data); +} + static int click_select_channel_fcurve(bAnimContext *ac, bAnimListElem *ale, const short /* eEditKeyframes_Select or -1 */ selectmode, @@ -3201,14 +3250,19 @@ static int click_select_channel_fcurve(bAnimContext *ac, /* inverse selection status of this F-Curve only */ fcu->flag ^= FCURVE_SELECTED; } + else if (selectmode == SELECT_EXTEND_RANGE) { + animchannel_clear_selection(ac); + animchannel_select_range(ac, fcu); + } else { /* select F-Curve by itself */ ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR); fcu->flag |= FCURVE_SELECTED; } - /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */ - if (fcu->flag & FCURVE_SELECTED) { + /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list. + * Similar to outliner, do not change active element when selecting elements in range. */ + if ((fcu->flag & FCURVE_SELECTED) && (selectmode != SELECT_EXTEND_RANGE)) { ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type); } @@ -3473,6 +3527,9 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmE if (RNA_boolean_get(op->ptr, "extend")) { selectmode = SELECT_INVERT; } + else if (RNA_boolean_get(op->ptr, "extend_range")) { + selectmode = SELECT_EXTEND_RANGE; + } else if (RNA_boolean_get(op->ptr, "children_only")) { /* this is a bit of a special case for ActionGroups only... * should it be removed or extended to all instead? */ @@ -3526,6 +3583,9 @@ static void ANIM_OT_channels_click(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "extend_range", false, "Extend Range", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* Key-map: Enable with `Ctrl-Shift`. */ prop = RNA_def_boolean(ot->srna, "children_only", false, "Select Children Only", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index f027a46b470..7632b84d595 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -58,6 +58,7 @@ typedef enum eEditKeyframes_Select { SELECT_SUBTRACT = (1 << 2), /* flip ok status of keyframes based on key status */ SELECT_INVERT = (1 << 3), + SELECT_EXTEND_RANGE = (1 << 4), } eEditKeyframes_Select; /* "selection map" building modes */ -- 2.30.2 From 8a24c92c083cfb097f582fa6a8dff4b412c95be6 Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Sat, 11 Feb 2023 11:52:42 +0530 Subject: [PATCH 02/18] Use break instead of return --- source/blender/editors/animation/anim_channels_edit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index ca93627f268..995ad861ec8 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3220,7 +3220,7 @@ static void animchannel_select_range(bAnimContext *ac, FCurve *cursor) if (cursor->flag & FCURVE_ACTIVE) { cursor->flag |= FCURVE_SELECTED; - return; + break; } /* Select first and last element from the range. Reverse selection status on extremes. */ -- 2.30.2 From e6c71764e4b931fabdb55cafeb4daf56653f01df Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Sun, 5 Mar 2023 16:30:45 +0530 Subject: [PATCH 03/18] Range selection of gpencil layer --- .../editors/animation/anim_channels_edit.c | 83 +++++++++++++------ 1 file changed, 59 insertions(+), 24 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 5df5d7370f3..4b0c01e2e9d 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3195,44 +3195,75 @@ static void animchannel_clear_selection(bAnimContext *ac) ListBase anim_data = anim_channels_for_selection(ac); LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { - if (ale->type != ANIMTYPE_FCURVE) { - continue; + switch (ale->type) { + case ANIMTYPE_FCURVE: { + FCurve *fcu = (FCurve *)ale->data; + fcu->flag &= ~FCURVE_SELECTED; + } + break; + case ANIMTYPE_GPLAYER: { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + gpl->flag &= ~GP_LAYER_SELECT; + } + break; + default: + break; } - - FCurve *fcu = (FCurve *)ale->data; - fcu->flag &= ~FCURVE_SELECTED; } ANIM_animdata_freelist(&anim_data); } -static void animchannel_select_range(bAnimContext *ac, FCurve *cursor) +/* Select channels that lies between active channel and last clicked channel. */ +static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_elem) { ListBase anim_data = anim_channels_for_selection(ac); bool selected = false; LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + switch (ale->type) { - if (ale->type != ANIMTYPE_FCURVE) { - continue; - } + case ANIMTYPE_FCURVE: + case ANIMTYPE_NLACURVE: { + FCurve *fcu = (FCurve *)ale->data; + FCurve *cursor = (FCurve *)cursor_elem->data; - FCurve *fcu = (FCurve *)ale->data; + if (cursor->flag & FCURVE_ACTIVE) { + cursor->flag |= FCURVE_SELECTED; + break; + } - if (cursor->flag & FCURVE_ACTIVE) { - cursor->flag |= FCURVE_SELECTED; - break; - } + /* Select first and last element from the range. Reverse selection status on extremes. */ + if ((fcu->flag & FCURVE_ACTIVE) || fcu == cursor) { + fcu->flag |= FCURVE_SELECTED; + selected = !selected; + } - /* Select first and last element from the range. Reverse selection status on extremes. */ - if ((fcu->flag & FCURVE_ACTIVE) || fcu == cursor) { - fcu->flag |= FCURVE_SELECTED; - selected = !selected; - } + /* Select elements between the range. */ + if (selected) { + fcu->flag |= FCURVE_SELECTED; + } + } break; + case ANIMTYPE_GPLAYER: { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + bGPDlayer *cursor = (bGPDlayer *)cursor_elem->data; - /* Select elements between the range. */ - if (selected) { - fcu->flag |= FCURVE_SELECTED; + if (cursor->flag & GP_LAYER_ACTIVE) { + cursor->flag |= GP_LAYER_SELECT; + break; + } + + if ((gpl->flag & GP_LAYER_ACTIVE) || gpl == cursor) { + gpl->flag |= GP_LAYER_SELECT; + selected = !selected; + } + + if (selected) { + gpl->flag |= GP_LAYER_SELECT; + } + } break; + default: + break; } } @@ -3253,7 +3284,7 @@ static int click_select_channel_fcurve(bAnimContext *ac, } else if (selectmode == SELECT_EXTEND_RANGE) { animchannel_clear_selection(ac); - animchannel_select_range(ac, fcu); + animchannel_select_range(ac, ale); } else { /* select F-Curve by itself */ @@ -3331,6 +3362,10 @@ static int click_select_channel_gplayer(bContext *C, /* invert selection status of this layer only */ gpl->flag ^= GP_LAYER_SELECT; } + else if (selectmode == SELECT_EXTEND_RANGE) { + animchannel_clear_selection(ac); + animchannel_select_range(ac, ale); + } else { /* select layer by itself */ ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR); @@ -3338,7 +3373,7 @@ static int click_select_channel_gplayer(bContext *C, } /* change active layer, if this is selected (since we must always have an active layer) */ - if (gpl->flag & GP_LAYER_SELECT) { + if ((gpl->flag & GP_LAYER_SELECT) && (selectmode != SELECT_EXTEND_RANGE)) { ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER); /* update other layer status */ BKE_gpencil_layer_active_set(gpd, gpl); -- 2.30.2 From 0cdeaed78116cfdf4fcb65175f1af2eeb27ceccc Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Sun, 5 Mar 2023 17:18:46 +0530 Subject: [PATCH 04/18] Changes suggested by reviewer - Ran clang format - Add code comments - Rename `selected` to `in_selection_range` - Move condition of "active flag check" outside of for loop (now added in `click_select_channel` functions of individual channels) - Tooltip for `extend_range` property --- .../editors/animation/anim_channels_edit.c | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 4b0c01e2e9d..8a267c00937 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3199,13 +3199,11 @@ static void animchannel_clear_selection(bAnimContext *ac) case ANIMTYPE_FCURVE: { FCurve *fcu = (FCurve *)ale->data; fcu->flag &= ~FCURVE_SELECTED; - } - break; + } break; case ANIMTYPE_GPLAYER: { bGPDlayer *gpl = (bGPDlayer *)ale->data; gpl->flag &= ~GP_LAYER_SELECT; - } - break; + } break; default: break; } @@ -3218,7 +3216,7 @@ static void animchannel_clear_selection(bAnimContext *ac) static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_elem) { ListBase anim_data = anim_channels_for_selection(ac); - bool selected = false; + bool in_selection_range = false; LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { switch (ale->type) { @@ -3228,19 +3226,14 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele FCurve *fcu = (FCurve *)ale->data; FCurve *cursor = (FCurve *)cursor_elem->data; - if (cursor->flag & FCURVE_ACTIVE) { - cursor->flag |= FCURVE_SELECTED; - break; - } - /* Select first and last element from the range. Reverse selection status on extremes. */ if ((fcu->flag & FCURVE_ACTIVE) || fcu == cursor) { fcu->flag |= FCURVE_SELECTED; - selected = !selected; + in_selection_range = !in_selection_range; } /* Select elements between the range. */ - if (selected) { + if (in_selection_range) { fcu->flag |= FCURVE_SELECTED; } } break; @@ -3248,17 +3241,12 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele bGPDlayer *gpl = (bGPDlayer *)ale->data; bGPDlayer *cursor = (bGPDlayer *)cursor_elem->data; - if (cursor->flag & GP_LAYER_ACTIVE) { - cursor->flag |= GP_LAYER_SELECT; - break; - } - if ((gpl->flag & GP_LAYER_ACTIVE) || gpl == cursor) { gpl->flag |= GP_LAYER_SELECT; - selected = !selected; + in_selection_range = !in_selection_range; } - if (selected) { + if (in_selection_range) { gpl->flag |= GP_LAYER_SELECT; } } break; @@ -3284,7 +3272,14 @@ static int click_select_channel_fcurve(bAnimContext *ac, } else if (selectmode == SELECT_EXTEND_RANGE) { animchannel_clear_selection(ac); - animchannel_select_range(ac, ale); + /* When active channel is being clicked again for range selection, only select the + * clicked/active channel. Otherwise call range selection function. */ + if ((fcu->flag & FCURVE_ACTIVE) == 0) { + animchannel_select_range(ac, ale); + } + else { + fcu->flag |= FCURVE_SELECTED; + } } else { /* select F-Curve by itself */ @@ -3364,7 +3359,14 @@ static int click_select_channel_gplayer(bContext *C, } else if (selectmode == SELECT_EXTEND_RANGE) { animchannel_clear_selection(ac); - animchannel_select_range(ac, ale); + /* When active channel is being clicked again for range selection, only select the + * clicked/active channel. Otherwise call range selection function. */ + if ((gpl->flag & FCURVE_ACTIVE) == 0) { + animchannel_select_range(ac, ale); + } + else { + gpl->flag |= GP_LAYER_SELECT; + } } else { /* select layer by itself */ @@ -3619,7 +3621,11 @@ static void ANIM_OT_channels_click(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "extend_range", false, "Extend Range", ""); + prop = RNA_def_boolean(ot->srna, + "extend_range", + false, + "Extend Range", + "Selection of active channel to clicked channel"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); /* Key-map: Enable with `Ctrl-Shift`. */ -- 2.30.2 From 72dc98fb142fcf2582aaf02a0ab55b97a357a531 Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Thu, 9 Mar 2023 08:47:50 +0530 Subject: [PATCH 05/18] Minor changes - Swap if-else code block - Add comment --- .../editors/animation/anim_channels_edit.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 8a267c00937..6e998644512 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3274,11 +3274,11 @@ static int click_select_channel_fcurve(bAnimContext *ac, animchannel_clear_selection(ac); /* When active channel is being clicked again for range selection, only select the * clicked/active channel. Otherwise call range selection function. */ - if ((fcu->flag & FCURVE_ACTIVE) == 0) { - animchannel_select_range(ac, ale); + if (fcu->flag & FCURVE_ACTIVE) { + fcu->flag |= FCURVE_SELECTED; } else { - fcu->flag |= FCURVE_SELECTED; + animchannel_select_range(ac, ale); } } else { @@ -3361,11 +3361,11 @@ static int click_select_channel_gplayer(bContext *C, animchannel_clear_selection(ac); /* When active channel is being clicked again for range selection, only select the * clicked/active channel. Otherwise call range selection function. */ - if ((gpl->flag & FCURVE_ACTIVE) == 0) { - animchannel_select_range(ac, ale); + if (gpl->flag & FCURVE_ACTIVE) { + gpl->flag |= GP_LAYER_SELECT; } else { - gpl->flag |= GP_LAYER_SELECT; + animchannel_select_range(ac, ale); } } else { @@ -3374,7 +3374,8 @@ static int click_select_channel_gplayer(bContext *C, gpl->flag |= GP_LAYER_SELECT; } - /* change active layer, if this is selected (since we must always have an active layer) */ + /* change active layer, if this is selected (since we must always have an active layer). + * Similar to outliner, do not change active element when selecting elements in range. */ if ((gpl->flag & GP_LAYER_SELECT) && (selectmode != SELECT_EXTEND_RANGE)) { ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER); /* update other layer status */ -- 2.30.2 From c95aca3571bc3fa998e31150ea2942566b6567ba Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Fri, 24 Mar 2023 21:08:21 +0530 Subject: [PATCH 06/18] Cleanup and use of is_cursor_elem - Add `break` within braces - Use `is_cursor_elem` to check whether clicked channel and current `ale` is same --- .../editors/animation/anim_channels_edit.c | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 6e998644512..0ee54301b6b 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3199,11 +3199,13 @@ static void animchannel_clear_selection(bAnimContext *ac) case ANIMTYPE_FCURVE: { FCurve *fcu = (FCurve *)ale->data; fcu->flag &= ~FCURVE_SELECTED; - } break; + break; + } case ANIMTYPE_GPLAYER: { bGPDlayer *gpl = (bGPDlayer *)ale->data; gpl->flag &= ~GP_LAYER_SELECT; - } break; + break; + } default: break; } @@ -3219,15 +3221,16 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele bool in_selection_range = false; LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + bool is_cursor_elem = (ale->data == cursor_elem->data); + switch (ale->type) { case ANIMTYPE_FCURVE: case ANIMTYPE_NLACURVE: { FCurve *fcu = (FCurve *)ale->data; - FCurve *cursor = (FCurve *)cursor_elem->data; /* Select first and last element from the range. Reverse selection status on extremes. */ - if ((fcu->flag & FCURVE_ACTIVE) || fcu == cursor) { + if ((fcu->flag & FCURVE_ACTIVE) || is_cursor_elem) { fcu->flag |= FCURVE_SELECTED; in_selection_range = !in_selection_range; } @@ -3236,12 +3239,12 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele if (in_selection_range) { fcu->flag |= FCURVE_SELECTED; } - } break; + break; + } case ANIMTYPE_GPLAYER: { bGPDlayer *gpl = (bGPDlayer *)ale->data; - bGPDlayer *cursor = (bGPDlayer *)cursor_elem->data; - if ((gpl->flag & GP_LAYER_ACTIVE) || gpl == cursor) { + if ((gpl->flag & GP_LAYER_ACTIVE) || is_cursor_elem) { gpl->flag |= GP_LAYER_SELECT; in_selection_range = !in_selection_range; } @@ -3249,7 +3252,8 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele if (in_selection_range) { gpl->flag |= GP_LAYER_SELECT; } - } break; + break; + } default: break; } -- 2.30.2 From d4b81d5ed2bdd06b92e32d67c43173b26eb707e5 Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Tue, 28 Mar 2023 16:18:28 +0530 Subject: [PATCH 07/18] Use is_active_elem to skip range selection of single element --- .../editors/animation/anim_channels_edit.c | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 0ee54301b6b..9d20b0aa27b 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3221,16 +3221,17 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele bool in_selection_range = false; LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { - bool is_cursor_elem = (ale->data == cursor_elem->data); - + const bool is_cursor_elem = (ale->data == cursor_elem->data); + bool is_active_elem = false; switch (ale->type) { case ANIMTYPE_FCURVE: case ANIMTYPE_NLACURVE: { FCurve *fcu = (FCurve *)ale->data; + is_active_elem = fcu->flag & FCURVE_ACTIVE; /* Select first and last element from the range. Reverse selection status on extremes. */ - if ((fcu->flag & FCURVE_ACTIVE) || is_cursor_elem) { + if (is_active_elem || is_cursor_elem) { fcu->flag |= FCURVE_SELECTED; in_selection_range = !in_selection_range; } @@ -3243,8 +3244,9 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele } case ANIMTYPE_GPLAYER: { bGPDlayer *gpl = (bGPDlayer *)ale->data; + is_active_elem = gpl->flag & GP_LAYER_ACTIVE; - if ((gpl->flag & GP_LAYER_ACTIVE) || is_cursor_elem) { + if (is_active_elem || is_cursor_elem) { gpl->flag |= GP_LAYER_SELECT; in_selection_range = !in_selection_range; } @@ -3257,6 +3259,11 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele default: break; } + if (is_active_elem && is_cursor_elem) { + /* Selection range is only one element when active channel and clicked channel are same. So + * exit out of the loop when this condition is hit. */ + break; + } } ANIM_animdata_freelist(&anim_data); @@ -3276,14 +3283,7 @@ static int click_select_channel_fcurve(bAnimContext *ac, } else if (selectmode == SELECT_EXTEND_RANGE) { animchannel_clear_selection(ac); - /* When active channel is being clicked again for range selection, only select the - * clicked/active channel. Otherwise call range selection function. */ - if (fcu->flag & FCURVE_ACTIVE) { - fcu->flag |= FCURVE_SELECTED; - } - else { - animchannel_select_range(ac, ale); - } + animchannel_select_range(ac, ale); } else { /* select F-Curve by itself */ @@ -3363,14 +3363,7 @@ static int click_select_channel_gplayer(bContext *C, } else if (selectmode == SELECT_EXTEND_RANGE) { animchannel_clear_selection(ac); - /* When active channel is being clicked again for range selection, only select the - * clicked/active channel. Otherwise call range selection function. */ - if (gpl->flag & FCURVE_ACTIVE) { - gpl->flag |= GP_LAYER_SELECT; - } - else { - animchannel_select_range(ac, ale); - } + animchannel_select_range(ac, ale); } else { /* select layer by itself */ -- 2.30.2 From cfe2266b73db5cfc4430a8555630f94766b2fc2e Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Sun, 9 Apr 2023 16:49:13 +0530 Subject: [PATCH 08/18] Replace select_range logic and move function definition above --- .../editors/animation/anim_channels_edit.c | 150 +++++++++--------- 1 file changed, 71 insertions(+), 79 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 9d20b0aa27b..68c6708fa91 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3027,6 +3027,77 @@ static int click_select_channel_scene(bAnimListElem *ale, return (ND_ANIMCHAN | NA_SELECTED); } +static void animchannel_clear_selection(bAnimContext *ac) +{ + ListBase anim_data = anim_channels_for_selection(ac); + + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + switch (ale->type) { + case ANIMTYPE_FCURVE: { + FCurve *fcu = (FCurve *)ale->data; + fcu->flag &= ~FCURVE_SELECTED; + break; + } + case ANIMTYPE_GPLAYER: { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + gpl->flag &= ~GP_LAYER_SELECT; + break; + } + default: + break; + } + } + + ANIM_animdata_freelist(&anim_data); +} + +/* Select channels that lies between active channel and last clicked channel. */ +static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_elem) +{ + ListBase anim_data = anim_channels_for_selection(ac); + bool in_selection_range = false; + + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + bool is_active_elem = false; + + switch (ale->type) { + case ANIMTYPE_FCURVE: + case ANIMTYPE_NLACURVE: { + FCurve *fcu = (FCurve *)ale->data; + is_active_elem = fcu->flag & FCURVE_ACTIVE; + break; + } + case ANIMTYPE_GPLAYER: { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + is_active_elem = gpl->flag & GP_LAYER_ACTIVE; + break; + } + default: + break; + } + + const bool is_cursor_elem = (ale->data == cursor_elem->data); + + if (is_active_elem || is_cursor_elem) { + /* Select first and last element from the range. Reverse selection status on extremes. */ + ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); + in_selection_range = !in_selection_range; + } + else if (in_selection_range) { + /* Select elements between the range. */ + ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); + } + + if (is_active_elem && is_cursor_elem) { + /* Selection range is only one element when active channel and clicked channel are same. So + * exit out of the loop when this condition is hit. */ + break; + } + } + + ANIM_animdata_freelist(&anim_data); +} + static int click_select_channel_object(bContext *C, bAnimContext *ac, bAnimListElem *ale, @@ -3190,85 +3261,6 @@ static int click_select_channel_group(bAnimContext *ac, return (ND_ANIMCHAN | NA_SELECTED); } -static void animchannel_clear_selection(bAnimContext *ac) -{ - ListBase anim_data = anim_channels_for_selection(ac); - - LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { - switch (ale->type) { - case ANIMTYPE_FCURVE: { - FCurve *fcu = (FCurve *)ale->data; - fcu->flag &= ~FCURVE_SELECTED; - break; - } - case ANIMTYPE_GPLAYER: { - bGPDlayer *gpl = (bGPDlayer *)ale->data; - gpl->flag &= ~GP_LAYER_SELECT; - break; - } - default: - break; - } - } - - ANIM_animdata_freelist(&anim_data); -} - -/* Select channels that lies between active channel and last clicked channel. */ -static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_elem) -{ - ListBase anim_data = anim_channels_for_selection(ac); - bool in_selection_range = false; - - LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { - const bool is_cursor_elem = (ale->data == cursor_elem->data); - bool is_active_elem = false; - switch (ale->type) { - - case ANIMTYPE_FCURVE: - case ANIMTYPE_NLACURVE: { - FCurve *fcu = (FCurve *)ale->data; - is_active_elem = fcu->flag & FCURVE_ACTIVE; - - /* Select first and last element from the range. Reverse selection status on extremes. */ - if (is_active_elem || is_cursor_elem) { - fcu->flag |= FCURVE_SELECTED; - in_selection_range = !in_selection_range; - } - - /* Select elements between the range. */ - if (in_selection_range) { - fcu->flag |= FCURVE_SELECTED; - } - break; - } - case ANIMTYPE_GPLAYER: { - bGPDlayer *gpl = (bGPDlayer *)ale->data; - is_active_elem = gpl->flag & GP_LAYER_ACTIVE; - - if (is_active_elem || is_cursor_elem) { - gpl->flag |= GP_LAYER_SELECT; - in_selection_range = !in_selection_range; - } - - if (in_selection_range) { - gpl->flag |= GP_LAYER_SELECT; - } - break; - } - default: - break; - } - if (is_active_elem && is_cursor_elem) { - /* Selection range is only one element when active channel and clicked channel are same. So - * exit out of the loop when this condition is hit. */ - break; - } - } - - ANIM_animdata_freelist(&anim_data); -} - static int click_select_channel_fcurve(bAnimContext *ac, bAnimListElem *ale, const short /* eEditKeyframes_Select or -1 */ selectmode, -- 2.30.2 From b0e3eacaad574cb91e54b76eb214ea490590040d Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Tue, 11 Apr 2023 13:39:43 +0530 Subject: [PATCH 09/18] Include group-like channels when selecting range Group-channels are only included in selection when the channel type of clicked element matches. That is, groups are selected along with the general channels when clicked on group. - `is_selection_allowed` decides whether to include group channels or not - Clear general channels when object-channel is selected (`ANIM_anim_channels_select_set` added). Otherwise there would be two active channels. --- .../editors/animation/anim_channels_edit.c | 102 ++++++++++++++---- 1 file changed, 80 insertions(+), 22 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 68c6708fa91..521a4f1c109 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3059,8 +3059,46 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { bool is_active_elem = false; + bool is_selection_allowed = true; + const bool is_cursor_elem = (ale->data == cursor_elem->data); switch (ale->type) { + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + case ANIMTYPE_DSMESH: + case ANIMTYPE_DSNTREE: + case ANIMTYPE_DSTEX: + case ANIMTYPE_DSLAT: + case ANIMTYPE_DSLINESTYLE: + case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: + case ANIMTYPE_DSMCLIP: + case ANIMTYPE_DSHAIR: + case ANIMTYPE_DSPOINTCLOUD: + case ANIMTYPE_DSVOLUME: + case ANIMTYPE_NLAACTION: + case ANIMTYPE_DSSIMULATION: { + if (ale->adt) { + is_active_elem = ale->adt->flag & ADT_UI_ACTIVE; + } + is_selection_allowed = ale->type == cursor_elem->type; + break; + } + case ANIMTYPE_GROUP: { + bActionGroup *argp = (bActionGroup *)ale->data; + is_active_elem = argp->flag & AGRP_ACTIVE; + is_selection_allowed = ale->type == cursor_elem->type; + break; + } case ANIMTYPE_FCURVE: case ANIMTYPE_NLACURVE: { FCurve *fcu = (FCurve *)ale->data; @@ -3075,23 +3113,24 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele default: break; } + /* Restrict selection when active element is not found and group-channels are excluded from the + * selection. */ + if (is_selection_allowed || is_active_elem) { + if (is_active_elem || is_cursor_elem) { + /* Select first and last element from the range. Reverse selection status on extremes. */ + ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); + in_selection_range = !in_selection_range; + } + else if (in_selection_range) { + /* Select elements between the range. */ + ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); + } - const bool is_cursor_elem = (ale->data == cursor_elem->data); - - if (is_active_elem || is_cursor_elem) { - /* Select first and last element from the range. Reverse selection status on extremes. */ - ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); - in_selection_range = !in_selection_range; - } - else if (in_selection_range) { - /* Select elements between the range. */ - ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); - } - - if (is_active_elem && is_cursor_elem) { - /* Selection range is only one element when active channel and clicked channel are same. So - * exit out of the loop when this condition is hit. */ - break; + if (is_active_elem && is_cursor_elem) { + /* Selection range is only one element when active channel and clicked channel are same. So + * exit out of the loop when this condition is hit. */ + break; + } } } @@ -3121,8 +3160,13 @@ static int click_select_channel_object(bContext *C, adt->flag ^= ADT_UI_SELECTED; } } + else if (selectmode == SELECT_EXTEND_RANGE) { + animchannel_clear_selection(ac); + animchannel_select_range(ac, ale); + } else { /* deselect all */ + ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR); BKE_view_layer_synced_ensure(scene, view_layer); /* TODO: should this deselect all other types of channels too? */ LISTBASE_FOREACH (Base *, b, BKE_view_layer_object_bases_get(view_layer)) { @@ -3145,7 +3189,8 @@ static int click_select_channel_object(bContext *C, * to avoid getting stuck there, see: #48747. */ ED_object_base_activate_with_mode_exit_if_needed(C, base); /* adds notifier */ - if ((adt) && (adt->flag & ADT_UI_SELECTED)) { + /* Similar to outliner, do not change active element when selecting elements in range.*/ + if ((adt) && (adt->flag & ADT_UI_SELECTED) && (selectmode != SELECT_EXTEND_RANGE)) { adt->flag |= ADT_UI_ACTIVE; } @@ -3165,14 +3210,18 @@ static int click_select_channel_dummy(bAnimContext *ac, /* inverse selection status of this AnimData block only */ ale->adt->flag ^= ADT_UI_SELECTED; } + else if (selectmode == SELECT_EXTEND_RANGE) { + animchannel_clear_selection(ac); + animchannel_select_range(ac, ale); + } else { /* select AnimData block by itself */ ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR); ale->adt->flag |= ADT_UI_SELECTED; } - /* set active? */ - if (ale->adt->flag & ADT_UI_SELECTED) { + /* Similar to outliner, do not change active element when selecting elements in range. */ + if ((ale->adt->flag & ADT_UI_SELECTED) && (selectmode != SELECT_EXTEND_RANGE)) { ale->adt->flag |= ADT_UI_ACTIVE; } @@ -3218,6 +3267,10 @@ static int click_select_channel_group(bAnimContext *ac, /* inverse selection status of this group only */ agrp->flag ^= AGRP_SELECTED; } + else if (selectmode == SELECT_EXTEND_RANGE) { + animchannel_clear_selection(ac); + animchannel_select_range(ac, ale); + } else if (selectmode == -1) { /* select all in group (and deselect everything else) */ FCurve *fcu; @@ -3244,15 +3297,20 @@ static int click_select_channel_group(bAnimContext *ac, agrp->flag |= AGRP_SELECTED; } - /* if group is selected now, make group the 'active' one in the visible list */ + /* if group is selected now, make group the 'active' one in the visible list. + * Similar to outliner, do not change active element when selecting elements in range. */ if (agrp->flag & AGRP_SELECTED) { - ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); + if (selectmode != SELECT_EXTEND_RANGE) { + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); + } if (pchan) { ED_pose_bone_select(ob, pchan, true); } } else { - ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, NULL, ANIMTYPE_GROUP); + if (selectmode != SELECT_EXTEND_RANGE) { + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, NULL, ANIMTYPE_GROUP); + } if (pchan) { ED_pose_bone_select(ob, pchan, false); } -- 2.30.2 From 488fbf4f1b2bb60574e4a67cb2b95b2d0443a530 Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Sat, 15 Apr 2023 16:14:34 +0530 Subject: [PATCH 10/18] Following fixes: - Restrict channel selection to similar types. Channels that matches with the type of shift-clicked channel are selected (Example: Fcurve only). This prevents selection of Gpencil and fcurve channel at once. But for now its better to not allow both at once, see: https://projects.blender.org/blender/blender/pulls/106116 - Change selection mode when no active element is found. Otherwise all channels below the clicked channel would get selected. --- .../editors/animation/anim_channels_edit.c | 84 +++++++++++++++++-- 1 file changed, 78 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 521a4f1c109..dd0e02acf97 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3027,6 +3027,72 @@ static int click_select_channel_scene(bAnimListElem *ale, return (ND_ANIMCHAN | NA_SELECTED); } +/* Before selecting the range, check if any active element is present. */ +static bool animchannel_active_check(bAnimContext *ac, eAnim_ChannelType type) +{ + ListBase anim_data = anim_channels_for_selection(ac); + bool is_active_found = false; + + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + if (ale->type != type) { + continue; + } + + switch (ale->type) { + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + case ANIMTYPE_DSMESH: + case ANIMTYPE_DSNTREE: + case ANIMTYPE_DSTEX: + case ANIMTYPE_DSLAT: + case ANIMTYPE_DSLINESTYLE: + case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: + case ANIMTYPE_DSMCLIP: + case ANIMTYPE_DSHAIR: + case ANIMTYPE_DSPOINTCLOUD: + case ANIMTYPE_DSVOLUME: + case ANIMTYPE_NLAACTION: + case ANIMTYPE_DSSIMULATION: { + if (ale->adt) { + is_active_found |= ale->adt->flag & ADT_UI_ACTIVE; + } + break; + } + case ANIMTYPE_GROUP: { + bActionGroup *argp = (bActionGroup *)ale->data; + is_active_found |= argp->flag & AGRP_ACTIVE; + break; + } + case ANIMTYPE_FCURVE: + case ANIMTYPE_NLACURVE: { + FCurve *fcu = (FCurve *)ale->data; + is_active_found |= fcu->flag & FCURVE_ACTIVE; + break; + } + case ANIMTYPE_GPLAYER: { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + is_active_found |= gpl->flag & GP_LAYER_ACTIVE; + break; + } + default: + break; + } + } + + ANIM_animdata_freelist(&anim_data); + return is_active_found; +} + static void animchannel_clear_selection(bAnimContext *ac) { ListBase anim_data = anim_channels_for_selection(ac); @@ -3059,9 +3125,14 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { bool is_active_elem = false; - bool is_selection_allowed = true; + bool is_selection_allowed = ale->type == cursor_elem->type; const bool is_cursor_elem = (ale->data == cursor_elem->data); + /* Allow selection when active and clicked channel has same type. */ + if (!is_selection_allowed) { + continue; + } + switch (ale->type) { case ANIMTYPE_FILLACTD: /* Action Expander */ case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ @@ -3090,13 +3161,11 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele if (ale->adt) { is_active_elem = ale->adt->flag & ADT_UI_ACTIVE; } - is_selection_allowed = ale->type == cursor_elem->type; break; } case ANIMTYPE_GROUP: { bActionGroup *argp = (bActionGroup *)ale->data; is_active_elem = argp->flag & AGRP_ACTIVE; - is_selection_allowed = ale->type == cursor_elem->type; break; } case ANIMTYPE_FCURVE: @@ -3115,7 +3184,6 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele } /* Restrict selection when active element is not found and group-channels are excluded from the * selection. */ - if (is_selection_allowed || is_active_elem) { if (is_active_elem || is_cursor_elem) { /* Select first and last element from the range. Reverse selection status on extremes. */ ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); @@ -3131,7 +3199,6 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele * exit out of the loop when this condition is hit. */ break; } - } } ANIM_animdata_freelist(&anim_data); @@ -3472,7 +3539,7 @@ static int click_select_channel_masklayer(bAnimContext *ac, static int mouse_anim_channels(bContext *C, bAnimContext *ac, const int channel_index, - const short /* eEditKeyframes_Select or -1 */ selectmode) + short /* eEditKeyframes_Select or -1 */ selectmode) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; @@ -3510,6 +3577,11 @@ static int mouse_anim_channels(bContext *C, return 0; } + /* Change selection mode to single when no active element is found. */ + if ((selectmode == SELECT_EXTEND_RANGE) && !animchannel_active_check(ac, ale->type)) { + selectmode = SELECT_INVERT; + } + /* action to take depends on what channel we've got */ /* WARNING: must keep this in sync with the equivalent function in nla_channels.c */ switch (ale->type) { -- 2.30.2 From f444b3b5422aa984cd018ad6895a427894bfbe53 Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Sun, 16 Apr 2023 12:47:39 +0530 Subject: [PATCH 11/18] Include selection of pose-group channels --- .../editors/animation/anim_channels_edit.c | 53 +++++++++++-------- source/blender/editors/armature/pose_select.c | 4 +- source/blender/editors/include/ED_armature.h | 2 +- source/blender/editors/object/object_select.c | 2 +- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index dd0e02acf97..da0c76f4910 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -214,7 +214,7 @@ void ANIM_set_active_channel(bAnimContext *ac, ANIM_animdata_freelist(&anim_data); } -static void select_pchan_for_action_group(bAnimContext *ac, bActionGroup *agrp, bAnimListElem *ale) +static void select_pchan_for_action_group(bAnimContext *ac, bActionGroup *agrp, bAnimListElem *ale, const bool change_active) { /* Armatures-Specific Feature: * See mouse_anim_channels() -> ANIMTYPE_GROUP case for more details (#38737) @@ -230,11 +230,12 @@ static void select_pchan_for_action_group(bAnimContext *ac, bActionGroup *agrp, * TODO: check the first F-Curve or so to be sure... */ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name); + if (agrp->flag & AGRP_SELECTED) { - ED_pose_bone_select(ob, pchan, true); + ED_pose_bone_select(ob, pchan, true, change_active); } else { - ED_pose_bone_select(ob, pchan, false); + ED_pose_bone_select(ob, pchan, false, change_active); } } } @@ -372,7 +373,7 @@ static void anim_channels_select_set(bAnimContext *ac, case ANIMTYPE_GROUP: { bActionGroup *agrp = (bActionGroup *)ale->data; ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED); - select_pchan_for_action_group(ac, agrp, ale); + select_pchan_for_action_group(ac, agrp, ale, true); agrp->flag &= ~AGRP_ACTIVE; break; } @@ -2747,7 +2748,7 @@ static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectm switch (ale->type) { case ANIMTYPE_GROUP: { bActionGroup *agrp = (bActionGroup *)ale->data; - select_pchan_for_action_group(ac, agrp, ale); + select_pchan_for_action_group(ac, agrp, ale, true); /* always clear active flag after doing this */ agrp->flag &= ~AGRP_ACTIVE; break; @@ -3184,21 +3185,27 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele } /* Restrict selection when active element is not found and group-channels are excluded from the * selection. */ - if (is_active_elem || is_cursor_elem) { - /* Select first and last element from the range. Reverse selection status on extremes. */ - ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); - in_selection_range = !in_selection_range; + if (is_active_elem || is_cursor_elem) { + /* Select first and last element from the range. Reverse selection status on extremes. */ + ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); + in_selection_range = !in_selection_range; + if (ale->type == ANIMTYPE_GROUP) { + select_pchan_for_action_group(ac, (bActionGroup *)ale->data, ale, false); } - else if (in_selection_range) { - /* Select elements between the range. */ - ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); + } + else if (in_selection_range) { + /* Select elements between the range. */ + ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, ACHANNEL_SETFLAG_ADD); + if (ale->type == ANIMTYPE_GROUP) { + select_pchan_for_action_group(ac, (bActionGroup *)ale->data, ale, false); } + } - if (is_active_elem && is_cursor_elem) { - /* Selection range is only one element when active channel and clicked channel are same. So - * exit out of the loop when this condition is hit. */ - break; - } + if (is_active_elem && is_cursor_elem) { + /* Selection range is only one element when active channel and clicked channel are same. So + * exit out of the loop when this condition is hit. */ + break; + } } ANIM_animdata_freelist(&anim_data); @@ -3369,17 +3376,17 @@ static int click_select_channel_group(bAnimContext *ac, if (agrp->flag & AGRP_SELECTED) { if (selectmode != SELECT_EXTEND_RANGE) { ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); - } - if (pchan) { - ED_pose_bone_select(ob, pchan, true); + if (pchan) { + ED_pose_bone_select(ob, pchan, true, true); + } } } else { if (selectmode != SELECT_EXTEND_RANGE) { ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, NULL, ANIMTYPE_GROUP); - } - if (pchan) { - ED_pose_bone_select(ob, pchan, false); + if (pchan) { + ED_pose_bone_select(ob, pchan, false, true); + } } } diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 21938ad8727..82a5448e5d1 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -92,7 +92,7 @@ void ED_pose_bone_select_tag_update(Object *ob) DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); } -void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select) +void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select, const bool change_active) { bArmature *arm; @@ -109,7 +109,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select) /* change selection state - activate too if selected */ if (select) { pchan->bone->flag |= BONE_SELECTED; - arm->act_bone = pchan->bone; + arm->act_bone = change_active ? pchan->bone : arm->act_bone; } else { pchan->bone->flag &= ~BONE_SELECTED; diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 13908d63bb6..2ec0019edf9 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -357,7 +357,7 @@ void ED_pose_bone_select_tag_update(struct Object *ob); /** * Utility method for changing the selection status of a bone. */ -void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select); +void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select, const bool change_active); /* meshlaplacian.cc */ diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 8d085cfc92a..235919c490e 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -345,7 +345,7 @@ bool ED_object_jump_to_bone(bContext *C, /* Select it. */ ED_pose_deselect_all(ob, SEL_DESELECT, true); - ED_pose_bone_select(ob, pchan, true); + ED_pose_bone_select(ob, pchan, true, true); arm->act_bone = pchan->bone; -- 2.30.2 From faa5a9bebb3f4f7d8e0ebf43e0849a921c169dab Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Sun, 16 Apr 2023 16:18:08 +0530 Subject: [PATCH 12/18] Include group like channels in animchannel_clear_selection --- .../editors/animation/anim_channels_edit.c | 35 +++++++++++++++++++ source/blender/editors/armature/pose_select.c | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index da0c76f4910..555ad62ec15 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3100,6 +3100,41 @@ static void animchannel_clear_selection(bAnimContext *ac) LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { switch (ale->type) { + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + case ANIMTYPE_DSMESH: + case ANIMTYPE_DSNTREE: + case ANIMTYPE_DSTEX: + case ANIMTYPE_DSLAT: + case ANIMTYPE_DSLINESTYLE: + case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: + case ANIMTYPE_DSMCLIP: + case ANIMTYPE_DSHAIR: + case ANIMTYPE_DSPOINTCLOUD: + case ANIMTYPE_DSVOLUME: + case ANIMTYPE_NLAACTION: + case ANIMTYPE_DSSIMULATION: { + if (ale->adt) { + ale->adt->flag &= ~ADT_UI_SELECTED; + } + break; + } + case ANIMTYPE_GROUP: { + bActionGroup *agrp = (bActionGroup *)ale->data; + agrp->flag &= ~AGRP_SELECTED; + select_pchan_for_action_group(ac, agrp, ale, false); + break; + } case ANIMTYPE_FCURVE: { FCurve *fcu = (FCurve *)ale->data; fcu->flag &= ~FCURVE_SELECTED; diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 82a5448e5d1..59e857475af 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -113,7 +113,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select, const boo } else { pchan->bone->flag &= ~BONE_SELECTED; - arm->act_bone = NULL; + arm->act_bone = change_active ? NULL : arm->act_bone; } /* TODO: select and activate corresponding vgroup? */ -- 2.30.2 From c31fed5b2b0d1532dc7ecf3438a1b8f8d7a2866c Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Tue, 2 May 2023 15:55:01 +0530 Subject: [PATCH 13/18] Code cleanup - Document `change_active` parameter - Fix code comments - Remove default clauses - Rename `animchannel_active_check` to `animchannel_has_active_of_type` --- .../editors/animation/anim_channels_edit.c | 27 +++++++++---------- source/blender/editors/armature/pose_select.c | 2 +- source/blender/editors/include/ED_armature.h | 7 ++++- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 555ad62ec15..4263f4f98de 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -214,7 +214,12 @@ void ANIM_set_active_channel(bAnimContext *ac, ANIM_animdata_freelist(&anim_data); } -static void select_pchan_for_action_group(bAnimContext *ac, bActionGroup *agrp, bAnimListElem *ale, const bool change_active) +/* change_active determines whether to change the active bone of the armature when selecting pose + * channels. It is false during range selection otherwise true. */ +static void select_pchan_for_action_group(bAnimContext *ac, + bActionGroup *agrp, + bAnimListElem *ale, + const bool change_active) { /* Armatures-Specific Feature: * See mouse_anim_channels() -> ANIMTYPE_GROUP case for more details (#38737) @@ -3028,8 +3033,8 @@ static int click_select_channel_scene(bAnimListElem *ale, return (ND_ANIMCHAN | NA_SELECTED); } -/* Before selecting the range, check if any active element is present. */ -static bool animchannel_active_check(bAnimContext *ac, eAnim_ChannelType type) +/* Return whether active channel of given type is present. */ +static bool animchannel_has_active_of_type(bAnimContext *ac, const eAnim_ChannelType type) { ListBase anim_data = anim_channels_for_selection(ac); bool is_active_found = false; @@ -3085,8 +3090,6 @@ static bool animchannel_active_check(bAnimContext *ac, eAnim_ChannelType type) is_active_found |= gpl->flag & GP_LAYER_ACTIVE; break; } - default: - break; } } @@ -3131,8 +3134,8 @@ static void animchannel_clear_selection(bAnimContext *ac) } case ANIMTYPE_GROUP: { bActionGroup *agrp = (bActionGroup *)ale->data; - agrp->flag &= ~AGRP_SELECTED; - select_pchan_for_action_group(ac, agrp, ale, false); + agrp->flag &= ~AGRP_SELECTED; + select_pchan_for_action_group(ac, agrp, ale, false); break; } case ANIMTYPE_FCURVE: { @@ -3145,15 +3148,13 @@ static void animchannel_clear_selection(bAnimContext *ac) gpl->flag &= ~GP_LAYER_SELECT; break; } - default: - break; } } ANIM_animdata_freelist(&anim_data); } -/* Select channels that lies between active channel and last clicked channel. */ +/* Select channels that lies between active channel and cursor_elem. */ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_elem) { ListBase anim_data = anim_channels_for_selection(ac); @@ -3161,7 +3162,7 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { bool is_active_elem = false; - bool is_selection_allowed = ale->type == cursor_elem->type; + const bool is_selection_allowed = (ale->type == cursor_elem->type); const bool is_cursor_elem = (ale->data == cursor_elem->data); /* Allow selection when active and clicked channel has same type. */ @@ -3215,8 +3216,6 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele is_active_elem = gpl->flag & GP_LAYER_ACTIVE; break; } - default: - break; } /* Restrict selection when active element is not found and group-channels are excluded from the * selection. */ @@ -3620,7 +3619,7 @@ static int mouse_anim_channels(bContext *C, } /* Change selection mode to single when no active element is found. */ - if ((selectmode == SELECT_EXTEND_RANGE) && !animchannel_active_check(ac, ale->type)) { + if ((selectmode == SELECT_EXTEND_RANGE) && !animchannel_has_active_of_type(ac, ale->type)) { selectmode = SELECT_INVERT; } diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 59e857475af..59b4322c349 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -92,7 +92,7 @@ void ED_pose_bone_select_tag_update(Object *ob) DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); } -void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select, const bool change_active) +void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select, bool change_active) { bArmature *arm; diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 2ec0019edf9..14d66eaea93 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -356,8 +356,13 @@ bool ED_pose_deselect_all(struct Object *ob, int select_mode, bool ignore_visibi void ED_pose_bone_select_tag_update(struct Object *ob); /** * Utility method for changing the selection status of a bone. + * change_active determines whether to change the active bone of the armature when selecting pose + * channels. It is false during range selection otherwise true. */ -void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select, const bool change_active); +void ED_pose_bone_select(struct Object *ob, + struct bPoseChannel *pchan, + bool select, + bool change_active); /* meshlaplacian.cc */ -- 2.30.2 From b3c299277e42eb5307b7129d95b7cad175b02ba1 Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Tue, 2 May 2023 16:23:08 +0530 Subject: [PATCH 14/18] New function to find out the given channel is active ANIM_is_active_channel() returns whether given channel is active --- .../editors/animation/anim_channels_edit.c | 152 +++++++----------- source/blender/editors/include/ED_anim_api.h | 5 + 2 files changed, 63 insertions(+), 94 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 4263f4f98de..efa3bed6df4 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -214,6 +214,59 @@ void ANIM_set_active_channel(bAnimContext *ac, ANIM_animdata_freelist(&anim_data); } +bool ANIM_is_active_channel(bAnimListElem *ale) +{ + bool is_active_found = false; + switch (ale->type) { + case ANIMTYPE_FILLACTD: /* Action Expander */ + case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ + case ANIMTYPE_DSLAM: + case ANIMTYPE_DSCAM: + case ANIMTYPE_DSCACHEFILE: + case ANIMTYPE_DSCUR: + case ANIMTYPE_DSSKEY: + case ANIMTYPE_DSWOR: + case ANIMTYPE_DSPART: + case ANIMTYPE_DSMBALL: + case ANIMTYPE_DSARM: + case ANIMTYPE_DSMESH: + case ANIMTYPE_DSNTREE: + case ANIMTYPE_DSTEX: + case ANIMTYPE_DSLAT: + case ANIMTYPE_DSLINESTYLE: + case ANIMTYPE_DSSPK: + case ANIMTYPE_DSGPENCIL: + case ANIMTYPE_DSMCLIP: + case ANIMTYPE_DSHAIR: + case ANIMTYPE_DSPOINTCLOUD: + case ANIMTYPE_DSVOLUME: + case ANIMTYPE_NLAACTION: + case ANIMTYPE_DSSIMULATION: { + if (ale->adt) { + is_active_found = ale->adt->flag & ADT_UI_ACTIVE; + } + break; + } + case ANIMTYPE_GROUP: { + bActionGroup *argp = (bActionGroup *)ale->data; + is_active_found = argp->flag & AGRP_ACTIVE; + break; + } + case ANIMTYPE_FCURVE: + case ANIMTYPE_NLACURVE: { + FCurve *fcu = (FCurve *)ale->data; + is_active_found = fcu->flag & FCURVE_ACTIVE; + break; + } + case ANIMTYPE_GPLAYER: { + bGPDlayer *gpl = (bGPDlayer *)ale->data; + is_active_found = gpl->flag & GP_LAYER_ACTIVE; + break; + } + return is_active_found; + } +} + /* change_active determines whether to change the active bone of the armature when selecting pose * channels. It is false during range selection otherwise true. */ static void select_pchan_for_action_group(bAnimContext *ac, @@ -3043,53 +3096,9 @@ static bool animchannel_has_active_of_type(bAnimContext *ac, const eAnim_Channel if (ale->type != type) { continue; } - - switch (ale->type) { - case ANIMTYPE_FILLACTD: /* Action Expander */ - case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ - case ANIMTYPE_DSLAM: - case ANIMTYPE_DSCAM: - case ANIMTYPE_DSCACHEFILE: - case ANIMTYPE_DSCUR: - case ANIMTYPE_DSSKEY: - case ANIMTYPE_DSWOR: - case ANIMTYPE_DSPART: - case ANIMTYPE_DSMBALL: - case ANIMTYPE_DSARM: - case ANIMTYPE_DSMESH: - case ANIMTYPE_DSNTREE: - case ANIMTYPE_DSTEX: - case ANIMTYPE_DSLAT: - case ANIMTYPE_DSLINESTYLE: - case ANIMTYPE_DSSPK: - case ANIMTYPE_DSGPENCIL: - case ANIMTYPE_DSMCLIP: - case ANIMTYPE_DSHAIR: - case ANIMTYPE_DSPOINTCLOUD: - case ANIMTYPE_DSVOLUME: - case ANIMTYPE_NLAACTION: - case ANIMTYPE_DSSIMULATION: { - if (ale->adt) { - is_active_found |= ale->adt->flag & ADT_UI_ACTIVE; - } - break; - } - case ANIMTYPE_GROUP: { - bActionGroup *argp = (bActionGroup *)ale->data; - is_active_found |= argp->flag & AGRP_ACTIVE; - break; - } - case ANIMTYPE_FCURVE: - case ANIMTYPE_NLACURVE: { - FCurve *fcu = (FCurve *)ale->data; - is_active_found |= fcu->flag & FCURVE_ACTIVE; - break; - } - case ANIMTYPE_GPLAYER: { - bGPDlayer *gpl = (bGPDlayer *)ale->data; - is_active_found |= gpl->flag & GP_LAYER_ACTIVE; - break; - } + is_active_found = ANIM_is_active_channel(ale); + if (is_active_found) { + break; } } @@ -3170,53 +3179,8 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele continue; } - switch (ale->type) { - case ANIMTYPE_FILLACTD: /* Action Expander */ - case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ - case ANIMTYPE_DSLAM: - case ANIMTYPE_DSCAM: - case ANIMTYPE_DSCACHEFILE: - case ANIMTYPE_DSCUR: - case ANIMTYPE_DSSKEY: - case ANIMTYPE_DSWOR: - case ANIMTYPE_DSPART: - case ANIMTYPE_DSMBALL: - case ANIMTYPE_DSARM: - case ANIMTYPE_DSMESH: - case ANIMTYPE_DSNTREE: - case ANIMTYPE_DSTEX: - case ANIMTYPE_DSLAT: - case ANIMTYPE_DSLINESTYLE: - case ANIMTYPE_DSSPK: - case ANIMTYPE_DSGPENCIL: - case ANIMTYPE_DSMCLIP: - case ANIMTYPE_DSHAIR: - case ANIMTYPE_DSPOINTCLOUD: - case ANIMTYPE_DSVOLUME: - case ANIMTYPE_NLAACTION: - case ANIMTYPE_DSSIMULATION: { - if (ale->adt) { - is_active_elem = ale->adt->flag & ADT_UI_ACTIVE; - } - break; - } - case ANIMTYPE_GROUP: { - bActionGroup *argp = (bActionGroup *)ale->data; - is_active_elem = argp->flag & AGRP_ACTIVE; - break; - } - case ANIMTYPE_FCURVE: - case ANIMTYPE_NLACURVE: { - FCurve *fcu = (FCurve *)ale->data; - is_active_elem = fcu->flag & FCURVE_ACTIVE; - break; - } - case ANIMTYPE_GPLAYER: { - bGPDlayer *gpl = (bGPDlayer *)ale->data; - is_active_elem = gpl->flag & GP_LAYER_ACTIVE; - break; - } - } + is_active_elem = ANIM_is_active_channel(ale); + /* Restrict selection when active element is not found and group-channels are excluded from the * selection. */ if (is_active_elem || is_cursor_elem) { diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index a436fa43989..781fec12b0e 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -696,6 +696,11 @@ void ANIM_set_active_channel(bAnimContext *ac, void *channel_data, eAnim_ChannelType channel_type); +/** + * Return whether channel is active. + */ +bool ANIM_is_active_channel(bAnimListElem *ale); + /** * Delete the F-Curve from the given AnimData block (if possible), * as appropriate according to animation context. -- 2.30.2 From 981cb0a3de3868e560716aea31d18d76834e07df Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Fri, 5 May 2023 16:01:55 +0530 Subject: [PATCH 15/18] Cleanup - `is_active_found` removed - Replace ternary operator with `if` block --- .../editors/animation/anim_channels_edit.c | 25 +++++++------------ source/blender/editors/armature/pose_select.c | 8 ++++-- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index efa3bed6df4..86d404afdcc 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -216,7 +216,6 @@ void ANIM_set_active_channel(bAnimContext *ac, bool ANIM_is_active_channel(bAnimListElem *ale) { - bool is_active_found = false; switch (ale->type) { case ANIMTYPE_FILLACTD: /* Action Expander */ case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ @@ -243,27 +242,23 @@ bool ANIM_is_active_channel(bAnimListElem *ale) case ANIMTYPE_NLAACTION: case ANIMTYPE_DSSIMULATION: { if (ale->adt) { - is_active_found = ale->adt->flag & ADT_UI_ACTIVE; + return ale->adt->flag & ADT_UI_ACTIVE; } - break; } case ANIMTYPE_GROUP: { bActionGroup *argp = (bActionGroup *)ale->data; - is_active_found = argp->flag & AGRP_ACTIVE; - break; + return argp->flag & AGRP_ACTIVE; } case ANIMTYPE_FCURVE: case ANIMTYPE_NLACURVE: { FCurve *fcu = (FCurve *)ale->data; - is_active_found = fcu->flag & FCURVE_ACTIVE; - break; + return fcu->flag & FCURVE_ACTIVE; } case ANIMTYPE_GPLAYER: { bGPDlayer *gpl = (bGPDlayer *)ale->data; - is_active_found = gpl->flag & GP_LAYER_ACTIVE; - break; + return gpl->flag & GP_LAYER_ACTIVE; } - return is_active_found; + return false; } } @@ -3170,16 +3165,14 @@ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_ele bool in_selection_range = false; LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { - bool is_active_elem = false; - const bool is_selection_allowed = (ale->type == cursor_elem->type); - const bool is_cursor_elem = (ale->data == cursor_elem->data); - /* Allow selection when active and clicked channel has same type. */ - if (!is_selection_allowed) { + /* Allow selection when active channel and `cursor_elem` are of same type. */ + if (ale->type != cursor_elem->type) { continue; } - is_active_elem = ANIM_is_active_channel(ale); + const bool is_cursor_elem = (ale->data == cursor_elem->data); + const bool is_active_elem = ANIM_is_active_channel(ale); /* Restrict selection when active element is not found and group-channels are excluded from the * selection. */ diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 59b4322c349..5d8e5f8cd7b 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -109,11 +109,15 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select, bool chan /* change selection state - activate too if selected */ if (select) { pchan->bone->flag |= BONE_SELECTED; - arm->act_bone = change_active ? pchan->bone : arm->act_bone; + if (change_active) { + arm->act_bone = pchan->bone; + } } else { pchan->bone->flag &= ~BONE_SELECTED; - arm->act_bone = change_active ? NULL : arm->act_bone; + if (change_active) { + arm->act_bone = pchan->bone; + } } /* TODO: select and activate corresponding vgroup? */ -- 2.30.2 From 6075eb80151e3e42aa10e82de581c09eb41a4694 Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Fri, 5 May 2023 16:24:44 +0530 Subject: [PATCH 16/18] Add switch case for other channel types in ANIM_is_active_channel --- source/blender/editors/animation/anim_channels_edit.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 86d404afdcc..b8d98ecc423 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -258,8 +258,12 @@ bool ANIM_is_active_channel(bAnimListElem *ale) bGPDlayer *gpl = (bGPDlayer *)ale->data; return gpl->flag & GP_LAYER_ACTIVE; } - return false; + /* These channel types do not have active flags. */ + case ANIMTYPE_MASKLAYER: + case ANIMTYPE_SHAPEKEY: + break; } + return false; } /* change_active determines whether to change the active bone of the armature when selecting pose -- 2.30.2 From 8e3bb1f6e07a102354f32cf86a041eb9607a16a6 Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Fri, 5 May 2023 17:40:18 +0530 Subject: [PATCH 17/18] Fix minor error in 981cb0a3de3868e560716aea31d18d76834e07df --- source/blender/editors/armature/pose_select.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 5d8e5f8cd7b..3dd64e64768 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -116,7 +116,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select, bool chan else { pchan->bone->flag &= ~BONE_SELECTED; if (change_active) { - arm->act_bone = pchan->bone; + arm->act_bone = NULL; } } -- 2.30.2 From 7f7709f3978919718af0068bfe1663226e1ce98e Mon Sep 17 00:00:00 2001 From: Pratik Borhade Date: Fri, 5 May 2023 17:58:01 +0530 Subject: [PATCH 18/18] Replace clear_selection function with ANIM_anim_channels_select_set --- .../editors/animation/anim_channels_edit.c | 84 ++++--------------- source/blender/editors/include/ED_anim_api.h | 2 + 2 files changed, 20 insertions(+), 66 deletions(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index b8d98ecc423..b99dc79d63e 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -400,10 +400,15 @@ static void anim_channels_select_set(bAnimContext *ac, eAnimChannels_SetFlag sel) { bAnimListElem *ale; + /* Boolean to keep active channel status during range selection. */ + const bool change_active = (sel != ACHANNEL_SETFLAG_EXTEND_RANGE); for (ale = anim_data.first; ale; ale = ale->next) { switch (ale->type) { case ANIMTYPE_SCENE: { + if (change_active) { + break; + } Scene *scene = (Scene *)ale->data; ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED); @@ -430,8 +435,10 @@ static void anim_channels_select_set(bAnimContext *ac, case ANIMTYPE_GROUP: { bActionGroup *agrp = (bActionGroup *)ale->data; ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED); - select_pchan_for_action_group(ac, agrp, ale, true); - agrp->flag &= ~AGRP_ACTIVE; + select_pchan_for_action_group(ac, agrp, ale, change_active); + if (change_active) { + agrp->flag &= ~AGRP_ACTIVE; + } break; } case ANIMTYPE_FCURVE: @@ -439,7 +446,7 @@ static void anim_channels_select_set(bAnimContext *ac, FCurve *fcu = (FCurve *)ale->data; ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED); - if ((fcu->flag & FCURVE_SELECTED) == 0) { + if (!(fcu->flag & FCURVE_SELECTED) && change_active) { /* Only erase the ACTIVE flag when deselecting. This ensures that "select all curves" * retains the currently active curve. */ fcu->flag &= ~FCURVE_ACTIVE; @@ -486,7 +493,9 @@ static void anim_channels_select_set(bAnimContext *ac, /* need to verify that this data is valid for now */ if (ale->adt) { ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED); - ale->adt->flag &= ~ADT_UI_ACTIVE; + if (change_active) { + ale->adt->flag &= ~ADT_UI_ACTIVE; + } } break; } @@ -3105,63 +3114,6 @@ static bool animchannel_has_active_of_type(bAnimContext *ac, const eAnim_Channel return is_active_found; } -static void animchannel_clear_selection(bAnimContext *ac) -{ - ListBase anim_data = anim_channels_for_selection(ac); - - LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { - switch (ale->type) { - case ANIMTYPE_FILLACTD: /* Action Expander */ - case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ - case ANIMTYPE_DSLAM: - case ANIMTYPE_DSCAM: - case ANIMTYPE_DSCACHEFILE: - case ANIMTYPE_DSCUR: - case ANIMTYPE_DSSKEY: - case ANIMTYPE_DSWOR: - case ANIMTYPE_DSPART: - case ANIMTYPE_DSMBALL: - case ANIMTYPE_DSARM: - case ANIMTYPE_DSMESH: - case ANIMTYPE_DSNTREE: - case ANIMTYPE_DSTEX: - case ANIMTYPE_DSLAT: - case ANIMTYPE_DSLINESTYLE: - case ANIMTYPE_DSSPK: - case ANIMTYPE_DSGPENCIL: - case ANIMTYPE_DSMCLIP: - case ANIMTYPE_DSHAIR: - case ANIMTYPE_DSPOINTCLOUD: - case ANIMTYPE_DSVOLUME: - case ANIMTYPE_NLAACTION: - case ANIMTYPE_DSSIMULATION: { - if (ale->adt) { - ale->adt->flag &= ~ADT_UI_SELECTED; - } - break; - } - case ANIMTYPE_GROUP: { - bActionGroup *agrp = (bActionGroup *)ale->data; - agrp->flag &= ~AGRP_SELECTED; - select_pchan_for_action_group(ac, agrp, ale, false); - break; - } - case ANIMTYPE_FCURVE: { - FCurve *fcu = (FCurve *)ale->data; - fcu->flag &= ~FCURVE_SELECTED; - break; - } - case ANIMTYPE_GPLAYER: { - bGPDlayer *gpl = (bGPDlayer *)ale->data; - gpl->flag &= ~GP_LAYER_SELECT; - break; - } - } - } - - ANIM_animdata_freelist(&anim_data); -} - /* Select channels that lies between active channel and cursor_elem. */ static void animchannel_select_range(bAnimContext *ac, bAnimListElem *cursor_elem) { @@ -3230,7 +3182,7 @@ static int click_select_channel_object(bContext *C, } } else if (selectmode == SELECT_EXTEND_RANGE) { - animchannel_clear_selection(ac); + ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_EXTEND_RANGE); animchannel_select_range(ac, ale); } else { @@ -3280,7 +3232,7 @@ static int click_select_channel_dummy(bAnimContext *ac, ale->adt->flag ^= ADT_UI_SELECTED; } else if (selectmode == SELECT_EXTEND_RANGE) { - animchannel_clear_selection(ac); + ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_EXTEND_RANGE); animchannel_select_range(ac, ale); } else { @@ -3337,7 +3289,7 @@ static int click_select_channel_group(bAnimContext *ac, agrp->flag ^= AGRP_SELECTED; } else if (selectmode == SELECT_EXTEND_RANGE) { - animchannel_clear_selection(ac); + ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_EXTEND_RANGE); animchannel_select_range(ac, ale); } else if (selectmode == -1) { @@ -3401,7 +3353,7 @@ static int click_select_channel_fcurve(bAnimContext *ac, fcu->flag ^= FCURVE_SELECTED; } else if (selectmode == SELECT_EXTEND_RANGE) { - animchannel_clear_selection(ac); + ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_EXTEND_RANGE); animchannel_select_range(ac, ale); } else { @@ -3481,7 +3433,7 @@ static int click_select_channel_gplayer(bContext *C, gpl->flag ^= GP_LAYER_SELECT; } else if (selectmode == SELECT_EXTEND_RANGE) { - animchannel_clear_selection(ac); + ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_EXTEND_RANGE); animchannel_select_range(ac, ale); } else { diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 781fec12b0e..57f6e1487b0 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -530,6 +530,8 @@ typedef enum eAnimChannels_SetFlag { ACHANNEL_SETFLAG_INVERT = 2, /** some on -> all off / all on */ ACHANNEL_SETFLAG_TOGGLE = 3, + /** turn off, keep active flag **/ + ACHANNEL_SETFLAG_EXTEND_RANGE = 4, } eAnimChannels_SetFlag; /* types of settings for AnimChannels */ -- 2.30.2