kas_core/core/layout.rs
1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4// https://www.apache.org/licenses/LICENSE-2.0
5
6//! Layout, Tile and TileExt traits
7
8use crate::geom::Rect;
9use crate::layout::{AlignHints, AxisInfo, SizeRules};
10use crate::theme::{DrawCx, SizeCx};
11use kas_macros::autoimpl;
12
13#[allow(unused)]
14use super::{Events, Tile, Widget, WidgetCoreRect};
15#[allow(unused)] use crate::layout::{self};
16#[allow(unused)] use kas_macros as macros;
17
18/// Positioning and drawing routines for [`Widget`]s
19///
20/// `Layout` is used to implement [`Widget`] sizing and drawing operations
21/// ("layout").
22/// See [`Widget`] documentation and the [`#widget`] macro.
23/// `Layout` may not be implemented independently.
24///
25/// # Implementation
26///
27/// The [`#widget`] macro will, when its `layout` property is specified,
28/// generate an implementation of this trait (if omitted from the surrounding
29/// `#[impl_self]`) or provide default implementations of its methods (if an
30/// explicit impl of `Layout` is found but some methods are missing).
31///
32/// # Call order
33///
34/// Widgets must be [**configured**](Events#configuration) before any
35/// `Layout` methods are called. This is not applicable to non-widgets.
36///
37/// ### Sizing
38///
39/// Sizing involves calling the following in order:
40///
41/// 1. [`Layout::size_rules`] for the horizontal axis
42/// 2. [`Layout::size_rules`] for the vertical axis
43/// 3. [`Layout::set_rect`]
44///
45/// This order is required initially. Resizing may start at any of the above
46/// steps but must then proceed in-order for all remaining steps. If the scale
47/// factor is changed, then resizing must start from step 1.
48///
49/// Typically parent widgets call these methods from their own implementations
50/// of [`Layout::size_rules`] and [`Layout::set_rect`]. When calling these
51/// methods at other times, be sure to respect the call order.
52///
53/// Other `Layout` methods may only be called once sizing is complete.
54///
55/// [`#widget`]: macros::widget
56#[autoimpl(for<T: trait + ?Sized> &'_ mut T, Box<T>)]
57pub trait Layout {
58 /// Get the widget's region
59 ///
60 /// Coordinates are relative to the parent's coordinate space.
61 ///
62 /// This is often the [`Rect`] passed to [`Layout::set_rect`], though it is
63 /// not required to be; for example some widgets align themselves within
64 /// their allocated `rect` when it is too large; widgets may also exceed
65 /// their allocated `rect` if it is smaller than their minimum size.
66 ///
67 /// This method is usually implemented by the `#[widget]` macro as
68 /// [`WidgetCoreRect::rect`] or from macro-defined layout.
69 fn rect(&self) -> Rect;
70
71 /// Calculate size requirements for an `axis`
72 ///
73 /// This method is used both to initialize a widget at a given scale factor
74 /// and to assess size requirements.
75 ///
76 /// # Calling
77 ///
78 /// This method is called during sizing (see [above](Layout#call-order)).
79 ///
80 /// # Implementation
81 ///
82 /// For a description of the widget size model, see [`SizeRules`].
83 ///
84 /// For row/column/grid layouts, a [`crate::layout::RulesSolver`] engine
85 /// may be useful.
86 ///
87 /// ## Default implementation
88 ///
89 /// The [`#[layout]`](macro@crate::layout) macro may be used to
90 /// provide a default implementation.
91 fn size_rules(&mut self, cx: &mut SizeCx, axis: AxisInfo) -> SizeRules;
92
93 /// Set size and position
94 ///
95 /// # Calling
96 ///
97 /// This method is called to finalize sizing (see
98 /// [above](Layout#call-order)).
99 ///
100 /// # Implementation
101 ///
102 /// The size of the assigned `rect` is normally at least the minimum size
103 /// requested by [`Self::size_rules`], but this is not guaranteed. In case
104 /// this minimum is not met, it is permissible for the widget to draw
105 /// outside of its assigned `rect` and to not function as normal.
106 ///
107 /// The assigned `rect` may be larger than the widget's size requirements,
108 /// regardless of the [`Stretch`] policy used: containers divide up space
109 /// based on children's [`SizeRules`] but do not attempt to align content
110 /// when excess space is available. Instead, content is responsible for
111 /// aligning itself using the provided `hints` and/or local information.
112 ///
113 /// This method must ensure that the widget's new [`Rect`] is available
114 /// through [`Layout::rect`]. The easiest way to achieve this is usually
115 /// to call [`WidgetCoreRect::set_rect`] and allow the `#[widget]` macro to
116 /// provide an implementation of [`Layout::rect`].
117 ///
118 /// ## Default implementation
119 ///
120 /// The [`#[layout]`](macro@crate::layout) macro may be used to
121 /// provide a default implementation.
122 ///
123 /// [`Stretch`]: crate::layout::Stretch
124 fn set_rect(&mut self, cx: &mut SizeCx, rect: Rect, hints: AlignHints);
125
126 /// Draw a widget and its children
127 ///
128 /// # Calling
129 ///
130 /// This method is invoked each frame to draw visible widgets. It should
131 /// draw itself and recurse into all visible children.
132 ///
133 /// # Implementation
134 ///
135 /// ## Default implementation
136 ///
137 /// The [`#[layout]`](macro@crate::layout) macro may be used to
138 /// provide a default implementation.
139 ///
140 /// ## Method modification
141 ///
142 /// The `#[widget]` macro injects a call to [`DrawCx::set_id`] into this
143 /// method where possible, allowing correct detection of disabled and
144 /// highlight states.
145 ///
146 /// This method modification should never cause issues (besides the implied
147 /// limitation that widgets cannot easily detect a parent's state while
148 /// being drawn).
149 fn draw(&self, draw: DrawCx);
150}
151
152/// Macro-defined layout
153///
154/// This trait is a copy of [`Layout`], implemented by the
155/// [`#[layout]`](macro@crate::layout) macro. In some cases it is useful to
156/// invoke `kas::MacroDefinedLayout::set_rect` (or other method) from the
157/// corresponding [`Layout`] method to perform some other action before using
158/// the default implementation.
159///
160/// [`#[layout]`]: kas::layout
161pub trait MacroDefinedLayout {
162 /// Get the widget's region
163 fn rect(&self) -> Rect;
164
165 /// Get size rules for the given axis
166 fn size_rules(&mut self, cx: &mut SizeCx, axis: AxisInfo) -> SizeRules;
167
168 /// Set size and position
169 fn set_rect(&mut self, cx: &mut SizeCx, rect: Rect, hints: AlignHints);
170
171 /// Draw a widget and its children
172 fn draw(&self, draw: DrawCx);
173}