mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Add OpenMenu(Point?) overload for custom positioning
Co-authored-by: tig <585482+tig@users.noreply.github.com>
This commit is contained in:
@@ -236,12 +236,33 @@ public class MenuBar : Menu, IDesignable
|
||||
/// The first menu item in the PopoverMenu will be selected and focused.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool OpenMenu ()
|
||||
public bool OpenMenu () { return OpenMenu (null); }
|
||||
|
||||
/// <summary>
|
||||
/// Opens the first menu item with a <see cref="PopoverMenu"/> at the specified screen position.
|
||||
/// This is useful for programmatically opening the menu, for example when using the MenuBar as a dropdown list.
|
||||
/// </summary>
|
||||
/// <param name="position">
|
||||
/// The screen position at which to open the menu. If <see langword="null"/>, the menu will be positioned
|
||||
/// at the default location (bottom-left of the first MenuBarItem).
|
||||
/// </param>
|
||||
/// <returns><see langword="true"/> if a menu was opened; <see langword="false"/> otherwise.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method activates the MenuBar and shows the first MenuBarItem that has a PopoverMenu.
|
||||
/// The first menu item in the PopoverMenu will be selected and focused.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// When using MenuBar as a dropdown button next to a TextField, you can position the menu
|
||||
/// to align with the left edge of the TextField by passing the TextField's screen position.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool OpenMenu (Point? position)
|
||||
{
|
||||
if (SubViews.OfType<MenuBarItem> ().FirstOrDefault (mbi => mbi.PopoverMenu is { }) is { } first)
|
||||
{
|
||||
Active = true;
|
||||
ShowItem (first);
|
||||
ShowItem (first, position);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -401,7 +422,11 @@ public class MenuBar : Menu, IDesignable
|
||||
/// Shows the specified popover, but only if the menu bar is active.
|
||||
/// </summary>
|
||||
/// <param name="menuBarItem"></param>
|
||||
private void ShowItem (MenuBarItem? menuBarItem)
|
||||
/// <param name="position">
|
||||
/// The screen position at which to show the popover. If <see langword="null"/>, the menu will be positioned
|
||||
/// at the default location (bottom-left of the MenuBarItem).
|
||||
/// </param>
|
||||
private void ShowItem (MenuBarItem? menuBarItem, Point? position = null)
|
||||
{
|
||||
// Logging.Debug ($"{Title} - {menuBarItem?.Id}");
|
||||
|
||||
@@ -447,7 +472,8 @@ public class MenuBar : Menu, IDesignable
|
||||
if (menuBarItem.PopoverMenu is { })
|
||||
{
|
||||
menuBarItem.PopoverMenu.App ??= App;
|
||||
menuBarItem.PopoverMenu.MakeVisible (new Point (menuBarItem.FrameToScreen ().X, menuBarItem.FrameToScreen ().Bottom));
|
||||
Point menuPosition = position ?? new Point (menuBarItem.FrameToScreen ().X, menuBarItem.FrameToScreen ().Bottom);
|
||||
menuBarItem.PopoverMenu.MakeVisible (menuPosition);
|
||||
}
|
||||
|
||||
menuBarItem.Accepting += OnMenuItemAccepted;
|
||||
|
||||
@@ -794,4 +794,48 @@ public class MenuBarTests ()
|
||||
Application.End (rs);
|
||||
top.Dispose ();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[AutoInitShutdown]
|
||||
public void OpenMenu_With_Position_Opens_At_Specified_Location ()
|
||||
{
|
||||
// Arrange
|
||||
var top = new Toplevel ()
|
||||
{
|
||||
App = ApplicationImpl.Instance
|
||||
};
|
||||
|
||||
var menuBar = new MenuBar () { Id = "menuBar", X = 10, Y = 0 };
|
||||
top.Add (menuBar);
|
||||
|
||||
var menuItem1 = new MenuItem { Id = "menuItem1", Title = "Item _1" };
|
||||
var menu = new Menu ([menuItem1]) { Id = "menu" };
|
||||
var menuBarItem = new MenuBarItem { Id = "menuBarItem", Title = "_File" };
|
||||
var menuBarItemPopover = new PopoverMenu ();
|
||||
|
||||
menuBar.Add (menuBarItem);
|
||||
menuBarItem.PopoverMenu = menuBarItemPopover;
|
||||
menuBarItemPopover.Root = menu;
|
||||
|
||||
SessionToken rs = Application.Begin (top);
|
||||
Assert.False (menuBar.Active);
|
||||
Assert.False (menuBar.IsOpen ());
|
||||
|
||||
// Act - Open menu at custom position (0, 1)
|
||||
Point customPosition = new Point (0, 1);
|
||||
bool result = menuBar.OpenMenu (customPosition);
|
||||
|
||||
// Assert
|
||||
Assert.True (result);
|
||||
Assert.True (menuBar.Active);
|
||||
Assert.True (menuBar.IsOpen ());
|
||||
Assert.True (menuBarItem.PopoverMenu.Visible);
|
||||
|
||||
// The menu's Root should be positioned at or near the custom position
|
||||
// (GetMostVisibleLocationForSubMenu may adjust it to fit on screen)
|
||||
Assert.NotNull (menuBarItemPopover.Root);
|
||||
|
||||
Application.End (rs);
|
||||
top.Dispose ();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user