Class PopupMenu
Menu (with checkable items,
separators and cascading submenus) as a real native window: an
undecorated, floating, transparent OS window (like a ComboBox popup) that may
overflow the owner window exactly like a true OS menu.
The menu is positioned relative to the screen and never overflows the visible area: each column flips (opens above / to the left) and then clamps against the monitor's work area, so it stays on screen no matter where the pointer is. A single native window is sized to the open cascade's bounding box and re-fit as submenus open/close; the whole cascade is rendered and hit-tested inside it.
It grabs keyboard focus while open (arrows navigate, Enter chooses, Esc closes); a press back in the owner window, an item choice, or Esc dismisses. Requires a windowed scene; headless scenes have no display to place it on.
Two presentations: a window of its own, or an overlay inside the owner window;
same cascade, flip, clamp and navigation either way, but an overlay is clamped to that window
rather than to the display, so a menu near the bottom edge has less room than it would
elsewhere. setDisplayMode(limn.components.DisplayMode) chooses; displayMode() answers what was actually
used, which is not always the same thing. Two platforms have no choice and always draw in
scene: macOS exclusive fullscreen, where taking focus minimizes the fullscreen owner, and any
window reporting no NativeWindow.supportsAbsolutePositioning() (Wayland),
where a menu window would open somewhere other than the anchor.
new PopupMenu(menu).showAt(grid, mouseX, mouseY); // context menu at the pointer
The whole cascade renders at one ControlSize step, resolved once when
the menu opens: from setControlSize(limn.scene.ControlSize) if set, else through the anchor widget, else
from the owner scene. Mixing steps across columns would desynchronise the submenu
y-alignment, the column overlap and the shared border weight.
And at one LayoutDirection, resolved through the same link at the same
moment. Reading right to left the whole cascade is mirrored: the root column aligns to the
anchor's right edge, submenus open to the left, the check gutter is on the right and the
accelerator hint and the submenu chevron on the left, and the arrow keys that open and close
a submenu swap. What does not mirror is the check mark itself, which no platform mirrors,
and the accelerator strings, which name physical keys.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidclose()Closes the menu (idempotent).static DisplayModebooleanisOpen()Whether the cascade is currently showing.Runslistenerwhen the menu closes (dismissed or an item chosen).onRootLeading(Runnable listener) Hook for the arrow that walks toward the leading side at the root column (MenuBar: go to the previous menu).onRootTrailing(Runnable listener) Hook for the arrow that walks toward the trailing side on a root item without a submenu (MenuBar: the next menu).setControlSize(ControlSize size) Pins the step of the whole cascade, overriding what the anchor or the owner scene would give it, the escape hatch for "a compact context menu over a MEDIUM surface".static voidThe presentation everyPopupMenubuilt after this call starts from, including the ones the toolkit builds where an application never sees the object:MenuBar's dropdowns,ContextMenus, and a text field's own context menu.setDisplayMode(DisplayMode mode) Asks for a presentation; seeDisplayMode.setModal(boolean value) Makes the native popup block the owner window (window-modal), enforced by the backend exactly like aDialog: a press on the parent is ignored and beeps, and the menu closes only on a choice or Escape.voidshowAnchored(Scene ownerScene, float ax, float ay, float aw, float ah) Opens the menu attached to an anchor rectangle in scene coordinates.voidshowAnchored(Widget anchor, float ax, float ay, float aw, float ah) Opens the menu attached to an anchor rectangle inanchor's scene coordinates, sized at the step resolved onanchor: it drops below the rect (a menu-bar dropdown) and flips above when there is no room.voidOpens the menu with its corner at the scene point(x, y), at the scene's step.voidOpens the menu with its corner at the scene point(x, y)(a context menu at the pointer), sized at the step resolved onanchor.
-
Constructor Details
-
PopupMenu
A popup presentingmenu; show it with one of theshow*methods.
-
-
Method Details
-
onClose
Runslistenerwhen the menu closes (dismissed or an item chosen). -
onRootLeading
Hook for the arrow that walks toward the leading side at the root column (MenuBar: go to the previous menu). That is LEFT reading left to right and RIGHT reading right to left; the physical key is flipped once, inside this class, so a listener registered here means "the previous menu" in either direction and must not flip again. -
onRootTrailing
Hook for the arrow that walks toward the trailing side on a root item without a submenu (MenuBar: the next menu). The trailing arrow is the one that opens a submenu where there is one, which is why it is the one that walks on where there is not;onRootLeadingstates the direction rule both share. -
setModal
Makes the native popup block the owner window (window-modal), enforced by the backend exactly like aDialog: a press on the parent is ignored and beeps, and the menu closes only on a choice or Escape. Defaultfalse(a press outside dismisses). Purely native: no in-scene overlay. -
setControlSize
Pins the step of the whole cascade, overriding what the anchor or the owner scene would give it, the escape hatch for "a compact context menu over a MEDIUM surface". Applied when the menu opens; a call on an already-open menu is ignored, because the columns' geometry snapshots were built from the row captured at open (seetokens).nullrestores inheritance. UI thread only. -
isOpen
public boolean isOpen()Whether the cascade is currently showing. -
popupWindow
- Returns:
- the popup's native window while open (screenshots/tests), else null.
-
showAt
Opens the menu with its corner at the scene point(x, y)(a context menu at the pointer), sized at the step resolved onanchor. This is the overload apps should use:new PopupMenu(m).showAt(grid, event.x(), event.y())makes a context menu over an XSMALL data grid XSMALL, which theSceneoverload cannot express.The coordinates are the anchor's scene coordinates (what
MouseEvent.x()reports), not anchor-local ones. -
showAt
Opens the menu with its corner at the scene point(x, y), at the scene's step. -
showAnchored
Opens the menu attached to an anchor rectangle inanchor's scene coordinates, sized at the step resolved onanchor: it drops below the rect (a menu-bar dropdown) and flips above when there is no room. A no-op for a widget outside a scene. UI thread only. -
showAnchored
Opens the menu attached to an anchor rectangle in scene coordinates. A no-op on a headless scene (no display to place the window on). UI thread only.The cascade takes the step resolved on the scene's root, the documented fallback, and the difference between "a context menu over an XSMALL data grid is XSMALL" and "it is whatever the scene says". Pass the widget it belongs to (
showAnchored(Widget, float, float, float, float)) to get the former. -
close
public void close()Closes the menu (idempotent). UI thread only. -
setDisplayMode
Asks for a presentation; seeDisplayMode. DefaultDisplayMode.NATIVE_WINDOW, which is what the platform's own menus do wherever a window can be placed at an anchor.A preference, not a guarantee, and only in one direction: a menu asked for
NATIVE_WINDOWstill draws in scene on Wayland and in macOS exclusive fullscreen, because on those a menu window does not land where the anchor is.IN_SCENEis always honoured; it needs nothing from the platform. ReaddisplayMode()for what happened.Takes effect on the next open; a menu already on screen is not re-presented under it.
-
setDefaultDisplayMode
The presentation everyPopupMenubuilt after this call starts from, including the ones the toolkit builds where an application never sees the object:MenuBar's dropdowns,ContextMenus, and a text field's own context menu.This exists because the choice is almost never per-menu. An application either shows its popups in windows or it does not: because everything it draws has to be inside one window for a screen share, because it is being screenshotted for its own documentation, or because it is a kiosk with no desktop behind it to float over. Setting that per call site means finding every call site, including the ones inside this toolkit.
Process-wide, like
Theme.setCurrent(limn.components.Theme)andFonts. Menus already open are unaffected, andsetDisplayMode(limn.components.DisplayMode)still overrides it for one menu. UI thread. -
defaultDisplayMode
- Returns:
- the presentation new menus start from.
-
displayMode
- Returns:
- how the menu is presented: while it is open, what it actually chose, including a
platform forcing
IN_SCENEover a request for a window. While it is closed, whatsetDisplayMode(limn.components.DisplayMode)last asked for, since nothing has been decided yet.
-