Skip to main content

makeover_layout/
picture.rs

1/// How a picture sits in the box it is given.
2///
3/// An intent rather than a value, so a renderer picks the expression it has:
4/// `object-fit` in a webview, a texture's UV rect in egui, and in a terminal a
5/// choice about how many cells the blit gets. Named because MNW already makes
6/// the distinction deliberately at 17 sites and makes it three different ways,
7/// which is a policy the app decided rather than one a shared crate would be
8/// picking by accident.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
10#[non_exhaustive]
11pub enum Fit {
12    /// The picture's own proportions, and the box takes the height they imply.
13    ///
14    /// The default because it is the only one that shows the whole picture at
15    /// its own shape, so a renderer that ignores this enum entirely is still
16    /// right about the common case. A screenshot wants this; the shipped MNW
17    /// carousel sets no `object-fit` at all, which is this.
18    #[default]
19    Natural,
20    /// Fill the box and crop whatever does not fit.
21    ///
22    /// For a picture in a slot whose shape the layout fixed: a thumbnail, an
23    /// avatar, cover art. 15 of MNW's 17 sites.
24    Cover,
25    /// Fit inside the box whole, leaving space on two sides.
26    ///
27    /// The letterbox. For when the whole picture matters more than filling the
28    /// space, and the space is not the picture's shape.
29    Contain,
30}
31
32/// A picture's own pixel dimensions.
33///
34/// Deliberately not [`makeover_geometry`]'s business. Geometry answers *how
35/// much space a thing should get*, which is a scale question with the same
36/// answer on every screen. This is the intrinsic size of one asset, which is a
37/// fact about that asset and varies per picture.
38///
39/// [`makeover_geometry`]: https://docs.rs/makeover-geometry
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
41#[non_exhaustive]
42pub struct Extent {
43    /// Width in the picture's own pixels.
44    pub width: u32,
45    /// Height in the picture's own pixels.
46    pub height: u32,
47}
48
49impl Extent {
50    /// A picture's dimensions.
51    #[must_use]
52    pub const fn new(width: u32, height: u32) -> Self {
53        Self { width, height }
54    }
55
56    /// Width over height, or `None` if either side is zero.
57    ///
58    /// The form a renderer actually reserves space with: a box that knows its
59    /// proportion holds the right height at any width, which is what a
60    /// responsive picture needs and what a fixed pixel height cannot give.
61    #[must_use]
62    pub fn ratio(self) -> Option<f32> {
63        (self.width > 0 && self.height > 0).then(|| self.width as f32 / self.height as f32)
64    }
65}