kas_core/core/
widget.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::{Layout, Node};
9#[allow(unused)] use crate::event::Used;
10use crate::event::{ConfigCx, Event, EventCx, IsUsed, Scroll, Unused};
11use crate::Id;
12use kas_macros::autoimpl;
13
14#[allow(unused)] use kas_macros as macros;
15
16/// Widget event-handling
17///
18/// This trait governs event handling as part of a [`Widget`] implementation.
19/// It is used by the [`#widget`] macro to generate hidden [`Widget`] methods.
20///
21/// The implementation of this method may be omitted where no event-handling is
22/// required. All methods have a default implementation.
23///
24/// # Widget lifecycle
25///
26/// 1.  The widget is configured ([`Events::configure`]) and immediately updated
27///     ([`Events::update`]).
28/// 2.  The widget has its size-requirements checked by calling
29///     [`Layout::size_rules`] for each axis.
30/// 3.  [`Layout::set_rect`] is called to position elements. This may use data
31///     cached by `size_rules`.
32/// 4.  The widget is updated again after any data change (see [`ConfigCx::update`]).
33/// 5.  The widget is ready for event-handling and drawing
34///     ([`Events::handle_event`], [`Layout::find_id`], [`Layout::draw`]).
35///
36/// Widgets are responsible for ensuring that their children may observe this
37/// lifecycle. Usually this simply involves inclusion of the child in layout
38/// operations. Steps of the lifecycle may be postponed until a widget becomes
39/// visible.
40///
41/// [`#widget`]: macros::widget
42pub trait Events: Widget + Sized {
43    /// Make an identifier for a child
44    ///
45    /// This is used to assign children identifiers. It may return
46    /// [`Id::default`] in order to avoid configuring the child, but in
47    /// this case the widget must configure via another means.
48    ///
49    /// If this is implemented explicitly then [`Layout::find_child_index`] must
50    /// be too.
51    ///
52    /// Default impl: `self.id_ref().make_child(index)`
53    #[inline]
54    fn make_child_id(&mut self, index: usize) -> Id {
55        self.id_ref().make_child(index)
56    }
57
58    /// Configure self
59    ///
60    /// Widgets are *configured* before sizing, drawing and event handling (see
61    /// [widget lifecycle](Widget#widget-lifecycle)). Configuration may be
62    /// repeated at any time.
63    ///
64    /// [`Self::update`] is always called immediately after this method,
65    /// followed by [`Self::configure_recurse`].
66    ///
67    /// The window's scale factor (and thus any sizes available through
68    /// [`ConfigCx::size_cx`]) may not be correct initially (some platforms
69    /// construct all windows using scale factor 1) and/or may change in the
70    /// future. Changes to the scale factor result in recalculation of
71    /// [`Layout::size_rules`] but not repeated configuration.
72    ///
73    /// The default implementation does nothing.
74    fn configure(&mut self, cx: &mut ConfigCx) {
75        let _ = cx;
76    }
77
78    /// Configure children
79    ///
80    /// This method is called after [`Self::configure`].
81    /// It usually configures all children.
82    ///
83    /// The default implementation suffices except where children should *not*
84    /// be configured (for example, to delay configuration of hidden children).
85    ///
86    /// Use [`Events::make_child_id`] and [`ConfigCx::configure`].
87    fn configure_recurse(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
88        for index in 0..self.num_children() {
89            let id = self.make_child_id(index);
90            if id.is_valid() {
91                self.as_node(data)
92                    .for_child(index, |node| cx.configure(node, id));
93            }
94        }
95    }
96
97    /// Update self using input data
98    ///
99    /// This method is called immediately after [`Self::configure`] and after
100    /// any input data is updated, before [`Layout::draw`] is called.
101    /// Typically this method is called immediately after the data is updated
102    /// but the call may be delayed until when the widget becomes visible.
103    ///
104    /// This method is called before [`Self::update_recurse`].
105    ///
106    /// The default implementation does nothing.
107    fn update(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
108        let _ = (cx, data);
109    }
110
111    /// Update children
112    ///
113    /// This method is called after [`Self::update`]. It usually configures all
114    /// children. Children should be updated even if their data is `()` or is
115    /// unchanged.
116    ///
117    /// The default implementation suffices except where children should *not*
118    /// be updated (for example, to delay update of hidden children).
119    ///
120    /// Use [`ConfigCx::update`].
121    fn update_recurse(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
122        for index in 0..self.num_children() {
123            self.as_node(data).for_child(index, |node| cx.update(node));
124        }
125    }
126
127    /// Is this widget navigable via <kbd>Tab</kbd> key?
128    ///
129    /// Note that when this method returns `false` the widget will not receive
130    /// navigation focus via the <kbd>Tab</kbd> key, but it may still receive
131    /// navigation focus through some other means, for example a keyboard
132    /// shortcut or a mouse click.
133    ///
134    /// Defaults to `false`. May instead be set via the `navigable` property of
135    /// the `#[widget]` macro.
136    #[inline]
137    fn navigable(&self) -> bool {
138        false
139    }
140
141    /// Mouse focus handler
142    ///
143    /// Called when mouse hover state changes.
144    ///
145    /// When the [`#widget`] macro properties `hover_highlight` or `cursor_icon`
146    /// are used, an instance of this method is generated. Otherwise, the
147    /// default implementation of this method does nothing.
148    ///
149    /// Note: to implement `hover_highlight`, simply request a redraw on
150    /// focus gain and loss. To implement `cursor_icon`, call
151    /// `cx.set_hover_cursor(EXPR);` on focus gain.
152    ///
153    /// [`#widget`]: macros::widget
154    #[inline]
155    fn handle_hover(&mut self, cx: &mut EventCx, state: bool) {
156        let _ = (cx, state);
157    }
158
159    /// Handle an [`Event`]
160    ///
161    /// This is the primary event handler (see [documentation](crate::event)).
162    ///
163    /// This method is called on the primary event target. In this case,
164    /// [`EventCx::last_child`] returns `None`.
165    ///
166    /// This method may also be called on ancestors during unwinding (if the
167    /// event remains [unused](Unused) and the event
168    /// [is reusable](Event::is_reusable)). In this case,
169    /// [`EventCx::last_child`] returns `Some(index)` with the index of the
170    /// child being unwound from.
171    ///
172    /// Default implementation of `handle_event`: do nothing; return
173    /// [`Unused`].
174    fn handle_event(&mut self, cx: &mut EventCx, data: &Self::Data, event: Event) -> IsUsed {
175        let _ = (cx, data, event);
176        Unused
177    }
178
179    /// Handler for messages from children/descendants
180    ///
181    /// This is the secondary event handler (see [documentation](crate::event)).
182    ///
183    /// It is implied that the stack contains at least one message.
184    /// Use [`EventCx::try_pop`] and/or [`EventCx::try_observe`].
185    ///
186    /// [`EventCx::last_child`] may be called to find the message's sender.
187    /// This may return [`None`] (if no child was visited, which implies that
188    /// the message was sent by `self`).
189    ///
190    /// The default implementation does nothing.
191    #[inline]
192    fn handle_messages(&mut self, cx: &mut EventCx, data: &Self::Data) {
193        let _ = (cx, data);
194    }
195
196    /// Handler for scrolling
197    ///
198    /// When, during [event handling](crate::event), a widget which is a strict
199    /// descendant of `self` (i.e. not `self`) calls [`EventCx::set_scroll`]
200    /// with a value other than [`Scroll::None`], this method is called.
201    ///
202    /// Note that [`Scroll::Rect`] values are in the child's coordinate space,
203    /// and must be translated to the widget's own coordinate space by this
204    /// method (this is not done by the default implementation since any widget
205    /// with non-zero translation very likely wants to implement this method
206    /// anyway).
207    ///
208    /// If the child is in an independent coordinate space, then this method
209    /// should call `cx.set_scroll(Scroll::None)` to avoid any reactions to
210    /// child's scroll requests.
211    ///
212    /// [`EventCx::last_child`] may be called to find the child responsible,
213    /// and should never return [`None`] (when called from this method).
214    ///
215    /// The default implementation does nothing.
216    #[inline]
217    fn handle_scroll(&mut self, cx: &mut EventCx, data: &Self::Data, scroll: Scroll) {
218        let _ = (cx, data, scroll);
219    }
220}
221
222/// Action of Widget::_nav_next
223#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
224#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
225#[derive(Copy, Clone, Debug, PartialEq, Eq)]
226pub enum NavAdvance {
227    /// Match only `focus` if navigable
228    None,
229    /// Walk children forwards, self first
230    ///
231    /// Parameter: whether this can match self (in addition to other widgets).
232    Forward(bool),
233    /// Walk children backwards, self last
234    ///
235    /// Parameter: whether this can match self (in addition to other widgets).
236    Reverse(bool),
237}
238
239/// The Widget trait
240///
241/// The primary widget trait covers event handling over super trait [`Layout`]
242/// which governs layout, drawing, child enumeration and identification.
243/// Most methods of `Widget` are hidden and only for use within the Kas library.
244///
245/// `Widget` is dyn-safe given a type parameter, e.g. `dyn Widget<Data = ()>`.
246/// [`Layout`] is dyn-safe without a type parameter. [`Node`] is a dyn-safe
247/// abstraction over a `&dyn Widget<Data = T>` plus a `&T` data parameter.
248///
249/// # Widget lifecycle
250///
251/// 1.  The widget is configured ([`Events::configure`]) and immediately updated
252///     ([`Events::update`]).
253/// 2.  The widget has its size-requirements checked by calling
254///     [`Layout::size_rules`] for each axis.
255/// 3.  [`Layout::set_rect`] is called to position elements. This may use data
256///     cached by `size_rules`.
257/// 4.  The widget is updated again after any data change (see [`ConfigCx::update`]).
258/// 5.  The widget is ready for event-handling and drawing
259///     ([`Events::handle_event`], [`Layout::find_id`], [`Layout::draw`]).
260///
261/// Widgets are responsible for ensuring that their children may observe this
262/// lifecycle. Usually this simply involves inclusion of the child in layout
263/// operations. Steps of the lifecycle may be postponed until a widget becomes
264/// visible.
265///
266/// # Implementing Widget
267///
268/// To implement a widget, use the [`#widget`] macro within an
269/// [`impl_scope`](macros::impl_scope). **This is the only supported method of
270/// implementing `Widget`.**
271///
272/// Explicit (partial) implementations of [`Widget`], [`Layout`] and [`Events`]
273/// are optional. The [`#widget`] macro completes implementations.
274///
275/// Synopsis:
276/// ```ignore
277/// impl_scope! {
278///     #[widget {
279///         // macro properties (all optional)
280///         Data = T;
281///         layout = self.foo;
282///     }]
283///     struct MyWidget {
284///         core: widget_core!(),
285///         #[widget] foo: impl Widget<Data = T> = make_foo(),
286///         // ...
287///     }
288///
289///     // Optional implementations:
290///     impl Layout for Self { /* ... */ }
291///     impl Events for Self { /* ... */ }
292///     impl Self { /* ... */ }
293/// }
294/// ```
295///
296/// Details may be categorised as follows:
297///
298/// -   **Data**: the type [`Widget::Data`] must be specified exactly once, but
299///     this type may be given in any of three locations: as a property of the
300///     [`#widget`] macro or as [`Widget::Data`].
301/// -   **Core** methods of [`Layout`] are *always* implemented via the [`#widget`]
302///     macro, whether or not an `impl Layout { ... }` item is present.
303/// -   **Introspection** methods [`Layout::num_children`], [`Layout::get_child`]
304///     and [`Widget::for_child_node`] are implemented by the [`#widget`] macro
305///     in most cases: child widgets embedded within a layout descriptor or
306///     included as fields marked with `#[widget]` are enumerated.
307/// -   **Introspection** methods [`Layout::find_child_index`] and
308///     [`Events::make_child_id`] have default implementations which *usually*
309///     suffice.
310/// -   **Layout** is specified either via [layout syntax](macros::widget#layout-1)
311///     or via implementation of at least [`Layout::size_rules`] and
312///     [`Layout::draw`] (optionally also `set_rect`, `nav_next`, `translation`
313///     and `find_id`).
314///-    **Event handling** is optional, implemented through [`Events`].
315///
316/// For examples, check the source code of widgets in the widgets library
317/// or [examples apps](https://github.com/kas-gui/kas/tree/master/examples).
318/// (Check that the code uses the same Kas version since the widget traits are
319/// not yet stable.)
320///
321/// [`#widget`]: macros::widget
322#[autoimpl(for<T: trait + ?Sized> &'_ mut T, Box<T>)]
323pub trait Widget: Layout {
324    /// Input data type
325    ///
326    /// Widget expects data of this type to be provided by reference when
327    /// calling any event-handling operation on this widget.
328    ///
329    /// This type may be specified using a [`#widget`] macro property in case
330    /// this trait is not explicitly implemented.
331    ///
332    /// [`#widget`]: macros::widget
333    type Data;
334
335    /// Erase type
336    ///
337    /// This method is implemented by the `#[widget]` macro.
338    fn as_node<'a>(&'a mut self, data: &'a Self::Data) -> Node<'a> {
339        let _ = data;
340        unimplemented!() // make rustdoc show that this is a provided method
341    }
342
343    /// Call closure on child with given `index`, if `index < self.num_children()`.
344    ///
345    /// Widgets with no children or using the `#[widget]` attribute on fields do
346    /// not need to implement this. Widgets with an explicit implementation of
347    /// [`Layout::num_children`] also need to implement this.
348    ///
349    /// It is recommended to use the methods on [`Node`]
350    /// instead of calling this method.
351    fn for_child_node(
352        &mut self,
353        data: &Self::Data,
354        index: usize,
355        closure: Box<dyn FnOnce(Node<'_>) + '_>,
356    ) {
357        let _ = (data, index, closure);
358        unimplemented!() // make rustdoc show that this is a provided method
359    }
360
361    /// Internal method: configure recursively
362    ///
363    /// Do not implement this method directly!
364    #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
365    #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
366    fn _configure(&mut self, cx: &mut ConfigCx, data: &Self::Data, id: Id);
367
368    /// Internal method: update recursively
369    ///
370    /// Do not implement this method directly!
371    #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
372    #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
373    fn _update(&mut self, cx: &mut ConfigCx, data: &Self::Data);
374
375    /// Internal method: send recursively
376    ///
377    /// Do not implement this method directly!
378    #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
379    #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
380    fn _send(&mut self, cx: &mut EventCx, data: &Self::Data, id: Id, event: Event) -> IsUsed;
381
382    /// Internal method: replay recursively
383    ///
384    /// Traverses the widget tree to `id`, then unwinds.
385    /// It is expected that some message is available on the stack.
386    ///
387    /// Do not implement this method directly!
388    #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
389    #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
390    fn _replay(&mut self, cx: &mut EventCx, data: &Self::Data, id: Id);
391
392    /// Internal method: search for the previous/next navigation target
393    ///
394    /// `focus`: the current focus or starting point.
395    ///
396    /// Do not implement this method directly!
397    #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
398    #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
399    fn _nav_next(
400        &mut self,
401        cx: &mut ConfigCx,
402        data: &Self::Data,
403        focus: Option<&Id>,
404        advance: NavAdvance,
405    ) -> Option<Id>;
406}