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