kas_core/core/
node.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//! Node API for widgets
7
8use super::Widget;
9use crate::event::{ConfigCx, Event, EventCx, IsUsed};
10use crate::geom::{Coord, Rect};
11use crate::layout::{AlignHints, AxisInfo, SizeRules};
12use crate::theme::{DrawCx, SizeCx};
13use crate::{Id, Layout, NavAdvance};
14
15#[cfg(not(feature = "unsafe_node"))]
16trait NodeT {
17    fn id_ref(&self) -> &Id;
18    fn rect(&self) -> Rect;
19
20    fn clone_node(&mut self) -> Node<'_>;
21    fn as_layout(&self) -> &dyn Layout;
22
23    fn num_children(&self) -> usize;
24    fn find_child_index(&self, id: &Id) -> Option<usize>;
25    fn for_child_node(&mut self, index: usize, f: Box<dyn FnOnce(Node<'_>) + '_>);
26
27    fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules;
28    fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints);
29
30    fn nav_next(&self, reverse: bool, from: Option<usize>) -> Option<usize>;
31    fn find_id(&mut self, coord: Coord) -> Option<Id>;
32    fn _draw(&mut self, draw: DrawCx);
33
34    fn _configure(&mut self, cx: &mut ConfigCx, id: Id);
35    fn _update(&mut self, cx: &mut ConfigCx);
36
37    fn _send(&mut self, cx: &mut EventCx, id: Id, event: Event) -> IsUsed;
38    fn _replay(&mut self, cx: &mut EventCx, id: Id);
39    fn _nav_next(
40        &mut self,
41        cx: &mut ConfigCx,
42        focus: Option<&Id>,
43        advance: NavAdvance,
44    ) -> Option<Id>;
45}
46#[cfg(not(feature = "unsafe_node"))]
47impl<'a, T> NodeT for (&'a mut dyn Widget<Data = T>, &'a T) {
48    fn id_ref(&self) -> &Id {
49        self.0.id_ref()
50    }
51    fn rect(&self) -> Rect {
52        self.0.rect()
53    }
54
55    fn clone_node(&mut self) -> Node<'_> {
56        Node::new(self.0, self.1)
57    }
58    fn as_layout(&self) -> &dyn Layout {
59        self.0.as_layout()
60    }
61
62    fn num_children(&self) -> usize {
63        self.0.num_children()
64    }
65    fn find_child_index(&self, id: &Id) -> Option<usize> {
66        self.0.find_child_index(id)
67    }
68
69    fn for_child_node(&mut self, index: usize, f: Box<dyn FnOnce(Node<'_>) + '_>) {
70        self.0.for_child_node(self.1, index, f);
71    }
72
73    fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
74        self.0.size_rules(sizer, axis)
75    }
76    fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
77        self.0.set_rect(cx, rect, hints);
78    }
79
80    fn nav_next(&self, reverse: bool, from: Option<usize>) -> Option<usize> {
81        self.0.nav_next(reverse, from)
82    }
83    fn find_id(&mut self, coord: Coord) -> Option<Id> {
84        self.0.find_id(coord)
85    }
86    fn _draw(&mut self, mut draw: DrawCx) {
87        draw.recurse(&mut self.0);
88    }
89
90    fn _configure(&mut self, cx: &mut ConfigCx, id: Id) {
91        self.0._configure(cx, self.1, id);
92    }
93    fn _update(&mut self, cx: &mut ConfigCx) {
94        self.0._update(cx, self.1);
95    }
96
97    fn _send(&mut self, cx: &mut EventCx, id: Id, event: Event) -> IsUsed {
98        self.0._send(cx, self.1, id, event)
99    }
100    fn _replay(&mut self, cx: &mut EventCx, id: Id) {
101        self.0._replay(cx, self.1, id);
102    }
103    fn _nav_next(
104        &mut self,
105        cx: &mut ConfigCx,
106        focus: Option<&Id>,
107        advance: NavAdvance,
108    ) -> Option<Id> {
109        self.0._nav_next(cx, self.1, focus, advance)
110    }
111}
112
113/// Type-erased widget with input data
114///
115/// This type is a `&mut dyn Widget<Data = A>` paired with input data `&A`,
116/// where the type `A` is erased.
117///
118/// The default implementation of this type uses a boxed trait object.
119/// The `unsafe_node` feature enables a more efficient unboxed implementation
120/// (this must make assumptions about VTables beyond what Rust specifies, thus
121/// lacks even the usual programmer-provided verification of `unsafe` code).
122pub struct Node<'a>(
123    #[cfg(not(feature = "unsafe_node"))] Box<dyn NodeT + 'a>,
124    #[cfg(feature = "unsafe_node")] &'a mut dyn Widget<Data = ()>,
125    #[cfg(feature = "unsafe_node")] &'a (),
126);
127
128impl<'a> Node<'a> {
129    /// Construct
130    #[inline(always)]
131    pub fn new<T: 'a>(widget: &'a mut dyn Widget<Data = T>, data: &'a T) -> Self {
132        cfg_if::cfg_if! {
133            if #[cfg(feature = "unsafe_node")] {
134                // Safety: since the vtable for dyn Widget<Data = T> only uses T as &T
135                // and T: Sized, the vtable should be equivalent for all T.
136                // We ensure here that the type of `data` matches that used by `widget`.
137                // NOTE: This makes assumptions beyond Rust's specification.
138                use std::mem::transmute;
139                unsafe { Node(transmute(widget), transmute(data)) }
140            } else {
141                Node(Box::new((widget, data)))
142            }
143        }
144    }
145
146    /// Reborrow with a new lifetime
147    ///
148    /// Rust allows references like `&T` or `&mut T` to be "reborrowed" through
149    /// coercion: essentially, the pointer is copied under a new, shorter, lifetime.
150    /// Until rfcs#1403 lands, reborrows on user types require a method call.
151    #[inline(always)]
152    pub fn re<'b>(&'b mut self) -> Node<'b>
153    where
154        'a: 'b,
155    {
156        cfg_if::cfg_if! {
157            if #[cfg(feature = "unsafe_node")] {
158                Node(self.0, self.1)
159            } else {
160                self.0.clone_node()
161            }
162        }
163    }
164
165    /// Reborrow as a `dyn Layout`
166    pub fn as_layout(&self) -> &dyn Layout {
167        self.0.as_layout()
168    }
169
170    /// Get the widget's identifier
171    #[inline]
172    pub fn id_ref(&self) -> &Id {
173        self.0.id_ref()
174    }
175
176    /// Get the widget's identifier
177    #[inline]
178    pub fn id(&self) -> Id {
179        self.id_ref().clone()
180    }
181
182    /// Test widget identifier for equality
183    ///
184    /// This method may be used to test against `Id`, `Option<Id>`
185    /// and `Option<&Id>`.
186    #[inline]
187    pub fn eq_id<T>(&self, rhs: T) -> bool
188    where
189        Id: PartialEq<T>,
190    {
191        *self.id_ref() == rhs
192    }
193
194    /// Check whether `id` is self or a descendant
195    ///
196    /// This function assumes that `id` is a valid widget.
197    #[inline]
198    pub fn is_ancestor_of(&self, id: &Id) -> bool {
199        self.id().is_ancestor_of(id)
200    }
201
202    /// Check whether `id` is not self and is a descendant
203    ///
204    /// This function assumes that `id` is a valid widget.
205    #[inline]
206    pub fn is_strict_ancestor_of(&self, id: &Id) -> bool {
207        !self.eq_id(id) && self.id().is_ancestor_of(id)
208    }
209
210    /// Get the widget's region, relative to its parent.
211    #[inline]
212    pub fn rect(&self) -> Rect {
213        self.0.rect()
214    }
215
216    /// Get the number of child widgets
217    ///
218    /// Every value in the range `0..self.num_children()` is a valid child
219    /// index.
220    #[inline]
221    pub fn num_children(&self) -> usize {
222        self.0.num_children()
223    }
224
225    /// Run `f` on some child by index and, if valid, return the result.
226    ///
227    /// Calls the closure and returns `Some(result)` exactly when
228    /// `index < self.num_children()`.
229    pub fn for_child<R>(&mut self, index: usize, f: impl FnOnce(Node<'_>) -> R) -> Option<R> {
230        let mut result = None;
231        let out = &mut result;
232        let f: Box<dyn for<'b> FnOnce(Node<'b>)> = Box::new(|node| {
233            *out = Some(f(node));
234        });
235        cfg_if::cfg_if! {
236            if #[cfg(feature = "unsafe_node")] {
237                self.0.for_child_node(self.1, index, f);
238            } else {
239                self.0.for_child_node(index, f);
240            }
241        }
242        result
243    }
244
245    /// Run a `f` on all children
246    pub fn for_children(&mut self, mut f: impl FnMut(Node<'_>)) {
247        for index in 0..self.0.num_children() {
248            // NOTE: for_child_node takes FnOnce hence we must wrap the closure
249            let f = &mut f;
250            let f: Box<dyn for<'b> FnOnce(Node<'b>)> = Box::new(|node| {
251                f(node);
252            });
253            cfg_if::cfg_if! {
254                if #[cfg(feature = "unsafe_node")] {
255                    self.0.for_child_node(self.1, index, f);
256                } else {
257                    self.0.for_child_node(index, f);
258                }
259            }
260        }
261    }
262
263    /// Find the child which is an ancestor of this `id`, if any
264    ///
265    /// If `Some(index)` is returned, this is *probably* but not guaranteed
266    /// to be a valid child index.
267    #[inline]
268    pub fn find_child_index(&self, id: &Id) -> Option<usize> {
269        self.0.find_child_index(id)
270    }
271
272    /// Find the descendant with this `id`, if any, and call `cb` on it
273    ///
274    /// Returns `Some(result)` if and only if node `id` was found.
275    pub fn find_node<F: FnOnce(Node<'_>) -> T, T>(&mut self, id: &Id, cb: F) -> Option<T> {
276        if let Some(index) = self.find_child_index(id) {
277            self.for_child(index, |mut node| node.find_node(id, cb))
278                .unwrap()
279        } else if self.eq_id(id) {
280            Some(cb(self.re()))
281        } else {
282            None
283        }
284    }
285}
286
287#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
288#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
289impl<'a> Node<'a> {
290    /// Get size rules for the given axis
291    pub(crate) fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
292        self.0.size_rules(sizer, axis)
293    }
294
295    /// Set size and position
296    pub(crate) fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
297        self.0.set_rect(cx, rect, hints);
298    }
299
300    /// Navigation in spatial order
301    pub(crate) fn nav_next(&self, reverse: bool, from: Option<usize>) -> Option<usize> {
302        self.0.nav_next(reverse, from)
303    }
304
305    /// Translate a coordinate to an [`Id`]
306    pub(crate) fn find_id(&mut self, coord: Coord) -> Option<Id> {
307        self.0.find_id(coord)
308    }
309
310    cfg_if::cfg_if! {
311        if #[cfg(feature = "unsafe_node")] {
312            /// Draw a widget and its children
313            pub(crate) fn _draw(&mut self, mut draw: DrawCx) {
314                draw.recurse(&mut self.0);
315            }
316        } else {
317            /// Draw a widget and its children
318            pub(crate) fn _draw(&mut self, draw: DrawCx) {
319                self.0._draw(draw);
320            }
321        }
322    }
323
324    /// Internal method: configure recursively
325    pub(crate) fn _configure(&mut self, cx: &mut ConfigCx, id: Id) {
326        cfg_if::cfg_if! {
327            if #[cfg(feature = "unsafe_node")] {
328                self.0._configure(cx, self.1, id);
329            } else {
330                self.0._configure(cx, id);
331            }
332        }
333    }
334
335    /// Internal method: update recursively
336    pub(crate) fn _update(&mut self, cx: &mut ConfigCx) {
337        cfg_if::cfg_if! {
338            if #[cfg(feature = "unsafe_node")] {
339                self.0._update(cx, self.1);
340            } else {
341                self.0._update(cx);
342            }
343        }
344    }
345
346    /// Internal method: send recursively
347    pub(crate) fn _send(&mut self, cx: &mut EventCx, id: Id, event: Event) -> IsUsed {
348        cfg_if::cfg_if! {
349            if #[cfg(feature = "unsafe_node")] {
350                self.0._send(cx, self.1, id, event)
351            } else {
352                self.0._send(cx, id, event)
353            }
354        }
355    }
356
357    /// Internal method: replay recursively
358    pub(crate) fn _replay(&mut self, cx: &mut EventCx, id: Id) {
359        cfg_if::cfg_if! {
360            if #[cfg(feature = "unsafe_node")] {
361                self.0._replay(cx, self.1, id);
362            } else {
363                self.0._replay(cx, id);
364            }
365        }
366    }
367
368    /// Internal method: search for the previous/next navigation target
369    // NOTE: public on account of ListView
370    pub fn _nav_next(
371        &mut self,
372        cx: &mut ConfigCx,
373        focus: Option<&Id>,
374        advance: NavAdvance,
375    ) -> Option<Id> {
376        cfg_if::cfg_if! {
377            if #[cfg(feature = "unsafe_node")] {
378                self.0._nav_next(cx, self.1, focus, advance)
379            } else {
380                self.0._nav_next(cx, focus, advance)
381            }
382        }
383    }
384}