Skip to main content

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}