// Copyright (c) 2022 Marceline Cramer // SPDX-License-Identifier: AGPL-3.0-or-later #[derive(Clone, Debug)] pub enum Unit { Fixed(f32), Percentage(f32), Stretch(f32), } impl Unit { pub fn as_fixed(&self, parent_size: f32) -> Option { match self { Unit::Fixed(u) => Some(*u), Unit::Percentage(u) => Some(u * parent_size), Unit::Stretch(_) => None, } } pub fn as_stretch(&self) -> f32 { if let Unit::Stretch(stretch) = self { *stretch } else { 0.0 } } pub fn calc_stretched(&self, parent_size: f32, stretch_factor: f32) -> f32 { match self { Unit::Fixed(u) => *u, Unit::Percentage(u) => u * parent_size, Unit::Stretch(u) => u * stretch_factor, } } } #[derive(Clone, Debug)] pub struct Constraint { pub desired: Unit, pub min: Option, pub max: Option, } impl Constraint { pub fn calc_minimum_size(&self, parent_size: f32) -> f32 { let desired = self.desired.as_fixed(parent_size).unwrap_or(0.0); if let Some(min) = self.min.as_ref() { let min = min.as_fixed(parent_size).unwrap_or(0.0); min.max(desired) } else { desired } } pub fn calc_stretch(&self) -> f32 { self.desired.as_stretch() + self.min.as_ref().map(|u| u.as_stretch()).unwrap_or(0.0) + self.max.as_ref().map(|u| u.as_stretch()).unwrap_or(0.0) } pub fn calc_stretched(&self, parent_size: f32, stretch_factor: f32) -> f32 { self.desired .calc_stretched(parent_size, stretch_factor) .max( self.min .as_ref() .map(|u| u.calc_stretched(parent_size, stretch_factor)) .unwrap_or(0.0), ) } } #[derive(Clone, Debug)] pub struct Metrics { pub margin_before: Constraint, pub content: Constraint, pub margin_after: Constraint, } impl Metrics { pub fn calc_minimum_size(&self, parent_size: f32) -> f32 { self.margin_before.calc_minimum_size(parent_size) + self.content.calc_minimum_size(parent_size) + self.margin_after.calc_minimum_size(parent_size) } pub fn calc_stretch(&self) -> f32 { self.margin_before.calc_stretch() + self.content.calc_stretch() + self.margin_after.calc_stretch() } } pub trait Node { fn get_flex_hori(&self) -> Metrics; fn get_flex_vert(&self) -> Metrics; } #[derive(Clone, Debug)] pub enum AbsoluteConstraint {} #[derive(Clone, Debug)] pub struct AbsoluteMetrics {} #[derive(Clone, Debug)] pub struct Position { pub start: f32, pub end: f32, } pub fn compute_layout(size: f32, nodes: &[Metrics]) -> Vec { let mut minimum_size = 0.0; let mut stretch_total = 0.0; for node in nodes.iter() { minimum_size += node.calc_minimum_size(size); stretch_total += stretch_total; } let remaining = (size - minimum_size).max(0.0); let stretch = remaining / stretch_total; let mut cursor = 0.0; let mut positions = Vec::new(); for node in nodes.iter() { cursor += node.margin_before.calc_stretched(size, stretch); let start = cursor; cursor += node.content.calc_stretched(size, stretch); let end = cursor; cursor += node.margin_after.calc_stretched(size, stretch); positions.push(Position { start, end }); } positions }