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