i_slint_core/items/
image.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4/*!
5This module contains the builtin image related items.
6
7When adding an item or a property, it needs to be kept in sync with different place.
8Lookup the [`crate::items`] module documentation.
9*/
10use 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]
34/// The implementation of the `Image` element
35pub 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]
180/// The implementation of the `ClippedImage` element
181pub 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}