Swipe¶
Header: winui/ui/scrolling/Swipe.hpp. Spec: winui/ui/scrolling/Swipe.hpp.
Reveals a strip of action items beside its content when the content is dragged sideways: the "swipe a list row to reveal Delete/Archive" pattern.
Dragging right reveals the left items, and dragging left the right ones. The control owns its content, which stays fully interactive. The items work with the mouse only and are not exposed to accessibility tools. The declarative form is ui::Swipe.
Example:
void reply(); // the app's own
void delete_row(); // the app's own
ui::SwipeItem reply_item{ .text = "Reply", .icon = ui::IconGlyph{0xE8C2}, .on_invoked = [&] { reply(); } };
ui::SwipeItem delete_item{ .text = "Delete",
.icon = ui::IconGlyph{0xE74D},
.background = ui::theme_colors::Critical,
.on_invoked = [&] { delete_row(); } };
window.set_content(ui::Swipe{
.left_items = { reply_item },
.right_items = { delete_item },
.right_mode = ui::SwipeMode::Execute,
.height = 68,
.content = ui::Text{ .text = "Swipe me",
.margin = ui::Thickness{12},
.vertical_alignment = ui::Alignment::Center },
});
// Imperatively:
auto swipe = std::make_unique<ui::SwipeControl>();
swipe->set_content(std::make_unique<ui::TextControl>("Swipe me"));
swipe->set_left_items({ .items = { reply_item } });
swipe->set_right_items({ .items = { delete_item }, .mode = ui::SwipeMode::Execute });
ui::Swipe¶
Reveals a strip of action items when its child is dragged sideways, as a list row's swipe actions. Builds a ui::SwipeControl. The callbacks are on each ui::SwipeItem, so the spec has no .on_* handler of its own for them.
Example:
struct Row { std::string name; };
ui::Spec swipe_row(const Row& row, std::function<void()> remove) // captures by value
{
return ui::Swipe{
.left_items = {{.text = "Flag", .icon = ui::Symbol::Flag}},
.right_items = {{.text = "Delete",
.background = ui::Color::from_rgba(196, 43, 28),
.on_invoked = [remove] { remove(); }}},
.right_mode = ui::SwipeMode::Execute,
.content = ui::Text{.text = row.name, .margin = ui::Thickness{12.0f}},
};
}
Every field, in the order a designated initializer names them:
ui::Swipe{
.left_items, .left_mode, .right_items, .right_mode, .background, .border_brush,
.border_thickness, .style, .margin, .width, .height, .min_width, .min_height, .max_width,
.max_height, .horizontal_alignment, .vertical_alignment, .visible, .tool_tip, .enabled,
.accessibility, .on_pointer_entered, .on_pointer_exited, .on_got_focus, .on_lost_focus,
.on_key_down, .on_wheel, .control, .content
}
Fields, in declaration order (designators must follow it):
| Field | Type | Default | |
|---|---|---|---|
left_items |
ui::Binding<std::vector<ui::SwipeItem>> |
Revealed by dragging the content to the right. | |
left_mode |
ui::SwipeMode |
ui::SwipeMode::Reveal |
Reveal, the default, shows the items to click. Execute invokes the single item on release. |
right_items |
ui::Binding<std::vector<ui::SwipeItem>> |
Revealed by dragging the content to the left. | |
right_mode |
ui::SwipeMode |
ui::SwipeMode::Reveal |
As left_mode, for right_items. |
background |
ui::Binding<ui::Paint> |
The fill, border color and border width behind the content, which move with it. A color is fixed or a theme resource, read again when the theme changes. | |
border_brush |
ui::Binding<ui::Paint> |
See background. |
|
border_thickness |
ui::Binding<ui::Thickness> |
See background. |
|
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::Swipe> |
Out: the handle that receives the built control. | |
content |
ui::Spec |
The row content that slides to reveal the items. |
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::SwipeControl; the caller owns it.
ui::SwipeControl¶
Derives from ui::Element.
Reveals a strip of action items beside its content when the content is dragged sideways: the "swipe a list row to reveal Delete/Archive" pattern.
Dragging right reveals the left items, and dragging left the right ones. The control owns its content, which stays fully interactive. The items work with the mouse only and are not exposed to accessibility tools. The declarative form is ui::Swipe.
Example:
void reply(); // the app's own
void delete_row(); // the app's own
ui::SwipeItem reply_item{ .text = "Reply", .icon = ui::IconGlyph{0xE8C2}, .on_invoked = [&] { reply(); } };
ui::SwipeItem delete_item{ .text = "Delete",
.icon = ui::IconGlyph{0xE74D},
.background = ui::theme_colors::Critical,
.on_invoked = [&] { delete_row(); } };
window.set_content(ui::Swipe{
.left_items = { reply_item },
.right_items = { delete_item },
.right_mode = ui::SwipeMode::Execute,
.height = 68,
.content = ui::Text{ .text = "Swipe me",
.margin = ui::Thickness{12},
.vertical_alignment = ui::Alignment::Center },
});
// Imperatively:
auto swipe = std::make_unique<ui::SwipeControl>();
swipe->set_content(std::make_unique<ui::TextControl>("Swipe me"));
swipe->set_left_items({ .items = { reply_item } });
swipe->set_right_items({ .items = { delete_item }, .mode = ui::SwipeMode::Execute });
SwipeControl¶
No content and no items; closed.
~SwipeControl¶
SwipeControl¶
set_content¶
Takes ownership of the swiped content and returns a non-owning pointer to it. The content is always measured, arranged, drawn and reachable. Only its drawn position changes.
content¶
The swiped content (owned by the control), or null.
left_items¶
Revealed by dragging the content to the right.
set_left_items¶
Replaces the item list and snaps closed.
right_items¶
Revealed by dragging the content to the left.
set_right_items¶
Replaces the item list and snaps closed.
set_background¶
The fill behind the content, moving with it. Transparent by default.
set_background¶
The fill behind the content as a theme resource, re-read on a theme change.
set_border_brush¶
The border color around the content, moving with it.
set_border_brush¶
The border color as a theme resource, re-read on a theme change.
set_border_thickness¶
The border width in DIPs, inside the control's bounds. Lays the control out again.
offset¶
Positive: the left items revealed by this many DIPs. Negative: the right items revealed by |offset|. Zero: closed.
is_open¶
Whether a strip shows, or is sliding open.
close¶
Slides the strip shut.
for_each_child¶
Visits the content, the only child. The control itself is not focusable, and whatever is focusable in the content is always in the tab order. The items are not children: they work with the mouse only and are not exposed to accessibility tools.
measure_override¶
The content's size plus the border, and at least an item's minimum height while there are items to reveal. Also measures the items' widths.
arrange_override¶
Arranges the content inside the border. offset() shifts it only when drawing.
render_override¶
Draws the revealed strip, then the background, border and content shifted by offset().
pointer_override¶
A horizontal drag moves the strip and takes the gesture from the content. A tap on an item invokes it, and a tap on the content while open closes the strip.
handled_pointer_override¶
A press and release the content took still start and end a drag, so a swipe can begin on a button.
covers_children_at¶
Open or dragged, the strip covers the content.
tick_override¶
Ticks the content, then advances the 250 ms snap, invoking an Execute item as it settles.
enabled_changed¶
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.
struct SwipeItem¶
One action in a SwipeControl's strip: a label under an icon, its own colors, and what happens when it is invoked. A value type, built with designated initializers and handed over in a SwipeItems list.
Example:
void archive_message(); // the app's own
ui::SwipeItem archive{
.text = "Archive",
.icon = ui::IconGlyph{0xE7B8},
.background = ui::Color::from_argb(0xFF3E6FA7),
.foreground = ui::colors::White,
.on_invoked = [&] { archive_message(); },
};
text¶
The text. Falls back to the command's text.
icon¶
The icon, drawn 16 DIPs tall above the text. Falls back to the command's icon.
background¶
A color, a brush or a ThemeColor. In Execute mode a gradient spans the whole control. Empty uses the theme's item background in Reveal, and in Execute the theme's two colors for before and after the swipe passes its threshold.
foreground¶
The text and icon color. Unset uses the theme's item foreground, which in Execute is a pair for before and after the threshold.
behavior_on_invoked¶
What the strip does after the item is invoked.
command¶
A command run after on_invoked, while it is enabled. Its text and icon fill the text and icon left empty.
command_parameter¶
Handed to the command's execute.
on_invoked¶
Fires on a tap in Reveal mode or a completed swipe in Execute mode, before the command runs.
display_text¶
The text drawn: text, or the command's text when text is empty.
display_icon¶
The icon drawn: icon, or the command's icon when icon is empty.
struct SwipeItemInvokedEventArgs¶
The arguments of an item's on_invoked: the item that was invoked, whose text or icon the handler may change, and the control it was swiped from.
| Field | Type | Default | |
|---|---|---|---|
swipe_control |
SwipeControl& |
The control the item was swiped from. | |
item |
SwipeItem& |
The invoked item. Its text and icon may be changed here. |
class SwipeItemInvokedHandler¶
SwipeItem::on_invoked's handler: a callable that takes the event args, or one that takes nothing.
Copyable, since SwipeItem lives in a std::vector that a caller builds with a brace list.
Example:
bool flagged = false;
ui::SwipeItem flag{ .text = "Flag", .on_invoked = [&] { flagged = true; } };
ui::SwipeItem mark_read{ .text = "Mark read",
.on_invoked = [](ui::SwipeItemInvokedEventArgs& e) { e.item.text = "Marked"; } };
SwipeItemInvokedHandler¶
No handler. Invoking it does nothing.
SwipeItemInvokedHandler¶
template <typename F>
SwipeItemInvokedHandler(F handler)
requires std::invocable<F&> || std::invocable<F&, SwipeItemInvokedEventArgs&>
Wraps a callable taking SwipeItemInvokedEventArgs&, or one taking nothing.
operator()¶
Calls the handler, if there is one.
operator bool¶
Whether a handler is set.
struct SwipeItems¶
One side's items and how they are revealed. An Execute set shows a single item, as wide as the control.
| Field | Type | Default | |
|---|---|---|---|
items |
std::vector<SwipeItem> |
The strip's items, in order from the left. | |
mode |
SwipeMode |
SwipeMode::Reveal |
Reveal (a drawer) or Execute (swipe to run). |
Enumerations¶
SwipeMode¶
How a Swipe side shows its items. Reveal opens a drawer of items at their natural widths, as far as it is dragged. Execute shows one item as wide as the control, invoked by swiping it all the way, as in "swipe to archive".
| Value | |
|---|---|
Reveal |
A drawer of items at their natural widths. A tap invokes one. |
Execute |
One item as wide as the control, invoked by swiping past the threshold. |
SwipeBehaviorOnInvoked¶
What the strip does after an item is invoked. Auto closes, as Close does, in both modes.
| Value | |
|---|---|
Auto |
Close after the item runs. |
Close |
Close after the item runs. |
RemainOpen |
Leave the strip open after the item runs. |
Tests¶
tests/test_swipe.cpp