WindowControls
September 4, 2026 ยท View on GitHub
The minimize / maximize / close button cluster on the trailing edge of
a TitleBar. Rendered only when
PlatformTitleBarHost::renders_custom_controls is true
(Windows + Wayland; never on macOS).
These are deliberately NOT built on top of the regular Button widget:
Button carries a 72 dp minimum width, themed padding, focus ring and
border, none of which are appropriate for a flush-fitting Win11-style
window control. Instead, each control is a small composing widget
ControlButton built from primitives (FixedSize + ZStack +
RectWidget + Center + TextWidget) so we inherit centering, theming and
reactive hover for free.
For M2 the maximize/restore swap is not implemented โ the maximize
button always shows the โก glyph. M3+ will add a Signal<bool>-driven
glyph swap once the host can update it from WindowEvent::Resized.
API reference
๐ Full rustdoc API for this module
pub struct WindowControlsLayout
Layout snapshot that WindowControls exports to its parent TitleBar
so the after_paint aggregator can read the per-button WidgetIds.
Populated during WindowControls::build.
The maximize slot is the Switcher that wraps the two glyph
buttons (โก / โ), not either child directly: the inactive
Switcher child is dormant and has Rect::ZERO bounds, but the
Switcher container itself is always laid out by the parent
HStack and has valid bounds. A synthetic tap dispatched at the
Switcher's bounds-center routes through hit-testing to whichever
child is currently visible.
pub struct WindowControlsLayout { /* fields */ }
pub type ControlAction
Action invoked when a ControlButton is tapped.
pub type ControlAction = Rc<dyn Fn(&mut EventContext)>;
pub struct ControlButton
A compact, flush-fitting window-control button.
Composes existing primitives โ a FixedSize cell wrapping a ZStack
of (hover background, centred glyph). Hover state is tracked in a
Signal<bool> that drives a derived Signal<SurfaceRole> background,
so a hover change repaints with no relayout. Both the glyph color
(fg) and the hover surface are stored as roles (ColorProp /
SurfaceRole) that resolve against the current theme at paint time โ
so the cluster retints live across ctx.set_theme(...) without a
rebuild.
pub struct ControlButton { /* fields */ }
Methods
pub fn new(glyph: &'static str, width: f32, height: f32, fg: impl Into<ColorProp>) -> Self
Create a control button with the given Unicode glyph, fixed cell dimensions, and
foreground color role. The hover background defaults to transparent until overridden
via hover_background.
pub fn hover_background(mut self, role: SurfaceRole) -> Self
Set the surface role painted over the title bar background while the pointer is inside
the button cell. The default is SurfaceRole::Transparent (flat).
pub fn on_tap(mut self, action: impl Fn(&mut EventContext) + 'static) -> Self
Register the callback invoked when the user taps this button.
pub struct WindowControls
The minimize / maximize / close cluster, laid out as an HStack of
ControlButtons. Each cell forwards taps to the supplied host.
pub struct WindowControls { /* fields */ }
Methods
pub fn new( host: Rc<dyn PlatformTitleBarHost>, show_restore: Signal<bool>, close_action: Option<CloseAction>, ) -> Self
Build the minimize / maximize / close cluster for the given platform host.
show_restore drives the maximize โ restore swap: true renders the
Restore affordance (a11y name and action), false the Maximize
one. It is deliberately not called is_maximized: a window is also
restorable โ and must not offer "maximize" โ while it is
WindowPlacement::Fullscreen,
which WindowPlacement::is_maximized reports as false. See
crate::title_bar::TitleBar's own derivation.
close_action overrides the default ctx.close_window() behaviour (e.g.
to show a "save before closing?" dialog).