layout.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. //! Layout calculations for the widget tree.
  2. //!
  3. //! Layout calculations are done in two passes:
  4. //! - **Arrangement**: computes minimum sizes, net size policies, and records parent/child relationships between
  5. //! nodes.
  6. //! - **Layout**: given minimum sizes and net size policies from the arrangement step, computes
  7. //! exact pixel values for positions and sizes.
  8. use std::{ops::Deref, rc::Rc};
  9. use cache::{Layer, LayoutCacheKey, NodeState};
  10. use kahlo::math::{PixelBox, PixelSideOffsets};
  11. mod arr;
  12. mod cache;
  13. mod calc;
  14. pub use cache::LayoutCache;
  15. pub use calc::recalculate;
  16. /// Sizing policy for a layout dimension. Defaults to no minimum or desired size and a low-weighted
  17. /// desire to take up slack space.
  18. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
  19. pub struct SizePolicy {
  20. /// The minimum number of pixels required along this dimension to avoid overlap and other
  21. /// issues.
  22. pub minimum: usize,
  23. /// The number of pixels requested to have a comfortable amount of space and avoid ugly-looking
  24. /// UI.
  25. pub desired: usize,
  26. /// How much to take up any remaining slack space.
  27. pub slack_weight: usize,
  28. }
  29. impl Default for SizePolicy {
  30. fn default() -> Self {
  31. Self {
  32. minimum: 0,
  33. desired: 0,
  34. slack_weight: 1,
  35. }
  36. }
  37. }
  38. impl SizePolicy {
  39. pub fn expanding(weight: usize) -> Self {
  40. Self {
  41. minimum: 0,
  42. desired: 0,
  43. slack_weight: weight,
  44. }
  45. }
  46. pub fn fixed(size: usize) -> Self {
  47. Self {
  48. minimum: size,
  49. desired: size,
  50. slack_weight: 0,
  51. }
  52. }
  53. pub fn max(self, rhs: SizePolicy) -> SizePolicy {
  54. Self {
  55. minimum: self.minimum.max(rhs.minimum),
  56. desired: self.desired.max(rhs.desired),
  57. slack_weight: self.slack_weight.max(rhs.slack_weight),
  58. }
  59. }
  60. pub fn max_preserve_slack(self, rhs: SizePolicy) -> SizePolicy {
  61. Self {
  62. minimum: self.minimum.max(rhs.minimum),
  63. desired: self.desired.max(rhs.desired),
  64. slack_weight: self.slack_weight,
  65. }
  66. }
  67. }
  68. impl std::ops::Add<Self> for SizePolicy {
  69. type Output = Self;
  70. fn add(self, rhs: Self) -> Self::Output {
  71. Self {
  72. minimum: self.minimum + rhs.minimum,
  73. desired: self.desired + rhs.desired,
  74. slack_weight: self.slack_weight + rhs.slack_weight,
  75. }
  76. }
  77. }
  78. /// How to horizontally align a smaller node inside a larger node.
  79. #[derive(Clone, Copy, PartialEq, Debug)]
  80. pub enum HorizontalAlignment {
  81. Left,
  82. Centre,
  83. Right,
  84. }
  85. impl Default for HorizontalAlignment {
  86. fn default() -> Self {
  87. Self::Centre
  88. }
  89. }
  90. #[derive(Clone, Copy, PartialEq, Debug)]
  91. pub enum VerticalAlignment {
  92. Top,
  93. Centre,
  94. Bottom,
  95. }
  96. impl Default for VerticalAlignment {
  97. fn default() -> Self {
  98. Self::Centre
  99. }
  100. }
  101. /// What sort of layout does a node represent?
  102. #[derive(Clone, Copy, PartialEq, Debug)]
  103. pub enum NodeBehaviour {
  104. /// A fixed rendering area, probably a root node.
  105. Fixed { area: PixelBox },
  106. /// An ordinary box sitting inside another node, hinting its size and receiving a final
  107. /// size assignment from its parent.
  108. Element,
  109. /// A node that floats above other content, anchored with a zero-size flexbox.
  110. Anchored,
  111. }
  112. #[derive(Clone)]
  113. pub enum ChildArrangement {
  114. Custom(std::rc::Rc<dyn arr::ArrangementCalculator>),
  115. Column,
  116. Row,
  117. Table,
  118. }
  119. impl std::fmt::Debug for ChildArrangement {
  120. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  121. match self {
  122. Self::Custom(_) => f.write_str("ChildArrangement::Custom"),
  123. Self::Column => f.write_str("ChildArrangement::Column"),
  124. Self::Row => f.write_str("ChildArrangement::Row"),
  125. Self::Table => f.write_str("ChildArrangement::Table"),
  126. }
  127. }
  128. }
  129. impl Deref for ChildArrangement {
  130. type Target = dyn arr::ArrangementCalculator;
  131. fn deref(&self) -> &Self::Target {
  132. match self {
  133. Self::Custom(calc) => calc.as_ref(),
  134. Self::Column => &arr::LineArrangement::Column,
  135. Self::Row => &arr::LineArrangement::Row,
  136. Self::Table => todo!(),
  137. }
  138. }
  139. }
  140. pub struct LayoutNode {
  141. /// Human-readable label for making layout tree dumps easier to read.
  142. label: Option<String>,
  143. /// Unique identifier for this LayoutNode
  144. cache_key: LayoutCacheKey,
  145. /// Reference to the global layout item cache.
  146. cache: Rc<LayoutCache>,
  147. /// Layout behaviour, or how this node behaves with respect to its parent.
  148. behaviour: NodeBehaviour,
  149. /// Child arrangement, or how this node arranges its children.
  150. child_arrangement: ChildArrangement,
  151. /// Width policy: how does this widget take up horizontal space?
  152. width_policy: SizePolicy,
  153. /// Height policy: how does this widget take up vertical space?
  154. height_policy: SizePolicy,
  155. /// Horizontal alignment of children inside this node.
  156. halign: HorizontalAlignment,
  157. /// Vertical alignment of children inside this node.
  158. valign: VerticalAlignment,
  159. /// User-exposed margins, or spacing between the parent and the render area of this node.
  160. margin: PixelSideOffsets,
  161. }
  162. impl std::fmt::Debug for LayoutNode {
  163. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  164. f.debug_struct("LayoutNode")
  165. .field("label", &self.label)
  166. .field("cache_key", &self.cache_key)
  167. .field("behaviour", &self.behaviour)
  168. .field("child_arrangement", &self.child_arrangement)
  169. .field("width_policy", &self.width_policy)
  170. .field("height_policy", &self.height_policy)
  171. .field("margin", &self.margin)
  172. .finish()
  173. }
  174. }
  175. impl LayoutNode {
  176. pub fn new(cache: Rc<LayoutCache>) -> Self {
  177. let cache_key = LayoutCacheKey::generate();
  178. cache.update_queue.borrow_mut().push(cache_key);
  179. Self {
  180. label: None,
  181. cache_key,
  182. cache,
  183. behaviour: NodeBehaviour::Element,
  184. child_arrangement: ChildArrangement::Column,
  185. width_policy: SizePolicy::default(),
  186. height_policy: SizePolicy::default(),
  187. halign: HorizontalAlignment::default(),
  188. valign: VerticalAlignment::default(),
  189. margin: PixelSideOffsets::new_all_same(0),
  190. }
  191. }
  192. pub fn relayout(&self) {
  193. self.cache.update_queue.borrow_mut().push(self.cache_key);
  194. }
  195. pub fn relayout_tree(&self) {
  196. let mut to_mark : Vec<LayoutCacheKey> = vec![self.cache_key];
  197. while let Some(next) = to_mark.pop() {
  198. self.cache.with_state(next, |ns| {
  199. ns.needs_update = true;
  200. to_mark.extend(ns.children.iter());
  201. });
  202. }
  203. }
  204. pub fn render_area(&self) -> Option<PixelBox> {
  205. self.cache
  206. .with_state(self.cache_key, |ns| ns.area)
  207. .flatten()
  208. .map(|pb| pb.inner_box(self.margin))
  209. }
  210. /// Checks if node needs to be rerendered, clearing the flag if so.
  211. pub fn render_check(&self) -> bool {
  212. self.cache.with_state(self.cache_key, |ns| {
  213. let ret = ns.needs_render;
  214. ns.needs_render = false;
  215. ret
  216. }).unwrap_or(false)
  217. }
  218. pub fn render_needed(&self) {
  219. self.cache.render_queue.borrow_mut().push(self.cache_key);
  220. }
  221. }
  222. /// Accessors
  223. impl LayoutNode {
  224. pub fn label(&self) -> Option<&str> {
  225. self.label.as_ref().map(String::as_str)
  226. }
  227. pub fn set_label(&mut self, to: impl AsRef<str>) {
  228. self.label = Some(to.as_ref().to_string());
  229. }
  230. pub fn behaviour(&self) -> NodeBehaviour {
  231. self.behaviour
  232. }
  233. pub fn set_behaviour(&mut self, mode: NodeBehaviour) -> &mut Self {
  234. if self.behaviour != mode {
  235. self.behaviour = mode;
  236. self.relayout();
  237. }
  238. self
  239. }
  240. pub fn arrangement(&self) -> &ChildArrangement {
  241. &self.child_arrangement
  242. }
  243. pub fn set_arrangement(&mut self, arr: ChildArrangement) -> &mut Self {
  244. self.child_arrangement = arr;
  245. self.relayout();
  246. self
  247. }
  248. pub fn width_policy(&self) -> SizePolicy {
  249. self.width_policy
  250. }
  251. pub fn set_width_policy(&mut self, policy: SizePolicy) -> &mut Self {
  252. self.width_policy = policy;
  253. self.relayout();
  254. self
  255. }
  256. pub fn height_policy(&self) -> SizePolicy {
  257. self.height_policy
  258. }
  259. pub fn set_height_policy(&mut self, policy: SizePolicy) -> &mut Self {
  260. self.height_policy = policy;
  261. self.relayout();
  262. self
  263. }
  264. pub fn halign(&self) -> HorizontalAlignment {
  265. self.halign
  266. }
  267. pub fn set_halign(&mut self, halign: HorizontalAlignment) -> &mut Self {
  268. self.halign = halign;
  269. self
  270. }
  271. pub fn valign(&self) -> VerticalAlignment {
  272. self.valign
  273. }
  274. pub fn set_valign(&mut self, valign: VerticalAlignment) -> &mut Self {
  275. self.valign = valign;
  276. self
  277. }
  278. pub fn margin(&self) -> PixelSideOffsets {
  279. self.margin
  280. }
  281. pub fn margin_mut(&mut self) -> &mut PixelSideOffsets {
  282. &mut self.margin
  283. }
  284. }
  285. impl Clone for LayoutNode {
  286. fn clone(&self) -> Self {
  287. Self {
  288. label: self.label.clone(),
  289. cache_key: LayoutCacheKey::generate(),
  290. cache: self.cache.clone(),
  291. behaviour: self.behaviour,
  292. child_arrangement: self.child_arrangement.clone(),
  293. width_policy: self.width_policy,
  294. height_policy: self.height_policy,
  295. halign: self.halign,
  296. valign: self.valign,
  297. margin: self.margin,
  298. }
  299. }
  300. }
  301. impl Drop for LayoutNode {
  302. fn drop(&mut self) {
  303. self.cache.update_queue.borrow_mut().push(self.cache_key);
  304. }
  305. }
  306. fn dump_node_tree_helper(lna: LayoutNodeAccess, indent: usize, out: &mut String) {
  307. let ind = " ".repeat(indent);
  308. out.push_str(ind.as_str());
  309. out.push_str("Node (");
  310. out.push_str(match lna.label() {
  311. Some(v) => v,
  312. None => "<anon>",
  313. });
  314. out.push_str(
  315. format!(
  316. ") [wpol: {}/{}/{} hpol: {}/{}/{} behaviour: {:?} upd: {:?} rend: {:?}]\n",
  317. lna.width_policy.minimum,
  318. lna.width_policy.desired,
  319. lna.width_policy.slack_weight,
  320. lna.height_policy.minimum,
  321. lna.height_policy.desired,
  322. lna.height_policy.slack_weight,
  323. lna.behaviour,
  324. lna.cache.with_state(lna.cache_key, |v| v.needs_update),
  325. lna.cache.with_state(lna.cache_key, |v| v.needs_render),
  326. )
  327. .as_str(),
  328. );
  329. out.push_str(ind.as_str());
  330. out.push_str(" ");
  331. out.push_str(format!("render area: {:?}\n", lna.render_area()).as_str());
  332. for child in lna.child_iter() {
  333. dump_node_tree_helper(child, indent + 1, out);
  334. }
  335. }
  336. pub fn dump_node_tree(lna: LayoutNodeAccess, out: &mut String) {
  337. out.clear();
  338. dump_node_tree_helper(lna, 0, out);
  339. }
  340. /// Iterator implementation to iterate across children of a LayoutNodeContainer
  341. #[derive(Clone)]
  342. pub struct LayoutChildIter<'l> {
  343. lnc: &'l dyn LayoutNodeContainer,
  344. next_index: usize,
  345. }
  346. impl<'l> LayoutChildIter<'l> {
  347. fn new(lnc: &'l dyn LayoutNodeContainer) -> Self {
  348. Self { lnc, next_index: 0 }
  349. }
  350. }
  351. impl<'l> Iterator for LayoutChildIter<'l> {
  352. type Item = LayoutNodeAccess<'l>;
  353. fn next(&mut self) -> Option<Self::Item> {
  354. let index = self.next_index;
  355. if index >= self.lnc.layout_child_count() {
  356. None
  357. } else {
  358. self.next_index += 1;
  359. self.lnc.layout_child(index)
  360. }
  361. }
  362. }
  363. /// Wrapper struct to access a [`LayoutNodeContainer`].
  364. #[derive(Clone, Copy)]
  365. pub struct LayoutNodeAccess<'l> {
  366. lnc: &'l dyn LayoutNodeContainer,
  367. }
  368. impl<'l> LayoutNodeAccess<'l> {
  369. pub fn new(lnc: &'l dyn LayoutNodeContainer) -> Self {
  370. Self { lnc }
  371. }
  372. }
  373. impl<'l> Deref for LayoutNodeAccess<'l> {
  374. type Target = LayoutNode;
  375. fn deref(&self) -> &Self::Target {
  376. self.lnc.layout_node()
  377. }
  378. }
  379. impl<'l> LayoutNodeAccess<'l> {
  380. pub fn child(&self, ndx: usize) -> Option<LayoutNodeAccess<'l>> {
  381. self.lnc.layout_child(ndx)
  382. }
  383. pub fn child_len(&self) -> usize {
  384. self.lnc.layout_child_count()
  385. }
  386. pub fn child_iter(&self) -> LayoutChildIter {
  387. LayoutChildIter::new(self.lnc)
  388. }
  389. }
  390. /// Data source trait for LayoutNodeAccess.
  391. pub trait LayoutNodeContainer {
  392. fn layout_node(&self) -> &LayoutNode;
  393. fn layout_child(&self, ndx: usize) -> Option<LayoutNodeAccess<'_>>;
  394. fn layout_child_count(&self) -> usize;
  395. }
  396. /// Helper struct to store a leaf LayoutNode and automatically provide a LayoutNodeContainer impl
  397. pub struct LeafLayoutNode(LayoutNode);
  398. impl LeafLayoutNode {
  399. pub fn new(ln: LayoutNode) -> Self {
  400. Self(ln)
  401. }
  402. }
  403. impl From<LayoutNode> for LeafLayoutNode {
  404. fn from(value: LayoutNode) -> Self {
  405. Self::new(value)
  406. }
  407. }
  408. impl std::ops::Deref for LeafLayoutNode {
  409. type Target = LayoutNode;
  410. fn deref(&self) -> &Self::Target {
  411. &self.0
  412. }
  413. }
  414. impl std::ops::DerefMut for LeafLayoutNode {
  415. fn deref_mut(&mut self) -> &mut Self::Target {
  416. &mut self.0
  417. }
  418. }
  419. impl LayoutNodeContainer for LeafLayoutNode {
  420. fn layout_node(&self) -> &LayoutNode {
  421. &self.0
  422. }
  423. fn layout_child(&self, _ndx: usize) -> Option<LayoutNodeAccess<'_>> {
  424. None
  425. }
  426. fn layout_child_count(&self) -> usize {
  427. 0
  428. }
  429. }
  430. /// Helper LayoutNodeContainer implementation for LayoutNodes with one child
  431. pub struct LinearAccess<'l>(&'l LayoutNode, LayoutNodeAccess<'l>);
  432. impl<'l> LinearAccess<'l> {
  433. pub fn new(parent: &'l LayoutNode, child: LayoutNodeAccess<'l>) -> Self {
  434. Self(parent, child)
  435. }
  436. }
  437. impl<'l> LayoutNodeContainer for LinearAccess<'l> {
  438. fn layout_node(&self) -> &LayoutNode {
  439. self.0
  440. }
  441. fn layout_child(&self, ndx: usize) -> Option<LayoutNodeAccess> {
  442. if ndx == 0 {
  443. Some(self.1)
  444. } else {
  445. None
  446. }
  447. }
  448. fn layout_child_count(&self) -> usize {
  449. 1
  450. }
  451. }