use alloc::vec::Vec;
use denise::Rect;
use crate::widget::{BoxedWidget, VisualState};
slotmap::new_key_type! {
pub struct NodeId;
}
impl NodeId {
#[inline]
pub fn as_ffi(self) -> u64 {
use slotmap::Key as _;
self.data().as_ffi()
}
#[inline]
pub fn from_ffi(value: u64) -> Self {
use slotmap::KeyData;
NodeId::from(KeyData::from_ffi(value))
}
}
pub(crate) struct Node<M> {
pub(crate) widget: BoxedWidget<M>,
pub(crate) layout: Rect,
pub(crate) bounds: Rect,
pub(crate) clip: Rect,
pub(crate) z: i32,
pub(crate) visible: bool,
pub(crate) enabled: bool,
pub(crate) parent: Option<NodeId>,
pub(crate) children: Vec<NodeId>,
pub(crate) scene: usize,
pub(crate) state: VisualState,
pub(crate) scrollable: bool,
pub(crate) scroll: denise::Point,
}
impl<M> Node<M> {
pub(crate) fn new(widget: BoxedWidget<M>, layout: Rect, scene: usize) -> Self {
Self {
widget,
layout,
bounds: layout,
clip: layout,
z: 0,
visible: true,
enabled: true,
parent: None,
children: Vec::new(),
scene,
state: VisualState::NONE,
scrollable: false,
scroll: denise::Point::ZERO,
}
}
#[inline]
pub(crate) fn paintable(&self) -> bool {
self.visible && !self.clip.is_empty()
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct Scene {
pub(crate) root: NodeId,
pub(crate) dim: u8,
pub(crate) popup: Option<Popup>,
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct Popup {
pub(crate) anchor: NodeId,
pub(crate) container: NodeId,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ffi_round_trip_preserves_identity() {
use slotmap::SlotMap;
let mut map: SlotMap<NodeId, u32> = SlotMap::with_key();
let a = map.insert(1);
assert_eq!(NodeId::from_ffi(a.as_ffi()), a);
}
#[test]
fn a_stale_id_does_not_resolve_to_the_next_node() {
use slotmap::SlotMap;
let mut map: SlotMap<NodeId, u32> = SlotMap::with_key();
let a = map.insert(1);
map.remove(a);
let b = map.insert(2);
assert_ne!(a, b);
assert_eq!(map.get(a), None);
}
}