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