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
8#[allow(unused)] use super::{Events, Layout};
9use super::{Node, Tile};
10use crate::Id;
11#[allow(unused)] use crate::event::EventState;
12use crate::event::{ConfigCx, Event, EventCx, IsUsed, NavAdvance};
13#[allow(unused)] use kas_macros as macros;
14use kas_macros::autoimpl;
15
16/// The Widget trait
17///
18/// The primary widget trait covers event handling over super trait [`Tile`]
19/// which governs layout, drawing, child enumeration and identification.
20/// Most methods of `Widget` are hidden and only for use within the Kas library.
21///
22/// `Widget` is dyn-safe given a type parameter, e.g. `dyn Widget<Data = ()>`.
23/// [`Tile`] is dyn-safe without a type parameter. [`Node`] is a dyn-safe
24/// abstraction over a `&dyn Widget<Data = T>` plus a `&T` data parameter.
25///
26/// # Widget lifecycle
27///
28/// 1. The widget is configured ([`Events::configure`]) and immediately updated
29/// ([`Events::update`]).
30/// 2. The widget has its size-requirements checked by calling
31/// [`Layout::size_rules`] for each axis.
32/// 3. [`Layout::set_rect`] is called to position elements. This may use data
33/// cached by `size_rules`.
34/// 4. The widget is updated again after any data change (see [`ConfigCx::update`]).
35/// 5. The widget is ready for event-handling and drawing
36/// ([`Events::handle_event`], [`Layout::try_probe`], [`Layout::draw`]).
37///
38/// Widgets are responsible for ensuring that their children may observe this
39/// lifecycle. Usually this simply involves inclusion of the child in layout
40/// operations. Steps of the lifecycle may be postponed until a widget becomes
41/// visible.
42///
43/// # Implementing Widget
44///
45/// To implement a widget, use the [`#widget`] macro within an
46/// [`impl_self`](macros::impl_self), [`impl_scope!`](macros::impl_scope) or
47/// [`impl_anon!`](macros::impl_anon) macro.
48/// **This is the only supported method of implementing `Widget`.**
49///
50/// Explicit (partial) implementations of [`Widget`], [`Layout`], [`Tile`] and [`Events`]
51/// are optional. The [`#widget`] macro completes implementations.
52///
53/// Synopsis:
54/// ```ignore
55/// #[impl_self]
56/// mod MyWidget {
57/// #[widget {
58/// // macro properties (all optional)
59/// Data = T;
60/// }]
61/// #[layout(self.foo)]
62/// struct MyWidget {
63/// core: widget_core!(),
64/// #[widget] foo: impl Widget<Data = T> = make_foo(),
65/// // ...
66/// }
67///
68/// // Optional implementations:
69/// impl Layout for Self { /* ... */ }
70/// impl Events for Self { /* ... */ }
71/// impl Self { /* ... */ }
72/// }
73/// ```
74///
75/// Details may be categorised as follows:
76///
77/// - **Data**: the type [`Widget::Data`] must be specified exactly once, but
78/// this type may be given in any of three locations: as a property of the
79/// [`#widget`] macro or as [`Widget::Data`].
80/// - **Core** methods of [`Tile`] are *always* implemented via the [`#widget`]
81/// macro, whether or not an `impl Tile { ... }` item is present.
82/// - **Introspection** methods [`Tile::child_indices`], [`Tile::get_child`]
83/// and [`Widget::child_node`] are implemented by the [`#widget`] macro
84/// in most cases: child widgets embedded within a layout descriptor or
85/// included as fields marked with `#[widget]` are enumerated.
86/// - **Introspection** methods [`Tile::find_child_index`] and
87/// [`Events::make_child_id`] have default implementations which *usually*
88/// suffice.
89/// - **Layout** is specified either via [layout syntax](macros::widget#layout-1)
90/// or via implementation of at least [`Layout::size_rules`] and
91/// [`Layout::draw`] (optionally also `set_rect`, `nav_next`, `translation`
92/// and [`Tile::probe`]).
93///- **Event handling** is optional, implemented through [`Events`].
94///
95/// For examples, check the source code of widgets in the widgets library
96/// or [examples apps](https://github.com/kas-gui/kas/tree/master/examples).
97/// (Check that the code uses the same Kas version since the widget traits are
98/// not yet stable.)
99///
100/// [`#widget`]: macros::widget
101#[autoimpl(for<T: trait + ?Sized> &'_ mut T, Box<T>)]
102pub trait Widget: Tile {
103 /// Input data type
104 ///
105 /// Widget expects data of this type to be provided by reference when
106 /// calling any event-handling operation on this widget.
107 ///
108 /// Type `Data` should be specified either here (`impl Widget { ... }`) or
109 /// in `impl Events { ... }`. Alternatively, if the widget has no children
110 /// and no explicit `impl Events` or `impl Widget`, then `Data = ()` is
111 /// assumed; or, if the prior conditions are met and `#[collection]` is used
112 /// on some field, then `Data = <#field_ty as ::kas::Collection>::Data` is
113 /// assumed.
114 ///
115 /// [`#widget`]: macros::widget
116 //
117 // SAFETY: the unsafe_node feature requires Data: Sized.
118 type Data: Sized;
119
120 /// Erase type
121 ///
122 /// This method is implemented by the `#[widget]` macro.
123 fn as_node<'a>(&'a mut self, data: &'a Self::Data) -> Node<'a> {
124 let _ = data;
125 unimplemented!() // make rustdoc show that this is a provided method
126 }
127
128 /// Access a child as a [`Node`], if available
129 ///
130 /// This method is the `mut` version of [`Tile::get_child`] but which also
131 /// pairs the returned widget with its input `data`. It is expected to
132 /// succeed where [`Tile::get_child`] succeeds.
133 ///
134 /// Valid `index` values may be discovered by calling
135 /// [`Tile::child_indices`], [`Tile::find_child_index`] or
136 /// [`Tile::nav_next`]. The `index`-to-child mapping is not
137 /// required to remain fixed; use an [`Id`] to track a widget over time.
138 ///
139 /// This method must be implemented explicitly when [`Tile::get_child`] is.
140 /// It might also need to be implemented explicitly to map `data`, though
141 /// usually the `#[widget]` attribute on children specifies this mapping.
142 fn child_node<'n>(&'n mut self, data: &'n Self::Data, index: usize) -> Option<Node<'n>> {
143 let _ = (data, index);
144 unimplemented!() // make rustdoc show that this is a provided method
145 }
146
147 /// Internal method: configure recursively
148 ///
149 /// Do not implement this method directly!
150 #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
151 #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
152 fn _configure(&mut self, cx: &mut ConfigCx, data: &Self::Data, id: Id);
153
154 /// Internal method: update recursively
155 ///
156 /// Do not implement this method directly!
157 #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
158 #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
159 fn _update(&mut self, cx: &mut ConfigCx, data: &Self::Data);
160
161 /// Internal method: send recursively
162 ///
163 /// Do not implement this method directly!
164 #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
165 #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
166 fn _send(&mut self, cx: &mut EventCx, data: &Self::Data, id: Id, event: Event) -> IsUsed;
167
168 /// Internal method: replay recursively
169 ///
170 /// Traverses the widget tree to `id`, then unwinds.
171 /// It is expected that some message is available on the stack.
172 ///
173 /// Do not implement this method directly!
174 #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
175 #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
176 fn _replay(&mut self, cx: &mut EventCx, data: &Self::Data, id: Id);
177
178 /// Internal method: search for the previous/next navigation target
179 ///
180 /// `focus`: the current focus or starting point.
181 ///
182 /// Do not implement this method directly!
183 #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
184 #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
185 fn _nav_next(
186 &mut self,
187 cx: &mut ConfigCx,
188 data: &Self::Data,
189 focus: Option<&Id>,
190 advance: NavAdvance,
191 ) -> Option<Id>;
192}