Skip to content

Pager

Header: winui/ui/navigation/Pager.hpp. Spec: winui/ui/navigation/Pager.hpp.

A pager: First / Previous buttons, a page selector ("Page [n] of N" in a NumberBox or drop-down, or a row of page buttons), and Next / Last buttons.

It is made of controls it owns (Buttons, a NumberBox, a ComboBox), each a tab stop of its own. Page indices are 0-based, and the selector shows them 1-based. The navigation buttons disable themselves on the first and last page. An unset page count is an unknown count, shown with no "of N" and no Last button. The declarative form is ui::Pager.

Example:

auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
auto pager = std::make_unique<ui::PagerControl>();
pager->set_number_of_pages(12);
pager->set_display_mode(ui::PagerDisplayMode::ButtonPanel);
pager->set_first_button_visibility(ui::PagerButtonVisibility::Hidden);
pager->set_last_button_visibility(ui::PagerButtonVisibility::Hidden);
pager->on_selection_changed([](std::size_t page) { std::println("show page {}", page); });
ui::PagerControl* observer = stack->add(std::move(pager));
observer->set_selected_index(3); // "4" underlined; fires the handler with 3

// Or declaratively:
ui::Property<std::size_t> page{0};
stack->add(ui::Pager{
    .selected_index       = page,
    .number_of_pages      = 25,
    .on_selection_changed = [&](std::size_t index) { std::println("page {}", index); },
}.build());

ui::Pager

Navigation through a numbered collection of pages: First/Previous, a page selector, and Next/Last. Builds a ui::PagerControl.

number_of_pages is applied before selected_index, so a selection past the default of zero pages is not clamped away.

Example:

ui::Property<std::size_t> page{2};

window.set_content(ui::Pager{
    .selected_index       = page,
    .number_of_pages      = 12,
    .display_mode         = ui::PagerDisplayMode::ComboBox,
    .prefix_text          = "Page",
    .suffix_text          = "of",
    .on_selection_changed = [](std::size_t now) { std::println("page {}", now); },
});

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

ui::Pager{
    .selected_index, .number_of_pages, .display_mode, .first_button_visibility,
    .previous_button_visibility, .next_button_visibility, .last_button_visibility,
    .button_panel_always_show_first_last_page_index, .prefix_text, .suffix_text, .style,
    .margin, .width, .height, .min_width, .min_height, .max_width, .max_height,
    .horizontal_alignment, .vertical_alignment, .visible, .tool_tip, .enabled, .accessibility,
    .on_selection_changed, .on_pointer_entered, .on_pointer_exited, .on_got_focus,
    .on_lost_focus, .on_key_down, .on_wheel, .control
}

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

Field Type Default
selected_index ui::TwoWayField<std::size_t> {0} The current page, 0-based.
number_of_pages ui::Binding<std::optional<std::size_t>> {std::size_t{0}} The page count; nullopt is an unknown count.
display_mode ui::Binding<ui::PagerDisplayMode> {ui::PagerDisplayMode::Auto} The page selector: Auto, ComboBox, NumberBox or ButtonPanel.
first_button_visibility ui::Binding<ui::PagerButtonVisibility> {ui::PagerButtonVisibility::Visible} How the First button shows.
previous_button_visibility ui::Binding<ui::PagerButtonVisibility> {ui::PagerButtonVisibility::Visible} How the Previous button shows.
next_button_visibility ui::Binding<ui::PagerButtonVisibility> {ui::PagerButtonVisibility::Visible} How the Next button shows.
last_button_visibility ui::Binding<ui::PagerButtonVisibility> {ui::PagerButtonVisibility::Visible} How the Last button shows.
button_panel_always_show_first_last_page_index ui::Binding<bool> {true} Whether the button panel always offers pages 1 and N.
prefix_text ui::Binding<std::optional<std::string>> Text before the page selector; unset uses strings().pager.prefix ("Page").
suffix_text ui::Binding<std::optional<std::string>> Text after the page selector; unset uses strings().pager.suffix ("of").
on_selection_changed ui::Callback<void(std::size_t)> Called with the new page index.
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::Pager> Out: the handle that receives the built control.

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

build

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

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

ui::PagerControl

Derives from ui::Element.

A pager: First / Previous buttons, a page selector ("Page [n] of N" in a NumberBox or drop-down, or a row of page buttons), and Next / Last buttons.

It is made of controls it owns (Buttons, a NumberBox, a ComboBox), each a tab stop of its own. Page indices are 0-based, and the selector shows them 1-based. The navigation buttons disable themselves on the first and last page. An unset page count is an unknown count, shown with no "of N" and no Last button. The declarative form is ui::Pager.

Example:

auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
auto pager = std::make_unique<ui::PagerControl>();
pager->set_number_of_pages(12);
pager->set_display_mode(ui::PagerDisplayMode::ButtonPanel);
pager->set_first_button_visibility(ui::PagerButtonVisibility::Hidden);
pager->set_last_button_visibility(ui::PagerButtonVisibility::Hidden);
pager->on_selection_changed([](std::size_t page) { std::println("show page {}", page); });
ui::PagerControl* observer = stack->add(std::move(pager));
observer->set_selected_index(3); // "4" underlined; fires the handler with 3

// Or declaratively:
ui::Property<std::size_t> page{0};
stack->add(ui::Pager{
    .selected_index       = page,
    .number_of_pages      = 25,
    .on_selection_changed = [&](std::size_t index) { std::println("page {}", index); },
}.build());

PagerControl

PagerControl()

Zero pages, on page 0, in Auto mode, with every navigation button Visible and the default prefix and suffix text. Builds all of its parts up front.

~PagerControl

~PagerControl() override

PagerControl

PagerControl(const PagerControl&) = delete

operator=

PagerControl& operator=(const PagerControl&) = delete

number_of_pages

std::optional<std::size_t> number_of_pages() const

The page count: 0 by default, nullopt for an unknown count.

set_number_of_pages

void set_number_of_pages(std::optional<std::size_t> pages)

Sets the page count; nullopt is an unknown count. A selection past the new last page moves onto it and fires on_selection_changed.

set_number_of_pages

template <std::signed_integral I>
void set_number_of_pages(I pages)

A count given as a signed number, which must not be negative. Pass std::nullopt for an unknown count.

selected_index

std::size_t selected_index() const

The current page, 0-based.

set_selected_index

void set_selected_index(std::size_t index)

Selects page index, clamped to the last page. With an unknown count there is no upper limit. A change fires on_selection_changed.

display_mode

PagerDisplayMode display_mode() const

Which page selector shows. Auto by default.

set_display_mode

void set_display_mode(PagerDisplayMode mode)

Swaps the page selector and updates the layout.

effective_display_mode

PagerDisplayMode effective_display_mode() const

The mode in use, with Auto resolved.

first_button_visibility

PagerButtonVisibility first_button_visibility() const

How the First button shows: Visible by default.

set_first_button_visibility

void set_first_button_visibility(PagerButtonVisibility visibility)

Shows, hides or collapses the First button and updates the layout.

previous_button_visibility

PagerButtonVisibility previous_button_visibility() const

How the Previous button shows: Visible by default.

set_previous_button_visibility

void set_previous_button_visibility(PagerButtonVisibility visibility)

Shows, hides or collapses the Previous button and updates the layout.

next_button_visibility

PagerButtonVisibility next_button_visibility() const

How the Next button shows: Visible by default.

set_next_button_visibility

void set_next_button_visibility(PagerButtonVisibility visibility)

Shows, hides or collapses the Next button and updates the layout.

last_button_visibility

PagerButtonVisibility last_button_visibility() const

How the Last button shows: Visible by default (never shown with an unknown page count).

set_last_button_visibility

void set_last_button_visibility(PagerButtonVisibility visibility)

Shows, hides or collapses the Last button and updates the layout.

button_panel_always_show_first_last_page_index

bool button_panel_always_show_first_last_page_index() const

Whether the button panel always offers page 1 and page N, with an ellipsis between them and the pages around the current one. True by default.

set_button_panel_always_show_first_last_page_index

void set_button_panel_always_show_first_last_page_index(bool show)

Rebuilds the button panel's slots.

prefix_text

const std::string& prefix_text() const

The text before the selector: the control's own, else strings().pager.prefix ("Page").

set_prefix_text

void set_prefix_text(std::optional<std::string> text)

Sets the text before the selector, or with nullopt goes back to strings().pager.prefix, and updates the layout.

suffix_text

const std::string& suffix_text() const

The text between the selector and the page count: the control's own, else strings().pager.suffix ("of").

set_suffix_text

void set_suffix_text(std::optional<std::string> text)

Sets the text between the selector and the page count, or with nullopt goes back to strings().pager.suffix, and updates the layout.

on_selection_changed

void on_selection_changed(Callback<void(std::size_t)> handler)

Fired with the new page index when the selection changes.

first_button

ButtonControl* first_button() const

The First button, owned by the pager (present even while hidden).

previous_button

ButtonControl* previous_button() const

The Previous button, owned by the pager.

next_button

ButtonControl* next_button() const

The Next button, owned by the pager.

last_button

ButtonControl* last_button() const

The Last button, owned by the pager.

number_box

NumberBoxControl* number_box() const

The NumberBox selector, owned by the pager; only laid out in NumberBox mode.

combo_box

ComboBoxControl* combo_box() const

The drop-down selector, owned by the pager; only laid out in ComboBox mode.

first_button_visible

bool first_button_visible() const

Whether a navigation button is drawn (not collapsed, and not hidden on its edge).

previous_button_visible

bool previous_button_visible() const

As first_button_visible(), for Previous.

next_button_visible

bool next_button_visible() const

As first_button_visible(), for Next.

last_button_visible

bool last_button_visible() const

As first_button_visible(), for Last.

button_panel_items

std::vector<int> button_panel_items() const

The button panel as a caller sees it: page numbers, and 0 for an ellipsis.

button_panel_selected_item

int button_panel_selected_item() const

Which button_panel_items() entry the indicator underlines, or -1.

button_panel_button

ButtonControl* button_panel_button(std::size_t slot) const

The page-number button in button panel slot slot; nullptr when that slot is not a page button.

for_each_child

void for_each_child(ChildVisitor visit) const override

Lists the shown parts in tab order: First, Previous, the selector, Next, Last. Hidden parts get no focus, show no popups and are left out of automation.

automation_role

AutomationRole automation_role() const override

AutomationRole::Menu, over its parts.

measure_override

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

One row as tall as the tallest shown part: the left button pair, the selector, the right pair.

arrange_override

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

The selector centered, First/Previous hugging it from the left and Next/Last from the right.

render_override

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

Draws the shown parts and, in ButtonPanel mode, the 2px accent indicator.

clear_dirty_override

void clear_dirty_override(DirtyFlags flags) override

Clears the pager's flags and every part's, shown or not, unlike for_each_child(), so a part that is shown again does not carry flags from before it was hidden.

enabled_changed

void enabled_changed() override

is_enabled() flipped, through set_enabled() here or on an ancestor, or a move to another parent. Drop any press or hover state. The element is redrawn either way. No-op by default.

Enumerations

PagerDisplayMode

enum class PagerDisplayMode

Which page selector a Pager shows.

Value
Auto ComboBox under ten pages; NumberBox from ten, or with an unknown count.
ComboBox "Page [drop-down] of N": a drop-down of page numbers.
NumberBox "Page [n] of N": a NumberBox the page number is typed into.
ButtonPanel A row of page-number buttons with ellipses, the current page underlined in the accent.

PagerButtonVisibility

enum class PagerButtonVisibility

How a Pager shows one of its First/Previous/Next/Last buttons.

Value
Visible Always shown; still disabled on its own edge.
HiddenOnEdge invisible and disabled on its own edge, its room kept
Hidden collapsed: takes no room at all

Tests

  • tests/test_pager.cpp