iced_widget/pane_grid/
axis.rs

1use crate::core::Rectangle;
2
3/// A fixed reference line for the measurement of coordinates.
4#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
5pub enum Axis {
6    /// The horizontal axis: —
7    Horizontal,
8    /// The vertical axis: |
9    Vertical,
10}
11
12impl Axis {
13    /// Splits the provided [`Rectangle`] on the current [`Axis`] with the
14    /// given `ratio` and `spacing`.
15    pub fn split(
16        &self,
17        rectangle: &Rectangle,
18        ratio: f32,
19        spacing: f32,
20        min_size_a: f32,
21        min_size_b: f32,
22    ) -> (Rectangle, Rectangle, f32) {
23        match self {
24            Axis::Horizontal => {
25                let height_top = (rectangle.height * ratio - spacing / 2.0)
26                    .round()
27                    .max(min_size_a)
28                    .min(rectangle.height - min_size_b - spacing);
29
30                let height_bottom =
31                    (rectangle.height - height_top - spacing).max(min_size_b);
32
33                let ratio = (height_top + spacing / 2.0) / rectangle.height;
34
35                (
36                    Rectangle {
37                        height: height_top,
38                        ..*rectangle
39                    },
40                    Rectangle {
41                        y: rectangle.y + height_top + spacing,
42                        height: height_bottom,
43                        ..*rectangle
44                    },
45                    ratio,
46                )
47            }
48            Axis::Vertical => {
49                let width_left = (rectangle.width * ratio - spacing / 2.0)
50                    .round()
51                    .max(min_size_a)
52                    .min(rectangle.width - min_size_b - spacing);
53
54                let width_right =
55                    (rectangle.width - width_left - spacing).max(min_size_b);
56
57                let ratio = (width_left + spacing / 2.0) / rectangle.width;
58
59                (
60                    Rectangle {
61                        width: width_left,
62                        ..*rectangle
63                    },
64                    Rectangle {
65                        x: rectangle.x + width_left + spacing,
66                        width: width_right,
67                        ..*rectangle
68                    },
69                    ratio,
70                )
71            }
72        }
73    }
74
75    /// Calculates the bounds of the split line in a [`Rectangle`] region.
76    pub fn split_line_bounds(
77        &self,
78        rectangle: Rectangle,
79        ratio: f32,
80        spacing: f32,
81    ) -> Rectangle {
82        match self {
83            Axis::Horizontal => Rectangle {
84                x: rectangle.x,
85                y: (rectangle.y + rectangle.height * ratio - spacing / 2.0)
86                    .round(),
87                width: rectangle.width,
88                height: spacing,
89            },
90            Axis::Vertical => Rectangle {
91                x: (rectangle.x + rectangle.width * ratio - spacing / 2.0)
92                    .round(),
93                y: rectangle.y,
94                width: spacing,
95                height: rectangle.height,
96            },
97        }
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    enum Case {
106        Horizontal {
107            overall_height: f32,
108            spacing: f32,
109            top_height: f32,
110            bottom_y: f32,
111            bottom_height: f32,
112        },
113        Vertical {
114            overall_width: f32,
115            spacing: f32,
116            left_width: f32,
117            right_x: f32,
118            right_width: f32,
119        },
120    }
121
122    #[test]
123    fn split() {
124        let cases = vec![
125            // Even height, even spacing
126            Case::Horizontal {
127                overall_height: 10.0,
128                spacing: 2.0,
129                top_height: 4.0,
130                bottom_y: 6.0,
131                bottom_height: 4.0,
132            },
133            // Odd height, even spacing
134            Case::Horizontal {
135                overall_height: 9.0,
136                spacing: 2.0,
137                top_height: 4.0,
138                bottom_y: 6.0,
139                bottom_height: 3.0,
140            },
141            // Even height, odd spacing
142            Case::Horizontal {
143                overall_height: 10.0,
144                spacing: 1.0,
145                top_height: 5.0,
146                bottom_y: 6.0,
147                bottom_height: 4.0,
148            },
149            // Odd height, odd spacing
150            Case::Horizontal {
151                overall_height: 9.0,
152                spacing: 1.0,
153                top_height: 4.0,
154                bottom_y: 5.0,
155                bottom_height: 4.0,
156            },
157            // Even width, even spacing
158            Case::Vertical {
159                overall_width: 10.0,
160                spacing: 2.0,
161                left_width: 4.0,
162                right_x: 6.0,
163                right_width: 4.0,
164            },
165            // Odd width, even spacing
166            Case::Vertical {
167                overall_width: 9.0,
168                spacing: 2.0,
169                left_width: 4.0,
170                right_x: 6.0,
171                right_width: 3.0,
172            },
173            // Even width, odd spacing
174            Case::Vertical {
175                overall_width: 10.0,
176                spacing: 1.0,
177                left_width: 5.0,
178                right_x: 6.0,
179                right_width: 4.0,
180            },
181            // Odd width, odd spacing
182            Case::Vertical {
183                overall_width: 9.0,
184                spacing: 1.0,
185                left_width: 4.0,
186                right_x: 5.0,
187                right_width: 4.0,
188            },
189        ];
190        for case in cases {
191            match case {
192                Case::Horizontal {
193                    overall_height,
194                    spacing,
195                    top_height,
196                    bottom_y,
197                    bottom_height,
198                } => {
199                    let a = Axis::Horizontal;
200                    let r = Rectangle {
201                        x: 0.0,
202                        y: 0.0,
203                        width: 10.0,
204                        height: overall_height,
205                    };
206                    let (top, bottom, _ratio) =
207                        a.split(&r, 0.5, spacing, 0.0, 0.0);
208                    assert_eq!(
209                        top,
210                        Rectangle {
211                            height: top_height,
212                            ..r
213                        }
214                    );
215                    assert_eq!(
216                        bottom,
217                        Rectangle {
218                            y: bottom_y,
219                            height: bottom_height,
220                            ..r
221                        }
222                    );
223                }
224                Case::Vertical {
225                    overall_width,
226                    spacing,
227                    left_width,
228                    right_x,
229                    right_width,
230                } => {
231                    let a = Axis::Vertical;
232                    let r = Rectangle {
233                        x: 0.0,
234                        y: 0.0,
235                        width: overall_width,
236                        height: 10.0,
237                    };
238                    let (left, right, _ratio) =
239                        a.split(&r, 0.5, spacing, 0.0, 0.0);
240                    assert_eq!(
241                        left,
242                        Rectangle {
243                            width: left_width,
244                            ..r
245                        }
246                    );
247                    assert_eq!(
248                        right,
249                        Rectangle {
250                            x: right_x,
251                            width: right_width,
252                            ..r
253                        }
254                    );
255                }
256            }
257        }
258    }
259}