Parallax¶
Header: winui/ui/scrolling/Parallax.hpp. Spec: winui/ui/scrolling/Parallax.hpp.
Moves its single child at a different rate than another element scrolls, typically a background image behind a list or scroll view.
The child is laid out larger than the view by the shift, clipped to the view, and moved every frame through its own translation, which the Parallax controls from then on. The source is any element with Element::scroll_info(), such as a Scroll or a ListView. The Parallax does not own it and notices when it is destroyed. Set it after the tree is built. A source destroyed first stops the parallax. A Parallax is never focusable. ui::Parallax is the declarative form. It has no .source field, so set the source through .control.
Example:
auto row = std::make_unique<ui::StackControl>(ui::Orientation::Horizontal);
auto* parallax = row->add(std::make_unique<ui::ParallaxControl>());
parallax->set_vertical_shift(300.0f); // the background travels 300 DIPs over the whole scroll
parallax->set_child(std::make_unique<ui::TextControl>("Background"));
auto* scroll = row->add(std::make_unique<ui::ScrollControl>());
auto content = std::make_unique<ui::TextControl>("Tall content");
content->set_min_height(2000.0f);
scroll->set_child(std::move(content));
parallax->set_source(scroll); // non-owning; both already live in the same tree
window.set_content(std::move(row));
ui::Parallax¶
Moves one child at a different rate than another element scrolls. Builds a ui::ParallaxControl. There is no .source field. Call set_source() on .control once both the view and its source exist.
Example:
const std::vector<std::string> titles{"Arches", "Bryce Canyon", "Zion"};
ui::Control<ui::Parallax> parallax;
ui::Control<ui::ListView<std::string>> list;
window.set_content(ui::Grid{
.height = 700.0f,
.content = {
ui::Cell{.content = ui::Parallax{.vertical_shift = 500.0f,
.vertical_alignment = ui::Alignment::Leading,
.control = parallax,
.content = ui::Image{.source = ui::Bitmap::read("cliff.jpg")}}},
ui::Cell{.content = ui::ListView<std::string>{.items = titles, .control = list}},
},
});
parallax->set_source(list); // follow the list's scrolling
Every field, in the order a designated initializer names them:
ui::Parallax{
.horizontal_shift, .vertical_shift, .horizontal_source_start_offset,
.horizontal_source_end_offset, .vertical_source_start_offset, .vertical_source_end_offset,
.horizontal_source_offset_kind, .vertical_source_offset_kind, .max_horizontal_shift_ratio,
.max_vertical_shift_ratio, .horizontal_shift_clamped, .vertical_shift_clamped, .style,
.margin, .width, .height, .min_width, .min_height, .max_width, .max_height,
.horizontal_alignment, .vertical_alignment, .visible, .tool_tip, .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 | |
|---|---|---|---|
horizontal_shift |
ui::Binding<float> |
{0.0f} |
How far the child moves over the source's horizontal scroll range, in DIPs. 0, the default, is no parallax on that axis. The child is laid out this much wider. |
vertical_shift |
ui::Binding<float> |
{0.0f} |
The vertical counterpart of horizontal_shift. |
horizontal_source_start_offset |
ui::Binding<float> |
{0.0f} |
Where on the source's horizontal scroll range the parallax starts and ends, in DIPs, read per horizontal_source_offset_kind. |
horizontal_source_end_offset |
ui::Binding<float> |
{0.0f} |
See above. |
vertical_source_start_offset |
ui::Binding<float> |
{0.0f} |
Where on the source's vertical scroll range the parallax starts and ends, as the horizontal pair. |
vertical_source_end_offset |
ui::Binding<float> |
{0.0f} |
See above. |
horizontal_source_offset_kind |
ui::Binding<ui::ParallaxSourceOffsetKind> |
{ui::ParallaxSourceOffsetKind::Relative} |
Relative (the default) adds the offsets to the automatic range; Absolute uses them as is. |
vertical_source_offset_kind |
ui::Binding<ui::ParallaxSourceOffsetKind> |
{ui::ParallaxSourceOffsetKind::Relative} |
As horizontal_source_offset_kind, for the vertical offsets. |
max_horizontal_shift_ratio |
ui::Binding<float> |
{1.0f} |
The child never moves faster than this times the source. |
max_vertical_shift_ratio |
ui::Binding<float> |
{1.0f} |
As max_horizontal_shift_ratio. |
horizontal_shift_clamped |
bool |
true |
The child stops at the ends of the range. |
vertical_shift_clamped |
bool |
true |
As horizontal_shift_clamped. |
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::Parallax> |
Out: the handle that receives the built control. | |
content |
ui::Spec |
The moving child, typically a background image. |
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¶
Consumes the spec and returns the built ui::ParallaxControl; the caller owns it.
ui::ParallaxControl¶
Derives from ui::Element.
Moves its single child at a different rate than another element scrolls, typically a background image behind a list or scroll view.
The child is laid out larger than the view by the shift, clipped to the view, and moved every frame through its own translation, which the Parallax controls from then on. The source is any element with Element::scroll_info(), such as a Scroll or a ListView. The Parallax does not own it and notices when it is destroyed. Set it after the tree is built. A source destroyed first stops the parallax. A Parallax is never focusable. ui::Parallax is the declarative form. It has no .source field, so set the source through .control.
Example:
auto row = std::make_unique<ui::StackControl>(ui::Orientation::Horizontal);
auto* parallax = row->add(std::make_unique<ui::ParallaxControl>());
parallax->set_vertical_shift(300.0f); // the background travels 300 DIPs over the whole scroll
parallax->set_child(std::make_unique<ui::TextControl>("Background"));
auto* scroll = row->add(std::make_unique<ui::ScrollControl>());
auto content = std::make_unique<ui::TextControl>("Tall content");
content->set_min_height(2000.0f);
scroll->set_child(std::move(content));
parallax->set_source(scroll); // non-owning; both already live in the same tree
window.set_content(std::move(row));
ParallaxControl¶
An empty view with no child, no source and zero shift on both axes.
set_child¶
Takes ownership of the moving content and returns a non-owning pointer to it. The Parallax controls the child's translation from then on.
child¶
The content set by set_child() (non-owning), or nullptr.
source¶
The scrolling element to follow (Element::scroll_info()), or nullptr for none. Becomes nullptr by itself once the source is destroyed.
set_source¶
Follows source, which the Parallax does not own. Pass nullptr to stop following. Redraws.
horizontal_shift¶
How far the child moves over the source's horizontal range, in DIPs. 0, the default, is no parallax on that axis. The child is laid out this much larger than the view on that axis.
set_horizontal_shift¶
Lays the view out again, since the child's size depends on the shift, and redraws.
vertical_shift¶
Vertical counterpart of horizontal_shift().
set_vertical_shift¶
Lays the view out again and redraws.
horizontal_source_start_offset¶
Where the horizontal parallax starts on the source's scroll range, in DIPs. It is added to the automatic value or used as is, depending on the offset kind. 0 by default, as are the other offsets.
set_horizontal_source_start_offset¶
Redraws. The shift is recomputed on the next frame.
horizontal_source_end_offset¶
Where the horizontal parallax ends on the source's scroll range (see the start offset).
set_horizontal_source_end_offset¶
Marks the view for redraw.
vertical_source_start_offset¶
Where the vertical parallax starts on the source's scroll range, in DIPs.
set_vertical_source_start_offset¶
Marks the view for redraw.
vertical_source_end_offset¶
Where the vertical parallax ends on the source's scroll range, in DIPs.
set_vertical_source_end_offset¶
Marks the view for redraw.
horizontal_source_offset_kind¶
How the horizontal start/end offsets are interpreted; Relative by default.
set_horizontal_source_offset_kind¶
Marks the view for redraw.
vertical_source_offset_kind¶
How the vertical start/end offsets are interpreted; Relative by default.
set_vertical_source_offset_kind¶
Marks the view for redraw.
max_horizontal_shift_ratio¶
The child never moves faster than this times the source's own horizontal scrolling. 1.0 by default.
set_max_horizontal_shift_ratio¶
Marks the view for redraw.
max_vertical_shift_ratio¶
Vertical counterpart of max_horizontal_shift_ratio(); 1.0 by default.
set_max_vertical_shift_ratio¶
Marks the view for redraw.
is_horizontal_shift_clamped¶
Whether the child stops at the ends of the horizontal range instead of moving on with the scroll. True by default.
set_horizontal_shift_clamped¶
Marks the view for redraw.
is_vertical_shift_clamped¶
Vertical counterpart of is_horizontal_shift_clamped(); true by default.
set_vertical_shift_clamped¶
Marks the view for redraw.
current_shift¶
The child's current parallax offset on each axis, its translation.
for_each_child¶
Visits the child, if there is one.
children_hit_clip¶
The child is clipped to the bounds, and so is where it can be hit.
measure_override¶
Measures the child with the shift added to the available size. The Parallax takes the available size, or the child's size on an unbounded axis.
arrange_override¶
Arranges the child larger than the view by the shift. A child that stretches grows by the same ratio on the other axis.
render_override¶
Draws the child clipped to the view. Its translation carries the shift.
Enumerations¶
ParallaxSourceOffsetKind¶
Whether a Parallax source start or end offset is added to the automatic value (Relative, the default) or used as it is (Absolute).
| Value | |
|---|---|
Absolute |
The offset is the scroll position itself, in unzoomed DIPs. |
Relative |
The offset is added to the automatically computed start/end. |
Tests¶
tests/test_parallax.cpp