120 lines
4.1 KiB
Rust
120 lines
4.1 KiB
Rust
/// Size hint for table column/strip cell
|
|
#[derive(Clone, Debug, Copy)]
|
|
pub enum Size {
|
|
/// Absolute size in points
|
|
Absolute(f32),
|
|
/// Relative size relative to all available space. Values must be in range `0.0..=1.0`
|
|
Relative(f32),
|
|
/// [`Size::Relative`] with a minimum size in points
|
|
RelativeMinimum {
|
|
/// Relative size relative to all available space. Values must be in range `0.0..=1.0`
|
|
relative: f32,
|
|
/// Absolute minimum size in points
|
|
minimum: f32,
|
|
},
|
|
/// Multiple remainders each get the same space
|
|
Remainder,
|
|
/// [`Size::Remainder`] with a minimum size in points
|
|
RemainderMinimum(f32),
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct Sizing {
|
|
sizes: Vec<Size>,
|
|
}
|
|
|
|
impl Sizing {
|
|
pub fn new() -> Self {
|
|
Self { sizes: vec![] }
|
|
}
|
|
|
|
pub fn add(&mut self, size: Size) {
|
|
self.sizes.push(size);
|
|
}
|
|
|
|
pub fn into_lengths(self, length: f32, spacing: f32) -> Vec<f32> {
|
|
let mut remainders = 0;
|
|
let sum_non_remainder = self
|
|
.sizes
|
|
.iter()
|
|
.map(|size| match size {
|
|
Size::Absolute(absolute) => *absolute,
|
|
Size::Relative(relative) => {
|
|
assert!(*relative > 0.0, "Below 0.0 is not allowed.");
|
|
assert!(*relative <= 1.0, "Above 1.0 is not allowed.");
|
|
length * relative
|
|
}
|
|
Size::RelativeMinimum { relative, minimum } => {
|
|
assert!(*relative > 0.0, "Below 0.0 is not allowed.");
|
|
assert!(*relative <= 1.0, "Above 1.0 is not allowed.");
|
|
minimum.max(length * relative)
|
|
}
|
|
Size::Remainder | Size::RemainderMinimum(..) => {
|
|
remainders += 1;
|
|
0.0
|
|
}
|
|
})
|
|
.sum::<f32>()
|
|
+ spacing * (self.sizes.len() - 1) as f32;
|
|
|
|
let avg_remainder_length = if remainders == 0 {
|
|
0.0
|
|
} else {
|
|
let mut remainder_length = length - sum_non_remainder;
|
|
let avg_remainder_length = 0.0f32.max(remainder_length / remainders as f32).floor();
|
|
self.sizes.iter().for_each(|size| {
|
|
if let Size::RemainderMinimum(minimum) = size {
|
|
if *minimum > avg_remainder_length {
|
|
remainder_length -= minimum;
|
|
remainders -= 1;
|
|
}
|
|
}
|
|
});
|
|
if remainders > 0 {
|
|
0.0f32.max(remainder_length / remainders as f32)
|
|
} else {
|
|
0.0
|
|
}
|
|
};
|
|
|
|
self.sizes
|
|
.into_iter()
|
|
.map(|size| match size {
|
|
Size::Absolute(absolute) => absolute,
|
|
Size::Relative(relative) => length * relative,
|
|
Size::RelativeMinimum { relative, minimum } => minimum.max(length * relative),
|
|
Size::Remainder => avg_remainder_length,
|
|
Size::RemainderMinimum(minimum) => minimum.max(avg_remainder_length),
|
|
})
|
|
.collect()
|
|
}
|
|
}
|
|
|
|
impl From<Vec<Size>> for Sizing {
|
|
fn from(sizes: Vec<Size>) -> Self {
|
|
Self { sizes }
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_sizing() {
|
|
let sizing: Sizing = vec![Size::RemainderMinimum(20.0), Size::Remainder].into();
|
|
assert_eq!(sizing.clone().into_lengths(50.0, 0.0), vec![25.0, 25.0]);
|
|
assert_eq!(sizing.clone().into_lengths(30.0, 0.0), vec![20.0, 10.0]);
|
|
assert_eq!(sizing.clone().into_lengths(20.0, 0.0), vec![20.0, 0.0]);
|
|
assert_eq!(sizing.clone().into_lengths(10.0, 0.0), vec![20.0, 0.0]);
|
|
assert_eq!(sizing.into_lengths(20.0, 10.0), vec![20.0, 0.0]);
|
|
|
|
let sizing: Sizing = vec![
|
|
Size::RelativeMinimum {
|
|
relative: 0.5,
|
|
minimum: 10.0,
|
|
},
|
|
Size::Absolute(10.0),
|
|
]
|
|
.into();
|
|
assert_eq!(sizing.clone().into_lengths(50.0, 0.0), vec![25.0, 10.0]);
|
|
assert_eq!(sizing.clone().into_lengths(30.0, 0.0), vec![15.0, 10.0]);
|
|
assert_eq!(sizing.clone().into_lengths(20.0, 0.0), vec![10.0, 10.0]);
|
|
assert_eq!(sizing.into_lengths(10.0, 0.0), vec![10.0, 10.0]);
|
|
}
|