pub trait Layout {
Show 13 methods
// Required methods
fn size_rules(&mut self, sizer: SizeCx<'_>, axis: AxisInfo) -> SizeRules;
fn draw(&mut self, draw: DrawCx<'_>);
// Provided methods
fn as_layout(&self) -> &dyn Layout { ... }
fn id_ref(&self) -> &Id { ... }
fn rect(&self) -> Rect { ... }
fn widget_name(&self) -> &'static str { ... }
fn num_children(&self) -> usize { ... }
fn get_child(&self, index: usize) -> Option<&dyn Layout> { ... }
fn find_child_index(&self, id: &Id) -> Option<usize> { ... }
fn set_rect(&mut self, cx: &mut ConfigCx<'_>, rect: Rect) { ... }
fn nav_next(&self, reverse: bool, from: Option<usize>) -> Option<usize> { ... }
fn translation(&self) -> Offset { ... }
fn find_id(&mut self, coord: Coord) -> Option<Id> { ... }
}Expand description
Positioning and drawing routines for Widgets
Layout is a super-trait of Widget which:
- Has no
Dataparameter - Supports read-only tree reflection:
Self::get_child - Provides some basic operations:
Self::id_ref,Self::rect - Covers sizing and drawing operations (“layout”)
Implementing Layout
See Widget documentation and the #widget macro.
Layout may not be implemented independently.
Widget lifecycle
- The widget is configured (
Events::configure) and immediately updated (Events::update). - The widget has its size-requirements checked by calling
Self::size_rulesfor each axis (usually via recursion, sometimes vialayout::solve_size_rulesorlayout::SolveCache). Self::set_rectis called to position elements. This may use data cached bysize_rules.- The widget is updated again after any data change (see
ConfigCx::update). - The widget is ready for event-handling and drawing (
Events,Self::find_id,Self::draw).
Widgets are responsible for ensuring that their children may observe this lifecycle. Usually this simply involves inclusion of the child in layout operations. Steps of the lifecycle may be postponed until a widget becomes visible.
Tree reflection
Layout offers a reflection API over the widget tree via
Layout::get_child. This is limited to read-only functions, and thus
cannot directly violate the widget lifecycle, however note that the
id_ref could be invalid or could be valid but refer to a
node which has not yet been sized and positioned (and thus which it is not
valid to send events to).
Required Methods§
sourcefn size_rules(&mut self, sizer: SizeCx<'_>, axis: AxisInfo) -> SizeRules
fn size_rules(&mut self, sizer: SizeCx<'_>, axis: AxisInfo) -> SizeRules
Get size rules for the given axis
Typically, this method is called twice: first for the horizontal axis,
second for the vertical axis (with resolved width available through
the axis parameter allowing content wrapping).
For a description of the widget size model, see SizeRules.
This method is expected to cache any size requirements calculated from
children which would be required for space allocations in
Self::set_rect. As an example, the horizontal SizeRules for a
row layout is the sum of the rules for each column (plus margins);
these per-column SizeRules are also needed to calculate column
widths in Self::size_rules once the available size is known.
For row/column/grid layouts, a crate::layout::RulesSolver engine
may be useful.
Required: self is configured (ConfigCx::configure) before this
method is called, and that size_rules is called for the
horizontal axis before it is called for the vertical axis.
Further, Self::set_rect must be called after this method before
drawing or event handling.
sourcefn draw(&mut self, draw: DrawCx<'_>)
fn draw(&mut self, draw: DrawCx<'_>)
Draw a widget and its children
This method is invoked each frame to draw visible widgets. It should draw itself and recurse into all visible children.
It is expected that Self::set_rect is called before this method,
but failure to do so should not cause a fatal error.
The draw parameter is pre-parameterized with this widget’s
Id, allowing drawn components to react to input state. This
implies that when calling draw on children, the child’s id must be
supplied via DrawCx::re_id or DrawCx::recurse.
Provided Methods§
sourcefn as_layout(&self) -> &dyn Layout
fn as_layout(&self) -> &dyn Layout
Get as a dyn Layout
This method is implemented by the #[widget] macro.
sourcefn id_ref(&self) -> &Id
fn id_ref(&self) -> &Id
Get the widget’s identifier
Note that the default-constructed Id is invalid: any
operations on this value will cause a panic. A valid identifier is
assigned when the widget is configured (immediately before calling
Events::configure).
This method is implemented by the #[widget] macro.
sourcefn rect(&self) -> Rect
fn rect(&self) -> Rect
Get the widget’s region, relative to its parent.
This method is implemented by the #[widget] macro.
sourcefn widget_name(&self) -> &'static str
fn widget_name(&self) -> &'static str
Get the name of the widget struct
This method is implemented by the #[widget] macro.
sourcefn num_children(&self) -> usize
fn num_children(&self) -> usize
Get the number of child widgets
Every value in the range 0..self.num_children() is a valid child
index.
This method is usually implemented automatically by the #[widget]
macro. It should be implemented directly if and only if
Layout::get_child and Widget::for_child_node are
implemented directly.
sourcefn get_child(&self, index: usize) -> Option<&dyn Layout>
fn get_child(&self, index: usize) -> Option<&dyn Layout>
Access a child as a dyn Layout
This method is usually implemented automatically by the #[widget]
macro.
sourcefn find_child_index(&self, id: &Id) -> Option<usize>
fn find_child_index(&self, id: &Id) -> Option<usize>
Find the child which is an ancestor of this id, if any
If Some(index) is returned, this is probably but not guaranteed
to be a valid child index.
The default implementation simply uses Id::next_key_after.
Widgets may choose to assign children custom keys by overriding this
method and Events::make_child_id.
sourcefn set_rect(&mut self, cx: &mut ConfigCx<'_>, rect: Rect)
fn set_rect(&mut self, cx: &mut ConfigCx<'_>, rect: Rect)
Set size and position
This method is called after Self::size_rules and may use values
cached by size_rules (in the case size_rules is not called first,
the widget may exhibit incorrect layout but should not panic). This
method should not write over values cached by size_rules since
set_rect may be called multiple times consecutively.
After set_rect is called, the widget must be ready for drawing and event handling.
The size of the assigned rect is normally at least the minimum size
requested by Self::size_rules, but this is not guaranteed. In case
this minimum is not met, it is permissible for the widget to draw
outside of its assigned rect and to not function as normal.
The assigned rect may be larger than the widget’s size requirements,
regardless of the Stretch policy used. If the widget should never
stretch, it must align itself.
Example: the CheckBox widget uses an AlignPair (set from
size_rules’s AxisInfo) and uses ConfigCx::align_feature.
Another example: Label uses a Text object which handles alignment
internally.
Required: Self::size_rules is called for both axes before this
method is called, and that this method has been called after the last
call to Self::size_rules before any of the following methods:
Layout::find_id, Layout::draw, Events::handle_event.
Default implementation when not using the layout property: set rect
field of widget_core!() to the input rect.
Navigation in spatial order
Controls Tab navigation order of children. This method should:
- Return
Noneif there is no next child - Determine the next child after
from(if provided) or the whole range, optionally inreverseorder - Ensure that the selected widget is addressable through
Layout::get_child
Both from and the return value use the widget index, as used by
Layout::get_child.
Default implementation:
- Generated from
#[widget]’s layout property, if used (not always possible!) - Otherwise, iterate through children in order of definition
sourcefn translation(&self) -> Offset
fn translation(&self) -> Offset
Get translation of children relative to this widget
Usually this is zero; only widgets with scrollable or offset content
and child widgets need to implement this.
Such widgets must also implement Events::handle_scroll.
Affects event handling via Layout::find_id and affects the positioning
of pop-up menus. Layout::draw must be implemented directly using
DrawCx::with_clip_region to offset contents.
Default implementation: return Offset::ZERO
sourcefn find_id(&mut self, coord: Coord) -> Option<Id>
fn find_id(&mut self, coord: Coord) -> Option<Id>
Translate a coordinate to an Id
This method is used to determine which widget reacts to the mouse cursor
or a touch event. The result affects mouse-hover highlighting, event
handling by the target, and potentially also event handling by other
widgets (e.g. a Label widget will not handle touch events, but if it
is contained by a ScrollRegion, that widget may capture these via
Events::handle_event to implement touch scrolling).
The result is usually the widget which draws at the given coord, but
does not have to be. For example, a Button widget will return its own
id for coordinates drawn by internal content, while the CheckButton
widget uses an internal component for event handling and thus reports
this component’s id even over its own area.
It is expected that Layout::set_rect is called before this method,
but failure to do so should not cause a fatal error.
The default implementation suffices for widgets without children as well
as widgets using the layout property of #[widget].
Custom implementations may be required if:
- A custom
Layoutimplementation is used - Event stealing or donation is desired (but note that
layout = button: ..;does this already)
When writing a custom implementation:
- Widgets should test
self.rect().contains(coord), returningNoneif this test isfalse; otherwise, they should always return someId, either a childs or their own. - If the Widget uses a translated coordinate space (i.e.
self.translation() != Offset::ZERO) then passcoord + self.translation()to children.
The default implementation is non-trivial:
if !self.rect().contains(coord) {
return None;
}
let coord = coord + self.translation();
for child in ITER_OVER_CHILDREN {
if let Some(id) = child.find_id(coord) {
return Some(id);
}
}
Some(self.id())