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}