canary-rs/crates/sao-ui-rs/src/widgets/flex.rs

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
}