use super::Widget;
use crate::event::{ConfigCx, Event, EventCx, IsUsed};
use crate::geom::{Coord, Rect};
use crate::layout::{AlignHints, AxisInfo, SizeRules};
use crate::theme::SizeCx;
use crate::util::IdentifyWidget;
use crate::{Id, Tile};
#[cfg(not(feature = "unsafe_node"))]
trait NodeT {
fn id_ref(&self) -> &Id;
fn rect(&self) -> Rect;
fn clone_node(&mut self) -> Node<'_>;
fn as_tile(&self) -> &dyn Tile;
fn find_child_index(&self, id: &Id) -> Option<usize>;
fn child_node(&mut self, index: usize) -> Option<Node<'_>>;
fn size_rules(&mut self, cx: &mut SizeCx, axis: AxisInfo) -> SizeRules;
fn set_rect(&mut self, cx: &mut SizeCx, rect: Rect, hints: AlignHints);
fn _configure(&mut self, cx: &mut ConfigCx, id: Id);
fn _update(&mut self, cx: &mut ConfigCx);
fn _send(&mut self, cx: &mut EventCx, id: Id, event: Event) -> IsUsed;
fn _replay(&mut self, cx: &mut EventCx, id: Id);
}
#[cfg(not(feature = "unsafe_node"))]
impl<'a, T> NodeT for (&'a mut dyn Widget<Data = T>, &'a T) {
fn id_ref(&self) -> &Id {
self.0.id_ref()
}
fn rect(&self) -> Rect {
self.0.rect()
}
fn clone_node(&mut self) -> Node<'_> {
Node::new(self.0, self.1)
}
fn as_tile(&self) -> &dyn Tile {
self.0.as_tile()
}
fn find_child_index(&self, id: &Id) -> Option<usize> {
self.0.find_child_index(id)
}
fn child_node(&mut self, index: usize) -> Option<Node<'_>> {
self.0.child_node(self.1, index)
}
fn size_rules(&mut self, cx: &mut SizeCx, axis: AxisInfo) -> SizeRules {
self.0.size_rules(cx, axis)
}
fn set_rect(&mut self, cx: &mut SizeCx, rect: Rect, hints: AlignHints) {
self.0.set_rect(cx, rect, hints);
}
fn _configure(&mut self, cx: &mut ConfigCx, id: Id) {
self.0._configure(cx, self.1, id);
}
fn _update(&mut self, cx: &mut ConfigCx) {
self.0._update(cx, self.1);
}
fn _send(&mut self, cx: &mut EventCx, id: Id, event: Event) -> IsUsed {
self.0._send(cx, self.1, id, event)
}
fn _replay(&mut self, cx: &mut EventCx, id: Id) {
self.0._replay(cx, self.1, id);
}
}
pub struct Node<'a>(
#[cfg(not(feature = "unsafe_node"))] Box<dyn NodeT + 'a>,
#[cfg(feature = "unsafe_node")] &'a mut dyn Widget<Data = ()>,
#[cfg(feature = "unsafe_node")] &'a (),
);
impl<'a> Node<'a> {
#[inline(always)]
pub fn new<T: 'a>(widget: &'a mut dyn Widget<Data = T>, data: &'a T) -> Self {
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
use std::mem::transmute;
#[allow(clippy::missing_transmute_annotations)]
unsafe { Node(transmute(widget), transmute(data)) }
} else {
Node(Box::new((widget, data)))
}
}
}
#[inline(always)]
pub fn re<'b>(&'b mut self) -> Node<'b>
where
'a: 'b,
{
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
Node(self.0, self.1)
} else {
self.0.clone_node()
}
}
}
pub fn as_tile(&self) -> &dyn Tile {
self.0.as_tile()
}
#[inline]
pub fn id_ref(&self) -> &Id {
self.0.id_ref()
}
#[inline]
pub fn id(&self) -> Id {
self.0.id_ref().clone()
}
#[inline]
pub fn identify(&self) -> IdentifyWidget<'_> {
self.0.as_tile().identify()
}
#[inline]
pub fn eq_id<T>(&self, rhs: T) -> bool
where
Id: PartialEq<T>,
{
*self.id_ref() == rhs
}
#[inline]
pub fn is_ancestor_of(&self, id: &Id) -> bool {
self.id().is_ancestor_of(id)
}
#[inline]
pub fn is_strict_ancestor_of(&self, id: &Id) -> bool {
!self.eq_id(id) && self.id().is_ancestor_of(id)
}
#[inline]
pub fn rect(&self) -> Rect {
self.0.rect()
}
#[inline]
pub fn try_probe(&self, coord: Coord) -> Option<Id> {
self.0.as_tile().try_probe(coord)
}
#[inline(always)]
pub fn get_child(&mut self, index: usize) -> Option<Node<'_>> {
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
self.0.child_node(self.1, index)
} else {
self.0.child_node(index)
}
}
}
#[inline]
pub fn find_child_index(&self, id: &Id) -> Option<usize> {
self.0.find_child_index(id)
}
#[inline(always)]
pub fn find_node<F: FnOnce(Node<'_>) -> T, T>(&mut self, id: &Id, cb: F) -> Option<T> {
if let Some(index) = self.find_child_index(id) {
if let Some(mut node) = self.get_child(index) {
node.find_node(id, cb)
} else {
debug_assert!(false);
None
}
} else if self.eq_id(id) {
Some(cb(self.re()))
} else {
None
}
}
}
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
impl<'a> Node<'a> {
pub(crate) fn size_rules(&mut self, cx: &mut SizeCx, axis: AxisInfo) -> SizeRules {
self.0.size_rules(cx, axis)
}
pub(crate) fn set_rect(&mut self, cx: &mut SizeCx, rect: Rect, hints: AlignHints) {
self.0.set_rect(cx, rect, hints);
}
pub(crate) fn _configure(&mut self, cx: &mut ConfigCx, id: Id) {
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
self.0._configure(cx, self.1, id);
} else {
self.0._configure(cx, id);
}
}
}
pub(crate) fn _update(&mut self, cx: &mut ConfigCx) {
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
self.0._update(cx, self.1);
} else {
self.0._update(cx);
}
}
}
pub(crate) fn _send(&mut self, cx: &mut EventCx, id: Id, event: Event) -> IsUsed {
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
self.0._send(cx, self.1, id, event)
} else {
self.0._send(cx, id, event)
}
}
}
pub(crate) fn _replay(&mut self, cx: &mut EventCx, id: Id) {
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
self.0._replay(cx, self.1, id);
} else {
self.0._replay(cx, id);
}
}
}
}