AnnotatedScrollBar¶
Header: winui/ui/scrolling/AnnotatedScrollBar.hpp. Spec: winui/ui/scrolling/AnnotatedScrollBar.hpp.
A vertical scroll bar with a rail you click or drag to jump, up and down step buttons, and offset annotations that stay visible and hide when they collide. It is for moving through long grouped content, such as a photo timeline or an alphabetical list.
Attach it to a Scroll with set_target(). It then follows the view's range, viewport and offset, scrolls it right away, and hides the view's own scroll bar while attached. For any other scrollable, leave the target unset, call set_maximum(), set_viewport_size() and set_value() yourself, and handle on_scroll_to_requested() and on_scroll_by_requested(). The top step button is AnnotatedScrollBarScrollingEventKind::IncrementButton and scrolls up, toward 0. on_detail_text_requested() supplies the floating tooltip shown over the rail while hovering or dragging. The arrow keys step, and Home and End jump to the ends.
Example:
const std::string long_text = "A text much taller than the window...";
ui::Control<ui::Scroll> view;
ui::Control<ui::AnnotatedScrollBar> bar;
window.set_content(ui::HorizontalStack{
.content = {
ui::Scroll{.max_height = 500.0f,
.control = view,
.content = ui::Text{.text = long_text, .wrapping = ui::TextWrapping::Wrap}},
ui::AnnotatedScrollBar{
.annotations = {{.text = "2024", .scroll_offset = 0.0},
{.text = "2025", .scroll_offset = 2400.0},
{.text = "2026", .scroll_offset = 5100.0}},
.max_height = 500.0f,
.on_detail_text_requested = [](double offset) { return std::format("{:.0f} px", offset); },
.control = bar,
},
},
});
bar->set_target(view); // bar now drives and mirrors the Scroll
bar->on_scrolling([](const ui::AnnotatedScrollBarScrollingArgs& args) {
const bool far_drag = args.kind == ui::AnnotatedScrollBarScrollingEventKind::Drag && args.offset > 9000.0;
return far_drag ? ui::Cancel : ui::Proceed;
});
ui::AnnotatedScrollBar¶
A vertical scroll bar with step buttons, a rail you click or drag to jump, and offset annotations that hide when they collide. Builds a ui::AnnotatedScrollBarControl. There is no .target field. Call set_target() on .control once both the bar and the ui::ScrollControl exist.
Example:
ui::Spec make_photo_grid(); // the app's own content
ui::Control<ui::Scroll> view;
ui::Control<ui::AnnotatedScrollBar> bar;
window.set_content(ui::HorizontalStack{.content = {
ui::Scroll{.max_height = 500.0f, .control = view, .content = make_photo_grid()},
ui::AnnotatedScrollBar{
.annotations = {{.text = "2024", .scroll_offset = 0.0},
{.text = "2025", .scroll_offset = 2400.0},
{.text = "2026", .scroll_offset = 5100.0}},
.max_height = 500.0f,
.on_detail_text_requested = [](double offset) { return std::format("{:.0f} px", offset); },
.control = bar,
},
}});
bar->set_target(view); // the bar now drives and mirrors the Scroll
Every field, in the order a designated initializer names them:
ui::AnnotatedScrollBar{
.value, .maximum, .small_change, .viewport_size, .annotations, .style, .margin, .width,
.height, .min_width, .min_height, .max_width, .max_height, .horizontal_alignment,
.vertical_alignment, .visible, .tool_tip, .enabled, .accessibility, .on_scrolling,
.on_detail_text_requested, .on_scroll_to_requested, .on_scroll_by_requested,
.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 | |
|---|---|---|---|
value |
ui::Binding<double> |
{0.0} |
The current offset in DIPs, for an unattached bar. Moves the thumb only and raises no scroll request. |
maximum |
ui::Binding<double> |
{0.0} |
The largest scroll offset in DIPs, for an unattached bar. The minimum is 0. |
small_change |
ui::Binding<double> |
{0.0} |
How far a step button or arrow key moves, in DIPs. 0, the default, derives it from the viewport. |
viewport_size |
ui::Binding<double> |
{0.0} |
The visible extent in DIPs, for an unattached bar. Sizes the thumb. |
annotations |
ui::Binding<std::vector<ui::AnnotatedScrollBarAnnotation>> |
Captions pinned beside the rail at scroll offsets. One that overlaps an earlier one hides. | |
on_scrolling |
ui::Callback<ui::Decision(const ui::AnnotatedScrollBarScrollingArgs&)> |
Raised before every scroll request, with the target offset and what caused it. Return ui::Cancel to drop it. | |
on_detail_text_requested |
ui::Callback<std::string(double)> |
The tooltip text for the offset under the pointer. Unset shows no tooltip. | |
on_scroll_to_requested |
ui::Callback<void(double)> |
Scroll to an absolute offset in DIPs. set_target() installs its own. Set it for another kind of scrollable. | |
on_scroll_by_requested |
ui::Callback<void(double)> |
Scroll by a delta in DIPs, negative is up. set_target() installs its own, too. | |
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::AnnotatedScrollBar> |
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¶
Consumes the spec and returns the built ui::AnnotatedScrollBarControl; the caller owns it.
ui::AnnotatedScrollBarControl¶
Derives from ui::Element, ui::RangeValueProvider.
A vertical scroll bar with a rail you click or drag to jump, up and down step buttons, and offset annotations that stay visible and hide when they collide. It is for moving through long grouped content, such as a photo timeline or an alphabetical list.
Attach it to a Scroll with set_target(). It then follows the view's range, viewport and offset, scrolls it right away, and hides the view's own scroll bar while attached. For any other scrollable, leave the target unset, call set_maximum(), set_viewport_size() and set_value() yourself, and handle on_scroll_to_requested() and on_scroll_by_requested(). The top step button is AnnotatedScrollBarScrollingEventKind::IncrementButton and scrolls up, toward 0. on_detail_text_requested() supplies the floating tooltip shown over the rail while hovering or dragging. The arrow keys step, and Home and End jump to the ends.
Example:
const std::string long_text = "A text much taller than the window...";
ui::Control<ui::Scroll> view;
ui::Control<ui::AnnotatedScrollBar> bar;
window.set_content(ui::HorizontalStack{
.content = {
ui::Scroll{.max_height = 500.0f,
.control = view,
.content = ui::Text{.text = long_text, .wrapping = ui::TextWrapping::Wrap}},
ui::AnnotatedScrollBar{
.annotations = {{.text = "2024", .scroll_offset = 0.0},
{.text = "2025", .scroll_offset = 2400.0},
{.text = "2026", .scroll_offset = 5100.0}},
.max_height = 500.0f,
.on_detail_text_requested = [](double offset) { return std::format("{:.0f} px", offset); },
.control = bar,
},
},
});
bar->set_target(view); // bar now drives and mirrors the Scroll
bar->on_scrolling([](const ui::AnnotatedScrollBarScrollingArgs& args) {
const bool far_drag = args.kind == ui::AnnotatedScrollBarScrollingEventKind::Drag && args.offset > 9000.0;
return far_drag ? ui::Cancel : ui::Proceed;
});
AnnotatedScrollBarControl¶
An unattached bar with an empty range and no annotations.
maximum¶
The largest scroll offset, in DIPs. The minimum is always 0, as for Scroll. With a target attached, the target's current scrollable_height().
set_maximum¶
Sets the range for an unattached bar and redraws. Ignored while target() is attached, since maximum() then reads target()->scrollable_height().
viewport_size¶
The visible extent in DIPs, which sizes the thumb and the automatic small change. With a target attached, the target's current height.
set_viewport_size¶
Sets the viewport extent for an unattached bar and redraws. Ignored while target() is attached, since viewport_size() then reads target()->bounds().height.
value¶
The current scroll offset in DIPs, 0 to maximum(). With a target attached, its current vertical_offset().
set_value¶
Moves the thumb and annotations only, and raises no scroll request. Ignored while target() is attached, since value() then reads target()->vertical_offset().
target¶
The Scroll this bar drives, or null, in which case the manual range values apply.
set_target¶
Attaches the bar to target, which must outlive this control. The bar does not own it. Installs the bar's own on_scroll_to_requested() and on_scroll_by_requested() handlers, replacing any set before. While attached, the target's own scroll bar is hidden (ScrollControl::set_show_scrollbar(false)), and it comes back when the bar detaches or moves to another target. Pass nullptr to detach. That clears the two handlers and goes back to the manual maximum(), viewport_size() and value(). Set on_scroll_to_requested() and on_scroll_by_requested() again afterward to drive another kind of scrollable.
annotations¶
The annotations, in the order given.
set_annotations¶
Replaces the annotations, then lays out again, since the annotations column fits the widest one, and redraws.
small_change¶
How far a step button or an arrow key moves value(), in DIPs. 0, the default, means automatic: an eighth of viewport_size().
set_small_change¶
Sets the step size in DIPs; negative values are taken as 0 (auto).
on_scrolling¶
Raised before every scroll request, whether from a click, a drag, a step button, an arrow key, or Home or End. Returning ui::Cancel drops the request.
on_detail_text_requested¶
Text for the floating detail tooltip shown while hovering over or dragging the rail, given the offset under the pointer. No tooltip opens while this is unset.
on_scroll_to_requested¶
Request to scroll to offset, in DIPs. set_target() installs its own handler. Set it yourself to drive a scrollable that is not a Scroll.
on_scroll_by_requested¶
Low-level request to scroll by delta DIPs (step buttons, arrow keys); negative is up.
focused¶
Whether the bar has keyboard focus.
focusable¶
Focusable while enabled.
automation_role¶
Exposed to accessibility tools as a Slider, with a range value, since it shows and sets a bounded scroll value.
measure_override¶
The labels column, as wide as the widest label, plus the fixed-width rail column. The height is what's offered.
pointer_override¶
Clicks and drags on the rail jump, the step buttons step, and hovering over the rail asks for the detail text.
render_override¶
Draws the rail, thumb, step buttons, visible labels and focus ring.
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.
focus_changed¶
Focus changes redraw the focus ring.
key_override¶
Up and Down step by small_change(). Home and End jump to 0 and maximum().
struct AnnotatedScrollBarAnnotation¶
A caption pinned beside a ui::AnnotatedScrollBar's rail at the position of a scroll offset. Annotations that would overlap a previous one are hidden.
| Field | Type | Default | |
|---|---|---|---|
text |
std::string |
Caption drawn right-aligned in the annotations column. | |
scroll_offset |
double |
0.0 |
Scroll offset (DIPs of the target's content) the annotation marks. |
struct AnnotatedScrollBarScrollingArgs¶
What on_scrolling gets before a scroll request is raised: where it goes and what caused it. The handler returns ui::Cancel to drop the request.
| Field | Type | Default | |
|---|---|---|---|
offset |
double |
0.0 |
The target offset. |
kind |
AnnotatedScrollBarScrollingEventKind |
AnnotatedScrollBarScrollingEventKind::Click |
What caused it. |
Enumerations¶
AnnotatedScrollBarScrollingEventKind¶
What caused an AnnotatedScrollBar scroll request. The top step button scrolls up, toward a smaller offset, and the bottom one scrolls down.
| Value | |
|---|---|
Click |
A click on the rail, Home or End, or an accessibility client setting the value. |
Drag |
Dragging along the rail. |
IncrementButton |
The top step button or Up arrow: scrolls toward 0. |
DecrementButton |
The bottom step button or Down arrow: scrolls toward maximum(). |
Tests¶
tests/test_annotated_scroll_bar.cpp