use super::Widget;
use crate::event::{ConfigCx, Event, EventCx, IsUsed};
use crate::geom::{Coord, Rect};
use crate::layout::{AxisInfo, SizeRules};
use crate::theme::{DrawCx, SizeCx};
use crate::{messages::Erased, Id, Layout, NavAdvance};
#[cfg(not(feature = "unsafe_node"))]
trait NodeT {
fn id_ref(&self) -> &Id;
fn rect(&self) -> Rect;
fn clone_node(&mut self) -> Node<'_>;
fn as_layout(&self) -> &dyn Layout;
fn num_children(&self) -> usize;
fn find_child_index(&self, id: &Id) -> Option<usize>;
fn for_child_node(&mut self, index: usize, f: Box<dyn FnOnce(Node<'_>) + '_>);
fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules;
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect);
fn nav_next(&self, reverse: bool, from: Option<usize>) -> Option<usize>;
fn find_id(&mut self, coord: Coord) -> Option<Id>;
fn _draw(&mut self, draw: DrawCx);
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, disabled: bool, event: Event) -> IsUsed;
fn _replay(&mut self, cx: &mut EventCx, id: Id, msg: Erased);
fn _nav_next(
&mut self,
cx: &mut ConfigCx,
focus: Option<&Id>,
advance: NavAdvance,
) -> Option<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_layout(&self) -> &dyn Layout {
self.0.as_layout()
}
fn num_children(&self) -> usize {
self.0.num_children()
}
fn find_child_index(&self, id: &Id) -> Option<usize> {
self.0.find_child_index(id)
}
fn for_child_node(&mut self, index: usize, f: Box<dyn FnOnce(Node<'_>) + '_>) {
self.0.for_child_node(self.1, index, f);
}
fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
self.0.size_rules(sizer, axis)
}
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) {
self.0.set_rect(cx, rect);
}
fn nav_next(&self, reverse: bool, from: Option<usize>) -> Option<usize> {
self.0.nav_next(reverse, from)
}
fn find_id(&mut self, coord: Coord) -> Option<Id> {
self.0.find_id(coord)
}
fn _draw(&mut self, mut draw: DrawCx) {
draw.recurse(&mut self.0);
}
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, disabled: bool, event: Event) -> IsUsed {
self.0._send(cx, self.1, id, disabled, event)
}
fn _replay(&mut self, cx: &mut EventCx, id: Id, msg: Erased) {
self.0._replay(cx, self.1, id, msg);
}
fn _nav_next(
&mut self,
cx: &mut ConfigCx,
focus: Option<&Id>,
advance: NavAdvance,
) -> Option<Id> {
self.0._nav_next(cx, self.1, focus, advance)
}
}
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;
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_layout(&self) -> &dyn Layout {
self.0.as_layout()
}
#[inline]
pub fn id_ref(&self) -> &Id {
self.0.id_ref()
}
#[inline]
pub fn id(&self) -> Id {
self.id_ref().clone()
}
#[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 num_children(&self) -> usize {
self.0.num_children()
}
pub fn for_child<R>(&mut self, index: usize, f: impl FnOnce(Node<'_>) -> R) -> Option<R> {
let mut result = None;
let out = &mut result;
let f: Box<dyn for<'b> FnOnce(Node<'b>)> = Box::new(|node| {
*out = Some(f(node));
});
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
self.0.for_child_node(self.1, index, f);
} else {
self.0.for_child_node(index, f);
}
}
result
}
pub fn for_children(&mut self, mut f: impl FnMut(Node<'_>)) {
for index in 0..self.0.num_children() {
let f = &mut f;
let f: Box<dyn for<'b> FnOnce(Node<'b>)> = Box::new(|node| {
f(node);
});
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
self.0.for_child_node(self.1, index, f);
} else {
self.0.for_child_node(index, f);
}
}
}
}
#[inline]
pub fn find_child_index(&self, id: &Id) -> Option<usize> {
self.0.find_child_index(id)
}
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) {
self.for_child(index, |mut node| node.find_node(id, cb))
.unwrap()
} else if self.eq_id(id) {
Some(cb(self.re()))
} else {
None
}
}
}
#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
#[cfg_attr(doc_cfg, doc(cfg(internal_doc)))]
impl<'a> Node<'a> {
pub(crate) fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
self.0.size_rules(sizer, axis)
}
pub(crate) fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) {
self.0.set_rect(cx, rect);
}
pub(crate) fn nav_next(&self, reverse: bool, from: Option<usize>) -> Option<usize> {
self.0.nav_next(reverse, from)
}
pub(crate) fn find_id(&mut self, coord: Coord) -> Option<Id> {
self.0.find_id(coord)
}
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
pub(crate) fn _draw(&mut self, mut draw: DrawCx) {
draw.recurse(&mut self.0);
}
} else {
pub(crate) fn _draw(&mut self, draw: DrawCx) {
self.0._draw(draw);
}
}
}
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,
disabled: bool,
event: Event,
) -> IsUsed {
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
self.0._send(cx, self.1, id, disabled, event)
} else {
self.0._send(cx, id, disabled, event)
}
}
}
pub(crate) fn _replay(&mut self, cx: &mut EventCx, id: Id, msg: Erased) {
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
self.0._replay(cx, self.1, id, msg);
} else {
self.0._replay(cx, id, msg);
}
}
}
pub fn _nav_next(
&mut self,
cx: &mut ConfigCx,
focus: Option<&Id>,
advance: NavAdvance,
) -> Option<Id> {
cfg_if::cfg_if! {
if #[cfg(feature = "unsafe_node")] {
self.0._nav_next(cx, self.1, focus, advance)
} else {
self.0._nav_next(cx, focus, advance)
}
}
}
}