slint/sixtyfps_runtime/corelib/layout.rs
2020-05-11 15:33:38 +02:00

89 lines
2.7 KiB
Rust

type Coord = f32;
#[derive(Debug, Default)]
pub struct LayoutData {
// inputs
min: Coord,
max: Coord,
pref: Coord,
stretch: f32,
// outputs
pos: Coord,
size: Coord,
}
/// Layout the items within a specified size
///
/// This is quite a simple implementation for now
pub fn layout_items(data: &mut [LayoutData], start_pos: Coord, size: Coord) {
let (min, _max, perf, mut s) = data.iter().fold((0., 0., 0., 0.), |(min, max, pref, s), it| {
(min + it.min, max + it.max, pref + it.pref, s + it.stretch)
});
if size >= perf {
// bigger than the prefered size
// distribute each item its prefered size
let mut pos = start_pos;
for it in data.iter_mut() {
it.size = it.pref;
it.pos = pos;
pos += it.size;
}
// Allocate the space according to the stretch. Until all space is distributed, or all item
// have reached their maximum size
let mut extra_space = size - perf;
while s > 0. && extra_space > 0. {
let extra_per_stretch = extra_space / s;
s = 0.;
let mut pos = start_pos;
for it in data.iter_mut() {
let give = (extra_per_stretch * it.stretch).min(it.max - it.size);
it.size += give;
extra_space -= give;
if give > 0. {
s += it.stretch;
}
it.pos = pos;
pos += it.size;
}
}
} else
/*if size < min*/
{
// We have less than the minimum size
// distribute the difference proportional to the size (TODO: and stretch)
let ratio = size / min;
let mut pos = start_pos;
for it in data {
it.size = it.min * ratio;
it.pos = pos;
pos += it.size;
}
}
}
#[test]
fn test_layout_items() {
let my_items = &mut [
LayoutData { min: 100., max: 200., pref: 100., stretch: 1., ..Default::default() },
LayoutData { min: 50., max: 300., pref: 100., stretch: 1., ..Default::default() },
LayoutData { min: 50., max: 150., pref: 100., stretch: 1., ..Default::default() },
];
layout_items(my_items, 100., 650.);
assert_eq!(my_items[0].size, 200.);
assert_eq!(my_items[1].size, 300.);
assert_eq!(my_items[2].size, 150.);
layout_items(my_items, 100., 200.);
assert_eq!(my_items[0].size, 100.);
assert_eq!(my_items[1].size, 50.);
assert_eq!(my_items[2].size, 50.);
layout_items(my_items, 100., 300.);
assert_eq!(my_items[0].size, 100.);
assert_eq!(my_items[1].size, 100.);
assert_eq!(my_items[2].size, 100.);
}