diff --git a/sixtyfps_runtime/corelib/layout.rs b/sixtyfps_runtime/corelib/layout.rs new file mode 100644 index 000000000..f54eb44fa --- /dev/null +++ b/sixtyfps_runtime/corelib/layout.rs @@ -0,0 +1,89 @@ +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.); +} diff --git a/sixtyfps_runtime/corelib/lib.rs b/sixtyfps_runtime/corelib/lib.rs index a31778d88..74e83e2e4 100644 --- a/sixtyfps_runtime/corelib/lib.rs +++ b/sixtyfps_runtime/corelib/lib.rs @@ -3,6 +3,7 @@ use core::ptr::NonNull; use kurbo::BezPath; pub mod graphics; +pub mod layout; pub mod abi { pub mod datastructures;