ScaleToFit¶
Header: winui/ui/containers/ScaleToFit.hpp. Spec: winui/ui/containers/ScaleToFit.hpp.
One child, laid out at its natural size and drawn scaled to the room the ScaleToFit is given.
The child is measured with unbounded room, then drawn with a scale that stretch() and stretch_direction() decide. The ScaleToFit asks for the scaled size. Text is scaled like a picture and keeps its line breaks and font size. Pointer input is mapped back through the same scale, so the child's controls keep working at any size. A popup opened from inside is anchored where its owner would be unscaled. With UniformToFill, the overflow is clipped.
Example:
auto box = std::make_unique<ui::ScaleToFitControl>();
auto* label = box->set_child(std::make_unique<ui::TextControl>("42"));
box->set_stretch(ui::Stretch::Uniform);
box->set_stretch_direction(ui::StretchDirection::UpOnly); // grow the text, never shrink it
window.set_content(std::move(box));
label->set_text("43"); // the observer stays valid, and the next layout scales the new text
// Or declaratively, filling a 200x100 slot:
window.set_content(ui::ScaleToFit{
.width = 200.0f,
.height = 100.0f,
.content = ui::Text{.text = "42"},
});
ui::ScaleToFit¶
One child scaled to the room it is given. Builds a ui::ScaleToFitControl.
The child is measured at its natural size and then scaled, text and strokes included.
Example:
window.set_content(ui::ScaleToFit{
.stretch = ui::Stretch::Uniform,
.stretch_direction = ui::StretchDirection::DownOnly, // shrink to fit, never enlarge
.width = 200.0f,
.height = 100.0f,
.content = ui::Text{.text = "Scaled to fit", .role = ui::TextRole::Header},
});
Every field, in the order a designated initializer names them:
ui::ScaleToFit{
.stretch, .stretch_direction, .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 | |
|---|---|---|---|
stretch |
ui::Binding<ui::Stretch> |
{ui::Stretch::Uniform} |
How the child's natural size maps to the box. Uniform, the default, keeps its aspect ratio. |
stretch_direction |
ui::Binding<ui::StretchDirection> |
{ui::StretchDirection::Both} |
UpOnly only enlarges, DownOnly only shrinks, and Both, the default, does both. |
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::ScaleToFit> |
Out: the handle that receives the built control. | |
content |
ui::Spec |
The scaled child. |
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::ScaleToFitControl; the caller owns it.
ui::ScaleToFitControl¶
Derives from ui::Element.
One child, laid out at its natural size and drawn scaled to the room the ScaleToFit is given.
The child is measured with unbounded room, then drawn with a scale that stretch() and stretch_direction() decide. The ScaleToFit asks for the scaled size. Text is scaled like a picture and keeps its line breaks and font size. Pointer input is mapped back through the same scale, so the child's controls keep working at any size. A popup opened from inside is anchored where its owner would be unscaled. With UniformToFill, the overflow is clipped.
Example:
auto box = std::make_unique<ui::ScaleToFitControl>();
auto* label = box->set_child(std::make_unique<ui::TextControl>("42"));
box->set_stretch(ui::Stretch::Uniform);
box->set_stretch_direction(ui::StretchDirection::UpOnly); // grow the text, never shrink it
window.set_content(std::move(box));
label->set_text("43"); // the observer stays valid, and the next layout scales the new text
// Or declaratively, filling a 200x100 slot:
window.set_content(ui::ScaleToFit{
.width = 200.0f,
.height = 100.0f,
.content = ui::Text{.text = "42"},
});
ScaleToFitControl¶
An empty ScaleToFit, Uniform and Both.
set_child¶
Takes ownership of the single child and returns a non-owning observer. Replaces and destroys any previous child, and nullptr clears it. Updates layout.
child¶
The child, or nullptr. Owned by the ScaleToFit.
stretch¶
How the child is scaled. Uniform by default. None never scales, and Fill scales each axis to its room. Uniform fits inside the room and UniformToFill covers it, both keeping the aspect ratio.
set_stretch¶
Changes the stretch. Updates layout.
stretch_direction¶
Whether scaling may enlarge, shrink or both. Both by default.
set_stretch_direction¶
Changes which way scaling may go. Updates layout.
scale_x¶
The horizontal scale the child is drawn at, from the last arrange. 1 before the first.
scale_y¶
The vertical scale, like scale_x(). The two differ only under Stretch::Fill.
compute_scale_factor¶
The x and y factors that fit content into available under the current stretch() and stretch_direction(). An unbounded axis (ui::Unbounded) uses the other axis's factor. With both unbounded, the factors are 1 and 1.
for_each_child¶
The child, when there is one.
measure_override¶
Implement these instead of measure() and arrange(). The base class has already applied margin, size limits and alignment by the time these run. measure_override() is pure (every concrete Element must size itself); arrange_override() defaults to a no-op since most leaves need nothing beyond having bounds() set, which the base already did.
arrange_override¶
Position children within the rect arrange() settled on (also in bounds(), window DIPs). Default: nothing, for a leaf.
render_override¶
What the control draws, in layout coordinates; render() has already applied the visual layer. A container draws its children through their render(), never their render_override().
map_to_children¶
The point as the scaled child sees it.
children_hit_clip¶
The child is clipped to the bounds, and can be hit only inside them.
Enumerations¶
StretchDirection¶
Which way a ScaleToFit may scale its child.
| Value | |
|---|---|
UpOnly |
Only enlarge. A child bigger than the room is drawn at its natural size. |
DownOnly |
Only shrink. A child smaller than the room is drawn at its natural size. |
Both |
The default. Scale either way. |
Tests¶
tests/test_layout_panels.cpp