use core::{
clone::Clone,
cmp::{
Eq,
PartialEq,
},
default::Default,
marker::{
Copy,
Sized,
},
option::{
Option,
Option::{
None,
Some,
},
},
};
pub use euclid::Rect;
use crate::{
geometry::Area,
node::Node,
prelude::{
AreaModel,
Gaps,
},
};
extern crate alloc;
use alloc::vec::Vec;
#[derive(Debug, Default, Clone)]
pub struct LayoutNode<Data: NodeData> {
pub area: Area,
pub inner_area: Area,
pub margin: Gaps,
pub data: Option<Data>,
}
impl<Data: NodeData> PartialEq for LayoutNode<Data> {
fn eq(&self, other: &Self) -> bool {
self.area == other.area
&& self.inner_area == other.inner_area
&& self.margin == other.margin
}
}
impl<Data: NodeData> LayoutNode<Data> {
pub fn visible_area(&self) -> Area {
self.area.without_gaps(&self.margin)
}
}
pub trait NodeKey: Clone + PartialEq + Eq + core::hash::Hash + Copy + core::fmt::Debug {}
pub trait NodeData: Clone {}
impl NodeKey for usize {}
impl NodeData for () {}
#[cfg(feature = "dioxus")]
impl NodeKey for freya_native_core::NodeId {}
pub trait DOMAdapter<Key: NodeKey> {
fn root_id(&self) -> Key;
fn get_node(&self, node_id: &Key) -> Option<Node>;
fn height(&self, node_id: &Key) -> Option<u16>;
fn parent_of(&self, node_id: &Key) -> Option<Key>;
fn children_of(&mut self, node_id: &Key) -> Vec<Key>;
fn is_node_valid(&mut self, node_id: &Key) -> bool;
fn closest_common_parent(&self, node_a: &Key, node_b: &Key) -> Option<Key> {
let height_a = self.height(node_a)?;
let height_b = self.height(node_b)?;
let (node_a, node_b) = match height_a.cmp(&height_b) {
core::cmp::Ordering::Less => (
*node_a,
balance_heights(self, *node_b, *node_a).unwrap_or(*node_b),
),
core::cmp::Ordering::Equal => (*node_a, *node_b),
core::cmp::Ordering::Greater => (
balance_heights(self, *node_a, *node_b).unwrap_or(*node_a),
*node_b,
),
};
let mut currents = (node_a, node_b);
loop {
if currents.0 == currents.1 {
return Some(currents.0);
}
let parent_a = self.parent_of(¤ts.0);
if let Some(parent_a) = parent_a {
currents.0 = parent_a;
} else if self.root_id() != currents.0 {
break;
}
let parent_b = self.parent_of(¤ts.1);
if let Some(parent_b) = parent_b {
currents.1 = parent_b;
} else if self.root_id() != currents.1 {
break;
}
}
None
}
}
fn balance_heights<Key: NodeKey>(
dom_adapter: &(impl DOMAdapter<Key> + ?Sized),
base: Key,
target: Key,
) -> Option<Key> {
let target_height = dom_adapter.height(&target)?;
let mut current = base;
loop {
if dom_adapter.height(¤t)? == target_height {
break;
}
let parent_current = dom_adapter.parent_of(¤t);
if let Some(parent_current) = parent_current {
current = parent_current;
}
}
Some(current)
}