kas_core/core/events.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//! Widget and Events traits
7
8#[allow(unused)] use super::Layout;
9use super::{Tile, Widget};
10use crate::Id;
11#[allow(unused)] use crate::event::EventState;
12use crate::event::{ConfigCx, CursorIcon, Event, EventCx, IsUsed, Scroll, Unused};
13#[allow(unused)] use kas_macros as macros;
14
15/// Widget event-handling
16///
17/// This trait governs event handling as part of a [`Widget`] implementation.
18/// It is used by the [`#widget`] macro to generate hidden [`Widget`] methods.
19///
20/// The implementation of this method may be omitted where no event-handling is
21/// required. All methods have a default implementation.
22///
23/// Type [`Widget::Data`] may be specified in `impl Events { ... }` instead of
24/// in `impl Widget { ... }` (this is permitted since it allows may `#[widget]`
25/// definitions to omit `impl Widget { ... }` altogether).
26///
27/// # Widget lifecycle
28///
29/// 1. The widget is configured ([`Events::configure`],
30/// [`Events::configure_recurse`]) and immediately updated
31/// ([`Events::update`]).
32///
33/// The widget may be re-configured at any time without expectation that
34/// the layout will be resized / set again.
35/// 2. The widget is updated by calling [`Events::update`] immediately after
36/// it is configured and also after any update to input data (or other data
37/// which may have changed, such as that exposed by [`EventState::config`]).
38/// 3. The widget is "sized" by calling [`Layout::size_rules`] for the
39/// horizontal axis then for the vertical axis.
40///
41/// These methods may be called again at any time without expectation that
42/// the layout will be set again.
43/// 4. [`Layout::set_rect`] is called to "set" layout.
44///
45/// This method may be called again at any time.
46/// 5. The widget is ready for event-handling and drawing
47/// ([`Events::handle_event`], [`Layout::try_probe`], [`Layout::draw`]).
48///
49/// Widgets are responsible for ensuring that their children may observe this
50/// lifecycle. Usually this simply involves inclusion of the child in layout
51/// operations. Steps of the lifecycle may be postponed until a widget becomes
52/// visible.
53///
54/// [`#widget`]: macros::widget
55pub trait Events: Widget + Sized {
56 /// Does this widget have a different appearance on mouse over?
57 ///
58 /// If `true`, then the mouse moving over and leaving the widget will cause
59 /// a redraw. (Note that [`Layout::draw`] can infer the mouse-over state and
60 /// start animations.)
61 const REDRAW_ON_MOUSE_OVER: bool = false;
62
63 /// The mouse cursor icon to use on mouse over
64 ///
65 /// Defaults to `None`.
66 #[inline]
67 fn mouse_over_icon(&self) -> Option<CursorIcon> {
68 None
69 }
70
71 /// Make an identifier for a child
72 ///
73 /// This is used to assign children identifiers. It may return
74 /// [`Id::default`] in order to avoid configuring the child, but in
75 /// this case the widget must configure via another means.
76 ///
77 /// If this is implemented explicitly then [`Tile::find_child_index`] must
78 /// be too.
79 ///
80 /// Default impl: `self.id_ref().make_child(index)`
81 #[inline]
82 fn make_child_id(&mut self, index: usize) -> Id {
83 self.id_ref().make_child(index)
84 }
85
86 /// Configure self
87 ///
88 /// Widgets are *configured* before sizing, drawing and event handling (see
89 /// [widget lifecycle](Widget#widget-lifecycle)).
90 ///
91 /// Configuration may be repeated at any time. If `id` changes, children
92 /// must be assigned new/updated identifiers.
93 ///
94 /// [`Self::update`] is always called immediately after this method,
95 /// followed by [`Self::configure_recurse`].
96 ///
97 /// The window's scale factor (and thus any sizes available through
98 /// [`ConfigCx::size_cx`]) may not be correct initially (some platforms
99 /// construct all windows using scale factor 1) and/or may change in the
100 /// future. Changes to the scale factor result in recalculation of
101 /// [`Layout::size_rules`] but not repeated configuration.
102 ///
103 /// The default implementation does nothing.
104 fn configure(&mut self, cx: &mut ConfigCx) {
105 let _ = cx;
106 }
107
108 /// Configure children
109 ///
110 /// This method is called after [`Self::configure`].
111 /// The default implementation configures all children.
112 ///
113 /// An explicit implementation is required in cases where not all children
114 /// should be configured immediately (for example, a stack or paged list may
115 /// choose not to configure hidden children until just before they become
116 /// visible). To configure children explicitly, generate an [`Id`] by
117 /// calling [`Events::make_child_id`] on `self` then pass this `id` to
118 /// [`ConfigCx::configure`].
119 ///
120 /// The default implementation configures children in the range
121 /// [`Tile::child_indices`]. In cases where [`Tile::child_indices`] hides
122 /// some children, a custom implementation of this method might be needed.
123 fn configure_recurse(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
124 for index in self.child_indices().into_iter() {
125 let id = self.make_child_id(index);
126 if id.is_valid()
127 && let Some(node) = self.as_node(data).get_child(index)
128 {
129 cx.configure(node, id);
130 }
131 }
132 }
133
134 /// Update self using input data
135 ///
136 /// This method is called immediately after [`Self::configure`] and after
137 /// any input data is updated, before [`Layout::draw`] is called.
138 /// Typically this method is called immediately after the data is updated
139 /// but the call may be delayed until when the widget becomes visible.
140 ///
141 /// This method is called before [`Self::update_recurse`].
142 ///
143 /// The default implementation does nothing.
144 fn update(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
145 let _ = (cx, data);
146 }
147
148 /// Update children
149 ///
150 /// This method is called after [`Self::update`]. It usually configures all
151 /// children. Children should be updated even if their data is `()` or is
152 /// unchanged.
153 ///
154 /// The default implementation updates children in the range
155 /// [`Tile::child_indices`]. This is usually sufficient.
156 ///
157 /// Use [`ConfigCx::update`].
158 fn update_recurse(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
159 for index in self.child_indices().into_iter() {
160 if let Some(node) = self.as_node(data).get_child(index) {
161 cx.update(node);
162 }
163 }
164 }
165
166 /// Mouse focus handler
167 ///
168 /// Called when mouse moves over or leaves this widget.
169 /// (This is a low-level alternative
170 /// to [`Self::REDRAW_ON_MOUSE_OVER`] and [`Self::mouse_over_icon`].)
171 ///
172 /// `state` is true when the mouse is over this widget.
173 #[inline]
174 fn handle_mouse_over(&mut self, cx: &mut EventCx, state: bool) {
175 if Self::REDRAW_ON_MOUSE_OVER {
176 cx.redraw(&self);
177 }
178 if state && let Some(icon) = self.mouse_over_icon() {
179 cx.set_mouse_over_icon(icon);
180 }
181 }
182
183 /// Handle an [`Event`]
184 ///
185 /// This is the primary event handler (see [documentation](crate::event)).
186 ///
187 /// This method is called on the primary event target. In this case,
188 /// [`EventCx::last_child`] returns `None`.
189 ///
190 /// This method may also be called on ancestors during unwinding (if the
191 /// event remains [unused](Unused) and the event
192 /// [is reusable](Event::is_reusable)). In this case,
193 /// [`EventCx::last_child`] returns `Some(index)` with the index of the
194 /// child being unwound from.
195 ///
196 /// Default implementation of `handle_event`: do nothing; return
197 /// [`Unused`].
198 fn handle_event(&mut self, cx: &mut EventCx, data: &Self::Data, event: Event) -> IsUsed {
199 let _ = (cx, data, event);
200 Unused
201 }
202
203 /// Handler for messages from children/descendants
204 ///
205 /// This is the secondary event handler (see [documentation](crate::event)).
206 ///
207 /// It is implied that the stack contains at least one message.
208 /// Use [`EventCx::try_pop`] and/or [`EventCx::try_peek`].
209 ///
210 /// [`EventCx::last_child`] may be called to find the message's sender.
211 /// This may return [`None`] (if no child was visited, which implies that
212 /// the message was sent by `self`).
213 ///
214 /// The default implementation does nothing.
215 #[inline]
216 fn handle_messages(&mut self, cx: &mut EventCx, data: &Self::Data) {
217 let _ = (cx, data);
218 }
219
220 /// Handler for scrolling
221 ///
222 /// When, during [event handling](crate::event), a widget which is a strict
223 /// descendant of `self` (i.e. not `self`) calls [`EventCx::set_scroll`]
224 /// with a value other than [`Scroll::None`], this method is called.
225 ///
226 /// Note that [`Scroll::Rect`] values are in the child's coordinate space,
227 /// and must be translated to the widget's own coordinate space by this
228 /// method (this is not done by the default implementation since any widget
229 /// with non-zero translation very likely wants to implement this method
230 /// anyway).
231 ///
232 /// If the child is in an independent coordinate space, then this method
233 /// should call `cx.set_scroll(Scroll::None)` to avoid any reactions to
234 /// child's scroll requests.
235 ///
236 /// [`EventCx::last_child`] may be called to find the child responsible,
237 /// and should never return [`None`] (when called from this method).
238 ///
239 /// The default implementation does nothing.
240 #[inline]
241 fn handle_scroll(&mut self, cx: &mut EventCx, data: &Self::Data, scroll: Scroll) {
242 let _ = (cx, data, scroll);
243 }
244}