Fixes #3974. TabView steals keypresses from active ContextMenu

This commit is contained in:
BDisp
2025-03-18 00:39:41 +00:00
committed by Tig
parent 9735d8c584
commit 2ed7bb76c3
3 changed files with 176 additions and 6 deletions

View File

@@ -84,6 +84,94 @@ public class TabView : View
}
);
AddCommand (
Command.Up,
() =>
{
if (_style.TabsOnBottom)
{
if (_tabsBar is { HasFocus: true } && _containerView.CanFocus)
{
_containerView.SetFocus ();
return true;
}
}
else
{
if (_containerView is { HasFocus: true })
{
var mostFocused = _containerView.MostFocused;
if (mostFocused is { })
{
for (int? i = mostFocused.SuperView?.InternalSubViews.IndexOf (mostFocused) - 1; i > -1; i--)
{
var view = mostFocused.SuperView?.InternalSubViews [(int)i];
if (view is { CanFocus: true, Enabled: true, Visible: true })
{
view.SetFocus ();
return true;
}
}
}
SelectedTab?.SetFocus ();
return true;
}
}
return false;
}
);
AddCommand (
Command.Down,
() =>
{
if (_style.TabsOnBottom)
{
if (_containerView is { HasFocus: true })
{
var mostFocused = _containerView.MostFocused;
if (mostFocused is { })
{
for (int? i = mostFocused.SuperView?.InternalSubViews.IndexOf (mostFocused) + 1; i < mostFocused.SuperView?.InternalSubViews.Count; i++)
{
var view = mostFocused.SuperView?.InternalSubViews [(int)i];
if (view is { CanFocus: true, Enabled: true, Visible: true })
{
view.SetFocus ();
return true;
}
}
}
SelectedTab?.SetFocus ();
return true;
}
}
else
{
if (_tabsBar is { HasFocus: true } && _containerView.CanFocus)
{
_containerView.SetFocus ();
return true;
}
}
return false;
}
);
// Default keybindings for this view
KeyBindings.Add (Key.CursorLeft, Command.Left);
KeyBindings.Add (Key.CursorRight, Command.Right);
@@ -91,6 +179,8 @@ public class TabView : View
KeyBindings.Add (Key.End, Command.RightEnd);
KeyBindings.Add (Key.PageDown, Command.PageDown);
KeyBindings.Add (Key.PageUp, Command.PageUp);
KeyBindings.Add (Key.CursorUp, Command.Up);
KeyBindings.Add (Key.CursorDown, Command.Down);
}
/// <summary>
@@ -155,7 +245,7 @@ public class TabView : View
private bool TabCanSetFocus ()
{
return IsInitialized && SelectedTab is { } && (_selectedTabHasFocus || !_containerView.CanFocus);
return IsInitialized && SelectedTab is { } && (HasFocus || (bool)_containerView?.HasFocus) && (_selectedTabHasFocus || !_containerView.CanFocus);
}
private void ContainerViewCanFocus (object sender, EventArgs eventArgs)
@@ -518,7 +608,7 @@ public class TabView : View
{
SelectedTab?.SetFocus ();
}
else
else if (HasFocus)
{
SelectedTab?.View?.SetFocus ();
}

View File

@@ -2135,4 +2135,84 @@ public class ContextMenuTests (ITestOutputHelper output)
top.Dispose ();
}
[Fact]
[AutoInitShutdown]
public void Menu_Opened_In_SuperView_With_TabView_Has_Precedence_On_Key_Press ()
{
var win = new Window
{
Title = "My Window",
X = 0,
Y = 0,
Width = Dim.Fill (),
Height = Dim.Fill ()
};
// Tab View
var tabView = new TabView
{
X = 1,
Y = 1,
Width = Dim.Fill () - 2,
Height = Dim.Fill () - 2
};
tabView.AddTab (new () { DisplayText = "Tab 1" }, true);
tabView.AddTab (new () { DisplayText = "Tab 2" }, false);
win.Add (tabView);
// Context Menu
var menuItems = new MenuBarItem (
[
new ("Item 1", "First item", () => MessageBox.Query ("Action", "Item 1 Clicked", "OK")),
new MenuBarItem (
"Submenu",
new List<MenuItem []>
{
new []
{
new MenuItem (
"Sub Item 1",
"Submenu item",
() => { MessageBox.Query ("Action", "Sub Item 1 Clicked", "OK"); })
}
})
]);
var cm = new ContextMenu ();
win.MouseClick += (s, e) =>
{
if (e.Flags.HasFlag (MouseFlags.Button3Clicked)) // Right-click
{
cm.Position = e.Position;
cm.Show (menuItems);
}
};
Application.Begin (win);
cm.Show (menuItems);
Assert.True (cm.MenuBar!.IsMenuOpen);
Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown));
Assert.True (cm.MenuBar!.IsMenuOpen);
Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
Assert.True (cm.MenuBar!.IsMenuOpen);
Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown));
Assert.True (cm.MenuBar!.IsMenuOpen);
Assert.True (Application.RaiseKeyDownEvent (Key.CursorRight));
Assert.True (cm.MenuBar!.IsMenuOpen);
Assert.True (Application.RaiseKeyDownEvent (Key.CursorLeft));
Assert.True (cm.MenuBar!.IsMenuOpen);
Assert.True (Application.RaiseKeyDownEvent (Key.CursorLeft));
Assert.False (cm.MenuBar!.IsMenuOpen);
Assert.True (tabView.HasFocus);
win.Dispose ();
}
}

View File

@@ -434,9 +434,8 @@ public class TabViewTests (ITestOutputHelper output)
Assert.Equal (btnSubView, top.MostFocused);
Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
// TabRow now has TabGroup which only F6 is allowed
Assert.NotEqual (tab2, top.MostFocused);
Assert.Equal (btn, top.MostFocused);
Assert.Equal (tab2, top.MostFocused);
Assert.NotEqual (btn, top.MostFocused);
Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
Assert.Equal (btnSubView, top.MostFocused);
@@ -459,7 +458,8 @@ public class TabViewTests (ITestOutputHelper output)
// Press the cursor up key to focus the selected tab which it's the only way to do that
Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
Assert.Equal (tab2, tv.SelectedTab);
Assert.Equal (btn, top.Focused);
Assert.False (tab2.View.HasFocus);
Assert.Equal (tv, top.Focused);
Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
Assert.Equal (tv, top.Focused);