Skip to main content

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}