136 lines
3.5 KiB
Rust
136 lines
3.5 KiB
Rust
// 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<f32> {
|
|
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<Unit>,
|
|
pub max: Option<Unit>,
|
|
}
|
|
|
|
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<Position> {
|
|
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
|
|
}
|