// ui.rs
// *************************************************************************
// * Copyright (C) 2018-2020 Daniel Mueller (deso@posteo.net) *
// * *
// * This program is free software: you can redistribute it and/or modify *
// * it under the terms of the GNU General Public License as published by *
// * the Free Software Foundation, either version 3 of the License, or *
// * (at your option) any later version. *
// * *
// * This program is distributed in the hope that it will be useful, *
// * but WITHOUT ANY WARRANTY; without even the implied warranty of *
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
// * GNU General Public License for more details. *
// * *
// * You should have received a copy of the GNU General Public License *
// * along with this program. If not, see <http://www.gnu.org/licenses/>. *
// *************************************************************************
use std::any::Any;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;
use std::future::Future;
use std::ops::Deref;
use std::pin::Pin;
use std::rc::Rc;
use std::slice::Iter;
#[cfg(debug_assertions)]
use std::sync::atomic::AtomicUsize;
#[cfg(debug_assertions)]
use std::sync::atomic::Ordering;
use async_trait::async_trait;
use crate::BBox;
use crate::Mergeable;
use crate::Placeholder;
use crate::Renderer;
use crate::Widget;
/// An `Index` is our internal representation of an `Id`. `Id`s can
/// belong to different `Ui` objects and a validation step converts them
/// into an `Index`.
#[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]
struct Index {
idx: usize,
}
impl Index {
fn new(idx: usize) -> Self {
Self { idx }
}
}
impl Display for Index {
/// Format the `Index` into the given formatter.
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "{}", self.idx)
}
}
/// An `Id` uniquely representing a widget.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Id {
#[cfg(debug_assertions)]
ui_id: usize,
idx: Index,
}
impl Id {
#[allow(unused_variables)]
fn new<E, M>(idx: usize, ui: &Ui<E, M>) -> Id
where
E: 'static + Debug,
M: 'static + Debug,
{
Self {
#[cfg(debug_assertions)]
ui_id: ui.id,
idx: Index::new(idx),
}
}
}
impl Display for Id {
/// Format the `Id` into the given formatter.
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "{}", self.idx)
}
}
/// An internally used trait for abstracting over the invocation of
/// event hooks.
#[async_trait(?Send)]
trait Hooker<E, M>
where
E: Debug,
M: Debug,
{
async fn invoke(
&self,
ui: &mut Ui<E, M>,
pre_hook_event: Option<E>,
unhandled: Option<E>,
event: Option<&E>,
) -> Option<E>;
}
fn merge<E>(e1: Option<E>, e2: Option<E>) -> Option<E>
where
E: Mergeable,
{
match (e1, e2) {
(Some(e1), Some(e2)) => Some(e1.merge_with(e2)),
(Some(e), None) | (None, Some(e)) => Some(e),
(None, None) => None,
}
}
struct Hooked {}
#[async_trait(?Send)]
impl<E, M> Hooker<E, M> for Hooked
where
E: Debug + Mergeable,
M: Debug,
{
async fn invoke(
&self,
ui: &mut Ui<E, M>,
pre_hook_event: Option<E>,
unhandled: Option<E>,
event: Option<&E>,
) -> Option<E> {
let mut result = None;
for idx in ui.hooked.clone().as_ref() {
match &ui.widgets[idx.idx].0.event_hook {
Some(hook_fn) => {
let widget = ui.widgets[idx.idx].1.clone();
let event = hook_fn.0(widget.as_ref(), ui, event).await;
result = merge(result, event);
},
None => debug_assert!(false, "Widget registered as hooked but no hook func found"),
};
}
merge(merge(pre_hook_event, unhandled), result)
}
}
struct NotHooked {}
#[async_trait(?Send)]
impl<E, M> Hooker<E, M> for NotHooked
where
E: Debug,
M: Debug,
{
async fn invoke(
&self,
_ui: &mut Ui<E, M>,
pre_hook_event: Option<E>,
unhandled: Option<E>,
_event: Option<&E>,
) -> Option<E> {
debug_assert!(pre_hook_event.is_none());
unhandled
}
}
/// An iterator over the children of a widget.
pub(crate) type ChildIter<'widget> = Iter<'widget, Id>;
type NewDataFn = dyn FnOnce() -> Box<dyn Any>;
type NewWidgetFn<E, M> = dyn FnOnce(Id, &mut dyn MutCap<E, M>) -> Box<dyn Widget<E, M>>;
type EventHookFn<E, M> = &'static dyn for<'f> Fn(
&'f dyn Widget<E, M>,
&'f mut dyn MutCap<E, M>,
Option<&'f E>,
) -> Pin<Box<dyn Future<Output = Option<E>> + 'f>>;
/// A capability allowing for various widget related operations.
pub trait Cap: Debug {
/// Retrieve a reference to a widget's data.
fn data(&self, widget: Id) -> &dyn Any;
/// Retrieve an iterator over the children. Iteration happens in
/// z-order, from highest to lowest.
fn children(&self, widget: Id) -> ChildIter<'_>;
/// Retrieve the `Id` of the root widget.
fn root_id(&self) -> Id;
/// Retrieve the parent of the given widget.
fn parent_id(&self, widget: Id) -> Option<Id>;
/// Check whether a widget has its visibility flag set.
///
/// Note that a return value of `true` does not necessary mean that
/// the widget is actually visible. A widget is only visible if all
/// its parents have the visibility flag set, too. The `is_displayed`
/// method can be used to check for actual visibility.
fn is_visible(&self, widget: Id) -> bool;
/// Check whether a widget is actually being displayed.
///
/// This method checks whether the referenced widget is actually being
/// displayed, that is, whether its own as well as its parents'
/// visibility flags are all set.
fn is_displayed(&self, widget: Id) -> bool;
/// Retrieve the currently focused widget.
fn focused(&self) -> Option<Id>;
/// Check whether the widget with the given `Id` is focused.
fn is_focused(&self, widget: Id) -> bool;
}
/// A mutable capability allowing for various widget related operations.
#[async_trait(?Send)]
pub trait MutCap<E, M>: Cap + Deref<Target = dyn Cap>
where
E: Debug,
M: Debug,
{
/// Retrieve a mutable reference to a widget's data.
fn data_mut(&mut self, widget: Id) -> &mut dyn Any;
/// Add a widget to the `Ui` represented by the capability.
// TODO: We should not require a Box here conceptually, but omitting
// it will require the unboxed closures feature to stabilize.
fn add_widget(
&mut self,
parent: Id,
new_data: Box<NewDataFn>,
new_widget: Box<NewWidgetFn<E, M>>,
) -> Id;
/// Show a widget, i.e., set its and its parents' visibility flag.
///
/// This method sets the referenced widget's visibility flag as well
/// as those of all its parents.
fn show(&mut self, widget: Id);
/// Hide a widget, i.e., unset its visibility flag.
///
/// This method makes sure that widget referenced is no longer
/// displayed. If the widget has children, all those children will
/// also be hidden.
fn hide(&mut self, widget: Id);
/// Focus a widget.
///
/// The focused widget is the one receiving certain types of events
/// (such as key events) first but may also be rendered in a different
/// color or be otherwise highlighted. Note that being focused implies
/// being visible. This invariant is enforced internally.
fn focus(&mut self, widget: Id);
/// Install or remove an event hook handler.
///
/// The event hook handler is a call back function that is invoked for
/// all events originating outside of the UI, i.e., those that come in
/// through the `Ui::handle` method. For such events, the event hook
/// handler gets to inspect the event before any widget gets a chance
/// to handle it "officially" through the `Handleable::handle` method
/// (pre-hook).
/// Furthermore, after widgets handled the event, the hook will be
/// invoked again, this time without an actual event (post-hook).
///
/// Event hook handlers are allowed to emit an event on their own,
/// just as "normal" event handlers. The events of all hooks get
/// merged into a single event. As such, they must be mergeable. Note
/// that the order in which multiple event hooks are invoked relative
/// to each other is unspecified, and that should be taken into
/// account when providing a `Mergeable` implementation for the
/// provided event type.
/// Furthermore, the final merged event is not passed to widgets, but
/// returned straight back.
///
/// Note that event hook functions are only able to inspect events and
/// not change or discard them.
///
/// A widget (identified by the given `Id`) may only register one
/// handler and subsequent requests will overwrite the previously
/// installed one. The method returns the handler that was previously
/// installed, if any.
fn hook_events(
&mut self,
widget: Id,
hook_fn: Option<EventHookFn<E, M>>,
) -> Option<EventHookFn<E, M>>
where
E: Mergeable;
/// Send the provided message to the given widget.
async fn send(&mut self, widget: Id, message: M) -> Option<M>;
/// Send the provided message to the given widget, without
/// transferring ownership of the message.
async fn call(&mut self, widget: Id, message: &mut M) -> Option<M>;
}
#[cfg(debug_assertions)]
fn get_next_ui_id() -> usize {
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
NEXT_ID.fetch_add(1, Ordering::Relaxed)
}
/// This type contains data that is common to all widgets.
#[derive(Debug)]
struct WidgetData<E, M>
where
E: 'static,
M: 'static,
{
/// The `Id` of the parent widget.
///
/// This value may only be `None` for the root widget.
parent_idx: Option<Index>,
/// The data associated with the widget.
data: Box<dyn Any>,
/// Vector of all the children that have this widget as a parent.
// Note that unfortunately there is no straight forward way to make
// this a Vec<Index> because we cannot use an impl trait return type
// for the `children` method present in `Cap`.
children: Vec<Id>,
/// An optional event hook that may be registered for the widget.
event_hook: Option<EventHook<E, M>>,
/// Flag indicating the widget's visibility state.
visible: bool,
}
impl<E, M> WidgetData<E, M> {
fn new(parent_idx: Option<Index>, data: Box<dyn Any>) -> Self {
Self {
parent_idx,
data,
children: Default::default(),
event_hook: None,
visible: true,
}
}
}
/// A struct wrapping an `EventHookFn` while implementing `Debug`.
struct EventHook<E, M>(EventHookFn<E, M>)
where
E: 'static,
M: 'static;
impl<E, M> Debug for EventHook<E, M> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "{:p}", self.0)
}
}
/// A `Ui` is a container for related widgets.
pub struct Ui<E, M>
where
E: 'static + Debug,
M: 'static + Debug,
{
#[cfg(debug_assertions)]
id: usize,
#[allow(clippy::type_complexity)]
widgets: Vec<(WidgetData<E, M>, Rc<dyn Widget<E, M>>)>,
hooker: &'static dyn Hooker<E, M>,
hooked: Rc<Vec<Index>>,
focused: Option<Index>,
}
impl<E, M> Ui<E, M>
where
E: 'static + Debug,
M: 'static + Debug,
{
/// Create a new `Ui` instance containing one widget that acts as the
/// root widget.
#[allow(clippy::new_ret_no_self)]
pub fn new<D, W>(new_data: D, new_root_widget: W) -> (Self, Id)
where
D: FnOnce() -> Box<dyn Any>,
W: FnOnce(Id, &mut dyn MutCap<E, M>) -> Box<dyn Widget<E, M>>,
{
static NOT_HOOKED: NotHooked = NotHooked {};
let mut ui = Self {
#[cfg(debug_assertions)]
id: get_next_ui_id(),
widgets: Default::default(),
hooker: &NOT_HOOKED,
hooked: Default::default(),
focused: None,
};
let id = ui._add_widget(None, new_data, new_root_widget);
debug_assert_eq!(id.idx.idx, 0);
(ui, id)
}
/// Add a widget to the `Ui`.
///
/// This method fulfills the exact same purpose as
/// `MutCap::add_widget`, but it does not require boxing up the
/// provided `FnOnce`.
// TODO: This method should be removed once we no longer require
// boxing up of `FnOnce` closures.
pub fn add_ui_widget<D, W>(&mut self, parent: Id, new_data: D, new_widget: W) -> Id
where
D: FnOnce() -> Box<dyn Any>,
W: FnOnce(Id, &mut dyn MutCap<E, M>) -> Box<dyn Widget<E, M>>,
{
let parent_idx = self.validate(parent);
self._add_widget(Some(parent_idx), new_data, new_widget)
}
/// Add a widget to the `Ui`.
fn _add_widget<D, W>(&mut self, parent_idx: Option<Index>, new_data: D, new_widget: W) -> Id
where
D: FnOnce() -> Box<dyn Any>,
W: FnOnce(Id, &mut dyn MutCap<E, M>) -> Box<dyn Widget<E, M>>,
{
let idx = Index::new(self.widgets.len());
let id = Id::new(idx.idx, self);
// We require some trickery here to allow for dynamic widget
// creation from within the constructor of another widget. In
// particular, we install a "dummy" widget that acts as a container
// to which newly created child widgets can be registered.
let dummy = Placeholder::new();
let data = new_data();
let data = WidgetData::new(parent_idx, data);
self.widgets.push((data, Rc::new(dummy)));
// The widget is already linked to its parent but the parent needs to
// know about the child as well. We do that registration before the
// widget is actually fully constructed to preserve the invariant
// that a widget's ID is part of the list of IDs managed by its
// parent.
if let Some(parent_idx) = parent_idx {
self.widgets[parent_idx.idx].0.children.push(id)
}
// TODO: Consider making NewWidgetFn return an Rc instead of a Box
// to begin with as Rc::from(Box) is a non-trivial operation.
let widget = Rc::<dyn Widget<E, M>>::from(new_widget(id, self));
// As a help for the user, check that the widget's ID is actually
// the correct one that we provided.
debug_assert_eq!(widget.id(), id, "Created widget does not have provided Id");
// Replace our placeholder with the actual widget we just created.
// Note that because we store the children separately as part of an
// `WidgetData` object there is no need for us to do anything about
// them. Note furthermore that this implies that the Widget trait's
// `add_child` method must not have any side effects.
self.widgets[idx.idx].1 = widget;
id
}
/// Validate an `Id`, converting it into the internally used `Index`.
#[inline]
fn validate(&self, id: Id) -> Index {
#[cfg(debug_assertions)]
debug_assert_eq!(id.ui_id, self.id, "The given Id belongs to a different Ui");
id.idx
}
/// Lookup a widget from an `Index`.
fn lookup(&self, idx: Index) -> &dyn Widget<E, M> {
self.widgets[idx.idx].1.as_ref()
}
fn children(&self, idx: Index) -> ChildIter<'_> {
self.widgets[idx.idx].0.children.iter()
}
/// Show the widget with the given `Index` and recursively all its parents.
///
/// Note that the given reordering function needs to be idempotent
/// with respect to repeated reordering of the same widgets.
fn show<F>(&mut self, idx: Index, reorder_fn: F)
where
F: Fn(&mut Ui<E, M>, Index),
{
// Always run before making the widget visible. The reorder function
// may check for visibility internally and relies in the value being
// that before the change.
reorder_fn(self, idx);
let data = &mut self.widgets[idx.idx].0;
data.visible = true;
if let Some(parent_idx) = data.parent_idx {
self.show(parent_idx, reorder_fn)
}
}
/// Reorder the widget with the given `Index` as the last visible one.
fn reorder<F>(&mut self, idx: Index, new_idx_fn: F)
where
F: FnOnce(&Ui<E, M>, &Vec<Id>) -> usize,
{
if let Some(parent_idx) = self.widgets[idx.idx].0.parent_idx {
// First retrieve the index of the widget we are interested in
// from its parent's list of children.
let children = &self.widgets[parent_idx.idx].0.children;
let id = Id::new(idx.idx, self);
let cur_idx = children.iter().position(|x| *x == id).unwrap();
// Now remove said widget from the list of children.
let id = self.widgets[parent_idx.idx].0.children.remove(cur_idx);
// Next find the spot where to insert the widget as the first
// hidden child.
let new_idx = new_idx_fn(self, &self.widgets[parent_idx.idx].0.children);
// And reinsert it at this spot.
self.widgets[parent_idx.idx].0.children.insert(new_idx, id)
} else {
// No parent. Nothing to do.
}
}
/// Reorder the widget with the given `Index` as the last visible one.
fn reorder_as_focused(&mut self, idx: Index) {
// Reordering to the top is an idempotent operations already, but it
// potentially involves allocation and deallocation and so don't do
// it unless necessary.
if !self.is_top_most_child(idx) {
self.reorder(idx, |_, _| 0);
}
}
/// Reorder the widget with the given `Index` as the last visible one.
fn reorder_as_visible(&mut self, idx: Index) {
// In order to appear idempotent, only reorder the given widget in
// the parent's list of children if it is not already visible.
if !self.is_visible(idx) {
self.reorder(idx, |ui, children| {
children
.iter()
.rev()
.position(|x| Cap::is_visible(ui, *x))
.map(|x| x + 1)
.unwrap_or_else(|| children.len())
})
}
}
/// Reorder the widget with the given `Index` as the first hidden one.
fn reorder_as_hidden(&mut self, idx: Index) {
if self.is_visible(idx) {
self.reorder(idx, |ui, children| {
children
.iter()
.position(|x| !Cap::is_visible(ui, *x))
.unwrap_or_else(|| children.len())
})
}
}
fn is_visible(&self, idx: Index) -> bool {
self.widgets[idx.idx].0.visible
}
fn is_displayed(&self, idx: Index) -> bool {
let data = &self.widgets[idx.idx].0;
data.visible && data.parent_idx.map_or(true, |x| self.is_displayed(x))
}
fn is_top_most_child(&self, idx: Index) -> bool {
let parent_idx = self.widgets[idx.idx].0.parent_idx;
if let Some(parent_idx) = parent_idx {
let children = &self.widgets[parent_idx.idx].0.children;
children[0].idx == idx
} else {
true
}
}
fn focus(&mut self, idx: Index) {
// We want to provide the invariant that a focused widget needs to
// be visible.
self.show(idx, Ui::reorder_as_focused);
self.focused = Some(idx);
}
/// Render the `Ui` with the given `Renderer`.
pub fn render(&self, renderer: &dyn Renderer) {
// We cannot simply iterate through all widgets in `self.widgets`
// when rendering, because we need to take parent-child
// relationships into account in case widgets cover each other.
let idx = self.validate(self.root_id());
let root = self.lookup(idx);
let bbox = renderer.renderable_area();
renderer.pre_render();
self.render_all(idx, root, renderer, bbox);
renderer.post_render();
}
/// Recursively render the given widget and its children.
fn render_all(&self, idx: Index, widget: &dyn Widget<E, M>, renderer: &dyn Renderer, bbox: BBox) {
if self.is_visible(idx) {
// TODO: Ideally we would want to go without the recursion stuff we
// have. This may not be possible (efficiently) with safe
// Rust, though. Not sure.
let bbox = widget.render(self, renderer, bbox);
for child_id in self.children(idx).rev() {
let child_idx = self.validate(*child_id);
let child = self.lookup(child_idx);
self.render_all(child_idx, child, renderer, bbox)
}
}
}
/// Handle an event.
///
/// This function performs the initial determination of which widget
/// is supposed to handle the given event and then passes it down to
/// the actual event handler.
pub async fn handle<T>(&mut self, event: T) -> Option<E>
where
T: Into<E>,
{
let event = event.into();
// Invoke the hooks before passing the event to the widgets on the
// "official" route.
let hook_event = self.hooker.invoke(self, None, None, Some(&event)).await;
// All events go to the focused widget first.
let idx = self.focused;
// Any hook emitted events are not passed to the widgets themselves,
// but just returned.
let unhandled = self.try_handle_event(idx, event).await;
self.hooker.invoke(self, hook_event, unhandled, None).await
}
/// Bubble up an event until it is handled by some `Widget`.
fn handle_event(
&mut self,
idx: Index,
event: E,
) -> Pin<Box<dyn Future<Output = Option<E>> + '_>> {
Box::pin(async move {
// The clone we perform here allows us to decouple the Widget from
// the Ui, which in turn makes it possible to pass a mutable Ui
// reference (in the form of a MutCap) to an immutable widget. It is
// nothing more but a reference count bump, though.
let widget = self.widgets[idx.idx].1.clone();
let event = widget.handle(self, event).await;
let parent_idx = self.widgets[idx.idx].0.parent_idx;
if let Some(event) = event {
self.try_handle_event(parent_idx, event).await
} else {
// The event got handled.
None
}
})
}
/// Handle an event.
async fn try_handle_event(&mut self, idx: Option<Index>, event: E) -> Option<E> {
if let Some(idx) = idx {
self.handle_event(idx, event).await
} else {
// There is no receiver for this event. That could have many
// reasons, for example, event propagation could have reached the
// root widget which does not contain a parent or we were trying
// to send an event to the focused widget and no widget had the
// focus. In any case, return the event as-is.
Some(event)
}
}
}
impl<E, M> Cap for Ui<E, M>
where
E: 'static + Debug,
M: 'static + Debug,
{
/// Retrieve a reference to a widget's data.
fn data(&self, widget: Id) -> &dyn Any {
let idx = self.validate(widget);
self.widgets[idx.idx].0.data.as_ref()
}
/// Retrieve an iterator over the children. Iteration happens in
/// z-order, from highest to lowest.
fn children(&self, widget: Id) -> ChildIter<'_> {
self.children(self.validate(widget))
}
/// Retrieve the `Id` of the root widget.
fn root_id(&self) -> Id {
debug_assert!(!self.widgets.is_empty());
// We do not unconditionally unwrap the Option returned by as_ref()
// here as it is possible that it is empty and we do not want to
// panic here. This is mostly important for unit testing.
debug_assert_eq!(self.validate(self.widgets[0].1.id()).idx, 0);
Id::new(0, self)
}
/// Retrieve the parent of the given widget.
fn parent_id(&self, widget: Id) -> Option<Id> {
let idx = self.validate(widget);
let parent_idx = self.widgets[idx.idx].0.parent_idx;
let parent_id = parent_idx.map(|x| Id::new(x.idx, self));
debug_assert!(parent_id.map_or(true, |x| Cap::children(self, x).any(|x| *x == widget)));
parent_id
}
/// Check whether a widget has its visibility flag set.
fn is_visible(&self, widget: Id) -> bool {
self.is_visible(self.validate(widget))
}
/// Check whether a widget is actually being displayed.
fn is_displayed(&self, widget: Id) -> bool {
self.is_displayed(self.validate(widget))
}
/// Retrieve the currently focused widget.
fn focused(&self) -> Option<Id> {
self.focused.map(|x| Id::new(x.idx, self))
}
/// Check whether the given widget is focused.
fn is_focused(&self, widget: Id) -> bool {
let idx = self.validate(widget);
let result = self.focused == Some(idx);
debug_assert!(result && self.is_displayed(idx) || !result);
debug_assert!(result && self.is_top_most_child(idx) || !result);
result
}
}
#[async_trait(?Send)]
impl<E, M> MutCap<E, M> for Ui<E, M>
where
E: 'static + Debug,
M: 'static + Debug,
{
/// Retrieve a mutable reference to a widget's data.
fn data_mut(&mut self, widget: Id) -> &mut dyn Any {
let idx = self.validate(widget);
self.widgets[idx.idx].0.data.as_mut()
}
/// Add a widget to the `Ui`.
fn add_widget(
&mut self,
parent: Id,
new_data: Box<NewDataFn>,
new_widget: Box<NewWidgetFn<E, M>>,
) -> Id {
self.add_ui_widget(parent, new_data, new_widget)
}
/// Show a widget, i.e., set its and its parents' visibility flag.
fn show(&mut self, widget: Id) {
let idx = self.validate(widget);
self.show(idx, Ui::reorder_as_visible);
}
/// Hide a widget, i.e., unset its visibility flag.
fn hide(&mut self, widget: Id) {
if self.is_focused(widget) {
self.focused = None
}
let idx = self.validate(widget);
self.reorder_as_hidden(idx);
self.widgets[idx.idx].0.visible = false;
}
/// Focus a widget.
fn focus(&mut self, widget: Id) {
let idx = self.validate(widget);
self.focus(idx)
}
/// Install or remove an event hook handler.
fn hook_events(
&mut self,
widget: Id,
hook_fn: Option<EventHookFn<E, M>>,
) -> Option<EventHookFn<E, M>>
where
E: Mergeable,
{
static HOOKED: Hooked = Hooked {};
self.hooker = &HOOKED;
let idx = self.validate(widget);
let data = &mut self.widgets[idx.idx].0;
let result = self.hooked.binary_search(&idx);
debug_assert_eq!(result.is_ok(), data.event_hook.is_some());
match hook_fn {
Some(_) => {
if let Err(i) = result {
Rc::make_mut(&mut self.hooked).insert(i, idx);
}
},
None => {
if let Ok(i) = result {
let _ = Rc::make_mut(&mut self.hooked).remove(i);
}
},
};
let prev_hook = data.event_hook.take();
data.event_hook = hook_fn.map(|x| EventHook(x));
prev_hook.map(|x| x.0)
}
/// Send the provided message to the given widget.
async fn send(&mut self, widget: Id, message: M) -> Option<M> {
let idx = self.validate(widget);
let widget = self.widgets[idx.idx].1.clone();
widget.react(message, self).await
}
/// Send the provided message to the given widget, without
/// transferring ownership of the message.
async fn call(&mut self, widget: Id, message: &mut M) -> Option<M> {
let idx = self.validate(widget);
let widget = self.widgets[idx.idx].1.clone();
widget.respond(message, self).await
}
}
impl<E, M> Debug for Ui<E, M>
where
E: 'static + Debug,
M: 'static + Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let mut debug = f.debug_struct("Ui");
#[cfg(debug_assertions)]
let _ = debug.field("id", &self.id);
debug.finish()
}
}
impl<E, M> Deref for Ui<E, M>
where
E: 'static + Debug,
M: 'static + Debug,
{
type Target = dyn Cap;
fn deref(&self) -> &Self::Target {
self
}
}