1use super::{
11 ImageFit, ImageHorizontalAlignment, ImageRendering, ImageTiling, ImageVerticalAlignment, Item,
12 ItemConsts, ItemRc, RenderingResult,
13};
14use crate::input::{
15 FocusEvent, FocusEventResult, InputEventFilterResult, InputEventResult, KeyEvent,
16 KeyEventResult, MouseEvent,
17};
18use crate::item_rendering::ItemRenderer;
19use crate::item_rendering::{CachedRenderingData, RenderImage};
20use crate::layout::{LayoutInfo, Orientation};
21use crate::lengths::{LogicalLength, LogicalRect, LogicalSize};
22#[cfg(feature = "rtti")]
23use crate::rtti::*;
24use crate::window::WindowAdapter;
25use crate::{Brush, Coord, Property};
26use alloc::rc::Rc;
27use const_field_offset::FieldOffsets;
28use core::pin::Pin;
29use i_slint_core_macros::*;
30
31#[repr(C)]
32#[derive(FieldOffsets, Default, SlintElement)]
33#[pin]
34pub struct ImageItem {
36 pub source: Property<crate::graphics::Image>,
37 pub width: Property<LogicalLength>,
38 pub height: Property<LogicalLength>,
39 pub image_fit: Property<ImageFit>,
40 pub image_rendering: Property<ImageRendering>,
41 pub colorize: Property<Brush>,
42 pub cached_rendering_data: CachedRenderingData,
43}
44
45impl Item for ImageItem {
46 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
47
48 fn layout_info(
49 self: Pin<&Self>,
50 orientation: Orientation,
51 _window_adapter: &Rc<dyn WindowAdapter>,
52 _self_rc: &ItemRc,
53 ) -> LayoutInfo {
54 let natural_size = self.source().size();
55 LayoutInfo {
56 preferred: match orientation {
57 _ if natural_size.width == 0 || natural_size.height == 0 => 0 as Coord,
58 Orientation::Horizontal => natural_size.width as Coord,
59 Orientation::Vertical => {
60 natural_size.height as Coord * self.width().get() / natural_size.width as Coord
61 }
62 },
63 ..Default::default()
64 }
65 }
66
67 fn input_event_filter_before_children(
68 self: Pin<&Self>,
69 _: &MouseEvent,
70 _window_adapter: &Rc<dyn WindowAdapter>,
71 _self_rc: &ItemRc,
72 ) -> InputEventFilterResult {
73 InputEventFilterResult::ForwardAndIgnore
74 }
75
76 fn input_event(
77 self: Pin<&Self>,
78 _: &MouseEvent,
79 _window_adapter: &Rc<dyn WindowAdapter>,
80 _self_rc: &ItemRc,
81 ) -> InputEventResult {
82 InputEventResult::EventIgnored
83 }
84
85 fn capture_key_event(
86 self: Pin<&Self>,
87 _: &KeyEvent,
88 _window_adapter: &Rc<dyn WindowAdapter>,
89 _self_rc: &ItemRc,
90 ) -> KeyEventResult {
91 KeyEventResult::EventIgnored
92 }
93
94 fn key_event(
95 self: Pin<&Self>,
96 _: &KeyEvent,
97 _window_adapter: &Rc<dyn WindowAdapter>,
98 _self_rc: &ItemRc,
99 ) -> KeyEventResult {
100 KeyEventResult::EventIgnored
101 }
102
103 fn focus_event(
104 self: Pin<&Self>,
105 _: &FocusEvent,
106 _window_adapter: &Rc<dyn WindowAdapter>,
107 _self_rc: &ItemRc,
108 ) -> FocusEventResult {
109 FocusEventResult::FocusIgnored
110 }
111
112 fn render(
113 self: Pin<&Self>,
114 backend: &mut &mut dyn ItemRenderer,
115 self_rc: &ItemRc,
116 size: LogicalSize,
117 ) -> RenderingResult {
118 (*backend).draw_image(self, self_rc, size, &self.cached_rendering_data);
119 RenderingResult::ContinueRenderingChildren
120 }
121
122 fn bounding_rect(
123 self: core::pin::Pin<&Self>,
124 _window_adapter: &Rc<dyn WindowAdapter>,
125 _self_rc: &ItemRc,
126 geometry: LogicalRect,
127 ) -> LogicalRect {
128 geometry
129 }
130
131 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
132 false
133 }
134}
135
136impl RenderImage for ImageItem {
137 fn target_size(self: Pin<&Self>) -> LogicalSize {
138 LogicalSize::from_lengths(self.width(), self.height())
139 }
140
141 fn source(self: Pin<&Self>) -> crate::graphics::Image {
142 self.source()
143 }
144
145 fn source_clip(self: Pin<&Self>) -> Option<crate::graphics::IntRect> {
146 None
147 }
148
149 fn image_fit(self: Pin<&Self>) -> ImageFit {
150 self.image_fit()
151 }
152
153 fn rendering(self: Pin<&Self>) -> ImageRendering {
154 self.image_rendering()
155 }
156
157 fn colorize(self: Pin<&Self>) -> Brush {
158 self.colorize()
159 }
160
161 fn alignment(self: Pin<&Self>) -> (ImageHorizontalAlignment, ImageVerticalAlignment) {
162 Default::default()
163 }
164
165 fn tiling(self: Pin<&Self>) -> (ImageTiling, ImageTiling) {
166 Default::default()
167 }
168}
169
170impl ItemConsts for ImageItem {
171 const cached_rendering_data_offset: const_field_offset::FieldOffset<
172 ImageItem,
173 CachedRenderingData,
174 > = ImageItem::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
175}
176
177#[repr(C)]
178#[derive(FieldOffsets, Default, SlintElement)]
179#[pin]
180pub struct ClippedImage {
182 pub source: Property<crate::graphics::Image>,
183 pub width: Property<LogicalLength>,
184 pub height: Property<LogicalLength>,
185 pub image_fit: Property<ImageFit>,
186 pub image_rendering: Property<ImageRendering>,
187 pub colorize: Property<Brush>,
188 pub source_clip_x: Property<i32>,
189 pub source_clip_y: Property<i32>,
190 pub source_clip_width: Property<i32>,
191 pub source_clip_height: Property<i32>,
192
193 pub horizontal_alignment: Property<ImageHorizontalAlignment>,
194 pub vertical_alignment: Property<ImageVerticalAlignment>,
195 pub horizontal_tiling: Property<ImageTiling>,
196 pub vertical_tiling: Property<ImageTiling>,
197
198 pub cached_rendering_data: CachedRenderingData,
199}
200
201impl Item for ClippedImage {
202 fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
203
204 fn layout_info(
205 self: Pin<&Self>,
206 orientation: Orientation,
207 _window_adapter: &Rc<dyn WindowAdapter>,
208 _self_rc: &ItemRc,
209 ) -> LayoutInfo {
210 LayoutInfo {
211 preferred: match orientation {
212 Orientation::Horizontal => self.source_clip_width() as Coord,
213 Orientation::Vertical => {
214 let source_clip_width = self.source_clip_width();
215 if source_clip_width == 0 {
216 0 as Coord
217 } else {
218 self.source_clip_height() as Coord * self.width().get()
219 / source_clip_width as Coord
220 }
221 }
222 },
223 ..Default::default()
224 }
225 }
226
227 fn input_event_filter_before_children(
228 self: Pin<&Self>,
229 _: &MouseEvent,
230 _window_adapter: &Rc<dyn WindowAdapter>,
231 _self_rc: &ItemRc,
232 ) -> InputEventFilterResult {
233 InputEventFilterResult::ForwardAndIgnore
234 }
235
236 fn input_event(
237 self: Pin<&Self>,
238 _: &MouseEvent,
239 _window_adapter: &Rc<dyn WindowAdapter>,
240 _self_rc: &ItemRc,
241 ) -> InputEventResult {
242 InputEventResult::EventIgnored
243 }
244
245 fn capture_key_event(
246 self: Pin<&Self>,
247 _: &KeyEvent,
248 _window_adapter: &Rc<dyn WindowAdapter>,
249 _self_rc: &ItemRc,
250 ) -> KeyEventResult {
251 KeyEventResult::EventIgnored
252 }
253
254 fn key_event(
255 self: Pin<&Self>,
256 _: &KeyEvent,
257 _window_adapter: &Rc<dyn WindowAdapter>,
258 _self_rc: &ItemRc,
259 ) -> KeyEventResult {
260 KeyEventResult::EventIgnored
261 }
262
263 fn focus_event(
264 self: Pin<&Self>,
265 _: &FocusEvent,
266 _window_adapter: &Rc<dyn WindowAdapter>,
267 _self_rc: &ItemRc,
268 ) -> FocusEventResult {
269 FocusEventResult::FocusIgnored
270 }
271
272 fn render(
273 self: Pin<&Self>,
274 backend: &mut &mut dyn ItemRenderer,
275 self_rc: &ItemRc,
276 size: LogicalSize,
277 ) -> RenderingResult {
278 (*backend).draw_image(self, self_rc, size, &self.cached_rendering_data);
279 RenderingResult::ContinueRenderingChildren
280 }
281
282 fn bounding_rect(
283 self: core::pin::Pin<&Self>,
284 _window_adapter: &Rc<dyn WindowAdapter>,
285 _self_rc: &ItemRc,
286 geometry: LogicalRect,
287 ) -> LogicalRect {
288 geometry
289 }
290
291 fn clips_children(self: core::pin::Pin<&Self>) -> bool {
292 false
293 }
294}
295
296impl RenderImage for ClippedImage {
297 fn target_size(self: Pin<&Self>) -> LogicalSize {
298 LogicalSize::from_lengths(self.width(), self.height())
299 }
300
301 fn source(self: Pin<&Self>) -> crate::graphics::Image {
302 self.source()
303 }
304
305 fn source_clip(self: Pin<&Self>) -> Option<crate::graphics::IntRect> {
306 Some(euclid::rect(
307 self.source_clip_x(),
308 self.source_clip_y(),
309 self.source_clip_width(),
310 self.source_clip_height(),
311 ))
312 }
313
314 fn image_fit(self: Pin<&Self>) -> ImageFit {
315 self.image_fit()
316 }
317
318 fn rendering(self: Pin<&Self>) -> ImageRendering {
319 self.image_rendering()
320 }
321
322 fn colorize(self: Pin<&Self>) -> Brush {
323 self.colorize()
324 }
325
326 fn alignment(self: Pin<&Self>) -> (ImageHorizontalAlignment, ImageVerticalAlignment) {
327 (self.horizontal_alignment(), self.vertical_alignment())
328 }
329
330 fn tiling(self: Pin<&Self>) -> (ImageTiling, ImageTiling) {
331 (self.horizontal_tiling(), self.vertical_tiling())
332 }
333}
334
335impl ItemConsts for ClippedImage {
336 const cached_rendering_data_offset: const_field_offset::FieldOffset<
337 ClippedImage,
338 CachedRenderingData,
339 > = ClippedImage::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
340}