Search guides and the APICtrl K
  1. API reference
  2. Native GUI

gfx/menu_bar.h

A menu bar, and the same menus as a list for a narrow editor.

#include <sonore/gfx/menu_bar.h>
On this page

Design notes

Driven by a model, not built from components

The menus are asked for when they open. A MenuBarModel names the top-level menus and builds each PopupMenu on demand, so a menu's ticks and greyed items are worked out from the plugin's state at the moment somebody looks -- not cached when the editor was built and wrong by the time anyone opens it. The same model drives a MenuBarComponent and a BurgerMenuComponent, so an editor that swaps one for the other when it gets narrow has one place where its menus are defined.

The keyboard is the hard part

F10 enters the bar with the first name lit; Left and Right walk the names; Down, Return or a letter opens one. With a menu open, Left and Right move to the neighbouring menu and Escape steps back to the bar rather than out of it -- a second Escape leaves. Alt with a menu's initial (or the letter after an '&' in its name) opens it from anywhere. That is the desktop's contract and every step of it is a test here.

One thing the peers cannot give: a tap of Alt ON ITS OWN. A bare modifier press is not a key event on any of the three platforms this SDK targets, so the route in from nothing is F10 or Alt+letter. Neither reaches a bar that is not an ancestor of the focused component by itself, either -- keys walk UP from the focus -- so the owner offers unhandled keys with handleShortcutKey(), from MouseRouter::onUnhandledKey, beside its commands.

Inside the editor

The menus open in a PopupMenuOverlay (popup_overlay.h), which is why moving the mouse along the bar with a menu open switches menus and why the bar hears Left and Right while a menu has the keyboard.

Types 3

class BurgerMenuComponent : public Widget, private detail::MenuModelListener

The same menus as one scrolling list: each top-level name a heading, its items under it.

For an editor too narrow for a bar -- usually inside a SidePanel opened by a burger button, which is the arrangement the name comes from. Re-reads the model whenever it says so and whenever refresh() is called, because a list that is always visible cannot build its contents on open the way a drop-down does.

↑↓ to move↵ to openEvery public name in the headers, and every guide