|
@@ -1,7 +1,4 @@
|
|
-use std::{
|
|
|
|
- ops::{Deref, DerefMut},
|
|
|
|
- rc::Rc,
|
|
|
|
-};
|
|
|
|
|
|
+use std::{ops::Deref, rc::Rc};
|
|
|
|
|
|
use crate::geom::IRect;
|
|
use crate::geom::IRect;
|
|
use cache::{Layer, LayoutCacheKey, NodeState};
|
|
use cache::{Layer, LayoutCacheKey, NodeState};
|
|
@@ -123,8 +120,8 @@ impl Deref for ChildArrangement {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-#[derive(Debug)]
|
|
|
|
pub struct LayoutNode {
|
|
pub struct LayoutNode {
|
|
|
|
+ label: Option<String>,
|
|
cache_key: LayoutCacheKey,
|
|
cache_key: LayoutCacheKey,
|
|
cache: Rc<LayoutCache>,
|
|
cache: Rc<LayoutCache>,
|
|
behaviour: NodeBehaviour,
|
|
behaviour: NodeBehaviour,
|
|
@@ -136,11 +133,27 @@ pub struct LayoutNode {
|
|
margin: BoxMeasure,
|
|
margin: BoxMeasure,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+impl std::fmt::Debug for LayoutNode {
|
|
|
|
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
+ f.debug_struct("LayoutNode")
|
|
|
|
+ .field("label", &self.label)
|
|
|
|
+ .field("cache_key", &self.cache_key)
|
|
|
|
+ .field("behaviour", &self.behaviour)
|
|
|
|
+ .field("child_arrangement", &self.child_arrangement)
|
|
|
|
+ .field("width_policy", &self.width_policy)
|
|
|
|
+ .field("height_policy", &self.height_policy)
|
|
|
|
+ .field("padding", &self.padding)
|
|
|
|
+ .field("margin", &self.margin)
|
|
|
|
+ .finish()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
impl LayoutNode {
|
|
impl LayoutNode {
|
|
pub fn new(cache: Rc<LayoutCache>) -> Self {
|
|
pub fn new(cache: Rc<LayoutCache>) -> Self {
|
|
let cache_key = LayoutCacheKey::generate();
|
|
let cache_key = LayoutCacheKey::generate();
|
|
cache.update_queue.borrow_mut().push(cache_key);
|
|
cache.update_queue.borrow_mut().push(cache_key);
|
|
Self {
|
|
Self {
|
|
|
|
+ label: None,
|
|
cache_key,
|
|
cache_key,
|
|
cache,
|
|
cache,
|
|
behaviour: NodeBehaviour::Element,
|
|
behaviour: NodeBehaviour::Element,
|
|
@@ -155,39 +168,56 @@ impl LayoutNode {
|
|
pub fn relayout(&self) {
|
|
pub fn relayout(&self) {
|
|
self.cache.update_queue.borrow_mut().push(self.cache_key);
|
|
self.cache.update_queue.borrow_mut().push(self.cache_key);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ pub fn cached_rect(&self) -> Option<IRect> {
|
|
|
|
+ self.cache
|
|
|
|
+ .with_state(self.cache_key, |ns| ns.rect)
|
|
|
|
+ .flatten()
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
// accessors
|
|
// accessors
|
|
impl LayoutNode {
|
|
impl LayoutNode {
|
|
|
|
+ pub fn label(&self) -> Option<&str> {
|
|
|
|
+ self.label.as_ref().map(String::as_str)
|
|
|
|
+ }
|
|
|
|
+ pub fn set_label(&mut self, to: impl AsRef<str>) {
|
|
|
|
+ self.label = Some(to.as_ref().to_string());
|
|
|
|
+ }
|
|
|
|
+
|
|
pub fn behaviour(&self) -> NodeBehaviour {
|
|
pub fn behaviour(&self) -> NodeBehaviour {
|
|
self.behaviour
|
|
self.behaviour
|
|
}
|
|
}
|
|
- pub fn set_behaviour(&mut self, mode: NodeBehaviour) {
|
|
|
|
|
|
+ pub fn set_behaviour(&mut self, mode: NodeBehaviour) -> &mut Self {
|
|
self.behaviour = mode;
|
|
self.behaviour = mode;
|
|
self.relayout();
|
|
self.relayout();
|
|
|
|
+ self
|
|
}
|
|
}
|
|
|
|
|
|
pub fn arrangement(&self) -> &ChildArrangement {
|
|
pub fn arrangement(&self) -> &ChildArrangement {
|
|
&self.child_arrangement
|
|
&self.child_arrangement
|
|
}
|
|
}
|
|
- pub fn set_arrangement(&mut self, arr: ChildArrangement) {
|
|
|
|
|
|
+ pub fn set_arrangement(&mut self, arr: ChildArrangement) -> &mut Self {
|
|
self.child_arrangement = arr;
|
|
self.child_arrangement = arr;
|
|
self.relayout();
|
|
self.relayout();
|
|
|
|
+ self
|
|
}
|
|
}
|
|
|
|
|
|
pub fn width_policy(&self) -> SizePolicy {
|
|
pub fn width_policy(&self) -> SizePolicy {
|
|
self.width_policy
|
|
self.width_policy
|
|
}
|
|
}
|
|
- pub fn set_width_policy(&mut self, policy: SizePolicy) {
|
|
|
|
|
|
+ pub fn set_width_policy(&mut self, policy: SizePolicy) -> &mut Self {
|
|
self.width_policy = policy;
|
|
self.width_policy = policy;
|
|
self.relayout();
|
|
self.relayout();
|
|
|
|
+ self
|
|
}
|
|
}
|
|
pub fn height_policy(&self) -> SizePolicy {
|
|
pub fn height_policy(&self) -> SizePolicy {
|
|
self.height_policy
|
|
self.height_policy
|
|
}
|
|
}
|
|
- pub fn set_height_policy(&mut self, policy: SizePolicy) {
|
|
|
|
|
|
+ pub fn set_height_policy(&mut self, policy: SizePolicy) -> &mut Self {
|
|
self.height_policy = policy;
|
|
self.height_policy = policy;
|
|
self.relayout();
|
|
self.relayout();
|
|
|
|
+ self
|
|
}
|
|
}
|
|
|
|
|
|
pub fn padding(&self) -> BoxMeasure {
|
|
pub fn padding(&self) -> BoxMeasure {
|
|
@@ -207,6 +237,7 @@ impl LayoutNode {
|
|
impl Clone for LayoutNode {
|
|
impl Clone for LayoutNode {
|
|
fn clone(&self) -> Self {
|
|
fn clone(&self) -> Self {
|
|
Self {
|
|
Self {
|
|
|
|
+ label: self.label.clone(),
|
|
cache_key: LayoutCacheKey::generate(),
|
|
cache_key: LayoutCacheKey::generate(),
|
|
cache: self.cache.clone(),
|
|
cache: self.cache.clone(),
|
|
behaviour: self.behaviour,
|
|
behaviour: self.behaviour,
|
|
@@ -225,35 +256,155 @@ impl Drop for LayoutNode {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+fn dump_node_tree_helper(lna: LayoutNodeAccess, indent: usize, out: &mut String) {
|
|
|
|
+ let ind = " ".repeat(indent);
|
|
|
|
+ out.push_str(ind.as_str());
|
|
|
|
+ out.push_str("Node (");
|
|
|
|
+ out.push_str(match lna.label() {
|
|
|
|
+ Some(v) => v,
|
|
|
|
+ None => "<anon>",
|
|
|
|
+ });
|
|
|
|
+ out.push_str(format!(") [wpol: {}/{}/{} hpol: {}/{}/{} behaviour: {:?}]\n",
|
|
|
|
+ lna.width_policy.minimum, lna.width_policy.desired, lna.width_policy.slack_weight,
|
|
|
|
+ lna.height_policy.minimum, lna.height_policy.desired, lna.height_policy.slack_weight,
|
|
|
|
+ lna.behaviour).as_str());
|
|
|
|
+ out.push_str(ind.as_str());
|
|
|
|
+ out.push_str(" ");
|
|
|
|
+ out.push_str(format!("cached rect: {:?}\n", lna.cached_rect()).as_str());
|
|
|
|
+
|
|
|
|
+ for child in lna.child_iter() {
|
|
|
|
+ dump_node_tree_helper(child, indent+1, out);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub fn dump_node_tree(lna: LayoutNodeAccess, out: &mut String) {
|
|
|
|
+ out.clear();
|
|
|
|
+ dump_node_tree_helper(lna, 0, out);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/// Iterator implementation to iterate across children of a LayoutNodeContainer
|
|
#[derive(Clone)]
|
|
#[derive(Clone)]
|
|
pub struct LayoutChildIter<'l> {
|
|
pub struct LayoutChildIter<'l> {
|
|
- lna: &'l dyn LayoutNodeAccess,
|
|
|
|
|
|
+ lnc: &'l dyn LayoutNodeContainer,
|
|
next_index: usize,
|
|
next_index: usize,
|
|
}
|
|
}
|
|
|
|
|
|
impl<'l> LayoutChildIter<'l> {
|
|
impl<'l> LayoutChildIter<'l> {
|
|
- pub fn new(lna: &'l dyn LayoutNodeAccess) -> Self {
|
|
|
|
- Self { lna, next_index: 0 }
|
|
|
|
|
|
+ fn new(lnc: &'l dyn LayoutNodeContainer) -> Self {
|
|
|
|
+ Self { lnc, next_index: 0 }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl<'l> Iterator for LayoutChildIter<'l> {
|
|
impl<'l> Iterator for LayoutChildIter<'l> {
|
|
- type Item = &'l dyn LayoutNodeAccess;
|
|
|
|
|
|
+ type Item = LayoutNodeAccess<'l>;
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let index = self.next_index;
|
|
let index = self.next_index;
|
|
- if index >= self.lna.child_count() {
|
|
|
|
|
|
+ if index >= self.lnc.layout_child_count() {
|
|
None
|
|
None
|
|
} else {
|
|
} else {
|
|
self.next_index += 1;
|
|
self.next_index += 1;
|
|
- self.lna.child(index)
|
|
|
|
|
|
+ self.lnc.layout_child(index)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/// Accessor trait for a [`LayoutNode`] tree, which has externally-stored relationships.
|
|
|
|
-pub trait LayoutNodeAccess: Deref<Target = LayoutNode> + DerefMut<Target = LayoutNode> {
|
|
|
|
- fn child_count(&self) -> usize;
|
|
|
|
- fn child(&self, ndx: usize) -> Option<&dyn LayoutNodeAccess>;
|
|
|
|
- fn child_iter(&self) -> LayoutChildIter;
|
|
|
|
|
|
+#[derive(Clone, Copy)]
|
|
|
|
+pub struct LayoutNodeAccess<'l> {
|
|
|
|
+ lnc: &'l dyn LayoutNodeContainer,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<'l> LayoutNodeAccess<'l> {
|
|
|
|
+ pub fn new(lnc: &'l dyn LayoutNodeContainer) -> Self {
|
|
|
|
+ Self { lnc }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<'l> Deref for LayoutNodeAccess<'l> {
|
|
|
|
+ type Target = LayoutNode;
|
|
|
|
+ fn deref(&self) -> &Self::Target {
|
|
|
|
+ self.lnc.layout_node()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<'l> LayoutNodeAccess<'l> {
|
|
|
|
+ pub fn child(&self, ndx: usize) -> Option<LayoutNodeAccess<'l>> {
|
|
|
|
+ self.lnc.layout_child(ndx)
|
|
|
|
+ }
|
|
|
|
+ pub fn child_len(&self) -> usize {
|
|
|
|
+ self.lnc.layout_child_count()
|
|
|
|
+ }
|
|
|
|
+ pub fn child_iter(&self) -> LayoutChildIter {
|
|
|
|
+ LayoutChildIter::new(self.lnc)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/// Data source trait for LayoutNodeAccess.
|
|
|
|
+pub trait LayoutNodeContainer {
|
|
|
|
+ fn layout_node(&self) -> &LayoutNode;
|
|
|
|
+ fn layout_child(&self, ndx: usize) -> Option<LayoutNodeAccess<'_>>;
|
|
|
|
+ fn layout_child_count(&self) -> usize;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/// Helper struct to store a leaf LayoutNode and automatically provide a LayoutNodeContainer impl
|
|
|
|
+pub struct LeafLayoutNode(LayoutNode);
|
|
|
|
+
|
|
|
|
+impl LeafLayoutNode {
|
|
|
|
+ pub fn new(ln: LayoutNode) -> Self {
|
|
|
|
+ Self(ln)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl From<LayoutNode> for LeafLayoutNode {
|
|
|
|
+ fn from(value: LayoutNode) -> Self {
|
|
|
|
+ Self::new(value)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl std::ops::Deref for LeafLayoutNode {
|
|
|
|
+ type Target = LayoutNode;
|
|
|
|
+ fn deref(&self) -> &Self::Target {
|
|
|
|
+ &self.0
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl std::ops::DerefMut for LeafLayoutNode {
|
|
|
|
+ fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
+ &mut self.0
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl LayoutNodeContainer for LeafLayoutNode {
|
|
|
|
+ fn layout_node(&self) -> &LayoutNode {
|
|
|
|
+ &self.0
|
|
|
|
+ }
|
|
|
|
+ fn layout_child(&self, _ndx: usize) -> Option<LayoutNodeAccess<'_>> {
|
|
|
|
+ None
|
|
|
|
+ }
|
|
|
|
+ fn layout_child_count(&self) -> usize {
|
|
|
|
+ 0
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/// Helper LayoutNodeContainer implementation for LayoutNodes with one child
|
|
|
|
+pub struct LinearAccess<'l>(&'l LayoutNode, LayoutNodeAccess<'l>);
|
|
|
|
+impl<'l> LinearAccess<'l> {
|
|
|
|
+ pub fn new(parent: &'l LayoutNode, child: LayoutNodeAccess<'l>) -> Self {
|
|
|
|
+ Self(parent, child)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+impl<'l> LayoutNodeContainer for LinearAccess<'l> {
|
|
|
|
+ fn layout_node(&self) -> &LayoutNode {
|
|
|
|
+ self.0
|
|
|
|
+ }
|
|
|
|
+ fn layout_child(&self, ndx: usize) -> Option<LayoutNodeAccess> {
|
|
|
|
+ if ndx == 0 {
|
|
|
|
+ Some(self.1)
|
|
|
|
+ } else {
|
|
|
|
+ None
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ fn layout_child_count(&self) -> usize {
|
|
|
|
+ 1
|
|
|
|
+ }
|
|
}
|
|
}
|