cranpose_ui_layout/
arrangement.rs1use crate::round_to_px;
4
5pub trait Arrangement {
7 fn arrange(&self, density: f32, total_size: f32, sizes: &[f32], out_positions: &mut [f32]);
11}
12
13#[derive(Clone, Copy, Debug, PartialEq)]
15pub enum LinearArrangement {
16 Start,
18 End,
20 Center,
22 SpaceBetween,
24 SpaceAround,
26 SpaceEvenly,
28 SpacedBy(f32),
30}
31
32impl LinearArrangement {
33 pub fn spaced_by(spacing: f32) -> Self {
35 Self::SpacedBy(spacing)
36 }
37
38 pub fn spacing(&self, density: f32) -> f32 {
41 match *self {
42 Self::SpacedBy(spacing) => round_to_px(spacing.max(0.0), density),
43 _ => 0.0,
44 }
45 }
46
47 fn fill_positions(
51 density: f32,
52 start: f32,
53 gap: f32,
54 sizes: &[f32],
55 out_positions: &mut [f32],
56 ) {
57 debug_assert_eq!(sizes.len(), out_positions.len());
58 let mut cursor = start;
59 for (size, position) in sizes.iter().zip(out_positions.iter_mut()) {
60 *position = round_to_px(cursor, density);
61 cursor += size + gap;
62 }
63 }
64
65 fn spaced_positions(spacing: f32, total_size: f32, sizes: &[f32], out_positions: &mut [f32]) {
69 let mut occupied = 0.0_f32;
70 for (&size, position) in sizes.iter().zip(out_positions.iter_mut()) {
71 *position = occupied.min(total_size - size);
72 let space_after = spacing.min(total_size - *position - size);
73 occupied = *position + size + space_after;
74 }
75 }
76}
77
78impl Arrangement for LinearArrangement {
79 fn arrange(&self, density: f32, total_size: f32, sizes: &[f32], out_positions: &mut [f32]) {
80 debug_assert_eq!(sizes.len(), out_positions.len());
81 if sizes.is_empty() {
82 return;
83 }
84
85 let remaining = total_size - sizes.iter().sum::<f32>();
86 let count = sizes.len() as f32;
87
88 match *self {
89 LinearArrangement::Start => {
90 Self::fill_positions(density, 0.0, 0.0, sizes, out_positions);
91 }
92 LinearArrangement::End => {
93 Self::fill_positions(density, remaining, 0.0, sizes, out_positions);
94 }
95 LinearArrangement::Center => {
96 Self::fill_positions(density, remaining / 2.0, 0.0, sizes, out_positions);
97 }
98 LinearArrangement::SpaceBetween => {
99 let gap = remaining / (count - 1.0).max(1.0);
100 Self::fill_positions(density, 0.0, gap, sizes, out_positions);
101 }
102 LinearArrangement::SpaceAround => {
103 let gap = remaining / count;
104 Self::fill_positions(density, gap / 2.0, gap, sizes, out_positions);
105 }
106 LinearArrangement::SpaceEvenly => {
107 let gap = remaining / (count + 1.0);
108 Self::fill_positions(density, gap, gap, sizes, out_positions);
109 }
110 LinearArrangement::SpacedBy(_) => {
111 Self::spaced_positions(self.spacing(density), total_size, sizes, out_positions);
112 }
113 }
114 }
115}
116
117#[cfg(test)]
118#[path = "tests/arrangement_tests.rs"]
119mod tests;