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}