duat_core/ui/
widget.rs

1//! APIs for the construction of widgets, and a few common ones.
2//!
3//! This module has the [`Widget`] trait, which is a region on the
4//! window containing a [`Text`], and may be modified by user mode
5//! (but not necessarily).
6//!
7//! These widgets will be used in two circumstances:
8//!
9//! - Being pushed to [`Widget`]s via the [`WidgetCreated`] [`hook`];
10//! - Being pushed to the outer edges of a window via
11//!   [`WindowCreated`];
12//!
13//! They can be pushed to all 4 sides of other widgets through the
14//! use of [`PushSpecs`]. When pushing widgets, you can also include
15//! [`Constraint`]s in order to get a specific size on the screen for
16//! the widget.
17//!
18//! ```rust
19//! # use duat_core::ui::PushSpecs;
20//! let specs = PushSpecs::left().hor_min(10.0).ver_len(2.0);
21//! ```
22//!
23//! When pushing a widget with these `specs` to another widget, Duat
24//! will put it on the left, and _try_ to give it a minimum width of
25//! `10.0`, and a height of `2.0`.
26//!
27//! This module also describes a [`WidgetCfg`], which is used in
28//! widget construction.
29//!
30//! [`File`]: crate::file::File
31//! [`PromptLine`]: docs.rs/duat-utils/latest/duat_utils/widgets/struct.PromptLine.html
32//! [`LineNumbers`]: docs.rs/duat-utils/latest/duat_utils/widgets/struct.LineNumbers.html
33//! [`StatusLine`]: docs.rs/duat-utils/latest/duat_utils/widgets/struct.StatusLine.html
34//! [`duat-term`]: https://docs.rs/duat-term/latest/duat_term/
35//! [`VertRule`]: https://docs.rs/duat-term/latest/duat_term/struct.VertRule.html
36//! [`WidgetCreated`]: crate::hook::WidgetCreated
37//! [`WindowCreated`]: crate::hook::WindowCreated
38//! [`Constraint`]: crate::ui::Constraint
39use std::sync::{Arc, Mutex};
40
41use super::{Area, AreaId, PushSpecs, Ui};
42use crate::{
43    cfg::PrintCfg,
44    context::Handle,
45    data::{Pass, RwData},
46    form::{self, Painter},
47    hook::{self, FocusedOn, UnfocusedFrom},
48    text::Text,
49    ui::{BuildInfo, GetAreaId},
50};
51
52/// An area where [`Text`] will be printed to the screen
53///
54/// Most widgets are supposed to be passive widgets, that simply show
55/// information about the current state of Duat. In order to
56/// show that information, widgets make use of [`Text`], which can
57/// show stylized text, buttons, and all sorts of other stuff. (For
58/// widgets that react to input, see the documentation for[`Mode`]).
59///
60/// For a demonstration on how to create a widget, I will create a
61/// widget that shows the uptime, in seconds, for Duat.
62///
63/// ```rust
64/// # use duat_core::{data::PeriodicChecker, text::Text};
65/// struct UpTime(Text, PeriodicChecker);
66/// ```
67///
68/// In order to be a proper widget, it must have a [`Text`] to
69/// display. The [`PeriodicChecker`] will be explained later. Next, I
70/// implement [`Widget`] on `UpTime`:
71///
72/// ```rust
73/// # use std::{marker::PhantomData, sync::OnceLock, time::{Duration, Instant}};
74/// # use duat_core::{data::PeriodicChecker, prelude::*};
75/// # struct UpTime(Text, PeriodicChecker);
76/// # struct UpTimeCfg;
77/// # impl<U: Ui> WidgetCfg<U> for UpTimeCfg {
78/// #     type Widget = UpTime;
79/// #     fn build(self, _: &mut Pass, _: BuildInfo<U>) -> (Self::Widget, PushSpecs) { todo!() }
80/// # }
81/// impl<U: Ui> Widget<U> for UpTime {
82///     type Cfg = UpTimeCfg;
83///
84///     fn cfg() -> Self::Cfg {
85///         UpTimeCfg
86///     }
87///     // more methods remain below
88/// #     fn text(&self) -> &Text { &self.0 }
89/// #     fn text_mut(&mut self) -> &mut Text { &mut self.0 }
90/// #     fn once() -> Result<(), Text> { Ok(()) }
91/// #     fn update(_: &mut Pass, handle: &Handle<Self, U>) {}
92/// #     fn needs_update(&self, pa: &Pass) -> bool { todo!(); }
93/// }
94/// ```
95///
96/// Notice the `UpTimeCfg` defined as the `Widget::Cfg` for `UpTime`.
97/// [`WidgetCfg`]s  exist to let users push [`Widget`]s to [`File`]s
98/// and the window through the [`WidgetCreated`] and [`WindowCreated`]
99/// [hooks]. It lets users configure widgets through methods defined
100/// by the widget author.
101///
102/// ```rust
103/// # use std::{sync::OnceLock, time::{Duration, Instant}};
104/// # use duat_core::{data::PeriodicChecker, prelude::*};
105/// # struct UpTime(Text, PeriodicChecker);
106/// struct UpTimeCfg;
107///
108/// impl<U: Ui> WidgetCfg<U> for UpTimeCfg {
109///     type Widget = UpTime;
110///
111///     fn build(self, _: &mut Pass, _: BuildInfo<U>) -> (Self::Widget, PushSpecs) {
112///         let checker = PeriodicChecker::new(std::time::Duration::from_secs(1));
113///         let widget = UpTime(Text::new(), checker);
114///         let specs = PushSpecs::below().ver_len(1.0);
115///
116///         (widget, specs)
117///     }
118/// }
119/// # impl<U: Ui> Widget<U> for UpTime {
120/// #     type Cfg = UpTimeCfg;
121/// #     fn cfg() -> Self::Cfg { UpTimeCfg }
122/// #     fn text(&self) -> &Text { &self.0 }
123/// #     fn text_mut(&mut self) -> &mut Text{ &mut self.0 }
124/// #     fn once() -> Result<(), Text> { Ok(()) }
125/// #     fn update(_: &mut Pass, handle: &Handle<Self, U>) {}
126/// #     fn needs_update(&self, pa: &Pass) -> bool { todo!(); }
127/// # }
128/// ```
129///
130/// The [`build`] method should return 2 objects:
131///
132/// * The widget itself.
133/// * [How] to push the widget around. This happens in an inside-out
134///   fashion.
135///
136/// Now, there are some other methods from [`Widget`] that need
137/// to be implemented for this to work. First of all, there needs to
138/// be a starting [`Instant`] to compare with the current moment in
139/// time.
140///
141/// The best time to do something like this is after Duat is done with
142/// initial setup. This happens when the [`ConfigLoaded`] hook is
143/// triggered.
144///
145/// ```rust
146/// # use duat_core::doc_duat as duat;
147/// setup_duat!(setup);
148/// use std::{sync::OnceLock, time::Instant};
149///
150/// use duat::prelude::*;
151///
152/// fn setup() {
153///     static START_TIME: OnceLock<Instant> = OnceLock::new();
154///     hook::add::<ConfigLoaded>(|_, _| START_TIME.set(Instant::now()).unwrap());
155/// }
156/// ```
157///
158/// This should be added to the `setup` function in the `config`
159/// crate. Obviously, requiring that the end user adds a [hook] for
160/// your [`Widget`] to work is poor UX design, so this should be
161/// placed inside of a [`Plugin`] instead.
162///
163/// Next I'm going to implement two other [`Widget`] functions:
164/// [`once`] and [`update`]. The [`once`] function will do things that
165/// should only happen once, even if multiple of a given [`Widget`]
166/// are spawned. The [`update`] function is where the [`Text`] should
167/// be updated:
168///
169/// ```rust
170/// # use std::{sync::OnceLock, time::Instant};
171/// # use duat_core::{prelude::*, data::PeriodicChecker};
172/// # struct UpTime(Text, PeriodicChecker);
173/// # struct UpTimeCfg;
174/// # impl<U: Ui> WidgetCfg<U> for UpTimeCfg {
175/// #     type Widget = UpTime;
176/// #     fn build(self, _: &mut Pass, _: BuildInfo<U>) -> (UpTime, PushSpecs) { todo!() }
177/// # }
178/// // This was set during the `setup` function
179/// static START_TIME: OnceLock<Instant> = OnceLock::new();
180/// impl<U: Ui> Widget<U> for UpTime {
181/// #     type Cfg = UpTimeCfg;
182/// #     fn cfg() -> Self::Cfg { UpTimeCfg }
183/// #     fn text(&self) -> &Text { &self.0 }
184/// #     fn text_mut(&mut self) -> &mut Text { &mut self.0 }
185/// #     fn needs_update(&self, pa: &Pass) -> bool { todo!(); }
186///     // ...
187///     fn update(pa: &mut Pass, handle: &Handle<Self, U>) {
188///         let start = START_TIME.get().unwrap();
189///         let elapsed = start.elapsed();
190///         let mins = elapsed.as_secs() / 60;
191///         let secs = elapsed.as_secs() % 60;
192///
193///         handle.write(pa).0 = txt!("[uptime.mins]{mins}m [uptime.secs]{secs}s").build();
194///     }
195///
196///     fn once() -> Result<(), Text> {
197///         form::set_weak("uptime.mins", Form::new().green());
198///         form::set_weak("uptime.secs", Form::new().green());
199///         Ok(())
200///     }
201/// }
202/// ```
203///
204/// In the [`once`] function, I am setting the `"UpTime"` [`Form`],
205/// which is going to be used on the `UpTime`'s [`Text`]. Finally, the
206/// only thing that remains to be done is a function to check for
207/// updates: [`Widget::needs_update`]. That's where the
208/// [`PeriodicChecker`] comes in:
209///
210/// ```rust
211/// # use std::{sync::OnceLock, time::{Duration, Instant}};
212/// # use duat_core::{data::PeriodicChecker, prelude::*};
213/// // This was set during the `setup` function
214/// static START_TIME: OnceLock<Instant> = OnceLock::new();
215///
216/// struct UpTime(Text, PeriodicChecker);
217///
218/// impl<U: Ui> Widget<U> for UpTime {
219///     type Cfg = UpTimeCfg;
220///
221///     fn needs_update(&self, pa: &Pass) -> bool {
222///         // Returns `true` once per second
223///         self.1.check()
224///     }
225///
226///     fn update(pa: &mut Pass, handle: &Handle<Self, U>) {
227///         let start = START_TIME.get().unwrap();
228///         let elapsed = start.elapsed();
229///         let mins = elapsed.as_secs() / 60;
230///         let secs = elapsed.as_secs() % 60;
231///
232///         handle.write(pa).0 = txt!("[uptime.mins]{mins}m [uptime.secs]{secs}s").build();
233///     }
234///
235///     fn cfg() -> Self::Cfg {
236///         UpTimeCfg
237///     }
238///
239///     // Some methods used in Duat
240///     fn text(&self) -> &Text {
241///         &self.0
242///     }
243///
244///     fn text_mut(&mut self) -> &mut Text {
245///         &mut self.0
246///     }
247///
248///     fn once() -> Result<(), Text> {
249///         form::set_weak("uptime.mins", Form::new().green());
250///         form::set_weak("uptime.secs", Form::new().green());
251///         Ok(())
252///     }
253/// }
254///
255/// struct UpTimeCfg;
256///
257/// impl<U: Ui> WidgetCfg<U> for UpTimeCfg {
258///     type Widget = UpTime;
259///
260///     fn build(self, _: &mut Pass, _: BuildInfo<U>) -> (UpTime, PushSpecs) {
261///         // You could imagine how a method on `UpTimeCfg` could
262///         // change the periodicity
263///         let checker = PeriodicChecker::new(Duration::from_secs(1));
264///         let widget = UpTime(Text::new(), checker);
265///         let specs = PushSpecs::below().ver_len(1.0);
266///
267///         (widget, specs)
268///     }
269/// }
270/// ```
271///
272/// [`Mode`]: crate::mode::Mode
273/// [`cfg`]: Widget::cfg
274/// [`build`]: WidgetCfg::build
275/// [How]: PushSpecs
276/// [`PeriodicChecker`]: crate::data::PeriodicChecker
277/// [`WidgetCreated`]: crate::hook::WidgetCreated
278/// [`WindowCreated`]: crate::hook::WindowCreated
279/// [hooks]: crate::hook
280/// [`PhantomData<U>`]: std::marker::PhantomData
281/// [`Instant`]: std::time::Instant
282/// [`ConfigLoaded`]: crate::hook::ConfigLoaded
283/// [`once`]: Widget::once
284/// [`update`]: Widget::update
285/// [`Form`]: crate::form::Form
286/// [`form::set_weak*`]: crate::form::set_weak
287/// [`txt!`]: crate::text::txt
288/// [`Plugin`]: crate::Plugin
289/// [`File`]: crate::file::File
290pub trait Widget<U: Ui>: Send + 'static {
291    /// The configuration type
292    ///
293    /// This configuration type is used when pushing [`Widget`]s
294    /// around the screen. It should follow the builder pattern,
295    /// making it very easy to concatenatively (?) modify it before
296    /// adding it in.
297    /// 
298    /// When implementing this, you are free to remove the `where` clause.
299    type Cfg: WidgetCfg<U, Widget = Self>
300    where
301        Self: Sized;
302
303    /// Returns a [`WidgetCfg`], for use in layout construction
304    ///
305    /// This function exists primarily so the [`WidgetCfg`]s
306    /// themselves don't need to be in scope. You will want to use
307    /// these in [hooks] like [`WidgetCreated`]:
308    ///
309    /// ```rust
310    /// # use duat_core::doc_duat as duat;
311    /// setup_duat!(setup);
312    /// use duat::prelude::*;
313    ///
314    /// fn setup() {
315    ///     hook::remove("FileWidgets");
316    ///     // A type `W: Widget` is an alias for `WidgetCreated<W>`
317    ///     hook::add::<File>(|_, (cfg, builder)| {
318    ///         // Screw it, LineNumbers on both sides.
319    ///         builder.push(LineNumbers::cfg());
320    ///         builder.push(LineNumbers::cfg().on_the_right().align_right());
321    ///         cfg
322    ///     });
323    /// }
324    /// ```
325    /// 
326    /// When implementing this, you are free to remove the `where` clause.
327    /// 
328    /// [hooks]: crate::hook
329    /// [`WidgetCreated`]: crate::hook::WidgetCreated
330    fn cfg() -> Self::Cfg
331    where
332        Self: Sized;
333
334    ////////// Stateful functions
335
336    /// Updates the widget, allowing the modification of its
337    /// [`Area`]
338    ///
339    /// This function will be triggered when Duat deems that a change
340    /// has happened to this [`Widget`], which is when
341    /// [`RwData<Self>::has_changed`] returns `true`. This can happen
342    /// from many places, like [hooks], [commands], editing by
343    /// [`Mode`]s, etc.
344    ///
345    /// Importantly, [`update`] should be able to handle any number of
346    /// changes that have taken place in this [`Widget`], so you
347    /// should avoid depending on state which may become
348    /// desynchronized.
349    /// 
350    /// When implementing this, you are free to remove the `where` clause.
351    ///
352    /// [hooks]: crate::hook
353    /// [commands]: crate::cmd
354    /// [`Mode`]: crate::mode::Mode
355    /// [`update`]: Widget::update
356    #[allow(unused)]
357    fn update(pa: &mut Pass, handle: &Handle<Self, U>)
358    where
359        Self: Sized;
360
361    /// Actions to do whenever this [`Widget`] is focused
362    /// 
363    /// When implementing this, you are free to remove the `where` clause.
364    #[allow(unused)]
365    fn on_focus(pa: &mut Pass, handle: &Handle<Self, U>)
366    where
367        Self: Sized,
368    {
369    }
370
371    /// Actions to do whenever this [`Widget`] is unfocused
372    /// 
373    /// When implementing this, you are free to remove the `where` clause.
374    #[allow(unused)]
375    fn on_unfocus(pa: &mut Pass, handle: &Handle<Self, U>)
376    where
377        Self: Sized,
378    {
379    }
380
381    /// Tells Duat that this [`Widget`] should be updated
382    ///
383    /// Determining wether a [`Widget`] should be updated, for a good
384    /// chunk of them, will require some code like this:
385    ///
386    /// ```rust
387    /// # use duat_core::prelude::*;
388    /// # struct Cfg;
389    /// # impl<U: Ui> WidgetCfg<U> for Cfg {
390    /// #     type Widget = MyWidget<U>;
391    /// #     fn build(self, _: &mut Pass, _: BuildInfo<U>) -> (Self::Widget, PushSpecs) {
392    /// #         todo!();
393    /// #     }
394    /// # }
395    /// struct MyWidget<U: Ui>(Handle<File<U>, U>);
396    ///
397    /// impl<U: Ui> Widget<U> for MyWidget<U> {
398    /// #   type Cfg = Cfg;
399    /// #   fn cfg() -> Self::Cfg { todo!() }
400    /// #   fn update(_: &mut Pass, handle: &Handle<Self, U>) { todo!() }
401    /// #   fn text(&self) -> &Text { todo!() }
402    /// #   fn text_mut(&mut self) -> &mut Text { todo!() }
403    /// #   fn once() -> Result<(), Text> { todo!() }
404    ///     // ...
405    ///     fn needs_update(&self, pa: &Pass) -> bool {
406    ///         self.0.has_changed()
407    ///     }
408    /// }
409    /// ```
410    ///
411    /// In this case, `MyWidget` is telling Duat that it should be
412    /// updated whenever the file in the [`Handle<File>`] gets
413    /// changed.
414    ///
415    /// One exception to this is the [`StatusLine`], which can be
416    /// altered if any of its parts get changed, some of them depend
417    /// on a [`Handle<File>`], but a lot of others depend on checking
418    /// functions which might need to be triggered.
419    ///
420    /// [`StatusLine`]: https://docs.rs/duat-core/latest/duat_utils/widgets/struct.StatusLine.html
421    fn needs_update(&self, pa: &Pass) -> bool;
422
423    /// The text that this widget prints out
424    fn text(&self) -> &Text;
425
426    /// A mutable reference to the [`Text`] that is printed
427    fn text_mut(&mut self) -> &mut Text;
428
429    /// The [configuration] for how to print [`Text`]
430    ///
431    /// The default configuration, used when `print_cfg` is not
432    /// implemented,can be found at [`PrintCfg::new`].
433    ///
434    /// [configuration]: PrintCfg
435    fn print_cfg(&self) -> PrintCfg {
436        PrintCfg::new()
437    }
438
439    /// Prints the widget
440    ///
441    /// Very rarely shouuld you actually implement this method, one
442    /// example of where this is actually implemented is in
443    /// [`File::print`], where [`Area::print_with`] is called in
444    /// order to simultaneously update the list of lines numbers,
445    /// for widgets like [`LineNumbers`] to read.
446    ///
447    /// [`LineNumbers`]: docs.rs/duat-utils/latest/duat_utils/widgets/struct.LineNumbers.html
448    /// [`File::print`]: crate::file::File::print
449    fn print(&mut self, painter: Painter, area: &U::Area) {
450        let cfg = self.print_cfg();
451        area.print(self.text_mut(), cfg, painter)
452    }
453
454    /// Actions taken when this widget opens for the first time
455    ///
456    /// Examples of things that should go in here are [`form`]
457    /// functions, [hooks], [commands] you want executed only once
458    /// 
459    /// When implementing this, you are free to remove the `where` clause.
460    ///
461    /// [hooks]: crate::hook
462    /// [commands]: crate::cmd
463    fn once() -> Result<(), Text>
464    where
465        Self: Sized;
466}
467
468/// A configuration struct for a [`Widget`]
469///
470/// This configuration is used to make adjustments on how a widget
471/// will be added to a file or a window. These adjustments are
472/// primarily configurations for the widget itself, and to what
473/// direction it will be pushed:
474///
475/// ```rust
476/// # use duat_core::doc_duat as duat;
477/// setup_duat!(setup);
478/// use duat::prelude::*;
479///
480/// fn setup() {
481///     hook::add::<File>(|_, (file_cfg, builder)| {
482///         // Change pushing direction to the right.
483///         let cfg = LineNumbers::cfg().on_the_right();
484///         // Changes the alignment of the numbers.
485///         // Then pushes the widget.
486///         builder.push(cfg.align_right().align_main_left());
487///         file_cfg
488///     });
489/// }
490/// ```
491///
492/// In this case, the `LineNumbers::cfg` function will return the
493/// `LineNumbers::Cfg` type, which can be modified to then be pushed
494/// to the [`File`] via the [`builder`].
495///
496/// [`File`]: crate::file::File
497/// [`builder`]: super::UiBuilder
498pub trait WidgetCfg<U: Ui>: Sized + 'static {
499    /// The [`Widget`] that will be created by this [`WidgetCfg`]
500    type Widget: Widget<U, Cfg = Self>;
501
502    /// Builds the [`Widget`] alongside [`PushSpecs`]
503    ///
504    /// The [`PushSpecs`] are determined by the [`WidgetCfg`] itself,
505    /// and the end user is meant to change it by public facing
506    /// functions in the [`WidgetCfg`]. This is to prevent nonsensical
507    /// [`Widget`] pushing, like [`LineNumbers`] on the bottom of a
508    /// [`File`], for example.
509    ///
510    /// [`LineNumbers`]: docs.rs/duat-utils/latest/duat_utils/widgets/struct.LineNumbers.html
511    /// [`File`]: crate::file::File
512    fn build(self, pa: &mut Pass, info: BuildInfo<U>) -> (Self::Widget, PushSpecs);
513}
514
515/// Elements related to the [`Widget`]s
516#[derive(Clone)]
517pub(crate) struct Node<U: Ui> {
518    handle: Handle<dyn Widget<U>, U>,
519    update: Arc<dyn Fn(&mut Pass) + Send>,
520    print: Arc<dyn Fn(&mut Pass) + Send>,
521    on_focus: Arc<dyn Fn(&mut Pass, Handle<dyn Widget<U>, U>) + Send>,
522    on_unfocus: Arc<dyn Fn(&mut Pass, Handle<dyn Widget<U>, U>) + Send>,
523}
524
525impl<U: Ui> Node<U> {
526    /// Returns a new [`Node`]
527    pub(crate) fn new<W: Widget<U>>(widget: RwData<W>, area: U::Area, id: AreaId) -> Self {
528        let handle = Handle::new(widget, area, Arc::new(Mutex::new("")), id);
529        Self::from_handle(handle)
530    }
531
532    pub(crate) fn from_handle<W: Widget<U>>(handle: Handle<W, U>) -> Self {
533        Self {
534            handle: handle.to_dyn(),
535            update: Arc::new({
536                let handle = handle.clone();
537                move |pa| W::update(pa, &handle)
538            }),
539            print: Arc::new({
540                let handle = handle.clone();
541                move |pa| {
542                    let painter = form::painter_with_mask::<W>(*handle.mask().lock().unwrap());
543                    let (widget, area) = handle.write_with_area(pa);
544                    W::print(widget, painter, area);
545                }
546            }),
547            on_focus: Arc::new({
548                let handle = handle.clone();
549                move |pa, old| {
550                    hook::trigger(pa, FocusedOn((old, handle.clone())));
551                    W::on_focus(pa, &handle);
552                }
553            }),
554            on_unfocus: Arc::new({
555                let handle = handle.clone();
556                move |pa, new| {
557                    hook::trigger(pa, UnfocusedFrom((handle.clone(), new)));
558                    W::on_unfocus(pa, &handle);
559                }
560            }),
561        }
562    }
563
564    ////////// Reading and parts acquisition
565
566    pub(crate) fn read_as<'a, W: Widget<U>>(&'a self, pa: &'a Pass) -> Option<&'a W> {
567        self.handle.read_as(pa)
568    }
569
570    /// The [`Widget`] of this [`Node`]
571    pub(crate) fn widget(&self) -> &RwData<dyn Widget<U>> {
572        self.handle.widget()
573    }
574
575    /// The [`Ui::Area`] of this [`Widget`]
576    pub(crate) fn area(&self, pa: &Pass) -> &U::Area {
577        self.handle.area(pa)
578    }
579
580    /// Returns the downcast ref of this [`Widget`].
581    pub(crate) fn try_downcast<W: Widget<U>>(&self) -> Option<Handle<W, U>> {
582        self.handle.try_downcast()
583    }
584
585    /// The "parts" of this [`Node`]
586    pub(crate) fn handle(&self) -> &Handle<dyn Widget<U>, U> {
587        &self.handle
588    }
589
590    /// The [`Widget`]s that are related to this [`Widget`]
591    pub(crate) fn related_widgets(&self) -> &RwData<Vec<Handle<dyn Widget<U>, U>>> {
592        self.handle.related()
593    }
594
595    ////////// Querying functions
596
597    /// Wether the value within is `W`
598    pub(crate) fn data_is<W: 'static>(&self) -> bool {
599        self.handle.widget().data_is::<W>()
600    }
601
602    /// Wether this and [`RwData`] point to the same value
603    pub(crate) fn ptr_eq<W: ?Sized>(&self, other: &RwData<W>) -> bool {
604        self.handle.ptr_eq(other)
605    }
606
607    /// Wether this [`Widget`] needs to be updated
608    pub(crate) fn needs_update(&self, pa: &Pass) -> bool {
609        self.handle.has_changed() || self.handle.read(pa).needs_update(pa)
610    }
611
612    ////////// Eventful functions
613
614    /// Updates and prints this [`Node`]
615    pub(crate) fn update_and_print(&self, pa: &mut Pass) {
616        (self.update)(pa);
617
618        let (widget, area) = self.handle.write_with_area(pa);
619        let cfg = widget.print_cfg();
620        widget.text_mut().add_selections(area, cfg);
621
622        if area.print_info() != <U::Area as Area>::PrintInfo::default() {
623            widget.text_mut().update_bounds();
624        }
625
626        (self.print)(pa);
627
628        self.handle.text_mut(pa).remove_selections();
629    }
630
631    /// What to do when focusing
632    pub(crate) fn on_focus(&self, pa: &mut Pass, old: Handle<dyn Widget<U>, U>) {
633        self.handle.area(pa).set_as_active();
634        (self.on_focus)(pa, old)
635    }
636
637    /// What to do when unfocusing
638    pub(crate) fn on_unfocus(&self, pa: &mut Pass, new: Handle<dyn Widget<U>, U>) {
639        (self.on_unfocus)(pa, new)
640    }
641}
642
643impl<U: Ui> GetAreaId for Node<U> {
644    fn area_id(&self) -> AreaId {
645        self.handle.area_id()
646    }
647}
648
649impl<T: GetAreaId, U: Ui> PartialEq<T> for Node<U> {
650    fn eq(&self, other: &T) -> bool {
651        self.area_id() == other.area_id()
652    }
653}
654
655impl<U: Ui> Eq for Node<U> {}