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