use crate::base::{Rect, Size};
use crate::reactive::{GenArena, Key};
use super::style::Style;
pub type MeasureFn = Box<dyn Fn(Size) -> Size>;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct LayoutId(pub(crate) Key);
pub(crate) struct LayoutNode {
pub style: Style,
pub parent: Option<LayoutId>,
pub children: Vec<LayoutId>,
pub measure: Option<MeasureFn>,
pub rect: Rect,
}
#[derive(Default)]
pub struct LayoutTree {
pub(crate) nodes: GenArena<LayoutNode>,
pub(crate) geometry_damage: Vec<Rect>,
}
impl LayoutTree {
pub fn new() -> Self {
Self::default()
}
pub fn add(&mut self, style: Style) -> LayoutId {
LayoutId(self.nodes.insert(LayoutNode {
style,
parent: None,
children: Vec::new(),
measure: None,
rect: Rect::ZERO,
}))
}
pub fn add_leaf(&mut self, style: Style, measure: MeasureFn) -> LayoutId {
let id = self.add(style);
self.nodes.get_mut(id.0).expect("just added").measure = Some(measure);
id
}
pub fn add_child(&mut self, parent: LayoutId, child: LayoutId) {
assert!(
self.nodes.contains(parent.0),
"layout: add_child on stale parent"
);
{
let c = self
.nodes
.get_mut(child.0)
.expect("layout: add_child on stale child");
debug_assert!(c.parent.is_none(), "layout: child already attached");
c.parent = Some(parent);
}
self.nodes
.get_mut(parent.0)
.expect("checked")
.children
.push(child);
}
pub fn remove(&mut self, id: LayoutId) {
let Some(node) = self.nodes.get(id.0) else {
return;
};
if let Some(parent) = node.parent {
if let Some(p) = self.nodes.get_mut(parent.0) {
p.children.retain(|c| *c != id);
}
}
let mut stack = vec![id];
while let Some(cur) = stack.pop() {
if let Some(node) = self.nodes.remove(cur.0) {
stack.extend(node.children);
}
}
}
pub fn set_style(&mut self, id: LayoutId, style: Style) {
if let Some(node) = self.nodes.get_mut(id.0) {
node.style = style;
}
}
pub fn style(&self, id: LayoutId) -> Option<&Style> {
self.nodes.get(id.0).map(|n| &n.style)
}
pub fn set_measure(&mut self, id: LayoutId, measure: Option<MeasureFn>) {
if let Some(node) = self.nodes.get_mut(id.0) {
node.measure = measure;
}
}
pub fn rect(&self, id: LayoutId) -> Rect {
self.nodes.get(id.0).map(|n| n.rect).unwrap_or(Rect::ZERO)
}
pub(crate) fn assign_rect(&mut self, id: LayoutId, rect: Rect) {
if let Some(node) = self.nodes.get_mut(id.0) {
if node.rect != rect {
let old = node.rect;
node.rect = rect;
if !old.is_empty() {
self.geometry_damage.push(old);
}
if !rect.is_empty() {
self.geometry_damage.push(rect);
}
}
}
}
pub fn take_geometry_damage(&mut self) -> Vec<Rect> {
std::mem::take(&mut self.geometry_damage)
}
pub fn children(&self, id: LayoutId) -> &[LayoutId] {
self.nodes
.get(id.0)
.map(|n| n.children.as_slice())
.unwrap_or(&[])
}
pub fn parent(&self, id: LayoutId) -> Option<LayoutId> {
self.nodes.get(id.0).and_then(|n| n.parent)
}
pub fn is_alive(&self, id: LayoutId) -> bool {
self.nodes.contains(id.0)
}
pub fn len(&self) -> usize {
self.nodes.live()
}
pub fn is_empty(&self) -> bool {
self.nodes.live() == 0
}
}