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