Skip to content

Commit 7aae0c2

Browse files
BDisptig
andauthored
Fixes #3968. Menu appears in wrong place when opened in a subview (#3979)
* Fixes #3968. Menu appears in wrong place when opened in a subview * Fixes #3965. Cannot exit a Window with a CanFocus true MenuBar * Fixes #3981. Drivers crash when middle or right click on a ContextMenu item --------- Co-authored-by: Tig <[email protected]>
1 parent ef20ff6 commit 7aae0c2

File tree

6 files changed

+280
-72
lines changed

6 files changed

+280
-72
lines changed

Terminal.Gui/Views/Menu/ContextMenu.cs

+30-12
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public void Dispose ()
104104
if (_menuBar is { })
105105
{
106106
_menuBar.MenuAllClosed -= MenuBar_MenuAllClosed;
107+
_container?.Remove (_menuBar);
107108
}
108109
Application.UngrabMouse ();
109110
_menuBar?.Dispose ();
@@ -177,16 +178,16 @@ public void Show (MenuBarItem? menuItems)
177178
}
178179

179180
MenuItems = menuItems;
180-
_container = Application.Top;
181+
_container = GetTopSuperView (Host);
181182
_container!.Closing += Container_Closing;
182183
_container.Deactivate += Container_Deactivate;
183184
_container.Disposing += Container_Disposing;
184-
Rectangle frame = Application.Screen;
185+
Rectangle viewport = _container.Viewport;
185186
Point position = Position;
186187

187188
if (Host is { })
188189
{
189-
Point pos = Host.ViewportToScreen (frame).Location;
190+
Point pos = Host.Frame.Location;
190191
pos.Y += Host.Frame.Height > 0 ? Host.Frame.Height - 1 : 0;
191192

192193
if (position != pos)
@@ -197,11 +198,11 @@ public void Show (MenuBarItem? menuItems)
197198

198199
Rectangle rect = Menu.MakeFrame (position.X, position.Y, MenuItems.Children);
199200

200-
if (rect.Right >= frame.Right)
201+
if (rect.Right >= viewport.Right)
201202
{
202-
if (frame.Right - rect.Width >= 0 || !ForceMinimumPosToZero)
203+
if (viewport.Right - rect.Width >= 0 || !ForceMinimumPosToZero)
203204
{
204-
position.X = frame.Right - rect.Width;
205+
position.X = viewport.Right - rect.Width;
205206
}
206207
else if (ForceMinimumPosToZero)
207208
{
@@ -213,17 +214,17 @@ public void Show (MenuBarItem? menuItems)
213214
position.X = 0;
214215
}
215216

216-
if (rect.Bottom >= frame.Bottom)
217+
if (rect.Bottom >= viewport.Bottom)
217218
{
218-
if (frame.Bottom - rect.Height - 1 >= 0 || !ForceMinimumPosToZero)
219+
if (viewport.Bottom - rect.Height - 1 >= 0 || !ForceMinimumPosToZero)
219220
{
220221
if (Host is null)
221222
{
222-
position.Y = frame.Bottom - rect.Height - 1;
223+
position.Y = viewport.Bottom - rect.Height - 1;
223224
}
224225
else
225226
{
226-
Point pos = Host.ViewportToScreen (frame).Location;
227+
Point pos = Host.Frame.Location;
227228
position.Y = pos.Y - rect.Height - 1;
228229
}
229230
}
@@ -251,12 +252,29 @@ public void Show (MenuBarItem? menuItems)
251252
_menuBar._isContextMenuLoading = true;
252253
_menuBar.MenuAllClosed += MenuBar_MenuAllClosed;
253254

254-
_menuBar.BeginInit ();
255-
_menuBar.EndInit ();
255+
_container.Add (_menuBar);
256256
IsShow = true;
257257
_menuBar.OpenMenu ();
258258
}
259259

260+
internal static Toplevel? GetTopSuperView (View? view)
261+
{
262+
if (view is Toplevel toplevel)
263+
{
264+
return toplevel;
265+
}
266+
267+
for (View? sv = view?.SuperView; sv != null; sv = sv.SuperView)
268+
{
269+
if (sv is Toplevel top)
270+
{
271+
return top;
272+
}
273+
}
274+
275+
return (Toplevel?)view?.SuperView ?? Application.Top;
276+
}
277+
260278
private void Container_Closing (object? sender, ToplevelClosingEventArgs obj) { Hide (); }
261279
private void Container_Deactivate (object? sender, ToplevelEventArgs e) { Hide (); }
262280
private void Container_Disposing (object? sender, EventArgs e) { Dispose (); }

Terminal.Gui/Views/Menu/MenuBar.cs

+29-31
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public MenuBar ()
7373
Y = 0;
7474
Width = Dim.Fill ();
7575
Height = 1; // BUGBUG: Views should avoid setting Height as doing so implies Frame.Size == GetContentSize ().
76-
Menus = new MenuBarItem [] { };
76+
Menus = [];
7777

7878
//CanFocus = true;
7979
_selected = -1;
@@ -111,9 +111,14 @@ public MenuBar ()
111111
Command.Cancel,
112112
() =>
113113
{
114-
CloseMenuBar ();
114+
if (IsMenuOpen)
115+
{
116+
CloseMenuBar ();
115117

116-
return true;
118+
return true;
119+
}
120+
121+
return false;
117122
}
118123
);
119124

@@ -556,10 +561,10 @@ internal void CloseAllMenus ()
556561

557562
private void CloseOtherOpenedMenuBar ()
558563
{
559-
if (Application.Top is { })
564+
if (SuperView is { })
560565
{
561566
// Close others menu bar opened
562-
Menu? menu = Application.Top.SubViews.FirstOrDefault (v => v is Menu m && m.Host != this && m.Host.IsMenuOpen) as Menu;
567+
Menu? menu = SuperView.SubViews.FirstOrDefault (v => v is Menu m && m.Host != this && m.Host.IsMenuOpen) as Menu;
563568
menu?.Host.CleanUp ();
564569
}
565570
}
@@ -595,7 +600,7 @@ internal bool CloseMenu (bool reopen, bool isSubMenu, bool ignoreUseSubMenusSing
595600
case false:
596601
if (_openMenu is { })
597602
{
598-
Application.Top?.Remove (_openMenu);
603+
SuperView?.Remove (_openMenu);
599604
}
600605

601606
SetNeedsDraw ();
@@ -634,7 +639,7 @@ internal bool CloseMenu (bool reopen, bool isSubMenu, bool ignoreUseSubMenusSing
634639

635640
if (OpenCurrentMenu is { })
636641
{
637-
Application.Top?.Remove (OpenCurrentMenu);
642+
SuperView?.Remove (OpenCurrentMenu);
638643
if (Application.MouseGrabView == OpenCurrentMenu)
639644
{
640645
Application.UngrabMouse ();
@@ -822,7 +827,7 @@ internal void OpenMenu (int index, int sIndex = -1, MenuBarItem? subMenu = null!
822827

823828
if (_openMenu is { })
824829
{
825-
Application.Top?.Remove (_openMenu);
830+
SuperView?.Remove (_openMenu);
826831
if (Application.MouseGrabView == _openMenu)
827832
{
828833
Application.UngrabMouse ();
@@ -838,34 +843,23 @@ internal void OpenMenu (int index, int sIndex = -1, MenuBarItem? subMenu = null!
838843
pos += Menus [i].TitleLength + (Menus [i].Help.GetColumns () > 0 ? Menus [i].Help.GetColumns () + 2 : 0) + _leftPadding + _rightPadding;
839844
}
840845

841-
var locationOffset = Point.Empty;
842846

843-
// if SuperView is null then it's from a ContextMenu
844-
if (SuperView is null)
845-
{
846-
locationOffset = GetScreenOffset ();
847-
}
848847

849-
if (SuperView is { } && SuperView != Application.Top)
850-
{
851-
locationOffset.X += SuperView.Border.Thickness.Left;
852-
locationOffset.Y += SuperView.Border.Thickness.Top;
853-
}
854848

855849
_openMenu = new ()
856850
{
857851
Host = this,
858-
X = Frame.X + pos + locationOffset.X,
859-
Y = Frame.Y + 1 + locationOffset.Y,
852+
X = Frame.X + pos,
853+
Y = Frame.Y + 1,
860854
BarItems = Menus [index],
861855
Parent = null
862856
};
863857
OpenCurrentMenu = _openMenu;
864858
OpenCurrentMenu._previousSubFocused = _openMenu;
865859

866-
if (Application.Top is { })
860+
if (SuperView is { })
867861
{
868-
Application.Top.Add (_openMenu);
862+
SuperView.Add (_openMenu);
869863
// _openMenu.SetRelativeLayout (Application.Screen.Size);
870864
}
871865
else
@@ -894,13 +888,11 @@ internal void OpenMenu (int index, int sIndex = -1, MenuBarItem? subMenu = null!
894888

895889
if (!UseSubMenusSingleFrame)
896890
{
897-
locationOffset = GetLocationOffset ();
898-
899891
OpenCurrentMenu = new ()
900892
{
901893
Host = this,
902-
X = last!.Frame.Left + last.Frame.Width + locationOffset.X,
903-
Y = last.Frame.Top + locationOffset.Y + last._currentChild,
894+
X = last!.Frame.Left + last.Frame.Width,
895+
Y = last.Frame.Top + last._currentChild + 1,
904896
BarItems = subMenu,
905897
Parent = last
906898
};
@@ -931,7 +923,7 @@ internal void OpenMenu (int index, int sIndex = -1, MenuBarItem? subMenu = null!
931923

932924
OpenCurrentMenu._previousSubFocused = last._previousSubFocused;
933925
_openSubMenu.Add (OpenCurrentMenu);
934-
Application.Top?.Add (OpenCurrentMenu);
926+
SuperView?.Add (OpenCurrentMenu);
935927

936928
if (!OpenCurrentMenu.IsInitialized)
937929
{
@@ -1014,7 +1006,7 @@ internal void RemoveAllOpensSubMenus ()
10141006
{
10151007
foreach (Menu item in _openSubMenu)
10161008
{
1017-
Application.Top!.Remove (item);
1009+
SuperView?.Remove (item);
10181010
if (Application.MouseGrabView == item)
10191011
{
10201012
Application.UngrabMouse ();
@@ -1263,7 +1255,7 @@ private void RemoveSubMenu (int index, bool ignoreUseSubMenusSingleFrame = false
12631255
if (_openSubMenu is { })
12641256
{
12651257
menu = _openSubMenu [i];
1266-
Application.Top!.Remove (menu);
1258+
SuperView!.Remove (menu);
12671259
_openSubMenu.Remove (menu);
12681260

12691261
if (Application.MouseGrabView == menu)
@@ -1544,8 +1536,14 @@ internal bool HandleGrabView (MouseEventArgs me, View current)
15441536

15451537
if (me.View != current)
15461538
{
1539+
View v = current;
15471540
Application.UngrabMouse ();
1548-
View v = me.View;
1541+
1542+
if (((Menu)me.View).Host.SuperView is { } && ((Menu)me.View).Host.SuperView!.InternalSubViews.Contains(me.View))
1543+
{
1544+
v = me.View;
1545+
}
1546+
15491547
Application.GrabMouse (v);
15501548
MouseEventArgs nme;
15511549

0 commit comments

Comments
 (0)