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