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
8use super::{Tile, Widget};
9use crate::event::{ConfigCx, CursorIcon, Event, EventCx, IsUsed, Scroll, Unused};
10use crate::{ActionResize, ChildIndices};
11use crate::{Id, geom::Coord};
12#[allow(unused)] use crate::{Layout, event::EventState};
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/// # Implementation
21///
22/// The implementation of this trait may be omitted where no event-handling is
23/// required. All methods have a default implementation.
24///
25/// ## Foreign items
26///
27/// The [`#widget`] macro permits implementation of the following items within
28/// `impl Events`:
29///
30/// - `type` [`Widget::Data`]
31///
32/// ## Call order
33///
34/// ### Configuration
35///
36/// It is required that widgets are configured before other methods are called.
37/// This is invoked by calling [`ConfigCx::configure`]
38/// and involves the following operations:
39///
40/// 1. Set the widget [`Id`], as returned by [`Tile::id`]
41/// 2. Call [`Events::configure`]
42/// 3. Call [`Events::update`]
43/// 4. Recurse configuration to children (see [`Events::recurse_indices`])
44/// 5. Call [`Events::post_configure`]
45///
46/// Note that both [`configure`](Self::configure) and [`update`](Self::update)
47/// may be called before child widgets have been configured. This is important
48/// to ensure that parent widgets are always updated before their children. Any
49/// logic using child identifiers should be placed in
50/// [`post_configure`](Self::post_configure).
51///
52/// Configuration may be repeated at any time.
53///
54/// ### Update
55///
56/// Widgets must be updated during configure (see above), since
57/// [`Events::update`] must be called before sizing and before other widget
58/// methods.
59///
60/// Widgets must also be updated after their input data (see [`Widget::Data`])
61/// changes (unless not visible, in which case the update may be postponed until
62/// they become visible). Updates may happen at other times (mostly because
63/// data-change-detection has false positives). Note that custom widgets with
64/// state must explicitly update affected children when their state changes.
65///
66/// An update is invoked by calling [`ConfigCx::update`],
67/// resulting in the following operations:
68///
69/// 1. Call [`Events::update`]
70/// 2. Recurse the update to children (see [`Events::recurse_indices`])
71///
72/// ### Sizing
73///
74/// Sizing must happen after initial configuration but is not necessarily
75/// repeated after reconfiguration. See [`Layout#sizing`].
76///
77/// [`#widget`]: macros::widget
78pub trait Events: Widget + Sized {
79 /// Does this widget have a different appearance on mouse over?
80 ///
81 /// If `true`, then the mouse moving over and leaving the widget will cause
82 /// a redraw. (Note that [`Layout::draw`] can infer the mouse-over state and
83 /// start animations.)
84 const REDRAW_ON_MOUSE_OVER: bool = false;
85
86 /// The mouse pointer icon to use on mouse over
87 ///
88 /// Defaults to `None`.
89 #[inline]
90 fn mouse_over_icon(&self) -> Option<CursorIcon> {
91 None
92 }
93
94 /// Make an identifier for a child
95 ///
96 /// This is used to assign children identifiers. It may return
97 /// [`Id::default`] in order to avoid configuring the child, but in
98 /// this case the widget must configure via another means.
99 ///
100 /// If this is implemented explicitly then [`Tile::find_child_index`] must
101 /// be too.
102 ///
103 /// Default impl: `self.id_ref().make_child(index)`
104 #[inline]
105 fn make_child_id(&mut self, index: usize) -> Id {
106 self.id_ref().make_child(index)
107 }
108
109 /// Probe a coordinate for a widget's [`Id`]
110 ///
111 /// Returns the [`Id`] of the widget expected to handle clicks and touch
112 /// events at the given `coord`. Typically this is the lowest descendant in
113 /// the widget tree at the given `coord`, but it is not required to be; e.g.
114 /// a `Button` may use an inner widget as a label but return its own [`Id`]
115 /// to indicate that the button (not the inner label) handles clicks.
116 ///
117 /// # Calling
118 ///
119 /// This method may only be called after the widget is sized.
120 ///
121 /// Call [`Tile::try_probe`] instead.
122 ///
123 /// # Implementation
124 ///
125 /// The callee may usually assume that it occupies `coord` and may thus
126 /// return its own [`Id`] when no child occupies the input `coord`.
127 /// If there are cases where a click within [`Layout::rect`] should be
128 /// considered a miss (non-rectangular hit-testing) then
129 /// [`Tile::try_probe`] must be implemented instead.
130 ///
131 /// If the [`Tile::translation`] is non-zero for any child, then the
132 /// coordinate passed to that child must be translated:
133 /// `coord + translation`.
134 ///
135 /// ## Default implementation
136 ///
137 /// The default implementation returns `self.id()` and may be used for
138 /// childless widgets. If the [`layout`](macro@crate::layout) attribute
139 /// macro is used or an explicit implementation of [`Tile::try_probe`] is
140 /// provided, these are used instead of the default implementation of this
141 /// method.
142 fn probe(&self, coord: Coord) -> Id {
143 let _ = coord;
144 self.id()
145 }
146
147 /// Configure self
148 ///
149 /// # Calling
150 ///
151 /// This method is called as part of [configuration](Self#configuration).
152 /// This method is called *before* children are assigned identifiers; see
153 /// also [`post_configure`](Self::post_configure).
154 ///
155 /// Invoke by calling [`ConfigCx::configure`].
156 ///
157 /// # Implementation
158 ///
159 /// The window's scale factor (and thus any sizes available through
160 /// [`ConfigCx::size_cx`]) may change at run-time; this is common since some
161 /// platforms require sizing with scale factor 1 before . Such changes require resizing (calling [`Layout::size_rules`]
162 /// again) but do not require reconfiguration.
163 ///
164 /// The default implementation does nothing.
165 fn configure(&mut self, cx: &mut ConfigCx) {
166 let _ = cx;
167 }
168
169 /// Configure self (post-child-configuration actions)
170 ///
171 /// # Calling
172 ///
173 /// This method is called as part of [configuration](Self#configuration).
174 ///
175 /// The default implementation does nothing.
176 fn post_configure(&mut self, cx: &mut ConfigCx) {
177 let _ = cx;
178 }
179
180 /// Update self using input data
181 ///
182 /// # Calling
183 ///
184 /// This method is called as part of [configuration](Self#configuration)
185 /// and [update](Self#update).
186 ///
187 /// Invoke by calling [`ConfigCx::update`].
188 ///
189 /// # Implementation
190 ///
191 /// The default implementation does nothing.
192 fn update(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
193 let _ = (cx, data);
194 }
195
196 /// Recursion control
197 ///
198 /// [Configuration](Self#configuration) and [update](Self#update) normally
199 /// recurse to all children listed by [`Tile::child_indices`]; this
200 /// recursion is controlled by this method.
201 ///
202 /// # Calling
203 ///
204 /// This method is called after [`Self::update`].
205 ///
206 /// # Implementation
207 ///
208 /// The default implementation returns the result of [`Tile::child_indices`].
209 #[inline]
210 fn recurse_indices(&self) -> ChildIndices {
211 self.child_indices()
212 }
213
214 /// Mouse focus handler
215 ///
216 /// # Calling
217 ///
218 /// This method may only be called after the widget is sized.
219 ///
220 /// Called when mouse moves over or leaves this widget.
221 /// (This is a low-level alternative
222 /// to [`Self::REDRAW_ON_MOUSE_OVER`] and [`Self::mouse_over_icon`].)
223 ///
224 /// # Implementation
225 ///
226 /// `state` is true when the mouse is over this widget.
227 #[inline]
228 fn handle_mouse_over(&mut self, cx: &mut EventCx, state: bool) {
229 if Self::REDRAW_ON_MOUSE_OVER {
230 cx.redraw();
231 }
232 if state && let Some(icon) = self.mouse_over_icon() {
233 cx.set_mouse_over_icon(icon);
234 }
235 }
236
237 /// Notification that a child received navigation focus
238 ///
239 /// This is received after the child `id` receives [`Event::NavFocus`],
240 /// hence [`EventCx::last_child`] should be set.
241 ///
242 /// # Calling
243 ///
244 /// This method may only be called after the widget is sized.
245 #[inline]
246 fn child_nav_focus(&mut self, cx: &mut EventCx, id: Id) {
247 let _ = (cx, id);
248 }
249
250 /// Handle an [`Event`]
251 ///
252 /// This is the primary event handler (see [documentation](crate::event)).
253 ///
254 /// # Calling
255 ///
256 /// This method may only be called after the widget is sized.
257 ///
258 /// This method is called on the primary event target. In this case,
259 /// [`EventCx::last_child`] returns `None`.
260 ///
261 /// This method may also be called on ancestors during unwinding (if the
262 /// event remains [unused](Unused) and the event
263 /// [is reusable](Event::is_reusable)). In this case,
264 /// [`EventCx::last_child`] returns `Some(index)` with the index of the
265 /// child being unwound from.
266 ///
267 /// # Implementation
268 ///
269 /// Default implementation of `handle_event`: do nothing; return
270 /// [`Unused`].
271 fn handle_event(&mut self, cx: &mut EventCx, data: &Self::Data, event: Event) -> IsUsed {
272 let _ = (cx, data, event);
273 Unused
274 }
275
276 /// Handler for messages from children/descendants
277 ///
278 /// This is the secondary event handler (see [documentation](crate::event)).
279 ///
280 /// # Calling
281 ///
282 /// This method may only be called after the widget is configured. The
283 /// widget may or may not be sized.
284 ///
285 /// # Implementation
286 ///
287 /// It is implied that the stack contains at least one message.
288 /// Use [`EventCx::try_pop`] and/or [`EventCx::try_peek`] to handle known
289 /// messages. It is sufficient to handle a single message excepting where a
290 /// sender pushes multiple messages at once using [`EventCx::push`]. (Note
291 /// that messages sent using [`EventState::send`] are sent individually.)
292 ///
293 /// [`EventCx::last_child`] may be called to find the message's sender.
294 /// This may return [`None`] (if no child was visited, which implies that
295 /// the message was sent by `self`).
296 ///
297 /// The default implementation does nothing.
298 #[inline]
299 fn handle_messages(&mut self, cx: &mut EventCx, data: &Self::Data) {
300 let _ = (cx, data);
301 }
302
303 /// Handler for resize requests
304 ///
305 /// # Calling
306 ///
307 /// This method may only be called after the widget is sized.
308 ///
309 /// This method is called during [event handling](crate::event) whenever a
310 /// resize action is required (see [`ConfigCx::resize`]).
311 ///
312 /// # Implementation
313 ///
314 /// Some widgets (for example, a scroll region) are able to handle resizes
315 /// locally and should implement this method to do so
316 /// (thus avoiding the need for a full-window resize).
317 ///
318 /// Return `Some(ActionResize)` if further resizing is needed, or `None` if
319 /// resizing is complete.
320 ///
321 /// The default implementation simply returns `Some(ActionResize)`.
322 #[inline]
323 #[must_use]
324 fn handle_resize(&mut self, cx: &mut ConfigCx, data: &Self::Data) -> Option<ActionResize> {
325 let _ = (cx, data);
326 Some(ActionResize)
327 }
328
329 /// Handler for scrolling
330 ///
331 /// # Calling
332 ///
333 /// This method may only be called after the widget is sized.
334 ///
335 /// This method is called during [event handling](crate::event) whenever the
336 /// scroll action is not [`Scroll::None`] (see [`EventCx::set_scroll`]).
337 ///
338 /// # Implementation
339 ///
340 /// Widgets should implement this if they support scrolling of children,
341 /// have [`translation`](Tile::translation) of children or would isolate
342 /// parents from the scrolling of a child.
343 ///
344 /// This method is expected to deal with scrolling only; if the content size
345 /// has changed and `cx.resize()` is called by the affected child, then
346 /// [`Self::handle_resize`] should be called before this method.
347 ///
348 /// [`EventCx::last_child`] may be called to find the child responsible,
349 /// and should never return [`None`] (when called from this method).
350 ///
351 /// The default implementation does nothing.
352 #[inline]
353 fn handle_scroll(&mut self, cx: &mut EventCx, data: &Self::Data, scroll: Scroll) {
354 let _ = (cx, data, scroll);
355 }
356}