Skip to content

Commit 4111b0e

Browse files
committed
Fixes gui-cs#3974. TabView steals keypresses from active ContextMenu
1 parent 56c8b20 commit 4111b0e

File tree

3 files changed

+176
-6
lines changed

3 files changed

+176
-6
lines changed

Terminal.Gui/Views/TabView/TabView.cs

+92-2
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,103 @@ public TabView ()
8484
}
8585
);
8686

87+
AddCommand (
88+
Command.Up,
89+
() =>
90+
{
91+
if (_style.TabsOnBottom)
92+
{
93+
if (_tabsBar is { HasFocus: true } && _containerView.CanFocus)
94+
{
95+
_containerView.SetFocus ();
96+
97+
return true;
98+
}
99+
}
100+
else
101+
{
102+
if (_containerView is { HasFocus: true })
103+
{
104+
var mostFocused = _containerView.MostFocused;
105+
106+
if (mostFocused is { })
107+
{
108+
for (int? i = mostFocused.SuperView?.InternalSubViews.IndexOf (mostFocused) - 1; i > -1; i--)
109+
{
110+
var view = mostFocused.SuperView?.InternalSubViews [(int)i];
111+
112+
if (view is { CanFocus: true, Enabled: true, Visible: true })
113+
{
114+
view.SetFocus ();
115+
116+
return true;
117+
}
118+
}
119+
}
120+
121+
SelectedTab?.SetFocus ();
122+
123+
return true;
124+
}
125+
}
126+
127+
return false;
128+
}
129+
);
130+
131+
AddCommand (
132+
Command.Down,
133+
() =>
134+
{
135+
if (_style.TabsOnBottom)
136+
{
137+
if (_containerView is { HasFocus: true })
138+
{
139+
var mostFocused = _containerView.MostFocused;
140+
141+
if (mostFocused is { })
142+
{
143+
for (int? i = mostFocused.SuperView?.InternalSubViews.IndexOf (mostFocused) + 1; i < mostFocused.SuperView?.InternalSubViews.Count; i++)
144+
{
145+
var view = mostFocused.SuperView?.InternalSubViews [(int)i];
146+
147+
if (view is { CanFocus: true, Enabled: true, Visible: true })
148+
{
149+
view.SetFocus ();
150+
151+
return true;
152+
}
153+
}
154+
}
155+
156+
SelectedTab?.SetFocus ();
157+
158+
return true;
159+
}
160+
}
161+
else
162+
{
163+
if (_tabsBar is { HasFocus: true } && _containerView.CanFocus)
164+
{
165+
_containerView.SetFocus ();
166+
167+
return true;
168+
}
169+
}
170+
171+
return false;
172+
}
173+
);
174+
87175
// Default keybindings for this view
88176
KeyBindings.Add (Key.CursorLeft, Command.Left);
89177
KeyBindings.Add (Key.CursorRight, Command.Right);
90178
KeyBindings.Add (Key.Home, Command.LeftStart);
91179
KeyBindings.Add (Key.End, Command.RightEnd);
92180
KeyBindings.Add (Key.PageDown, Command.PageDown);
93181
KeyBindings.Add (Key.PageUp, Command.PageUp);
182+
KeyBindings.Add (Key.CursorUp, Command.Up);
183+
KeyBindings.Add (Key.CursorDown, Command.Down);
94184
}
95185

96186
/// <summary>
@@ -155,7 +245,7 @@ public Tab? SelectedTab
155245

156246
private bool TabCanSetFocus ()
157247
{
158-
return IsInitialized && SelectedTab is { } && (_selectedTabHasFocus || !_containerView.CanFocus);
248+
return IsInitialized && SelectedTab is { } && (HasFocus || (bool)_containerView?.HasFocus) && (_selectedTabHasFocus || !_containerView.CanFocus);
159249
}
160250

161251
private void ContainerViewCanFocus (object sender, EventArgs eventArgs)
@@ -518,7 +608,7 @@ internal IEnumerable<Tab> CalculateViewport (Rectangle bounds)
518608
{
519609
SelectedTab?.SetFocus ();
520610
}
521-
else
611+
else if (HasFocus)
522612
{
523613
SelectedTab?.View?.SetFocus ();
524614
}

Tests/UnitTests/Views/ContextMenuTests.cs

+80
Original file line numberDiff line numberDiff line change
@@ -2135,4 +2135,84 @@ public void Menu_Without_SubMenu_Is_Closed_When_Pressing_Key_Right_Or_Key_Left (
21352135

21362136
top.Dispose ();
21372137
}
2138+
2139+
[Fact]
2140+
[AutoInitShutdown]
2141+
public void Menu_Opened_In_SuperView_With_TabView_Has_Precedence_On_Key_Press ()
2142+
{
2143+
var win = new Window
2144+
{
2145+
Title = "My Window",
2146+
X = 0,
2147+
Y = 0,
2148+
Width = Dim.Fill (),
2149+
Height = Dim.Fill ()
2150+
};
2151+
2152+
// Tab View
2153+
var tabView = new TabView
2154+
{
2155+
X = 1,
2156+
Y = 1,
2157+
Width = Dim.Fill () - 2,
2158+
Height = Dim.Fill () - 2
2159+
};
2160+
tabView.AddTab (new () { DisplayText = "Tab 1" }, true);
2161+
tabView.AddTab (new () { DisplayText = "Tab 2" }, false);
2162+
win.Add (tabView);
2163+
2164+
// Context Menu
2165+
var menuItems = new MenuBarItem (
2166+
[
2167+
new ("Item 1", "First item", () => MessageBox.Query ("Action", "Item 1 Clicked", "OK")),
2168+
new MenuBarItem (
2169+
"Submenu",
2170+
new List<MenuItem []>
2171+
{
2172+
new []
2173+
{
2174+
new MenuItem (
2175+
"Sub Item 1",
2176+
"Submenu item",
2177+
() => { MessageBox.Query ("Action", "Sub Item 1 Clicked", "OK"); })
2178+
}
2179+
})
2180+
]);
2181+
2182+
var cm = new ContextMenu ();
2183+
2184+
win.MouseClick += (s, e) =>
2185+
{
2186+
if (e.Flags.HasFlag (MouseFlags.Button3Clicked)) // Right-click
2187+
{
2188+
cm.Position = e.Position;
2189+
cm.Show (menuItems);
2190+
}
2191+
};
2192+
Application.Begin (win);
2193+
2194+
cm.Show (menuItems);
2195+
Assert.True (cm.MenuBar!.IsMenuOpen);
2196+
2197+
Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown));
2198+
Assert.True (cm.MenuBar!.IsMenuOpen);
2199+
2200+
Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
2201+
Assert.True (cm.MenuBar!.IsMenuOpen);
2202+
2203+
Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown));
2204+
Assert.True (cm.MenuBar!.IsMenuOpen);
2205+
2206+
Assert.True (Application.RaiseKeyDownEvent (Key.CursorRight));
2207+
Assert.True (cm.MenuBar!.IsMenuOpen);
2208+
2209+
Assert.True (Application.RaiseKeyDownEvent (Key.CursorLeft));
2210+
Assert.True (cm.MenuBar!.IsMenuOpen);
2211+
2212+
Assert.True (Application.RaiseKeyDownEvent (Key.CursorLeft));
2213+
Assert.False (cm.MenuBar!.IsMenuOpen);
2214+
Assert.True (tabView.HasFocus);
2215+
2216+
win.Dispose ();
2217+
}
21382218
}

Tests/UnitTests/Views/TabViewTests.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -434,9 +434,8 @@ public void ProcessKey_Down_Up_Right_Left_Home_End_PageDown_PageUp_F6 ()
434434
Assert.Equal (btnSubView, top.MostFocused);
435435

436436
Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
437-
// TabRow now has TabGroup which only F6 is allowed
438-
Assert.NotEqual (tab2, top.MostFocused);
439-
Assert.Equal (btn, top.MostFocused);
437+
Assert.Equal (tab2, top.MostFocused);
438+
Assert.NotEqual (btn, top.MostFocused);
440439

441440
Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
442441
Assert.Equal (btnSubView, top.MostFocused);
@@ -459,7 +458,8 @@ public void ProcessKey_Down_Up_Right_Left_Home_End_PageDown_PageUp_F6 ()
459458
// Press the cursor up key to focus the selected tab which it's the only way to do that
460459
Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
461460
Assert.Equal (tab2, tv.SelectedTab);
462-
Assert.Equal (btn, top.Focused);
461+
Assert.False (tab2.View.HasFocus);
462+
Assert.Equal (tv, top.Focused);
463463

464464
Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
465465
Assert.Equal (tv, top.Focused);

0 commit comments

Comments
 (0)