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