TileView¶
Header: winui/ui/collections/TileView.hpp. Spec: winui/ui/collections/TileView.hpp.
Templated items in wrapping rows of equal cells, virtualized and selectable.
Every cell is the size of the first item's container, or set_item_width() and set_item_height_cell(). A line holds as many cells as fit, or maximum_rows_or_columns(). Each item sits in a container with a backplate for hover and press, a 2 pixel accent frame when selected, and a check box in the top-right corner in Multiple mode. Items, templates, selection, drag reordering and scrolling come from ListViewBase. When grouped (set_group_keys()), each group header takes a line of its own and its cells start on the next.
Example:
// Declarative: a 3-column picker of 96x96 tiles.
std::vector<std::string> names{"Red", "Green", "Blue", "Cyan", "Magenta", "Yellow"};
window.set_content(ui::TileView<std::string>{
.items = names,
.maximum_rows_or_columns = 3,
.on_item_click = [](const std::string& name) { std::println("picked {}", name); },
.item = [](const std::string& name) -> ui::Spec {
return ui::Text{.text = name, .width = 96.0f, .height = 96.0f};
},
});
// Imperative:
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
auto grid = std::make_unique<ui::TileViewControl>();
grid->set_item_template([](std::size_t i) { return std::make_unique<ui::TextControl>(std::to_string(i)); });
grid->set_item_count(12);
grid->set_item_width(100.0f);
grid->set_item_height_cell(64.0f);
grid->set_selection_mode(ui::SelectionMode::Multiple);
stack->add(std::move(grid));
ui::TileView¶
Templated items in rows of equal cells. Builds a ui::TileViewControl.
It shares ListViewBase with ui::ListView. .items, .item and .key take the same sources, and selection, click, drag and reorder work the same way. The cells wrap. .layout swaps the equal cells for another arrangement and keeps everything else.
Example:
std::vector<ui::Color> swatches{ui::Color::from_rgb(0xE81123), ui::Color::from_rgb(0x0078D4),
ui::Color::from_rgb(0x107C10), ui::Color::from_rgb(0xFFB900)};
ui::Property<ui::Color> picked{ui::colors::Black};
window.set_content(ui::TileView<ui::Color>{
.items = swatches,
.maximum_rows_or_columns = 4,
.on_item_click = [&](const ui::Color& color) { picked = color; },
.item = [](const ui::Color& color) -> ui::Spec
{ return ui::Border{.background = color, .width = 40.0f, .height = 40.0f}; },
});
Every field, in the order a designated initializer names them:
ui::TileView{
.header, .items, .key, .selected_index, .selected_indices, .item_transitions,
.selection_mode, .item_click_enabled, .item_invoked_enabled, .can_drag_items,
.can_reorder_items, .allow_drop, .group_by, .sticky_group_headers,
.maximum_rows_or_columns, .layout, .orientation, .background, .border_brush,
.border_thickness, .item_container_margin, .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_item_click,
.on_item_invoked, .on_drag_items_starting, .on_drag_items_completed, .on_items_reordered,
.on_pointer_entered, .on_pointer_exited, .on_got_focus, .on_lost_focus, .on_key_down,
.on_wheel, .control, .header_content, .footer_content, .item, .group_header_template,
.item_context_menu
}
Fields, in declaration order (designators must follow it):
| Field | Type | Default | |
|---|---|---|---|
header |
ui::Binding<std::string> |
A plain-text header above the first cell, in the group headers' text style. header_content wins over it. |
|
items |
ui::Binding<std::vector<T>> |
The collection: a ui::ObservableVectorui::Property<std::vector<T>>, a plain vector or a braced list. |
|
key |
ui::ItemKey<std::type_identity_t<T>> |
What identifies an item when .items is bound to a property; see ui::ListView. |
|
selected_index |
ui::TwoWayField<std::optional<std::size_t>> |
The selected item's index. Unset, the default, means nothing is selected. | |
selected_indices |
ui::Binding<std::vector<std::size_t>> |
Every selected item, as ascending positions in the collection. Bind a ui::Property<std::vector<std::size_t>> to read and set the selection under Multiple or Extended. Two-way with ui::bind(). Left empty and unbound, .selected_index decides. |
|
item_transitions |
ui::Binding<ui::TransitionList> |
Transitions every item container runs (ui::TileViewControl::set_item_transitions()). | |
selection_mode |
ui::Binding<ui::SelectionMode> |
{ui::SelectionMode::Single} |
None, Single (the default), Multiple (check boxes) or Extended. |
item_click_enabled |
ui::Binding<bool> |
{false} |
Whether clicks raise on_item_click, before they select. Setting on_item_click turns it on unless it is bound. |
item_invoked_enabled |
ui::Binding<bool> |
{false} |
Whether Enter and double-clicks raise on_item_invoked. Setting on_item_invoked turns it on unless it is bound. |
can_drag_items |
ui::Binding<bool> |
{false} |
Whether items can be dragged out; see on_drag_items_starting. |
can_reorder_items |
ui::Binding<bool> |
{false} |
Whether dragging within the view moves the item, in the view and in the collection. |
allow_drop |
ui::Binding<bool> |
{false} |
Whether the view accepts drops. |
group_by |
ui::Callback<std::string(const std::type_identity_t<T>&)> |
Files the items under group headers by the key it returns for each item. The groups come in the order their keys first appear, and the items keep their order within a group, without sorting. Each header takes a line of its own, and the group's cells start on the next. Asked again on every collection change. Positions in the collection stay the indices. | |
sticky_group_headers |
ui::Binding<bool> |
{true} |
Whether the current group's header stays pinned at the top while its cells scroll under it. |
maximum_rows_or_columns |
ui::Binding<std::size_t> |
{0} |
The most cells in a line before wrapping; 0 is no limit. With a ui::TileLayout in layout, 0 keeps the layout's own maximum_rows_or_columns and anything else overrides it. |
layout |
ui::LayoutSpec |
How the cells are placed: equal cells when left out, ui::WrapLayout{} for cells of their own width, ui::LinedFlowLayout{} for a photo wall. With a layout other than a tile layout, maximum_rows_or_columns and orientation have no effect. |
|
orientation |
ui::Binding<std::optional<ui::Orientation>> |
The direction cells are laid in before they wrap, which also sets the scroll axis. Unset takes the orientation of a ui::TileLayout in layout, else Horizontal. When set, it overrides the layout's. |
|
background |
ui::Binding<ui::Paint> |
Background behind the cells; nullopt draws none. | |
border_brush |
ui::Binding<ui::Paint> |
The border color: a fixed color, or a theme color read again on a theme change. | |
border_thickness |
ui::Binding<ui::Thickness> |
The border thickness, DIPs; zero (the default) draws no border. | |
item_container_margin |
ui::Binding<std::optional<ui::Thickness>> |
{std::nullopt} |
Every item container's margin. nullopt keeps the default 0,0,4,4. |
on_selection_changed |
ui::Callback<void(ui::SelectedItem<std::type_identity_t<T>>)> |
Called with a copy of the first selected item, unset when nothing is selected (see ui::SelectedItem). The copy is safe to keep. | |
on_item_click |
ui::Callback<void(const std::type_identity_t<T>&)> |
Called with the clicked item. Turns item_click_enabled on. The reference is valid during the call. An item of a ui::ObservableVector stays at its address while it is in the collection. |
|
on_item_invoked |
ui::Callback<void(const std::type_identity_t<T>&)> |
Called with the item on Enter or a double-click. With SelectionMode::None a click or Space also invokes. Turns item_invoked_enabled on. The reference is valid as for on_item_click. |
|
on_drag_items_starting |
ui::Callback<ui::Decision(const ui::DragItemsStartingArgs&)> |
A drag of items starts. Fill in the drag package, or cancel. The args name the items by position. | |
on_drag_items_completed |
ui::Callback<void(const ui::DragItemsCompletedArgs&)> |
A drag of items ended, with the positions of the dragged items and what the drop did. | |
on_items_reordered |
ui::Callback<void(const ui::ItemsReorderedArgs&)> |
A reorder moved the item at position from to to. The collection has already been moved. |
|
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<std::type_identity_t<ui::TileView>> |
Out: the handle that receives the built control. Its type uses std::type_identity_t, so passing a handle does not take part in deducing the type argument. | |
header_content |
ui::Spec |
Content above the first cell (header_content) and after the last (footer_content). Both scroll with the cells. |
|
footer_content |
ui::Spec |
See header_content. |
|
item |
ui::Callback<ui::Spec(std::type_identity_t<T>&)> |
How one cell looks: a callable taking const T&, or T& to edit an item of a ui::ObservableVector. Left out, an item that is text is shown as that text. Any other item type needs one, and a debug build asserts without it. |
|
group_header_template |
ui::Callback<ui::Spec(const std::string& key)> |
A group header's content, given the group's key. Left out, the header shows the key as text. Needs .group_by. |
|
item_context_menu |
ui::Callback<std::vector<ui::MenuItem>(const std::type_identity_t<T>&)> |
The context menu of an item: a callable taking the item and returning the menu's entries. Called on a right-click on the item, or on Shift+F10 or the Menu key while it is current. The item is selected first. An empty list opens no menu. An item of a ui::ObservableVector stays where it is while it is in the collection, so an entry's on_click may keep a reference to it. Any other item is valid during the call only, so capture it by value. |
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¶
Consumes the spec and returns the built ui::TileViewControl; the caller owns it.
ui::TileViewControl¶
Derives from ui::ListViewBase.
Templated items in wrapping rows of equal cells, virtualized and selectable.
Every cell is the size of the first item's container, or set_item_width() and set_item_height_cell(). A line holds as many cells as fit, or maximum_rows_or_columns(). Each item sits in a container with a backplate for hover and press, a 2 pixel accent frame when selected, and a check box in the top-right corner in Multiple mode. Items, templates, selection, drag reordering and scrolling come from ListViewBase. When grouped (set_group_keys()), each group header takes a line of its own and its cells start on the next.
Example:
// Declarative: a 3-column picker of 96x96 tiles.
std::vector<std::string> names{"Red", "Green", "Blue", "Cyan", "Magenta", "Yellow"};
window.set_content(ui::TileView<std::string>{
.items = names,
.maximum_rows_or_columns = 3,
.on_item_click = [](const std::string& name) { std::println("picked {}", name); },
.item = [](const std::string& name) -> ui::Spec {
return ui::Text{.text = name, .width = 96.0f, .height = 96.0f};
},
});
// Imperative:
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
auto grid = std::make_unique<ui::TileViewControl>();
grid->set_item_template([](std::size_t i) { return std::make_unique<ui::TextControl>(std::to_string(i)); });
grid->set_item_count(12);
grid->set_item_width(100.0f);
grid->set_item_height_cell(64.0f);
grid->set_selection_mode(ui::SelectionMode::Multiple);
stack->add(std::move(grid));
TileViewControl¶
An empty grid in Single selection mode, horizontal orientation.
set_layout¶
Replaces the layout that places the cells and returns an observer. The default is equal cells (a TileLayoutEngine). Use a WrapLayoutEngine for cells of their own width, or a LinedFlowLayoutEngine for a photo wall. nullptr restores the default. With a layout that is not a TileLayoutEngine, the cell setters below have no effect, and the arrow keys find the item above or below by where the items are.
maximum_rows_or_columns¶
The most cells per row (per column when Vertical); 0 (the default) is as many as fit.
set_maximum_rows_or_columns¶
Caps the cells per row (per column when Vertical) and lays the view out again.
orientation¶
The fill direction; Horizontal by default.
set_orientation¶
Changes the fill direction, and the scroll axis with it, and lays the view out again.
set_item_width¶
Sets the cell width in DIPs. nullopt, the default, takes the first item's width.
set_item_height_cell¶
Sets the cell height in DIPs. nullopt, the default, takes the first item's height. It has its own name because ListViewBase::set_item_height() sets the list container height.
Tests¶
tests/test_list_view_base.cpp