Skip to main content

topcoat_view/svg/
view_box.rs

1use std::fmt::{self, Display};
2
3use topcoat_core::context::Cx;
4
5use crate::{AttributeValueViewParts, PartsWriter};
6
7/// The [`viewBox`] of an SVG element: `min-x`, `min-y`, `width`, and `height`.
8///
9/// [`viewBox`]: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox
10#[derive(Debug, Clone, Copy, PartialEq)]
11pub struct ViewBox {
12    pub min_x: f32,
13    pub min_y: f32,
14    pub width: f32,
15    pub height: f32,
16}
17
18impl ViewBox {
19    /// Creates a view box from its components.
20    #[must_use]
21    pub const fn new(min_x: f32, min_y: f32, width: f32, height: f32) -> Self {
22        Self {
23            min_x,
24            min_y,
25            width,
26            height,
27        }
28    }
29}
30
31impl Display for ViewBox {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        let mut buffer = zmij::Buffer::new();
34        f.write_str(buffer.format(self.min_x))?;
35        f.write_str(" ")?;
36        f.write_str(buffer.format(self.min_y))?;
37        f.write_str(" ")?;
38        f.write_str(buffer.format(self.width))?;
39        f.write_str(" ")?;
40        f.write_str(buffer.format(self.height))?;
41        Ok(())
42    }
43}
44
45impl AttributeValueViewParts for ViewBox {
46    fn attribute_present(&self) -> bool {
47        true
48    }
49
50    fn into_view_parts(self, _cx: &Cx, parts: &mut PartsWriter<'_>) {
51        parts.push_f32(self.min_x);
52        parts.push_str_unescaped(" ");
53        parts.push_f32(self.min_y);
54        parts.push_str_unescaped(" ");
55        parts.push_f32(self.width);
56        parts.push_str_unescaped(" ");
57        parts.push_f32(self.height);
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use topcoat_core::context::Cx;
64
65    use super::*;
66    use crate::{HtmlContext, View, ViewParts};
67
68    fn render(value: impl AttributeValueViewParts) -> String {
69        let mut parts = ViewParts::new();
70        value.into_view_parts(
71            &Cx::default(),
72            &mut PartsWriter::new(&mut parts, HtmlContext::AttributeValue),
73        );
74        View::new(parts).render(&Cx::default())
75    }
76
77    #[test]
78    fn displays_as_svg_view_box_value() {
79        assert_eq!(
80            ViewBox::new(0.0, 0.0, 24.0, 24.0).to_string(),
81            "0.0 0.0 24.0 24.0"
82        );
83        assert_eq!(
84            ViewBox::new(0.0, -0.5, 16.5, 16.0).to_string(),
85            "0.0 -0.5 16.5 16.0"
86        );
87    }
88
89    #[test]
90    fn renders_view_parts_as_space_separated_value() {
91        assert_eq!(
92            render(ViewBox::new(0.0, 0.0, 24.0, 24.0)),
93            "0.0 0.0 24.0 24.0"
94        );
95        assert_eq!(
96            render(ViewBox::new(0.0, -0.5, 16.5, 16.0)),
97            "0.0 -0.5 16.5 16.0"
98        );
99    }
100
101    #[test]
102    fn attribute_is_always_present() {
103        assert!(ViewBox::new(0.0, 0.0, 24.0, 24.0).attribute_present());
104    }
105}