From 5570ccb7e846e9e803d5882b66fee663377976d1 Mon Sep 17 00:00:00 2001 From: Raunak Bhagat Date: Wed, 20 Sep 2023 20:30:41 -0700 Subject: [PATCH 1/5] Implement 2-dimensional constraint solving --- src/lib.rs | 89 ++++++++++- src/solver/mod.rs | 368 +++++++++++++++++++++++++++++----------------- 2 files changed, 316 insertions(+), 141 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7994f5a..7bddcde 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,12 @@ impl Solver { constraint: Constraint, capacity: usize, ) -> Option { - matches!(constraint.fill_x, Fill::Scale(..)).then(|| { + let both_fills_are_absolute_scales = matches! { constraint.fill, Fill::Absolute { x: FillType::Scale(..), y: FillType::Scale(..) }}; + let both_fills_are_relative_scales = matches! { constraint.fill, Fill::Relative { main: FillType::Scale(..), cross: FillType::Scale(..) }}; + + let both_fills_are_scales = both_fills_are_absolute_scales | both_fills_are_relative_scales; + + both_fills_are_scales.then(|| { let root_key = self .constraint_tree .insert_root_with_capacity(constraint, capacity); @@ -189,7 +194,7 @@ impl Solver { // Solve method: - pub fn solve(&mut self, length_x: f64) { + pub fn solve(&mut self, length_x: f64, length_y: f64) { let is_dirty = self.is_dirty; let is_empty = self.constraint_tree.is_empty(); @@ -198,12 +203,14 @@ impl Solver { (true, false) => { let length_x = length_x.max(0.); + let length_y = length_y.max(0.); solve( &self.constraint_tree, &mut self.frame_tree, &mut self.key_map, length_x, + length_y, ); self.is_dirty = false; @@ -216,31 +223,96 @@ impl Solver { #[derive(Default, Debug, Clone, Copy, PartialEq)] pub struct Constraint { - pub fill_x: Fill, - pub padding: Padding, - pub align_x: Align, + pub fill: Fill, + pub content: Content, } #[derive(Debug, Clone, Copy, PartialEq)] pub enum Fill { + Absolute { x: FillType, y: FillType }, + Relative { main: FillType, cross: FillType }, +} + +impl Fill { + fn to_absolute_fill(self, direction: Direction) -> AbsoluteFill { + match self { + Self::Absolute { x, y } => AbsoluteFill { x, y }, + Self::Relative { main, cross } => match direction { + Direction::Horizontal => AbsoluteFill { x: main, y: cross }, + Direction::Vertical => AbsoluteFill { x: cross, y: main }, + }, + } + } + + fn to_absolute_fill_horizontal(self) -> AbsoluteFill { + match self { + Self::Absolute { x, y } => AbsoluteFill { x, y }, + Self::Relative { main, cross } => AbsoluteFill { x: main, y: cross }, + } + } + + fn to_absolute_fill_vertical(self) -> AbsoluteFill { + match self { + Self::Absolute { x, y } => AbsoluteFill { x, y }, + Self::Relative { main, cross } => AbsoluteFill { x: cross, y: main }, + } + } +} + +impl Default for Fill { + fn default() -> Self { + Self::Relative { + main: FillType::default(), + cross: FillType::default(), + } + } +} + +#[derive(Default, Debug, Clone, Copy, PartialEq)] +struct AbsoluteFill { + x: FillType, + y: FillType, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum FillType { Exact(f64), Scale(usize), Minimize, } -impl Default for Fill { +impl Default for FillType { fn default() -> Self { Self::Scale(1) } } +#[derive(Default, Debug, Clone, Copy, PartialEq)] +pub struct Content { + pub direction: Direction, + pub padding: Padding, + pub align_main: Align, + pub align_cross: Align, +} + #[derive(Default, Debug, Clone, Copy, PartialEq)] pub struct Padding { pub left: f64, pub right: f64, + + pub top: f64, + pub bottom: f64, } -#[derive(Default, Debug, Clone, Copy, PartialEq)] +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +pub enum Direction { + Horizontal, + + #[default] + Vertical, +} + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] pub enum Align { #[default] Start, @@ -252,4 +324,7 @@ pub enum Align { pub struct Frame { pub offset_x: f64, pub length_x: f64, + + pub offset_y: f64, + pub length_y: f64, } diff --git a/src/solver/mod.rs b/src/solver/mod.rs index aa1d2e1..41b7e22 100644 --- a/src/solver/mod.rs +++ b/src/solver/mod.rs @@ -1,52 +1,72 @@ -#[cfg(test)] -mod tests; - use std::collections::BTreeMap; use cherrytree::{Node, Tree}; use indexmap::IndexSet; -use crate::{Align, Constraint, ConstraintKey, Fill, Frame, FrameKey, Padding}; +use crate::{ + Align, Constraint, ConstraintKey, Content, Direction, FillType, Frame, + FrameKey, Padding, +}; pub(super) fn solve( constraint_tree: &Tree, frame_tree: &mut Tree, key_map: &mut BTreeMap, length_x: f64, + length_y: f64, ) { let (root_constraint_key, root_constraint_node) = constraint_tree.root_key_value().unwrap(); - match root_constraint_node.value.fill_x { - Fill::Scale(scale) => { - let length_x = match scale { - 0 => 0., - _ => length_x, - }; - - let root_frame = Frame { - offset_x: 0., - length_x, - }; - - let root_frame_key = frame_tree.insert_root(root_frame); - key_map.insert(root_constraint_key, root_frame_key); - - let root_content_frame = - generate_content_frame(length_x, root_constraint_node.value.padding); - - solve_child_keys( - constraint_tree, - frame_tree, - key_map, - root_constraint_node.child_keys, - root_frame_key, - root_content_frame, - root_constraint_node.value.align_x, - ); + let absolute_fill = root_constraint_node + .value + .fill + .to_absolute_fill(Direction::Vertical); + + let length_x = if let FillType::Scale(scale_x) = absolute_fill.x { + match scale_x { + 0 => 0., + _ => length_x, } + } else { + unreachable!() + }; - Fill::Exact(..) | Fill::Minimize => unreachable!(), - } + let length_y = if let FillType::Scale(scale_y) = absolute_fill.y { + match scale_y { + 0 => 0., + _ => length_y, + } + } else { + unreachable!() + }; + + let root_frame = Frame { + offset_x: 0., + length_x, + + offset_y: 0., + length_y, + }; + + let number_of_child_keys = root_constraint_node.child_keys.len(); + let root_frame_key = frame_tree.insert_root_with_capacity(root_frame, number_of_child_keys); + key_map.insert(root_constraint_key, root_frame_key); + + let root_content_frame = generate_content_frame( + root_constraint_node.value.content.padding, + length_x, + length_y, + ); + + solve_child_keys( + constraint_tree, + frame_tree, + key_map, + root_constraint_node.child_keys, + root_frame_key, + root_content_frame, + root_constraint_node.value.content, + ); } fn solve_child_keys( @@ -56,133 +76,213 @@ fn solve_child_keys( constraint_keys: &IndexSet, parent_frame_key: FrameKey, content_frame: Frame, - align_x: Align, + parent_content: Content, ) { - let mut data = iter(constraint_tree, constraint_keys) - .map(|(constraint_key, constraint_node)| (constraint_key, constraint_node, None)) - .collect::>(); - - let mut remaining_length_x = content_frame.length_x; - let mut total_scale: usize = 0; - - for (_, constraint_node, current_length_x) in data.iter_mut() { - match constraint_node.value.fill_x { - Fill::Exact(exact) => { - let length_x = exact.min(remaining_length_x); - *current_length_x = Some(length_x); - remaining_length_x -= length_x; - } - Fill::Scale(scale) => { - total_scale = total_scale.saturating_add(scale); - } - Fill::Minimize => { - let length_x = find_minimizing_length_x( + match parent_content.direction { + Direction::Horizontal => { + let mut remaining_length_x = content_frame.length_x; + let mut total_scale_x: usize = 0; + + let mut lengths = iter(constraint_tree, constraint_keys) + .map(|(_, constraint_node)| { + let absolute_fill = constraint_node.value.fill.to_absolute_fill_horizontal(); + let mut minimizing_length_y_cache = None; + + let length_x = match absolute_fill.x { + FillType::Exact(exact_x) => { + let exact_x = exact_x.min(remaining_length_x); + remaining_length_x -= exact_x; + Some(exact_x) + } + FillType::Scale(scale_x) => { + total_scale_x = total_scale_x.checked_add(scale_x).unwrap(); + None + } + FillType::Minimize => { + let (minimizing_length_x, minimizing_length_y) = find_minimizing_length(constraint_tree, constraint_node.child_keys, constraint_node.value.content.direction, remaining_length_x, content_frame.length_y); + minimizing_length_y_cache = Some(minimizing_length_y); + remaining_length_x -= minimizing_length_x; + Some(minimizing_length_x) + }, + }; + + let length_y = match absolute_fill.y { + FillType::Exact(exact_y) => exact_y.min(content_frame.length_y), + FillType::Scale(scale_y) => match scale_y { + 0 => 0., + _ => content_frame.length_y, + }, + FillType::Minimize => { + minimizing_length_y_cache.unwrap_or_else(|| { + let (_, minimizing_length_y) = find_minimizing_length(constraint_tree, constraint_node.child_keys, constraint_node.value.content.direction, remaining_length_x, content_frame.length_y); + minimizing_length_y + }) + }, + }; + + let remaining_length_y = content_frame.length_y - length_y; + let offset_y = content_frame.offset_y + + if remaining_length_y == 0. { + 0. + } else { + match parent_content.align_cross { + Align::Start => 0., + Align::Middle => remaining_length_y / 2., + Align::End => remaining_length_y, + } + }; + + (absolute_fill, length_x, length_y, offset_y) + }) + .collect::>(); + + let offset_x = content_frame.offset_x + + match total_scale_x { + 0 => { + if remaining_length_x == 0. { + 0. + } else { + match parent_content.align_main { + Align::Start => 0., + Align::Middle => remaining_length_x / 2., + Align::End => remaining_length_x, + } + } + } + _ => { + for (absolute_fill, length_x, _, _) in &mut lengths { + if let FillType::Scale(scale_x) = absolute_fill.x { + let proportion = (scale_x as f64) / (total_scale_x as f64); + *length_x = Some(proportion * remaining_length_x); + }; + } + + 0. + } + }; + + for ((constraint_key, consraint_node), (_, length_x, length_y, offset_y)) in + iter(constraint_tree, constraint_keys).zip(lengths) + { + let length_x = length_x.unwrap_or_default(); + + let frame = Frame { + offset_x, + length_x, + offset_y, + length_y, + }; + + let number_of_child_keys = consraint_node.child_keys.len(); + let frame_key = frame_tree + .insert_with_capacity(frame, parent_frame_key, number_of_child_keys) + .unwrap(); + key_map.insert(constraint_key, frame_key); + + let content_frame = generate_content_frame( + consraint_node.value.content.padding, + frame.length_x, + frame.length_y, + ); + + solve_child_keys( constraint_tree, - constraint_node.child_keys, - remaining_length_x, + frame_tree, + key_map, + consraint_node.child_keys, + frame_key, + content_frame, + consraint_node.value.content, ); - *current_length_x = Some(length_x); - remaining_length_x -= length_x; } } + Direction::Vertical => todo!(), } +} - let remaining_length_x = remaining_length_x.max(0.); - - let mut offset_x = match total_scale { - 0 => { - if remaining_length_x == 0. { - content_frame.offset_x - } else { - match align_x { - Align::Start => content_frame.offset_x, - Align::Middle => { - let half_remaining_length_x = remaining_length_x / 2.; - content_frame.offset_x + half_remaining_length_x - } - Align::End => content_frame.offset_x + remaining_length_x, - } - } - } - _ => { - for (_, constraint_node, current_length_x) in data.iter_mut() { - if let Fill::Scale(scale) = constraint_node.value.fill_x { - let length_x = ((scale as f64) / (total_scale as f64)) * remaining_length_x; - *current_length_x = Some(length_x); - } - } +fn find_minimizing_length( + constraint_tree: &Tree, + constraint_keys: &IndexSet, + direction: Direction, + max_length_x: f64, + max_length_y: f64, +) -> (f64, f64) { + match direction { + Direction::Horizontal => { + let mut remaining_length_x: f64 = max_length_x; + let mut max_seen_length_y: f64 = 0.; - content_frame.offset_x - } - }; + for (_, constraint_node) in iter(constraint_tree, constraint_keys) { + let Padding { left, right, top, bottom } = constraint_node.value.content.padding; - for (constraint_key, constraint_node, length_x) in data { - let length_x = length_x.unwrap_or_default(); + let absolute_fill = constraint_node.value.fill.to_absolute_fill_horizontal(); - let frame = Frame { offset_x, length_x }; + let mut sub_minimizing_length_y_cache = None; - let frame_key = frame_tree.insert(frame, parent_frame_key).unwrap(); - key_map.insert(constraint_key, frame_key); + let length_x = match absolute_fill.x { + FillType::Exact(exact_x) => exact_x + left + right, - offset_x += length_x; + FillType::Scale(..) => left + right, - let content_frame = generate_content_frame(length_x, constraint_node.value.padding); + FillType::Minimize => { + let (sub_minimizing_length_x, sub_minimizing_length_y) = find_minimizing_length(constraint_tree, constraint_keys, constraint_node.value.content.direction, remaining_length_x, max_length_y); - solve_child_keys( - constraint_tree, - frame_tree, - key_map, - constraint_node.child_keys, - frame_key, - content_frame, - constraint_node.value.align_x, - ); - } -} + sub_minimizing_length_y_cache = Some(sub_minimizing_length_y); -fn iter<'a>( - constraint_tree: &'a Tree, - constraint_keys: &'a IndexSet, -) -> impl ExactSizeIterator)> { - constraint_keys.iter().map(|&constraint_key| { - let constraint_node = constraint_tree.get(constraint_key).unwrap(); - (constraint_key, constraint_node) - }) -} + sub_minimizing_length_x + left + right + }, + }.min(remaining_length_x); -fn find_minimizing_length_x( - constraint_tree: &Tree, - constraint_keys: &IndexSet, - length_x: f64, -) -> f64 { - let mut total_length_x: f64 = 0.; - - for (_, constraint_node) in iter(constraint_tree, constraint_keys) { - match constraint_node.value.fill_x { - Fill::Exact(exact) => total_length_x = (total_length_x + exact).min(length_x), - Fill::Scale(..) => (), - Fill::Minimize => { - let remaining_length_x = length_x - total_length_x; - let minimize = find_minimizing_length_x( - constraint_tree, - constraint_node.child_keys, - remaining_length_x, - ); - total_length_x += minimize; + let length_y = match absolute_fill.y { + FillType::Exact(exact_y) => exact_y + top + bottom, + FillType::Scale(..) => top + bottom, + FillType::Minimize => sub_minimizing_length_y_cache.unwrap_or_else(|| { + let (_, sub_minimizing_length_y) = find_minimizing_length(constraint_tree, constraint_keys, constraint_node.value.content.direction, remaining_length_x, max_length_y); + sub_minimizing_length_y + }), + }; + + remaining_length_x -= length_x; + max_seen_length_y = max_seen_length_y.max(length_y); } - } - } - total_length_x + let minimizing_length_x = max_length_x - remaining_length_x; + let minimizing_length_y = max_seen_length_y.min(max_length_y); + + ( + minimizing_length_x, + minimizing_length_y, + ) + }, + + Direction::Vertical => todo!(), + } } -fn generate_content_frame(length_x: f64, padding: Padding) -> Frame { +fn generate_content_frame(padding: Padding, length_x: f64, length_y: f64) -> Frame { let content_start_x = padding.left.min(length_x); let content_end_x = (length_x - padding.right).max(0.); let content_length_x = (content_end_x - content_start_x).max(0.); + let content_start_y = padding.top.min(length_y); + let content_end_y = (length_y - padding.bottom).max(0.); + let content_length_y = (content_end_y - content_start_y).max(0.); + Frame { offset_x: content_start_x, length_x: content_length_x, + + offset_y: content_start_y, + length_y: content_length_y, } } + +fn iter<'a>( + constraint_tree: &'a Tree, + constraint_keys: &'a IndexSet, +) -> impl Iterator)> { + constraint_keys.iter().map(|&constraint_key| { + let constraint_node = constraint_tree.get(constraint_key).unwrap(); + (constraint_key, constraint_node) + }) +} From 8c025de7afa1c921e8479a1e99e5ebdbd22c0982 Mon Sep 17 00:00:00 2001 From: Raunak Bhagat Date: Thu, 21 Sep 2023 00:55:42 -0700 Subject: [PATCH 2/5] Finish 2-dimensional implementation --- src/lib.rs | 70 ++++++--- src/solver/mod.rs | 375 +++++++++++++++++++--------------------------- 2 files changed, 201 insertions(+), 244 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7bddcde..39d08a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -234,27 +234,13 @@ pub enum Fill { } impl Fill { - fn to_absolute_fill(self, direction: Direction) -> AbsoluteFill { + fn to_relative_fill(self, direction: Direction) -> RelativeFill { match self { - Self::Absolute { x, y } => AbsoluteFill { x, y }, - Self::Relative { main, cross } => match direction { - Direction::Horizontal => AbsoluteFill { x: main, y: cross }, - Direction::Vertical => AbsoluteFill { x: cross, y: main }, + Self::Absolute { x, y } => match direction { + Direction::Horizontal => RelativeFill { main: x, cross: y }, + Direction::Vertical => RelativeFill { main: y, cross: x }, }, - } - } - - fn to_absolute_fill_horizontal(self) -> AbsoluteFill { - match self { - Self::Absolute { x, y } => AbsoluteFill { x, y }, - Self::Relative { main, cross } => AbsoluteFill { x: main, y: cross }, - } - } - - fn to_absolute_fill_vertical(self) -> AbsoluteFill { - match self { - Self::Absolute { x, y } => AbsoluteFill { x, y }, - Self::Relative { main, cross } => AbsoluteFill { x: cross, y: main }, + Self::Relative { main, cross } => RelativeFill { main, cross }, } } } @@ -269,9 +255,9 @@ impl Default for Fill { } #[derive(Default, Debug, Clone, Copy, PartialEq)] -struct AbsoluteFill { - x: FillType, - y: FillType, +struct RelativeFill { + main: FillType, + cross: FillType, } #[derive(Debug, Clone, Copy, PartialEq)] @@ -304,6 +290,26 @@ pub struct Padding { pub bottom: f64, } +impl Padding { + fn to_relative_padding(self, direction: Direction) -> RelativePadding { + let Self { left, right, top, bottom } = self; + + match direction { + Direction::Horizontal => RelativePadding { main_start: left, main_end: right, cross_start: top, cross_end: bottom }, + Direction::Vertical => RelativePadding { main_start: top, main_end: bottom, cross_start: left, cross_end: right }, + } + } +} + +#[derive(Default, Debug, Clone, Copy, PartialEq)] +struct RelativePadding { + pub main_start: f64, + pub main_end: f64, + + pub cross_start: f64, + pub cross_end: f64, +} + #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] pub enum Direction { Horizontal, @@ -328,3 +334,23 @@ pub struct Frame { pub offset_y: f64, pub length_y: f64, } + +#[derive(Default, Debug, Clone, Copy, PartialEq)] +struct RelativeFrame { + pub offset_main: f64, + pub length_main: f64, + + pub offset_cross: f64, + pub length_cross: f64, +} + +impl RelativeFrame { + fn to_frame(self, direction: Direction) -> Frame { + let Self { offset_main, length_main, offset_cross, length_cross } = self; + + match direction { + Direction::Horizontal => Frame { offset_x: offset_main, length_x: length_main, offset_y: offset_cross, length_y: length_cross }, + Direction::Vertical => Frame { offset_x: offset_cross, length_x: length_cross, offset_y: offset_main, length_y: length_main }, + } + } +} diff --git a/src/solver/mod.rs b/src/solver/mod.rs index 41b7e22..be76942 100644 --- a/src/solver/mod.rs +++ b/src/solver/mod.rs @@ -1,12 +1,9 @@ use std::collections::BTreeMap; -use cherrytree::{Node, Tree}; +use cherrytree::{Tree, Node}; use indexmap::IndexSet; -use crate::{ - Align, Constraint, ConstraintKey, Content, Direction, FillType, Frame, - FrameKey, Padding, -}; +use crate::{ConstraintKey, Constraint, FrameKey, Frame, Content, RelativePadding, RelativeFrame, FillType, Align, Direction}; pub(super) fn solve( constraint_tree: &Tree, @@ -17,33 +14,23 @@ pub(super) fn solve( ) { let (root_constraint_key, root_constraint_node) = constraint_tree.root_key_value().unwrap(); - let absolute_fill = root_constraint_node - .value - .fill - .to_absolute_fill(Direction::Vertical); - - let length_x = if let FillType::Scale(scale_x) = absolute_fill.x { - match scale_x { - 0 => 0., - _ => length_x, - } - } else { - unreachable!() + let relative_fill = root_constraint_node.value.fill.to_relative_fill(Direction::Vertical); + + let length_x = match relative_fill.cross { + FillType::Scale(0) => 0., + FillType::Scale(_) => length_x, + _ => unreachable!(), }; - let length_y = if let FillType::Scale(scale_y) = absolute_fill.y { - match scale_y { - 0 => 0., - _ => length_y, - } - } else { - unreachable!() + let length_y = match relative_fill.main { + FillType::Scale(0) => 0., + FillType::Scale(_) => length_y, + _ => unreachable!(), }; let root_frame = Frame { offset_x: 0., length_x, - offset_y: 0., length_y, }; @@ -52,229 +39,173 @@ pub(super) fn solve( let root_frame_key = frame_tree.insert_root_with_capacity(root_frame, number_of_child_keys); key_map.insert(root_constraint_key, root_frame_key); - let root_content_frame = generate_content_frame( - root_constraint_node.value.content.padding, - length_x, - length_y, - ); - - solve_child_keys( - constraint_tree, - frame_tree, - key_map, - root_constraint_node.child_keys, - root_frame_key, - root_content_frame, - root_constraint_node.value.content, - ); + let relative_padding = root_constraint_node.value.content.padding.to_relative_padding(Direction::Vertical); + let root_relative_content_frame = generate_content_frame_relative(relative_padding, length_y, length_x); + + solve_child_keys_relative(constraint_tree, frame_tree, key_map, root_constraint_node.child_keys, root_frame_key, root_relative_content_frame, root_constraint_node.value.content); } -fn solve_child_keys( +fn solve_child_keys_relative( constraint_tree: &Tree, frame_tree: &mut Tree, key_map: &mut BTreeMap, constraint_keys: &IndexSet, parent_frame_key: FrameKey, - content_frame: Frame, + relative_content_frame: RelativeFrame, parent_content: Content, ) { - match parent_content.direction { - Direction::Horizontal => { - let mut remaining_length_x = content_frame.length_x; - let mut total_scale_x: usize = 0; - - let mut lengths = iter(constraint_tree, constraint_keys) - .map(|(_, constraint_node)| { - let absolute_fill = constraint_node.value.fill.to_absolute_fill_horizontal(); - let mut minimizing_length_y_cache = None; - - let length_x = match absolute_fill.x { - FillType::Exact(exact_x) => { - let exact_x = exact_x.min(remaining_length_x); - remaining_length_x -= exact_x; - Some(exact_x) - } - FillType::Scale(scale_x) => { - total_scale_x = total_scale_x.checked_add(scale_x).unwrap(); - None - } - FillType::Minimize => { - let (minimizing_length_x, minimizing_length_y) = find_minimizing_length(constraint_tree, constraint_node.child_keys, constraint_node.value.content.direction, remaining_length_x, content_frame.length_y); - minimizing_length_y_cache = Some(minimizing_length_y); - remaining_length_x -= minimizing_length_x; - Some(minimizing_length_x) - }, - }; - - let length_y = match absolute_fill.y { - FillType::Exact(exact_y) => exact_y.min(content_frame.length_y), - FillType::Scale(scale_y) => match scale_y { - 0 => 0., - _ => content_frame.length_y, - }, - FillType::Minimize => { - minimizing_length_y_cache.unwrap_or_else(|| { - let (_, minimizing_length_y) = find_minimizing_length(constraint_tree, constraint_node.child_keys, constraint_node.value.content.direction, remaining_length_x, content_frame.length_y); - minimizing_length_y - }) - }, - }; - - let remaining_length_y = content_frame.length_y - length_y; - let offset_y = content_frame.offset_y - + if remaining_length_y == 0. { - 0. - } else { - match parent_content.align_cross { - Align::Start => 0., - Align::Middle => remaining_length_y / 2., - Align::End => remaining_length_y, - } - }; - - (absolute_fill, length_x, length_y, offset_y) - }) - .collect::>(); - - let offset_x = content_frame.offset_x - + match total_scale_x { - 0 => { - if remaining_length_x == 0. { - 0. - } else { - match parent_content.align_main { - Align::Start => 0., - Align::Middle => remaining_length_x / 2., - Align::End => remaining_length_x, - } - } - } - _ => { - for (absolute_fill, length_x, _, _) in &mut lengths { - if let FillType::Scale(scale_x) = absolute_fill.x { - let proportion = (scale_x as f64) / (total_scale_x as f64); - *length_x = Some(proportion * remaining_length_x); - }; - } - - 0. - } - }; - - for ((constraint_key, consraint_node), (_, length_x, length_y, offset_y)) in - iter(constraint_tree, constraint_keys).zip(lengths) - { - let length_x = length_x.unwrap_or_default(); - - let frame = Frame { - offset_x, - length_x, - offset_y, - length_y, + let mut remaining_length_main = relative_content_frame.length_main; + let mut total_scale_main: usize = 0; + + let mut relative_lengths = iter(constraint_tree, constraint_keys) + .map(|(_, constraint_node)| { + let relatve_fill = constraint_node.value.fill.to_relative_fill(parent_content.direction); + + let mut cache = None; + + let length_main = match relatve_fill.main { + FillType::Exact(exact_main) => { + let exact_main = exact_main.min(remaining_length_main); + remaining_length_main -= exact_main; + Some(exact_main) + }, + FillType::Scale(scale_main) => { + total_scale_main = total_scale_main.checked_add(scale_main).unwrap(); + None + }, + FillType::Minimize => { + let (minimizing_length_main, minimizing_length_cross) = find_minimizing_length_relative(constraint_tree, constraint_node.child_keys, constraint_node.value.content.direction, remaining_length_main, relative_content_frame.length_cross); + cache = Some(minimizing_length_cross); + Some(minimizing_length_main) + }, + }; + + let length_cross = match relatve_fill.cross { + FillType::Exact(exact_cross) => exact_cross.min(relative_content_frame.length_cross), + FillType::Scale(0) => 0., + FillType::Scale(_) => relative_content_frame.length_cross, + FillType::Minimize => cache.unwrap_or_else(|| { + let (_, minimizing_length_cross) = find_minimizing_length_relative(constraint_tree, constraint_node.child_keys, constraint_node.value.content.direction, remaining_length_main, relative_content_frame.length_cross); + minimizing_length_cross + }), + }; + + let remaining_length_cross = relative_content_frame.length_cross - length_cross; + let offset_cross = relative_content_frame.offset_cross + match parent_content.align_cross { + Align::Start => 0., + Align::Middle => remaining_length_cross / 2., + Align::End => remaining_length_cross, + }; + + (relatve_fill, length_main, length_cross, offset_cross) + }) + .collect::>(); + + let mut offset_main = match total_scale_main { + 0 => relative_content_frame.offset_main + match parent_content.align_main { + Align::Start => 0., + Align::Middle => remaining_length_main / 2., + Align::End => remaining_length_main, + }, + _ => { + for (relative_fill, length_main, _, _) in &mut relative_lengths { + if let FillType::Scale(scale_main) = relative_fill.main { + let proportion = (scale_main as f64) / (total_scale_main as f64); + *length_main = Some(proportion * remaining_length_main); }; - - let number_of_child_keys = consraint_node.child_keys.len(); - let frame_key = frame_tree - .insert_with_capacity(frame, parent_frame_key, number_of_child_keys) - .unwrap(); - key_map.insert(constraint_key, frame_key); - - let content_frame = generate_content_frame( - consraint_node.value.content.padding, - frame.length_x, - frame.length_y, - ); - - solve_child_keys( - constraint_tree, - frame_tree, - key_map, - consraint_node.child_keys, - frame_key, - content_frame, - consraint_node.value.content, - ); } - } - Direction::Vertical => todo!(), - } -} - -fn find_minimizing_length( - constraint_tree: &Tree, - constraint_keys: &IndexSet, - direction: Direction, - max_length_x: f64, - max_length_y: f64, -) -> (f64, f64) { - match direction { - Direction::Horizontal => { - let mut remaining_length_x: f64 = max_length_x; - let mut max_seen_length_y: f64 = 0.; - for (_, constraint_node) in iter(constraint_tree, constraint_keys) { - let Padding { left, right, top, bottom } = constraint_node.value.content.padding; - - let absolute_fill = constraint_node.value.fill.to_absolute_fill_horizontal(); - - let mut sub_minimizing_length_y_cache = None; + 0. + }, + }; - let length_x = match absolute_fill.x { - FillType::Exact(exact_x) => exact_x + left + right, + for ((constraint_key, constraint_node), (_, length_main, length_cross, offset_cross)) in iter(constraint_tree, constraint_keys).zip(relative_lengths) { + let length_main = length_main.unwrap_or_default(); - FillType::Scale(..) => left + right, + let relative_frame = RelativeFrame { + offset_main, + length_main, + offset_cross, + length_cross, + }; - FillType::Minimize => { - let (sub_minimizing_length_x, sub_minimizing_length_y) = find_minimizing_length(constraint_tree, constraint_keys, constraint_node.value.content.direction, remaining_length_x, max_length_y); + offset_main -= length_main; - sub_minimizing_length_y_cache = Some(sub_minimizing_length_y); + let number_of_child_keys = constraint_node.child_keys.len(); + let frame = relative_frame.to_frame(parent_content.direction); + let frame_key = frame_tree.insert_with_capacity(frame, parent_frame_key, number_of_child_keys).unwrap(); + key_map.insert(constraint_key, frame_key); - sub_minimizing_length_x + left + right - }, - }.min(remaining_length_x); + let relative_padding = constraint_node.value.content.padding.to_relative_padding(parent_content.direction); + let relative_content_frame = generate_content_frame_relative(relative_padding, length_main, length_cross); - let length_y = match absolute_fill.y { - FillType::Exact(exact_y) => exact_y + top + bottom, - FillType::Scale(..) => top + bottom, - FillType::Minimize => sub_minimizing_length_y_cache.unwrap_or_else(|| { - let (_, sub_minimizing_length_y) = find_minimizing_length(constraint_tree, constraint_keys, constraint_node.value.content.direction, remaining_length_x, max_length_y); - sub_minimizing_length_y - }), - }; + solve_child_keys_relative(constraint_tree, frame_tree, key_map, constraint_node.child_keys, frame_key, relative_content_frame, constraint_node.value.content); + } +} - remaining_length_x -= length_x; - max_seen_length_y = max_seen_length_y.max(length_y); - } +fn generate_content_frame_relative(relative_padding: RelativePadding, length_main: f64, length_cross: f64) -> RelativeFrame { + let content_start_main = relative_padding.main_start.min(length_main); + let content_end_main = (length_main - relative_padding.main_end).max(0.); + let content_length_main = (content_end_main - content_start_main).max(0.); - let minimizing_length_x = max_length_x - remaining_length_x; - let minimizing_length_y = max_seen_length_y.min(max_length_y); + let content_start_cross = relative_padding.cross_start.min(length_cross); + let content_end_cross = (length_cross - relative_padding.cross_end).max(0.); + let content_length_cross = (content_end_cross - content_start_cross).max(0.); - ( - minimizing_length_x, - minimizing_length_y, - ) - }, - - Direction::Vertical => todo!(), + RelativeFrame { + offset_main: content_start_main, + length_main: content_length_main, + offset_cross: content_start_cross, + length_cross: content_length_cross, } } -fn generate_content_frame(padding: Padding, length_x: f64, length_y: f64) -> Frame { - let content_start_x = padding.left.min(length_x); - let content_end_x = (length_x - padding.right).max(0.); - let content_length_x = (content_end_x - content_start_x).max(0.); - - let content_start_y = padding.top.min(length_y); - let content_end_y = (length_y - padding.bottom).max(0.); - let content_length_y = (content_end_y - content_start_y).max(0.); +fn find_minimizing_length_relative( + constraint_tree: &Tree, + constraint_keys: &IndexSet, + direction: Direction, + max_length_main: f64, + max_length_cross: f64, +) -> (f64, f64) { + let mut remaining_length_main: f64 = max_length_main; + let mut max_seen_length_cross: f64 = 0.; + + let mut cache = None; + + for (_, constraint_node) in iter(constraint_tree, constraint_keys) { + let relative_fill = constraint_node.value.fill.to_relative_fill(direction); + let relative_padding = constraint_node.value.content.padding.to_relative_padding(direction); + + let length_main = match relative_fill.main { + FillType::Exact(exact_main) => exact_main + relative_padding.main_start + relative_padding.main_end, + FillType::Scale(..) => relative_padding.main_start + relative_padding.main_end, + FillType::Minimize => { + let (sub_minimizing_length_main, sub_minimizing_length_cross) = find_minimizing_length_relative(constraint_tree, constraint_node.child_keys, constraint_node.value.content.direction, remaining_length_main, max_length_cross); + cache = Some(sub_minimizing_length_cross); + sub_minimizing_length_main + }, + }.min(remaining_length_main); + + let length_cross = match relative_fill.cross { + FillType::Exact(exact_cross) => exact_cross + relative_padding.cross_start + relative_padding.cross_end, + FillType::Scale(..) => relative_padding.cross_start + relative_padding.cross_end, + FillType::Minimize => cache.unwrap_or_else(|| { + let (_, sub_minimizing_length_cross) = find_minimizing_length_relative(constraint_tree, constraint_node.child_keys, constraint_node.value.content.direction, remaining_length_main, max_length_cross); + sub_minimizing_length_cross + }), + }; + + remaining_length_main -= length_main; + max_seen_length_cross = max_seen_length_cross.max(length_cross); + } - Frame { - offset_x: content_start_x, - length_x: content_length_x, + let minimizing_length_main = max_length_main - remaining_length_main; + let minimizing_length_cross = max_seen_length_cross.min(max_length_cross); - offset_y: content_start_y, - length_y: content_length_y, - } + ( + minimizing_length_main, + minimizing_length_cross, + ) } fn iter<'a>( From 8483707f0c5eeef750591890c2cb613d1e80d435 Mon Sep 17 00:00:00 2001 From: Raunak Bhagat Date: Thu, 21 Sep 2023 18:56:38 -0700 Subject: [PATCH 3/5] Add a few basic tests --- tests/test_solver.rs | 125 ++++--------------------------------------- 1 file changed, 10 insertions(+), 115 deletions(-) diff --git a/tests/test_solver.rs b/tests/test_solver.rs index ed2a979..43c60d9 100644 --- a/tests/test_solver.rs +++ b/tests/test_solver.rs @@ -2,140 +2,35 @@ mod common; use common::{make_frame_tree, make_solver}; -use stretchbox::{Constraint, Fill, Frame}; +use stretchbox::{Constraint, Frame, Fill, FillType}; #[test] fn test_solver_with_empty_tree() { let mut solver = make_solver(None).unwrap(); - solver.solve(10.); + solver.solve(10., 10.); let actual_frame_tree = make_frame_tree(&solver); let expected_frame_tree = None; - assert_eq!(actual_frame_tree, expected_frame_tree); } #[test] -fn test_solver_with_zero_length() { - let mut solver = make_solver(Some(&node! { Constraint::default() })).unwrap(); - - solver.solve(0.); - - let actual_frame_tree = make_frame_tree(&solver); - let expected_frame_tree = Some(node! { Frame::default() }); +fn test_solver_with_invalid_root_constraint() { + let solver = make_solver(Some( + &node! { Constraint { fill: Fill::Absolute { x: FillType::Exact(10.), y: FillType::Scale(1) }, ..Default::default() } }, + )); - assert_eq!(actual_frame_tree, expected_frame_tree); + assert!(solver.is_none()); } #[test] -fn test_solver_with_nonzero_length() { +fn test_solver_with_single_element_tree() { let mut solver = make_solver(Some(&node! { Constraint::default() })).unwrap(); - solver.solve(100.); + solver.solve(10., 10.); let actual_frame_tree = make_frame_tree(&solver); - let expected_frame_tree = Some(node! { Frame { length_x: 100., ..Default::default() } }); - + let expected_frame_tree = Some(node! { Frame { offset_x: 0., length_x: 10., offset_y: 0., length_y: 10. }}); assert_eq!(actual_frame_tree, expected_frame_tree); } - -#[test] -fn test_solver_with_invalid_root_constraint() { - let solver = make_solver(Some( - &node! { Constraint { fill_x: Fill::Minimize, ..Default::default() } }, - )); - - assert!(solver.is_none()); -} - -// #[test] -// fn test_solver() { -// let mut solver = Solver::default(); - -// assert!(!solver.is_dirty()); - -// let root_constraint_key = solver.insert_root(Constraint { -// fill_x: Fill::Scale(1), -// padding: Padding { -// left: 1., -// right: 1., -// }, -// }); -// let child_constraint_key_1 = solver -// .insert( -// Constraint { -// fill_x: Fill::Scale(1), -// padding: Padding { -// left: 100., -// right: 100., -// }, -// }, -// root_constraint_key, -// ) -// .unwrap(); -// let child_constraint_key_2 = solver -// .insert( -// Constraint { -// fill_x: Fill::Exact(10.), -// padding: Padding { -// left: 100., -// right: 100., -// }, -// }, -// root_constraint_key, -// ) -// .unwrap(); -// let child_constraint_key_3 = solver -// .insert( -// Constraint { -// fill_x: Fill::Minimize, -// padding: Padding { -// left: 100., -// right: 100., -// }, -// }, -// root_constraint_key, -// ) -// .unwrap(); - -// assert!(solver.is_dirty()); - -// let did_solve = solver.solve(12.); -// assert!(did_solve); -// assert!(!solver.is_dirty()); - -// let root_frame = solver.get_frame(root_constraint_key).unwrap(); -// let child_frame_1 = solver.get_frame(child_constraint_key_1).unwrap(); -// let child_frame_2 = solver.get_frame(child_constraint_key_2).unwrap(); -// let child_frame_3 = solver.get_frame(child_constraint_key_3).unwrap(); - -// assert_eq!( -// root_frame, -// Frame { -// offset_x: 0., -// length_x: 12. -// } -// ); -// assert_eq!( -// child_frame_1, -// Frame { -// offset_x: 1., -// length_x: 0. -// } -// ); -// assert_eq!( -// child_frame_2, -// Frame { -// offset_x: 1., -// length_x: 10. -// } -// ); -// assert_eq!( -// child_frame_3, -// Frame { -// offset_x: 11., -// length_x: 0. -// } -// ); -// } From 565bdb37bf8a1ffea5f3611b08da5d028b4af7e9 Mon Sep 17 00:00:00 2001 From: Raunak Bhagat Date: Thu, 21 Sep 2023 19:18:02 -0700 Subject: [PATCH 4/5] Run formatter --- src/lib.rs | 42 +++++++++-- src/solver/mod.rs | 167 ++++++++++++++++++++++++++++++++----------- tests/test_solver.rs | 5 +- 3 files changed, 163 insertions(+), 51 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 39d08a8..4eec720 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -292,11 +292,26 @@ pub struct Padding { impl Padding { fn to_relative_padding(self, direction: Direction) -> RelativePadding { - let Self { left, right, top, bottom } = self; + let Self { + left, + right, + top, + bottom, + } = self; match direction { - Direction::Horizontal => RelativePadding { main_start: left, main_end: right, cross_start: top, cross_end: bottom }, - Direction::Vertical => RelativePadding { main_start: top, main_end: bottom, cross_start: left, cross_end: right }, + Direction::Horizontal => RelativePadding { + main_start: left, + main_end: right, + cross_start: top, + cross_end: bottom, + }, + Direction::Vertical => RelativePadding { + main_start: top, + main_end: bottom, + cross_start: left, + cross_end: right, + }, } } } @@ -346,11 +361,26 @@ struct RelativeFrame { impl RelativeFrame { fn to_frame(self, direction: Direction) -> Frame { - let Self { offset_main, length_main, offset_cross, length_cross } = self; + let Self { + offset_main, + length_main, + offset_cross, + length_cross, + } = self; match direction { - Direction::Horizontal => Frame { offset_x: offset_main, length_x: length_main, offset_y: offset_cross, length_y: length_cross }, - Direction::Vertical => Frame { offset_x: offset_cross, length_x: length_cross, offset_y: offset_main, length_y: length_main }, + Direction::Horizontal => Frame { + offset_x: offset_main, + length_x: length_main, + offset_y: offset_cross, + length_y: length_cross, + }, + Direction::Vertical => Frame { + offset_x: offset_cross, + length_x: length_cross, + offset_y: offset_main, + length_y: length_main, + }, } } } diff --git a/src/solver/mod.rs b/src/solver/mod.rs index be76942..42ce8ef 100644 --- a/src/solver/mod.rs +++ b/src/solver/mod.rs @@ -1,9 +1,12 @@ use std::collections::BTreeMap; -use cherrytree::{Tree, Node}; +use cherrytree::{Node, Tree}; use indexmap::IndexSet; -use crate::{ConstraintKey, Constraint, FrameKey, Frame, Content, RelativePadding, RelativeFrame, FillType, Align, Direction}; +use crate::{ + Align, Constraint, ConstraintKey, Content, Direction, FillType, Frame, FrameKey, RelativeFrame, + RelativePadding, +}; pub(super) fn solve( constraint_tree: &Tree, @@ -14,7 +17,10 @@ pub(super) fn solve( ) { let (root_constraint_key, root_constraint_node) = constraint_tree.root_key_value().unwrap(); - let relative_fill = root_constraint_node.value.fill.to_relative_fill(Direction::Vertical); + let relative_fill = root_constraint_node + .value + .fill + .to_relative_fill(Direction::Vertical); let length_x = match relative_fill.cross { FillType::Scale(0) => 0., @@ -39,10 +45,23 @@ pub(super) fn solve( let root_frame_key = frame_tree.insert_root_with_capacity(root_frame, number_of_child_keys); key_map.insert(root_constraint_key, root_frame_key); - let relative_padding = root_constraint_node.value.content.padding.to_relative_padding(Direction::Vertical); - let root_relative_content_frame = generate_content_frame_relative(relative_padding, length_y, length_x); - - solve_child_keys_relative(constraint_tree, frame_tree, key_map, root_constraint_node.child_keys, root_frame_key, root_relative_content_frame, root_constraint_node.value.content); + let relative_padding = root_constraint_node + .value + .content + .padding + .to_relative_padding(Direction::Vertical); + let root_relative_content_frame = + generate_content_frame_relative(relative_padding, length_y, length_x); + + solve_child_keys_relative( + constraint_tree, + frame_tree, + key_map, + root_constraint_node.child_keys, + root_frame_key, + root_relative_content_frame, + root_constraint_node.value.content, + ); } fn solve_child_keys_relative( @@ -59,7 +78,10 @@ fn solve_child_keys_relative( let mut relative_lengths = iter(constraint_tree, constraint_keys) .map(|(_, constraint_node)| { - let relatve_fill = constraint_node.value.fill.to_relative_fill(parent_content.direction); + let relatve_fill = constraint_node + .value + .fill + .to_relative_fill(parent_content.direction); let mut cache = None; @@ -68,45 +90,64 @@ fn solve_child_keys_relative( let exact_main = exact_main.min(remaining_length_main); remaining_length_main -= exact_main; Some(exact_main) - }, + } FillType::Scale(scale_main) => { total_scale_main = total_scale_main.checked_add(scale_main).unwrap(); None - }, + } FillType::Minimize => { - let (minimizing_length_main, minimizing_length_cross) = find_minimizing_length_relative(constraint_tree, constraint_node.child_keys, constraint_node.value.content.direction, remaining_length_main, relative_content_frame.length_cross); + let (minimizing_length_main, minimizing_length_cross) = + find_minimizing_length_relative( + constraint_tree, + constraint_node.child_keys, + constraint_node.value.content.direction, + remaining_length_main, + relative_content_frame.length_cross, + ); cache = Some(minimizing_length_cross); Some(minimizing_length_main) - }, + } }; let length_cross = match relatve_fill.cross { - FillType::Exact(exact_cross) => exact_cross.min(relative_content_frame.length_cross), + FillType::Exact(exact_cross) => { + exact_cross.min(relative_content_frame.length_cross) + } FillType::Scale(0) => 0., FillType::Scale(_) => relative_content_frame.length_cross, FillType::Minimize => cache.unwrap_or_else(|| { - let (_, minimizing_length_cross) = find_minimizing_length_relative(constraint_tree, constraint_node.child_keys, constraint_node.value.content.direction, remaining_length_main, relative_content_frame.length_cross); + let (_, minimizing_length_cross) = find_minimizing_length_relative( + constraint_tree, + constraint_node.child_keys, + constraint_node.value.content.direction, + remaining_length_main, + relative_content_frame.length_cross, + ); minimizing_length_cross }), }; let remaining_length_cross = relative_content_frame.length_cross - length_cross; - let offset_cross = relative_content_frame.offset_cross + match parent_content.align_cross { - Align::Start => 0., - Align::Middle => remaining_length_cross / 2., - Align::End => remaining_length_cross, - }; + let offset_cross = relative_content_frame.offset_cross + + match parent_content.align_cross { + Align::Start => 0., + Align::Middle => remaining_length_cross / 2., + Align::End => remaining_length_cross, + }; (relatve_fill, length_main, length_cross, offset_cross) }) .collect::>(); let mut offset_main = match total_scale_main { - 0 => relative_content_frame.offset_main + match parent_content.align_main { - Align::Start => 0., - Align::Middle => remaining_length_main / 2., - Align::End => remaining_length_main, - }, + 0 => { + relative_content_frame.offset_main + + match parent_content.align_main { + Align::Start => 0., + Align::Middle => remaining_length_main / 2., + Align::End => remaining_length_main, + } + } _ => { for (relative_fill, length_main, _, _) in &mut relative_lengths { if let FillType::Scale(scale_main) = relative_fill.main { @@ -116,10 +157,12 @@ fn solve_child_keys_relative( } 0. - }, + } }; - for ((constraint_key, constraint_node), (_, length_main, length_cross, offset_cross)) in iter(constraint_tree, constraint_keys).zip(relative_lengths) { + for ((constraint_key, constraint_node), (_, length_main, length_cross, offset_cross)) in + iter(constraint_tree, constraint_keys).zip(relative_lengths) + { let length_main = length_main.unwrap_or_default(); let relative_frame = RelativeFrame { @@ -133,17 +176,36 @@ fn solve_child_keys_relative( let number_of_child_keys = constraint_node.child_keys.len(); let frame = relative_frame.to_frame(parent_content.direction); - let frame_key = frame_tree.insert_with_capacity(frame, parent_frame_key, number_of_child_keys).unwrap(); + let frame_key = frame_tree + .insert_with_capacity(frame, parent_frame_key, number_of_child_keys) + .unwrap(); key_map.insert(constraint_key, frame_key); - let relative_padding = constraint_node.value.content.padding.to_relative_padding(parent_content.direction); - let relative_content_frame = generate_content_frame_relative(relative_padding, length_main, length_cross); - - solve_child_keys_relative(constraint_tree, frame_tree, key_map, constraint_node.child_keys, frame_key, relative_content_frame, constraint_node.value.content); + let relative_padding = constraint_node + .value + .content + .padding + .to_relative_padding(parent_content.direction); + let relative_content_frame = + generate_content_frame_relative(relative_padding, length_main, length_cross); + + solve_child_keys_relative( + constraint_tree, + frame_tree, + key_map, + constraint_node.child_keys, + frame_key, + relative_content_frame, + constraint_node.value.content, + ); } } -fn generate_content_frame_relative(relative_padding: RelativePadding, length_main: f64, length_cross: f64) -> RelativeFrame { +fn generate_content_frame_relative( + relative_padding: RelativePadding, + length_main: f64, + length_cross: f64, +) -> RelativeFrame { let content_start_main = relative_padding.main_start.min(length_main); let content_end_main = (length_main - relative_padding.main_end).max(0.); let content_length_main = (content_end_main - content_start_main).max(0.); @@ -174,23 +236,45 @@ fn find_minimizing_length_relative( for (_, constraint_node) in iter(constraint_tree, constraint_keys) { let relative_fill = constraint_node.value.fill.to_relative_fill(direction); - let relative_padding = constraint_node.value.content.padding.to_relative_padding(direction); + let relative_padding = constraint_node + .value + .content + .padding + .to_relative_padding(direction); let length_main = match relative_fill.main { - FillType::Exact(exact_main) => exact_main + relative_padding.main_start + relative_padding.main_end, + FillType::Exact(exact_main) => { + exact_main + relative_padding.main_start + relative_padding.main_end + } FillType::Scale(..) => relative_padding.main_start + relative_padding.main_end, FillType::Minimize => { - let (sub_minimizing_length_main, sub_minimizing_length_cross) = find_minimizing_length_relative(constraint_tree, constraint_node.child_keys, constraint_node.value.content.direction, remaining_length_main, max_length_cross); + let (sub_minimizing_length_main, sub_minimizing_length_cross) = + find_minimizing_length_relative( + constraint_tree, + constraint_node.child_keys, + constraint_node.value.content.direction, + remaining_length_main, + max_length_cross, + ); cache = Some(sub_minimizing_length_cross); sub_minimizing_length_main - }, - }.min(remaining_length_main); + } + } + .min(remaining_length_main); let length_cross = match relative_fill.cross { - FillType::Exact(exact_cross) => exact_cross + relative_padding.cross_start + relative_padding.cross_end, + FillType::Exact(exact_cross) => { + exact_cross + relative_padding.cross_start + relative_padding.cross_end + } FillType::Scale(..) => relative_padding.cross_start + relative_padding.cross_end, FillType::Minimize => cache.unwrap_or_else(|| { - let (_, sub_minimizing_length_cross) = find_minimizing_length_relative(constraint_tree, constraint_node.child_keys, constraint_node.value.content.direction, remaining_length_main, max_length_cross); + let (_, sub_minimizing_length_cross) = find_minimizing_length_relative( + constraint_tree, + constraint_node.child_keys, + constraint_node.value.content.direction, + remaining_length_main, + max_length_cross, + ); sub_minimizing_length_cross }), }; @@ -202,10 +286,7 @@ fn find_minimizing_length_relative( let minimizing_length_main = max_length_main - remaining_length_main; let minimizing_length_cross = max_seen_length_cross.min(max_length_cross); - ( - minimizing_length_main, - minimizing_length_cross, - ) + (minimizing_length_main, minimizing_length_cross) } fn iter<'a>( diff --git a/tests/test_solver.rs b/tests/test_solver.rs index 43c60d9..b58dc94 100644 --- a/tests/test_solver.rs +++ b/tests/test_solver.rs @@ -2,7 +2,7 @@ mod common; use common::{make_frame_tree, make_solver}; -use stretchbox::{Constraint, Frame, Fill, FillType}; +use stretchbox::{Constraint, Fill, FillType, Frame}; #[test] fn test_solver_with_empty_tree() { @@ -31,6 +31,7 @@ fn test_solver_with_single_element_tree() { solver.solve(10., 10.); let actual_frame_tree = make_frame_tree(&solver); - let expected_frame_tree = Some(node! { Frame { offset_x: 0., length_x: 10., offset_y: 0., length_y: 10. }}); + let expected_frame_tree = + Some(node! { Frame { offset_x: 0., length_x: 10., offset_y: 0., length_y: 10. }}); assert_eq!(actual_frame_tree, expected_frame_tree); } From 44e982723d800551b7c2756a2d637b1eab16ebfa Mon Sep 17 00:00:00 2001 From: Raunak Bhagat Date: Thu, 21 Sep 2023 19:23:03 -0700 Subject: [PATCH 5/5] Update dependency to use github (insead of local) --- Cargo.lock | 1 + Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 6711f40..76b5063 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,7 @@ version = 3 [[package]] name = "cherrytree" version = "0.1.0" +source = "git+https://github.com/raunakab/cherrytree#75aabcb9e4a54f8176ee15bd331275c07229e6b5" dependencies = [ "indexmap", "slotmap", diff --git a/Cargo.toml b/Cargo.toml index 24dcd66..e7d1b62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -cherrytree = { path = "../cherrytree" } +cherrytree = { git = "https://github.com/raunakab/cherrytree" } indexmap = "2.0.0" petgraph = "0.6.4" slotmap = "1.0.6"