Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Terminal.Gui/Views/Selectors/FlagSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Terminal.Gui.Views;
// Item HotKey - Focus item. Activate (Toggle) item. Do NOT Accept.
// Focused:
// Space key - Activate (Toggle) focused item. Do NOT Accept.
// Enter key - Activate (Toggle) and Accept the focused item.
// Enter key - Accept. Do NOT Toggle.
// HotKey - No-op.
// Item HotKey - Focus item, Activate (Toggle), and do NOT Accept.

Expand Down Expand Up @@ -60,6 +60,11 @@ public FlagSelector ()
/// </summary>
protected override bool ConsumeDispatch => true;

/// <summary>
/// FlagSelector does not toggle on Enter — Enter only accepts.
/// </summary>
protected override bool ActivateOnAccept => false;

// Set by OnHandlingHotKey to suppress the Activate that DefaultHotKeyHandler
// fires after RaiseHandlingHotKey. Checked and cleared in GetDispatchTarget.
private bool _suppressHotKeyActivate;
Expand Down
11 changes: 9 additions & 2 deletions Terminal.Gui/Views/Selectors/SelectorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ public SelectorStyles Styles
}
}

/// <summary>
/// Gets whether the Accept command (Enter key) should also invoke Activate (toggle/select) before accepting.
/// The default is <see langword="true"/> (OptionSelector behavior). Override to return <see langword="false"/>
/// to accept without activating (FlagSelector behavior).
/// </summary>
protected virtual bool ActivateOnAccept => true;

/// <inheritdoc/>
protected override bool OnAccepting (CommandEventArgs args)
{
Expand All @@ -167,7 +174,7 @@ protected override bool OnAccepting (CommandEventArgs args)
return true;
}

// Per spec: Enter key should Activate AND Accept for both OptionSelector and FlagSelector.
// Per spec: Enter key should Activate AND Accept for OptionSelector.
// Enter only triggers Command.Accept (View's default key binding), so invoke Activate here
// before continuing with Accept processing. Also handle direct programmatic Accept invocations
// (Binding is null) by activating the currently focused checkbox.
Expand All @@ -178,7 +185,7 @@ protected override bool OnAccepting (CommandEventArgs args)

bool directAccept = args.Context?.Binding is null && Focused is CheckBox;

if (!enterFromCheckBox && !directAccept)
if ((!enterFromCheckBox && !directAccept) || !ActivateOnAccept)
{
return args.Context?.Binding switch
{
Expand Down
30 changes: 30 additions & 0 deletions Tests/UnitTestsParallelizable/Views/FlagSelectorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,36 @@ public void FlagSelector_Command_HotKey_WhenFocused_Does_Not_Change_Value ()
Assert.Equal (valueBefore, flagSelector.Value);
}

// Copilot - Sonnet 4
// Per issue: Enter should just accept, not toggle, in FlagSelector
[Fact]
public void FlagSelector_Enter_Does_Not_Toggle_Value ()
{
using FlagSelector<SelectorStyles> flagSelector = new ();

CheckBox firstCheckBox = flagSelector.SubViews.OfType<CheckBox> ().ElementAt (0);
flagSelector.SetFocus ();
Assert.True (flagSelector.HasFocus);

SelectorStyles? valueBefore = flagSelector.Value;

int selectorValueChanged = 0;
flagSelector.ValueChanged += (_, _) => selectorValueChanged++;

int acceptingFired = 0;
flagSelector.Accepting += (_, _) => acceptingFired++;

// Press Enter on the focused checkbox
firstCheckBox.NewKeyDownEvent (Key.Enter);

// Value should NOT change (Enter does not toggle in FlagSelector)
Assert.Equal (0, selectorValueChanged);
Assert.Equal (valueBefore, flagSelector.Value);

// But Accepting should fire
Assert.Equal (1, acceptingFired);
}

// Tests for FlagSelector<TEnum>
[Fact]
public void GenericInitialization_ShouldSetDefaults ()
Expand Down
Loading