1mod layout;
4mod node;
5mod reconcile;
6
7pub use layout::measure_image;
8pub use node::ImageNode;
9pub use reconcile::reconcile_image;
10
11use std::sync::Arc;
12
13use crate::core::element::{Element, ElementKind};
14use crate::style::{Length, Style};
15
16#[derive(Clone, Debug, PartialEq, Eq, Hash)]
18pub enum ImageSource {
19 Path(Arc<str>),
21 Bytes(Arc<[u8]>),
23}
24
25#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
27pub enum ImageFit {
28 #[default]
30 Contain,
31 Crop,
33 Scale,
35}
36
37#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
39pub enum ImageProtocol {
40 #[default]
42 Auto,
43 Kitty,
45 Iterm2,
47 Sixel,
49 Halfblocks,
51}
52
53#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
55pub enum ImagePlayback {
56 #[default]
58 Playing,
59 Paused,
61}
62
63#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
65pub enum ImageRepeat {
66 #[default]
68 Loop,
69 Once,
71}
72
73#[derive(Clone)]
75pub struct Image {
76 pub source: ImageSource,
78 pub style: Style,
80 pub width: Length,
83 pub height: Length,
86 pub fit: ImageFit,
88 pub protocol: ImageProtocol,
90 pub alt: Option<Arc<str>>,
92 pub playback: ImagePlayback,
94 pub repeat: ImageRepeat,
96 pub speed_percent: u16,
98}
99
100impl Image {
101 pub fn new(src: impl Into<Arc<str>>) -> Self {
103 Self {
104 source: ImageSource::Path(src.into()),
105 style: Style::default(),
106 width: Length::Auto,
107 height: Length::Auto,
108 fit: ImageFit::default(),
109 protocol: ImageProtocol::default(),
110 alt: None,
111 playback: ImagePlayback::default(),
112 repeat: ImageRepeat::default(),
113 speed_percent: 100,
114 }
115 }
116
117 pub fn from_bytes(bytes: impl Into<Arc<[u8]>>) -> Self {
119 Self {
120 source: ImageSource::Bytes(bytes.into()),
121 style: Style::default(),
122 width: Length::Auto,
123 height: Length::Auto,
124 fit: ImageFit::default(),
125 protocol: ImageProtocol::default(),
126 alt: None,
127 playback: ImagePlayback::default(),
128 repeat: ImageRepeat::default(),
129 speed_percent: 100,
130 }
131 }
132
133 pub fn src(mut self, src: impl Into<Arc<str>>) -> Self {
135 self.source = ImageSource::Path(src.into());
136 self
137 }
138
139 pub fn bytes(mut self, bytes: impl Into<Arc<[u8]>>) -> Self {
141 self.source = ImageSource::Bytes(bytes.into());
142 self
143 }
144
145 pub fn style(mut self, style: Style) -> Self {
147 self.style = style;
148 self
149 }
150
151 pub fn width(mut self, width: Length) -> Self {
153 self.width = width;
154 self
155 }
156
157 pub fn height(mut self, height: Length) -> Self {
159 self.height = height;
160 self
161 }
162
163 pub fn fit(mut self, fit: ImageFit) -> Self {
165 self.fit = fit;
166 self
167 }
168
169 pub fn protocol(mut self, protocol: ImageProtocol) -> Self {
171 self.protocol = protocol;
172 self
173 }
174
175 pub fn alt(mut self, alt: impl Into<Arc<str>>) -> Self {
177 self.alt = Some(alt.into());
178 self
179 }
180
181 pub fn playback(mut self, playback: ImagePlayback) -> Self {
183 self.playback = playback;
184 self
185 }
186
187 pub fn paused(mut self, paused: bool) -> Self {
189 self.playback = if paused {
190 ImagePlayback::Paused
191 } else {
192 ImagePlayback::Playing
193 };
194 self
195 }
196
197 pub fn repeat(mut self, repeat: ImageRepeat) -> Self {
199 self.repeat = repeat;
200 self
201 }
202
203 pub fn looping(mut self, looping: bool) -> Self {
205 self.repeat = if looping {
206 ImageRepeat::Loop
207 } else {
208 ImageRepeat::Once
209 };
210 self
211 }
212
213 pub fn speed_percent(mut self, speed_percent: u16) -> Self {
215 self.speed_percent = speed_percent.max(1);
216 self
217 }
218}
219
220impl From<Image> for Element {
221 fn from(value: Image) -> Self {
222 Element::new(ElementKind::Image(value))
223 }
224}
225
226impl crate::layout::hash::LayoutHash for Image {
227 fn layout_hash(
228 &self,
229 hasher: &mut impl std::hash::Hasher,
230 _recurse: &dyn Fn(&crate::core::element::Element) -> Option<u64>,
231 ) -> Option<()> {
232 use std::hash::Hash;
233 self.width.hash(hasher);
234 self.height.hash(hasher);
235 self.fit.hash(hasher);
236 self.protocol.hash(hasher);
237 self.playback.hash(hasher);
238 self.repeat.hash(hasher);
239 self.speed_percent.hash(hasher);
240 self.source.hash(hasher);
241 self.alt.hash(hasher);
242 Some(())
243 }
244}