Skip to content

UXMenuBar

UXMenuBar is the app-level menu model. A menu is not a widget: the platform assembles it, draws it, tracks the pull-down, highlights the hover, and hit-tests the pick. GEM does this inside evnt_multi, AppKit as a real NSMenu, Win32 as a per-window HMENU, GTK as a per-window GtkPopoverMenuBar, the web as a DOM menu bar on the page. The model contains no drawing, no tracking and no hit-testing. It describes the menu, hands that description to the driver in install, and turns the resulting selection back into a callback call. This follows the same approach as UXButton (no drawing) and UXTextField (no editing).

#use <UXKit>
UXMenuBar* bar = new UXMenuBar();
UXMenu* file = bar.addMenu((u8*)" File ");
file.addItem((u8*)" Open... ", &controller.onOpen);
file.addSeparator();
file.addItem((u8*)" Quit ", &controller.onQuit);
bar.install(screenW); // from here on the bar is the platform's

A handler receives the item, so one method can serve several:

void onOpen(UXMenuItem* sender) { ... }

Building · addMenu · install Selections · handleSelection · performShortcut Live state · setChecked · setEnabled

UXMenu* addMenu(u8* title)

Appends a titled menu (see UXMenu) and returns it for item building.

void install(i32 screenW)

Hands the whole model to the driver and shows the bar. Build the model completely first, because the platform realizes it once.

void handleSelection(i32 titleObj, i32 itemObj)

The selection decoder the run loop calls with the platform’s message (GEM’s MN_SELECTED shape). It resolves the ordinals and fires the item’s action. Separators never fire, and stale indices fire nothing. App code never calls this directly.

bool performShortcut(UXEvent* ev)

Offers a key press to the menus. If it is an enabled item’s shortcut, the item fires and the result is true. UXApplication calls it for every key before the key window gets the key, on the backends whose menus do not handle their own shortcuts (Win32 and GEM). From 0.7.

void setChecked(u16 mi, u16 ii, bool on)

Sets the item’s tick in the model and the live menu together. The platform redraws.

void setEnabled(u16 mi, u16 ii, bool on)

Enables or greys the item in the model and the live menu together.

One neutral model has several realizations. GEM builds a bar of G_TITLEs with dropdown boxes and delivers MN_SELECTED. AppKit builds a real NSMenu on the system bar. Win32 has no screen bar, so it attaches the same model as an HMENU to every window, and a window opened after install still gets it. GTK does the same with a GtkPopoverMenuBar over a GMenu, one action per item, placed above the content. The window grows by the bar’s height, so the content keeps the size it was opened at. On the web the canvas is the widget layer, but a menu is a native service: the driver hands the page the whole bar, and ux_web_page.js (loaded on the page) builds it above the canvas as DOM. A pull-down opens on a click, follows the pointer from title to title while open, and closes on a pick, a click elsewhere or Escape. A phone or a tablet has no menu bar at all, so on iOS and Android the bar hangs from a button at the top right of the screen, above every window: a ”⋯” that opens a UIMenu on iOS, and the overflow ”⋮” that opens a PopupMenu on Android. Each title is a submenu, and separators divide the items. Checked and disabled states show the way each platform shows them, and a pick fires the item’s action just as a click in a desktop’s bar does.

A checkable view option:

UXMenu* view = bar.addMenu((u8*)" View ");
view.addItem((u8*)" Show Ruler ", &controller.onRuler);
void onRuler(UXMenuItem* sender) {
showRuler = !showRuler;
bar.setChecked((u16)1, (u16)0, showRuler);
}