calc.rs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. use super::{cache::LayoutCacheKey, Layer, LayoutNodeAccess, NodeBehaviour, NodeState};
  2. pub fn recalculate(node: LayoutNodeAccess) {
  3. if let NodeBehaviour::Fixed { area } = node.behaviour() {
  4. let layer = Layer::default();
  5. // propagate relayout flags up to the root
  6. node.cache.propagate_relayouts();
  7. // propagate rerender flags down to the leaves
  8. node.cache.propagate_rerenders();
  9. arrangement_pass(None, node, layer);
  10. node.child_arrangement.layout_step(node, area);
  11. } else {
  12. log::warn!("Layout root node does not have Fixed mode");
  13. }
  14. }
  15. fn arrangement_pass(parent: Option<LayoutCacheKey>, node: LayoutNodeAccess, layer: Layer) {
  16. // early-out check
  17. if node.cache.with_state(node.cache_key, |st| st.needs_update) == Some(false) {
  18. return;
  19. }
  20. for child in node.child_iter() {
  21. arrangement_pass(Some(node.cache_key), child, layer.nest());
  22. }
  23. // construct net size policy
  24. let child_policies = node
  25. .child_iter()
  26. .map(|child| {
  27. node.cache
  28. .with_state(child.cache_key, |s| s.net_policy)
  29. .unwrap()
  30. })
  31. .collect::<Vec<_>>();
  32. let (wpol, hpol) = node.child_arrangement.arrange_step(node, child_policies);
  33. let child_ids = node.child_iter().map(|ch| ch.cache_key).collect();
  34. if node.cache.has_state_for(node.cache_key) {
  35. node.cache.with_state(node.cache_key, |ns| {
  36. ns.net_policy = (wpol, hpol);
  37. ns.children = child_ids;
  38. });
  39. } else {
  40. node.cache.store(
  41. node.cache_key,
  42. parent,
  43. NodeState {
  44. needs_update: false,
  45. needs_render: true,
  46. net_policy: (wpol, hpol),
  47. area: None,
  48. layer,
  49. children: child_ids,
  50. },
  51. );
  52. }
  53. }
  54. #[cfg(test)]
  55. mod test {
  56. use kahlo::math::{PixelBox, PixelPoint, PixelRect, PixelSize};
  57. use crate::layout::{
  58. cache::LayoutCache, ChildArrangement, LayoutNode, LayoutNodeAccess, LayoutNodeContainer,
  59. NodeBehaviour, SizePolicy,
  60. };
  61. use super::recalculate;
  62. struct LayoutTree {
  63. children: Vec<LayoutTree>,
  64. node: LayoutNode,
  65. }
  66. impl LayoutNodeContainer for LayoutTree {
  67. fn layout_node(&self) -> &LayoutNode {
  68. &self.node
  69. }
  70. fn layout_child(&self, ndx: usize) -> Option<LayoutNodeAccess<'_>> {
  71. self.children.get(ndx).map(|t| LayoutNodeAccess::new(t))
  72. }
  73. fn layout_child_count(&self) -> usize {
  74. self.children.len()
  75. }
  76. }
  77. #[test]
  78. fn simple_test() {
  79. let cache = LayoutCache::new();
  80. let mut root = LayoutTree {
  81. children: vec![
  82. {
  83. let mut lt = LayoutTree {
  84. children: vec![],
  85. node: LayoutNode::new(cache.clone()),
  86. };
  87. lt.node.set_height_policy(SizePolicy {
  88. minimum: 1,
  89. desired: 1,
  90. slack_weight: 1,
  91. });
  92. lt
  93. },
  94. {
  95. let mut lt = LayoutTree {
  96. children: vec![],
  97. node: LayoutNode::new(cache.clone()),
  98. };
  99. lt.node.set_height_policy(SizePolicy {
  100. minimum: 2,
  101. desired: 3,
  102. slack_weight: 0,
  103. });
  104. lt
  105. },
  106. ],
  107. node: LayoutNode::new(cache.clone()),
  108. };
  109. root.node.set_behaviour(NodeBehaviour::Fixed {
  110. area: PixelBox::from_origin_and_size(PixelPoint::new(1, 1), PixelSize::new(2, 5)),
  111. });
  112. root.node.child_arrangement = ChildArrangement::Column;
  113. recalculate(LayoutNodeAccess::new(&root));
  114. println!("cache: {:?}", cache);
  115. // check that final rects match expectations
  116. assert_eq!(
  117. cache
  118. .with_state(root.node.cache_key, |ns| ns.area)
  119. .flatten(),
  120. Some(PixelBox::from_origin_and_size(
  121. PixelPoint::new(1, 1),
  122. PixelSize::new(2, 5)
  123. ))
  124. );
  125. assert_eq!(
  126. cache
  127. .with_state(root.children[0].node.cache_key, |ns| ns.area)
  128. .flatten(),
  129. Some(PixelBox::from_origin_and_size(
  130. PixelPoint::new(1, 1),
  131. PixelSize::new(2, 2)
  132. ))
  133. );
  134. }
  135. }