image.rs

  1use super::constrain_size_preserving_aspect_ratio;
  2use crate::{
  3    geometry::{
  4        rect::RectF,
  5        vector::{vec2f, Vector2F},
  6    },
  7    json::{json, ToJson},
  8    presenter::MeasurementContext,
  9    scene, Border, DebugContext, Element, ImageData, LayoutContext, PaintContext, SizeConstraint,
 10};
 11use serde::Deserialize;
 12use std::{ops::Range, sync::Arc};
 13
 14pub struct Image {
 15    data: Arc<ImageData>,
 16    style: ImageStyle,
 17}
 18
 19#[derive(Copy, Clone, Default, Deserialize)]
 20pub struct ImageStyle {
 21    #[serde(default)]
 22    pub border: Border,
 23    #[serde(default)]
 24    pub corner_radius: f32,
 25    #[serde(default)]
 26    pub height: Option<f32>,
 27    #[serde(default)]
 28    pub width: Option<f32>,
 29    #[serde(default)]
 30    pub grayscale: bool,
 31}
 32
 33impl Image {
 34    pub fn new(data: Arc<ImageData>) -> Self {
 35        Self {
 36            data,
 37            style: Default::default(),
 38        }
 39    }
 40
 41    pub fn with_style(mut self, style: ImageStyle) -> Self {
 42        self.style = style;
 43        self
 44    }
 45}
 46
 47impl Element for Image {
 48    type LayoutState = ();
 49    type PaintState = ();
 50
 51    fn layout(
 52        &mut self,
 53        constraint: SizeConstraint,
 54        _: &mut LayoutContext,
 55    ) -> (Vector2F, Self::LayoutState) {
 56        let desired_size = vec2f(
 57            self.style.width.unwrap_or_else(|| constraint.max.x()),
 58            self.style.height.unwrap_or_else(|| constraint.max.y()),
 59        );
 60        let size = constrain_size_preserving_aspect_ratio(
 61            constraint.constrain(desired_size),
 62            self.data.size().to_f32(),
 63        );
 64        (size, ())
 65    }
 66
 67    fn paint(
 68        &mut self,
 69        bounds: RectF,
 70        _: RectF,
 71        _: &mut Self::LayoutState,
 72        cx: &mut PaintContext,
 73    ) -> Self::PaintState {
 74        cx.scene.push_image(scene::Image {
 75            bounds,
 76            border: self.style.border,
 77            corner_radius: self.style.corner_radius,
 78            grayscale: self.style.grayscale,
 79            data: self.data.clone(),
 80        });
 81    }
 82
 83    fn rect_for_text_range(
 84        &self,
 85        _: Range<usize>,
 86        _: RectF,
 87        _: RectF,
 88        _: &Self::LayoutState,
 89        _: &Self::PaintState,
 90        _: &MeasurementContext,
 91    ) -> Option<RectF> {
 92        None
 93    }
 94
 95    fn debug(
 96        &self,
 97        bounds: RectF,
 98        _: &Self::LayoutState,
 99        _: &Self::PaintState,
100        _: &DebugContext,
101    ) -> serde_json::Value {
102        json!({
103            "type": "Image",
104            "bounds": bounds.to_json(),
105        })
106    }
107}