Class MenuBar
Menu
as a PopupMenu (a native window) below it; Left/Right walk between
menus, Down/Enter opens the focused one, and its submenus/checkable items
behave like any other popup.
MenuBar bar = new MenuBar()
.addMenu("File", 'F', fileMenu)
.addMenu("Edit", 'E', editMenu)
.addMenu("View", 'V', viewMenu);
The bar is the keyboard entry point to the whole menu system, and it is one while it
is in a scene rather than only while it is focused. From the moment it is attached it answers,
anywhere in the scene and without focus: an item's Accelerator runs that item; a bare
Alt released (or F10) moves focus here; Alt plus a declared access letter opens that
menu. All of it is offered only after the focused widget has declined the key, so a shortcut
never steals a keystroke from a text field that wanted it.
Where the system keeps the menu bar outside the window, which is macOS, the bar's
menus are shown there and not here: see setPlacement(limn.components.MenuBar.Placement) and isInSystemBar().
The widget then takes no room in its scene, and what the paragraph above says of the keyboard
is the system's to decide: it has its own keys for walking its bar, and it runs an item's
accelerator before the focused widget sees the key. An item made for an editing
command, MenuItem.of(MenuItem.Role), is the one written for that order: it does the
command in the focused widget, and lets the key through when the widget cannot. Three other
roles move an item to the application's own menu there (MenuItem.Role), and two
menus may be named for the system to add its own items to (setWindowMenu(limn.components.Menu),
setHelpMenu(limn.components.Menu)).
The strip mirrors where it reads right to left: the first title is at the right edge, each title's text sits on the pad of the side reading starts from, and Left selects the visually-left title, which is then the next one in declaration order. The dropdown inherits the direction through the anchor and mirrors with it. Accelerator labels do not mirror: they name physical keys.
The strip takes the width it is offered, as a platform's menu bar spans its window:
at the top of a Column it runs from edge to edge, bottom rule
included, whatever the column's cross alignment, and its titles keep to the end reading starts
from. Where no width is offered, in a Row outside
Expanded, it is as wide as its titles. The stretch past the last title
is drawn and not hit: a press there reaches whatever is beneath the bar.
The strip's height is the ControlSize step's
controlHeight, so a bar and the buttons beside it agree at every step, and the
dropdown opens at the bar's step because PopupMenu is anchored on this widget.
Every metric comes from the resolved SizeTokens row, every weight from
Strokes, including the bottom rule, the most visible hairline in the toolkit,
which stays 1 pt at XSMALL and at XLARGE.
-
Nested Class Summary
Nested Classes -
Constructor Summary
ConstructorsConstructorDescriptionMenuBar()An empty bar; add top-level menus withaddMenu(java.lang.String, limn.components.Menu). -
Method Summary
Modifier and TypeMethodDescriptionAppends a top-level menu whose title carries an access letter: it is underlined in the strip,Altplus that letter opens the menu from anywhere in the scene, and the bare letter opens it while the bar has focus.Appends a top-level menu with the given title, and no access letter.addMenu(I18nString title, char mnemonic, Menu menu) addMenu(String, char, Menu)with a title that follows the UI language.addMenu(I18nString title, Menu menu) A top-level menu whose title follows the UI language, and no access letter.protected floatThe baseline BASELINE rows align on, the expressiononPaint(limn.graphics.Canvas)draws titles with.booleanbooleanisOpen()protected voidThe strip, and one node per title.protected voidThe bar answers for the whole scene while it is attached: accelerators, Alt/F10 and Alt+letter all arrive here, after the focused widget has declined them.protected voidA bar removed from the tree must never strand its dropdown on screen, nor keep answering the scene's keyboard from outside it, which is what the unhook is for.protected voidCalled when this widget takes keyboard focus.protected voidCalled when this widget loses keyboard focus.protected @Nullable Widget<?> onHitTest(float localX, float localY) The bar's own points are its titles'.protected voidonKeyEvent(KeyEvent event) Key events (focused widget first, then ancestors).protected SizeonMeasure(Constraints constraints) Reports the size this widget wants withinconstraints.protected voidonMouseEvent(MouseEvent event) Mouse events (bubbling); callevent.consume()when handled.protected voidWidget's own background/content, in local coordinates.protected booleanonSyntheticAction(long key, Accessible.Action action, Accessible.Argument arg) Opens or closes one title's dropdown, through the same private path a click on it takes.setDisplayMode(DisplayMode mode) Asks for the presentation of every dropdown this bar opens; seeDisplayMode.setHelpMenu(@Nullable Menu menu) Names the help menu among this bar's menus.setPlacement(MenuBar.Placement value) Says where the bar is shown; seeMenuBar.Placement.setWindowMenu(@Nullable Menu menu) Names the menu of the application's windows among this bar's menus.Methods inherited from class limn.scene.Widget
acceptsTextInput, accessibleLabelAccessKey, accessibleLabelTarget, accessibleLabelText, add, add, announceChange, backdropReach, baselineOffsetOf, caretRect, children, clipboard, clipHeight, clipsChildren, clipWidth, clipX, clipY, controlSize, cursor, declaredControlSize, declaredLayoutDirection, declaredLocale, focusArrivedBackward, focusArrivedByTraversal, handleUserChange, height, hitTest, hitTestChild, id, imageCursor, inheritanceHost, invalidate, invalidate, invalidateAccessible, isEnabled, isFocusable, isFocused, isRightToLeft, isSelfEnabled, isShowing, isVisible, isVisibleByItsOwnFlag, layoutBox, layoutDirection, locale, localToScene, localToSceneBounds, markNeedsContainedLayout, markNeedsLayout, markNeedsLayoutInPlace, maxHeight, maxWidth, measure, minHeight, minWidth, moveChild, moveChild, moveChild, neutralBase, notifyChange, notifyTextEdit, observeChanges, onAccessibilityAction, onAccessibilityChild, onAccessibilityChildAction, onAccessibilityChildIdentity, onCanEdit, onCharTyped, onDragExit, onDragOver, onDragStart, onDrop, onEdit, onLayout, onPaintOverlay, onPreedit, overlayPassesPointer, paintChildren, paintOutset, paintsDecoration, paintsFromBackdrop, paintWidget, parent, remove, remove, requestFocus, requestFocus, revealInView, revealInView, runHandler, scene, sceneNanos, sceneToLocal, self, setAccessibleDescribedBy, setAccessibleDescription, setAccessibleDescription, setAccessibleIgnored, setAccessibleLabelledBy, setAccessibleName, setAccessibleName, setAccessibleRole, setControlSize, setCursor, setEnabled, setFocusable, setId, setImageCursor, setInheritanceHost, setLayoutDirection, setLocale, setMaxHeight, setMaxWidth, setMinHeight, setMinWidth, setPresentedElsewhere, setTooltip, setTooltip, setVisible, shapeText, textRuler, tooltip, tooltipSource, width, x, y
-
Constructor Details
-
MenuBar
public MenuBar()An empty bar; add top-level menus withaddMenu(java.lang.String, limn.components.Menu).
-
-
Method Details
-
addMenu
Appends a top-level menu with the given title, and no access letter. UI thread only. -
addMenu
A top-level menu whose title follows the UI language, and no access letter. UI thread only. -
addMenu
Appends a top-level menu whose title carries an access letter: it is underlined in the strip,Altplus that letter opens the menu from anywhere in the scene, and the bare letter opens it while the bar has focus.- Parameters:
mnemonic- a letter or digit, matched case-insensitively;0for none- Throws:
IllegalArgumentException- for any other character
-
addMenu
addMenu(String, char, Menu)with a title that follows the UI language. -
setDisplayMode
Asks for the presentation of every dropdown this bar opens; seeDisplayMode. DefaultDisplayMode.NATIVE_WINDOW, which is what a platform menu bar does.A preference, not a guarantee: a dropdown asked for
NATIVE_WINDOWis still drawn in scene where the platform cannot place a window at the anchor, and in a fullscreen window.IN_SCENEis always honoured, and the bar keeps its hover-to-switch behaviour under it, because pointer input over the strip falls through the overlay.Takes effect on the next open; a dropdown already down is not re-presented.
-
setPlacement
Says where the bar is shown; seeMenuBar.Placement. DefaultMenuBar.Placement.SYSTEM.A preference, as
setDisplayMode(limn.components.DisplayMode)is:isInSystemBar()answers what happened. UnderSYSTEMthe bar is still drawn in the window where the system keeps no bar for the application, while its window is fullscreen in the way that covers the system's bar, and when another bar of the same window got there first. -
placement
- Returns:
- where the bar asked to be shown
-
isInSystemBar
public boolean isInSystemBar()- Returns:
- whether the system's bar is showing this bar's menus, in which case the bar takes no room in its scene, paints nothing, holds no key and is read by a screen reader as the system's bar is. The answer can change while the application runs
-
setWindowMenu
Names the menu of the application's windows among this bar's menus. In the system's bar the system adds its own items to it, the list of windows among them, and an application that names none is given one there. In the window it changes nothing.- Parameters:
menu- a menu added to this bar, now or later, ornullfor none
-
setHelpMenu
Names the help menu among this bar's menus. In the system's bar the system adds its search to it. In the window it changes nothing.- Parameters:
menu- a menu added to this bar, now or later, ornullfor none
-
displayMode
- Returns:
- the presentation the next dropdown will be asked for.
-
isOpen
public boolean isOpen()- Returns:
- whether a dropdown is currently open.
-
onMeasure
Description copied from class:WidgetReports the size this widget wants withinconstraints. Called once per layout pass, and the result is cached against the constraints and the resolved axes (size step, layout direction, locale), so it must be a pure function of them and of this widget's own state.Resolve the
ControlSizeand theLayoutDirectiononce each here and thread them down; never read either in a constructor. The locale needs no threading: it is in scope, andI18n.locale()answers it wherever text is resolved. -
baselineOffset
protected float baselineOffset()The baseline BASELINE rows align on, the expressiononPaint(limn.graphics.Canvas)draws titles with.- Overrides:
baselineOffsetin classWidget<MenuBar>
-
onPaint
Description copied from class:WidgetWidget's own background/content, in local coordinates. -
onHitTest
The bar's own points are its titles'. The strip past the last one has nothing in it and is left to whatever is beneath, as it was when the bar ended at its last title and as a platform's empty menu-bar stretch is inert: a press there opens nothing and takes the keyboard from nobody, and the pointer over it is the one beneath rather than the hand the titles show. -
onMouseEvent
Description copied from class:WidgetMouse events (bubbling); callevent.consume()when handled.- Overrides:
onMouseEventin classWidget<MenuBar>
-
onKeyEvent
Description copied from class:WidgetKey events (focused widget first, then ancestors).- Overrides:
onKeyEventin classWidget<MenuBar>
-
onAttached
protected void onAttached()The bar answers for the whole scene while it is attached: accelerators, Alt/F10 and Alt+letter all arrive here, after the focused widget has declined them.- Overrides:
onAttachedin classWidget<MenuBar>
-
onDetached
protected void onDetached()A bar removed from the tree must never strand its dropdown on screen, nor keep answering the scene's keyboard from outside it, which is what the unhook is for.- Overrides:
onDetachedin classWidget<MenuBar>
-
onFocusGained
protected void onFocusGained()Description copied from class:WidgetCalled when this widget takes keyboard focus. Default: nothing.- Overrides:
onFocusGainedin classWidget<MenuBar>
-
onFocusLost
protected void onFocusLost()Description copied from class:WidgetCalled when this widget loses keyboard focus. Default: nothing.- Overrides:
onFocusLostin classWidget<MenuBar>
-
onAccessibility
The strip, and one node per title.Why the bar declares a selection. Its whole keyboard model is a cursor running along the titles, and the difference between two trees turns a moved cursor into an active-descendant event only for a node that carries the selection facet. Without it, marking a title active is a bit nobody diffs and Left/Right along the strip is silent to a reader. Not required, because with the bar unfocused and nothing open there is honestly no current title; not multi-selectable, because one menu is down at a time.
Why the toolkit names it. The constructor makes the bar focusable unconditionally, so it is a permanent tab stop, and a focusable node with no name at all is what the gallery's invariants refuse. The class holds no string of its own to offer. The name is redundant with the role, which is the argument against it and is why it is written down; an application that wants better still wins, because
setAccessibleNameis applied after this hook.Each title's box is its own, not the widget's: the same prefix sum over
titleWidth(int, limn.components.SizeTokens)that measure, paint,titleAt(float, limn.components.SizeTokens, boolean)and the dropdown's anchor share, with the row and the direction resolved once for the whole hook for the reason the geometry section states. A title past the strip's own width is not marked off screen: this class has no overflow handling of any kind, nothing clips it, and it really is painted over its neighbour and really is reachable by the keyboard. The overflow is a layout defect and telling a reader the title is not on screen would be a second one.The current title is not the hover.
hoverIndexis both the pointer's hover and the keyboard's cursor in this class, and publishing a bare hover as active would announce a title to a user whose keyboard is in a text field, once per mouse move across the strip. The open menu is consulted first and is not folded into the hover, because a pointer leaving the strip clears the hover while a dropdown is still down.A title whose menu is empty carries no operation.
PopupMenurefuses to show an empty menu on every platform, every time, so the popup state, the expanded facet, the opening verbs and the key binding are all gated on the menu having items — an absent verb rather than one that is always refused. It keepsFOCUS, which opens nothing: the arrows walk onto it, so a reader may too. The emptiness is read live from a model this bar never hears about, so a menu filled after the bar was drawn is republished on the next frame that walks, and on a quiet window not at all.- Overrides:
onAccessibilityin classWidget<MenuBar>- Parameters:
a- the builder for this node
-
onSyntheticAction
Opens or closes one title's dropdown, through the same private path a click on it takes.openMenu(int)andcloseMenu()are exactly what the pointer's own press branch calls, so an assistive technology's open builds the samePopupMenu, wires the same root-arrow callbacks and the same pointer pass-through, and reaches the application the same way. Nothing gains a public entry point for it.Three refusals, each of them a fact rather than a guard against a caller. A title whose menu is empty can never open one, so it is refused here as it is left without a verb above — deliberately stricter than the pointer, which has no such test and wedges the bar on such a title. A title already down is refused rather than reopened, because reopening tears the cascade down and builds another one, which the pointer never does. And a collapse addressed to a title that is not the open one is refused rather than quietly closing whatever is.
"Down" is the fact the describe hook publishes: this title is the open one and a cascade is on screen. A title whose show was refused is published collapsed with the verbs that open it, so its
EXPANDasks for the open again and itsCOLLAPSEis refused (until 2026-09-15 this hook and the verbs read the index alone, and the refused title publishedCOLLAPSEbesidecollapsed).The verbs answered are exactly the verbs
onAccessibility(limn.accessibility.Accessibility)publishes for the title's state:SHOW_MENUandEXPANDopen a closed title,COLLAPSEcloses the open one,FOCUStakes the keyboard and puts the bar's cursor on any title while no menu is down, without opening it, andPRESS— accepted here as a third synonym until 2026-09-14 — is refused, because a verb a node performs without publishing is one a reader cannot see and one platform invokes by accident.The answer to an open is whether a cascade is on screen, not whether the bar now believes one is: the show is refused outright over a window that cannot host a popup, and answering true there would report an action that did nothing.
- Overrides:
onSyntheticActionin classWidget<MenuBar>- Parameters:
key- the title's index, which is its keyaction- what is being askedarg- unused; every verb here is parameterless- Returns:
- whether this bar did it
-