Skip to content

SidePane

Header: winui/ui/panes/SidePane.hpp. Spec: winui/ui/panes/SidePane.hpp.

A content area with a pane beside it that opens, closes and collapses to a compact strip.

The view owns both the pane and the content. In the overlay modes an open pane closes on a click on the content or on Escape. That raises on_pane_closing(), which may cancel, and then closes the pane. Opening an overlay pane moves keyboard focus into it and keeps Tab there. The pane slides open and shut while the window animates, and changes at once otherwise. The declarative form is ui::SidePane.

Example:

ui::Property<bool> open{false};

window.set_content(ui::VerticalStack{ .content = {
    ui::Button{ .text = "Toggle pane", .on_click = [&] { open.toggle(); } },
    ui::SidePane{
        .is_pane_open   = open,
        .display_mode   = ui::SidePaneDisplayMode::CompactOverlay,
        .height         = 300,
        .on_pane_closed = [&] { open = false; }, // a light dismiss closes it without the binding
        .pane           = ui::Text{ .text = "PANE CONTENT", .margin = ui::Edges{.left = 60, .top = 12} },
        .content        = ui::Text{ .text = "Main content", .margin = ui::Thickness{12} },
    },
}});

// Imperatively:
auto split = std::make_unique<ui::SidePaneControl>();
split->set_display_mode(ui::SidePaneDisplayMode::Inline);
split->set_pane(std::make_unique<ui::TextControl>("Pane"));
split->set_content(std::make_unique<ui::TextControl>("Content"));
split->set_pane_open(true);

ui::SidePane

A content area and a pane that opens beside or over it. Builds a ui::SidePaneControl. .open_pane_length unset is Auto, the pane's own width. .is_pane_open = prop is two-way. A light dismiss closes the pane and writes false into the property before .on_pane_closed runs.

Example:

ui::Property<bool> open{false};

window.set_content(ui::SidePane{
    .is_pane_open   = open,
    .display_mode   = ui::SidePaneDisplayMode::CompactOverlay,
    .height         = 400.0f,
    .pane           = ui::VerticalStack{.content = {ui::Text{.text = "Navigation"}}},
    .content        = ui::VerticalStack{.content = {
        ui::Button{.text = "Toggle pane", .on_click = [&] { open.toggle(); }},
    }},
});

Every field, in the order a designated initializer names them:

ui::SidePane{
    .is_pane_open, .display_mode, .pane_placement, .open_pane_length, .compact_pane_length,
    .light_dismiss_overlay_mode, .pane_background, .style, .margin, .width, .height,
    .min_width, .min_height, .max_width, .max_height, .horizontal_alignment,
    .vertical_alignment, .visible, .tool_tip, .accessibility, .on_pane_opening,
    .on_pane_opened, .on_pane_closing, .on_pane_closed, .on_pointer_entered,
    .on_pointer_exited, .on_got_focus, .on_lost_focus, .on_key_down, .on_wheel, .control,
    .pane, .content
}

Fields, in declaration order (designators must follow it):

Field Type Default
is_pane_open ui::TwoWayField<bool> {false} Whether the pane is open.
display_mode ui::Binding<ui::SidePaneDisplayMode> {ui::SidePaneDisplayMode::Overlay} How the pane shows: Overlay (the default), Inline, CompactOverlay or CompactInline.
pane_placement ui::Binding<ui::SidePanePlacement> {ui::SidePanePlacement::Left} The side the pane is on.
open_pane_length ui::Binding<std::optional<float>> {320.0f} The open pane's width, DIPs; unset is Auto.
compact_pane_length ui::Binding<float> {48.0f} The strip a Compact* mode shows while closed, DIPs.
light_dismiss_overlay_mode ui::Binding<ui::LightDismissOverlayMode> {ui::LightDismissOverlayMode::Auto} Whether an open overlay pane dims the content. Auto does not dim.
pane_background ui::Binding<ui::Paint> The pane's fill, a Color or a ThemeColor. Empty (the default) uses the theme's pane color.
on_pane_opening ui::Callback<void()> The pane is about to open.
on_pane_opened ui::Callback<void()> Raised right after .on_pane_opening, as the slide starts.
on_pane_closing ui::Callback<ui::Decision()> The pane is about to close. Return ui::Cancel to keep it open. Only a light dismiss can be canceled.
on_pane_closed ui::Callback<void()> The pane has closed, however that happened.
on_pointer_entered ui::Action The pointer moved onto the control.
on_pointer_exited ui::Action The pointer left the control.
on_got_focus ui::Action Keyboard focus arrived on the control, or on anything inside it, from outside it. A control with nothing focusable in it never gets focus, and never raises this.
on_lost_focus ui::Action Keyboard focus left the control and everything inside it.
on_key_down ui::Callback<ui::Handling(const ui::KeyEvent&)> A key pressed while focus is on the control or inside it, before the control's own handling; ui::Handled stops it there (Element::on_key_down()).
on_wheel ui::Callback<ui::Handling(const ui::PointerEvent&)> A wheel turn over the control, before the control scrolls; ui::Handled stops it there (Element::on_wheel()).
control ui::ControlOut<ui::SidePane> Out: the handle that receives the built control.
pane ui::Spec The side region that opens and closes.
content ui::Spec The main area.

Plus the common fields style, margin, width, height, min_width, min_height, max_width, max_height, horizontal_alignment, vertical_alignment, visible, tool_tip, accessibility every spec carries (conventions).

build

std::unique_ptr<Element> build()&&

Consumes the spec and returns the built ui::SidePaneControl; the caller owns it.

ui::SidePaneControl

Derives from ui::Element.

A content area with a pane beside it that opens, closes and collapses to a compact strip.

The view owns both the pane and the content. In the overlay modes an open pane closes on a click on the content or on Escape. That raises on_pane_closing(), which may cancel, and then closes the pane. Opening an overlay pane moves keyboard focus into it and keeps Tab there. The pane slides open and shut while the window animates, and changes at once otherwise. The declarative form is ui::SidePane.

Example:

ui::Property<bool> open{false};

window.set_content(ui::VerticalStack{ .content = {
    ui::Button{ .text = "Toggle pane", .on_click = [&] { open.toggle(); } },
    ui::SidePane{
        .is_pane_open   = open,
        .display_mode   = ui::SidePaneDisplayMode::CompactOverlay,
        .height         = 300,
        .on_pane_closed = [&] { open = false; }, // a light dismiss closes it without the binding
        .pane           = ui::Text{ .text = "PANE CONTENT", .margin = ui::Edges{.left = 60, .top = 12} },
        .content        = ui::Text{ .text = "Main content", .margin = ui::Thickness{12} },
    },
}});

// Imperatively:
auto split = std::make_unique<ui::SidePaneControl>();
split->set_display_mode(ui::SidePaneDisplayMode::Inline);
split->set_pane(std::make_unique<ui::TextControl>("Pane"));
split->set_content(std::make_unique<ui::TextControl>("Content"));
split->set_pane_open(true);

SidePaneControl

SidePaneControl() = default

An Overlay view with the pane closed on the left, 320 DIPs open, 48 compact.

set_pane

template <typename T>
T* set_pane(std::unique_ptr<T> pane)

Takes ownership of the pane's element and returns a non-owning observer. Null clears it. Lays the view out again.

pane

Element* pane() const

The pane's element (owned by the view), or null.

set_content

template <typename T>
T* set_content(std::unique_ptr<T> content)

Takes ownership of the main area's element and returns a non-owning observer. Null clears it. Lays the view out again.

content

Element* content() const

The content's element (owned by the view), or null.

is_pane_open

bool is_pane_open() const

Whether the pane is open. Opening raises on_pane_opening, then on_pane_opened. Closing raises on_pane_closing, which cannot cancel a close made this way, then on_pane_closed.

set_pane_open

void set_pane_open(bool open)

Opens or closes the pane and starts the slide. Does nothing when the pane is already there.

display_mode

SidePaneDisplayMode display_mode() const

How the pane shows and whether it pushes the content; Overlay by default.

set_display_mode

void set_display_mode(SidePaneDisplayMode mode)

Changes the display mode and lays the view out again.

pane_placement

SidePanePlacement pane_placement() const

Which side the pane is on; Left by default.

set_pane_placement

void set_pane_placement(SidePanePlacement placement)

Moves the pane to the given side and lays the view out again.

open_pane_length

std::optional<float> open_pane_length() const

The open pane's width in DIPs, 320 by default; nullopt is Auto, the pane's own width.

set_open_pane_length

void set_open_pane_length(OptionalFloat length)

Changes the open width, in DIPs, and lays the view out again.

compact_pane_length

float compact_pane_length() const

The compact strip's width in DIPs, 48 by default.

set_compact_pane_length

void set_compact_pane_length(float length)

Changes the compact strip's width, in DIPs, and lays the view out again.

pane_background

std::optional<Color> pane_background() const

The pane's fixed fill; nullopt uses the theme's pane color.

pane_background_resource

ThemeColor pane_background_resource() const

The theme color the pane is filled from, or null.

set_pane_background

void set_pane_background(std::optional<Color> color)

Sets or clears the pane's fixed fill, replacing any theme color. Redraws.

set_pane_background

void set_pane_background(ThemeColor resource)

Fills the pane with a theme color read each time it is drawn, replacing any fixed color.

light_dismiss_overlay_mode

LightDismissOverlayMode light_dismiss_overlay_mode() const

Whether an open overlay pane dims the content behind it. Only On dims. Auto by default.

set_light_dismiss_overlay_mode

void set_light_dismiss_overlay_mode(LightDismissOverlayMode mode)

Changes the overlay mode and redraws.

on_pane_opening

void on_pane_opening(Callback<void()> handler)

The pane is about to open.

on_pane_opened

void on_pane_opened(Callback<void()> handler)

Raised right after on_pane_opening, as the slide starts.

on_pane_closing

void on_pane_closing(Callback<Decision()> handler)

The pane is about to close. Return ui::Cancel to keep it open. Only a light dismiss can be canceled. Closing through set_pane_open(false) raises it but closes regardless.

on_pane_closed

void on_pane_closed(Callback<void()> handler)

The pane has closed, however that happened. Use it to learn about a light dismiss when is_pane_open is not bound two-way.

can_light_dismiss

bool can_light_dismiss() const

Whether a click outside the pane or Escape would close it right now. True in an overlay mode with the pane open.

pane_bounds

const Rect& pane_bounds() const

The pane's column at its full open length, from the last arrange.

content_bounds

const Rect& content_bounds() const

The content's column, from the last arrange.

visible_pane_bounds

Rect visible_pane_bounds() const

The part of the pane that is showing right now, animation included; empty while hidden.

pane_progress

float pane_progress() const

How far open the pane is, from 0 (closed) to 1 (open), eased.

collect_focusables

void collect_focusables(std::vector<Element*>& out) override

The pane's tab stops, then the content's. Only the pane's while it holds focus.

for_each_child

void for_each_child(ChildVisitor visit) const override

Lists the content, then the pane, whether or not any of the pane shows.

sync_native

void sync_native(NativeHost& host) override

The content, then the pane while any of it shows.

automation_children

void automation_children(std::vector<Element*>& out) const override

The content, then the pane while any of it shows.

measure_override

Size measure_override(Size available, const MeasureContext& context) const override

Measures the pane, in the whole room for an Auto open length, and the content in what the display mode leaves it. Fills the available size.

arrange_override

void arrange_override(const Rect& final_rect, const ArrangeContext& context) override

Places the pane column at the open length and the content beside or under it.

render_override

void render_override(Renderer& renderer, const RenderContext& context) const override

Draws the content, the dimming overlay when it is on, then the visible part of the pane.

tick_override

void tick_override(Duration delta) override

Advances the slide and ticks the content, then the pane while any of it shows.

pointer_override

bool pointer_override(const PointerEvent& e) override

A release on the light-dismiss layer closes the pane.

hit_test_children

void hit_test_children(Point p, std::vector<Element*>& out) const override

The pane over the content.

covers_children_at

bool covers_children_at(Point p) const override

The light-dismiss layer, and the part of a sliding pane that is not shown yet.

take_focus_request

FocusRequest take_focus_request() override

Enter as a light-dismissable pane opens, Restore as it closes. The Window moves focus.

focus_request_root

Element* focus_request_root() override

The pane: where an Enter request puts focus.

key_override

bool key_override(const KeyEvent& e) override

Escape light-dismisses an open overlay pane.

Enumerations

SidePaneDisplayMode

enum class SidePaneDisplayMode

How a SidePane's pane is shown.

Value
Overlay Closed: hidden. Open: the pane lies over the content.
Inline Closed: hidden. Open: the content shrinks to make room beside the pane.
CompactOverlay Closed: a compact strip. Open: the whole pane lies over the content.
CompactInline Closed: a compact strip. Open: the whole pane sits beside the content.

SidePanePlacement

enum class SidePanePlacement

Which side a SidePane's pane is on.

Value
Left The pane on the left, the content to its right.
Right The pane on the right.

LightDismissOverlayMode

enum class LightDismissOverlayMode

Whether a light-dismissable surface dims what is behind it.

Value
Auto Behaves as Off.
On Dim what is behind the open surface.
Off Never dim.

Tests

  • tests/test_side_pane.cpp