i_slint_core/
items.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// cSpell: ignore nesw
5
6/*!
7This module contains the builtin items, either in this file or in sub-modules.
8
9When adding an item or a property, it needs to be kept in sync with different place.
10(This is less than ideal and maybe we can have some automation later)
11
12 - It needs to be changed in this module
13 - In the compiler: builtins.slint
14 - In the interpreter (new item only): dynamic_item_tree.rs
15 - For the C++ code (new item only): the cbindgen.rs to export the new item
16 - Don't forget to update the documentation
17*/
18
19#![allow(unsafe_code)]
20#![allow(non_upper_case_globals)]
21#![allow(missing_docs)] // because documenting each property of items is redundant
22
23use crate::graphics::{Brush, Color, FontRequest};
24use crate::input::{
25    FocusEvent, FocusEventResult, InputEventFilterResult, InputEventResult, KeyEventResult,
26    KeyEventType, MouseEvent,
27};
28use crate::item_rendering::{CachedRenderingData, RenderBorderRectangle, RenderRectangle};
29pub use crate::item_tree::{ItemRc, ItemTreeVTable};
30use crate::layout::LayoutInfo;
31use crate::lengths::{
32    LogicalBorderRadius, LogicalLength, LogicalRect, LogicalSize, LogicalVector, PointLengths,
33    RectLengths,
34};
35#[cfg(feature = "rtti")]
36use crate::rtti::*;
37use crate::window::{WindowAdapter, WindowAdapterRc, WindowInner};
38use crate::{Callback, Coord, Property, SharedString};
39use alloc::rc::Rc;
40use const_field_offset::FieldOffsets;
41use core::cell::Cell;
42use core::num::NonZeroU32;
43use core::pin::Pin;
44use i_slint_core_macros::*;
45use vtable::*;
46
47mod component_container;
48pub use self::component_container::*;
49mod flickable;
50pub use flickable::Flickable;
51mod text;
52pub use text::*;
53mod input_items;
54pub use input_items::*;
55mod image;
56pub use self::image::*;
57#[cfg(feature = "std")]
58mod path;
59pub use crate::menus::MenuItem;
60#[cfg(feature = "std")]
61pub use path::*;
62
63/// Alias for `&mut dyn ItemRenderer`. Required so cbindgen generates the ItemVTable
64/// despite the presence of trait object
65type ItemRendererRef<'a> = &'a mut dyn crate::item_rendering::ItemRenderer;
66
67/// Workarounds for cbindgen
68pub type VoidArg = ();
69pub type KeyEventArg = (KeyEvent,);
70type FocusReasonArg = (FocusReason,);
71type PointerEventArg = (PointerEvent,);
72type PointerScrollEventArg = (PointerScrollEvent,);
73type PointArg = (crate::api::LogicalPosition,);
74type MenuEntryArg = (MenuEntry,);
75type MenuEntryModel = crate::model::ModelRc<MenuEntry>;
76
77#[cfg(all(feature = "ffi", windows))]
78#[macro_export]
79macro_rules! declare_item_vtable {
80    (fn $getter:ident() -> $item_vtable_ty:ident for $item_ty:ty) => {
81        ItemVTable_static! {
82            #[unsafe(no_mangle)]
83            pub static $item_vtable_ty for $item_ty
84        }
85        #[unsafe(no_mangle)]
86        pub extern "C" fn $getter() -> *const ItemVTable {
87            use vtable::HasStaticVTable;
88            <$item_ty>::static_vtable()
89        }
90    };
91}
92#[cfg(not(all(feature = "ffi", windows)))]
93#[macro_export]
94macro_rules! declare_item_vtable {
95    (fn $getter:ident() -> $item_vtable_ty:ident for $item_ty:ty) => {
96        ItemVTable_static! {
97            #[unsafe(no_mangle)]
98            pub static $item_vtable_ty for $item_ty
99        }
100    };
101}
102
103/// Returned by the `render()` function on items to indicate whether the rendering of
104/// children should be handled by the caller, of if the item took care of that (for example
105/// through layer indirection)
106#[repr(C)]
107#[derive(Default)]
108pub enum RenderingResult {
109    #[default]
110    ContinueRenderingChildren,
111    ContinueRenderingWithoutChildren,
112}
113
114/// Items are the nodes in the render tree.
115#[cfg_attr(not(feature = "ffi"), i_slint_core_macros::remove_extern)]
116#[vtable]
117#[repr(C)]
118pub struct ItemVTable {
119    /// This function is called by the run-time after the memory for the item
120    /// has been allocated and initialized. It will be called before any user specified
121    /// bindings are set.
122    pub init: extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, my_item: &ItemRc),
123
124    /// offset in bytes from the *const ItemImpl.
125    /// isize::MAX  means None
126    #[allow(non_upper_case_globals)]
127    #[field_offset(CachedRenderingData)]
128    pub cached_rendering_data_offset: usize,
129
130    /// We would need max/min/preferred size, and all layout info
131    pub layout_info: extern "C" fn(
132        core::pin::Pin<VRef<ItemVTable>>,
133        orientation: Orientation,
134        window_adapter: &WindowAdapterRc,
135        self_rc: &ItemRc,
136    ) -> LayoutInfo,
137
138    /// Event handler for mouse and touch event. This function is called before being called on children.
139    /// Then, depending on the return value, it is called for the children, and their children, then
140    /// [`Self::input_event`] is called on the children, and finally [`Self::input_event`] is called
141    /// on this item again.
142    pub input_event_filter_before_children: extern "C" fn(
143        core::pin::Pin<VRef<ItemVTable>>,
144        MouseEvent,
145        window_adapter: &WindowAdapterRc,
146        self_rc: &ItemRc,
147    ) -> InputEventFilterResult,
148
149    /// Handle input event for mouse and touch event
150    pub input_event: extern "C" fn(
151        core::pin::Pin<VRef<ItemVTable>>,
152        MouseEvent,
153        window_adapter: &WindowAdapterRc,
154        self_rc: &ItemRc,
155    ) -> InputEventResult,
156
157    pub focus_event: extern "C" fn(
158        core::pin::Pin<VRef<ItemVTable>>,
159        &FocusEvent,
160        window_adapter: &WindowAdapterRc,
161        self_rc: &ItemRc,
162    ) -> FocusEventResult,
163
164    pub key_event: extern "C" fn(
165        core::pin::Pin<VRef<ItemVTable>>,
166        &KeyEvent,
167        window_adapter: &WindowAdapterRc,
168        self_rc: &ItemRc,
169    ) -> KeyEventResult,
170
171    pub render: extern "C" fn(
172        core::pin::Pin<VRef<ItemVTable>>,
173        backend: &mut ItemRendererRef,
174        self_rc: &ItemRc,
175        size: LogicalSize,
176    ) -> RenderingResult,
177
178    pub bounding_rect: extern "C" fn(
179        core::pin::Pin<VRef<ItemVTable>>,
180        window_adapter: &WindowAdapterRc,
181        self_rc: &ItemRc,
182        geometry: LogicalRect,
183    ) -> LogicalRect,
184
185    pub clips_children: extern "C" fn(core::pin::Pin<VRef<ItemVTable>>) -> bool,
186}
187
188/// Alias for `vtable::VRef<ItemVTable>` which represent a pointer to a `dyn Item` with
189/// the associated vtable
190pub type ItemRef<'a> = vtable::VRef<'a, ItemVTable>;
191
192#[repr(C)]
193#[derive(FieldOffsets, Default, SlintElement)]
194#[pin]
195/// The implementation of an empty items that does nothing
196pub struct Empty {
197    pub cached_rendering_data: CachedRenderingData,
198}
199
200impl Item for Empty {
201    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
202
203    fn layout_info(
204        self: Pin<&Self>,
205        _orientation: Orientation,
206        _window_adapter: &Rc<dyn WindowAdapter>,
207        _self_rc: &ItemRc,
208    ) -> LayoutInfo {
209        LayoutInfo { stretch: 1., ..LayoutInfo::default() }
210    }
211
212    fn input_event_filter_before_children(
213        self: Pin<&Self>,
214        _: MouseEvent,
215        _window_adapter: &Rc<dyn WindowAdapter>,
216        _self_rc: &ItemRc,
217    ) -> InputEventFilterResult {
218        InputEventFilterResult::ForwardAndIgnore
219    }
220
221    fn input_event(
222        self: Pin<&Self>,
223        _: MouseEvent,
224        _window_adapter: &Rc<dyn WindowAdapter>,
225        _self_rc: &ItemRc,
226    ) -> InputEventResult {
227        InputEventResult::EventIgnored
228    }
229
230    fn key_event(
231        self: Pin<&Self>,
232        _: &KeyEvent,
233        _window_adapter: &Rc<dyn WindowAdapter>,
234        _self_rc: &ItemRc,
235    ) -> KeyEventResult {
236        KeyEventResult::EventIgnored
237    }
238
239    fn focus_event(
240        self: Pin<&Self>,
241        _: &FocusEvent,
242        _window_adapter: &Rc<dyn WindowAdapter>,
243        _self_rc: &ItemRc,
244    ) -> FocusEventResult {
245        FocusEventResult::FocusIgnored
246    }
247
248    fn render(
249        self: Pin<&Self>,
250        _backend: &mut ItemRendererRef,
251        _self_rc: &ItemRc,
252        _size: LogicalSize,
253    ) -> RenderingResult {
254        RenderingResult::ContinueRenderingChildren
255    }
256
257    fn bounding_rect(
258        self: core::pin::Pin<&Self>,
259        _window_adapter: &Rc<dyn WindowAdapter>,
260        _self_rc: &ItemRc,
261        mut geometry: LogicalRect,
262    ) -> LogicalRect {
263        geometry.size = LogicalSize::zero();
264        geometry
265    }
266
267    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
268        false
269    }
270}
271
272impl ItemConsts for Empty {
273    const cached_rendering_data_offset: const_field_offset::FieldOffset<
274        Empty,
275        CachedRenderingData,
276    > = Empty::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
277}
278
279declare_item_vtable! {
280    fn slint_get_EmptyVTable() -> EmptyVTable for Empty
281}
282
283#[repr(C)]
284#[derive(FieldOffsets, Default, SlintElement)]
285#[pin]
286/// The implementation of the `Rectangle` element
287pub struct Rectangle {
288    pub background: Property<Brush>,
289    pub cached_rendering_data: CachedRenderingData,
290}
291
292impl Item for Rectangle {
293    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
294
295    fn layout_info(
296        self: Pin<&Self>,
297        _orientation: Orientation,
298        _window_adapter: &Rc<dyn WindowAdapter>,
299        _self_rc: &ItemRc,
300    ) -> LayoutInfo {
301        LayoutInfo { stretch: 1., ..LayoutInfo::default() }
302    }
303
304    fn input_event_filter_before_children(
305        self: Pin<&Self>,
306        _: MouseEvent,
307        _window_adapter: &Rc<dyn WindowAdapter>,
308        _self_rc: &ItemRc,
309    ) -> InputEventFilterResult {
310        InputEventFilterResult::ForwardAndIgnore
311    }
312
313    fn input_event(
314        self: Pin<&Self>,
315        _: MouseEvent,
316        _window_adapter: &Rc<dyn WindowAdapter>,
317        _self_rc: &ItemRc,
318    ) -> InputEventResult {
319        InputEventResult::EventIgnored
320    }
321
322    fn key_event(
323        self: Pin<&Self>,
324        _: &KeyEvent,
325        _window_adapter: &Rc<dyn WindowAdapter>,
326        _self_rc: &ItemRc,
327    ) -> KeyEventResult {
328        KeyEventResult::EventIgnored
329    }
330
331    fn focus_event(
332        self: Pin<&Self>,
333        _: &FocusEvent,
334        _window_adapter: &Rc<dyn WindowAdapter>,
335        _self_rc: &ItemRc,
336    ) -> FocusEventResult {
337        FocusEventResult::FocusIgnored
338    }
339
340    fn render(
341        self: Pin<&Self>,
342        backend: &mut ItemRendererRef,
343        self_rc: &ItemRc,
344        size: LogicalSize,
345    ) -> RenderingResult {
346        (*backend).draw_rectangle(self, self_rc, size, &self.cached_rendering_data);
347        RenderingResult::ContinueRenderingChildren
348    }
349
350    fn bounding_rect(
351        self: core::pin::Pin<&Self>,
352        _window_adapter: &Rc<dyn WindowAdapter>,
353        _self_rc: &ItemRc,
354        geometry: LogicalRect,
355    ) -> LogicalRect {
356        geometry
357    }
358
359    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
360        false
361    }
362}
363
364impl RenderRectangle for Rectangle {
365    fn background(self: Pin<&Self>) -> Brush {
366        self.background()
367    }
368}
369
370impl ItemConsts for Rectangle {
371    const cached_rendering_data_offset: const_field_offset::FieldOffset<
372        Rectangle,
373        CachedRenderingData,
374    > = Rectangle::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
375}
376
377declare_item_vtable! {
378    fn slint_get_RectangleVTable() -> RectangleVTable for Rectangle
379}
380
381#[repr(C)]
382#[derive(FieldOffsets, Default, SlintElement)]
383#[pin]
384/// The implementation of the `BasicBorderRectangle` element
385pub struct BasicBorderRectangle {
386    pub background: Property<Brush>,
387    pub border_width: Property<LogicalLength>,
388    pub border_radius: Property<LogicalLength>,
389    pub border_color: Property<Brush>,
390    pub cached_rendering_data: CachedRenderingData,
391}
392
393impl Item for BasicBorderRectangle {
394    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
395
396    fn layout_info(
397        self: Pin<&Self>,
398        _orientation: Orientation,
399        _window_adapter: &Rc<dyn WindowAdapter>,
400        _self_rc: &ItemRc,
401    ) -> LayoutInfo {
402        LayoutInfo { stretch: 1., ..LayoutInfo::default() }
403    }
404
405    fn input_event_filter_before_children(
406        self: Pin<&Self>,
407        _: MouseEvent,
408        _window_adapter: &Rc<dyn WindowAdapter>,
409        _self_rc: &ItemRc,
410    ) -> InputEventFilterResult {
411        InputEventFilterResult::ForwardAndIgnore
412    }
413
414    fn input_event(
415        self: Pin<&Self>,
416        _: MouseEvent,
417        _window_adapter: &Rc<dyn WindowAdapter>,
418        _self_rc: &ItemRc,
419    ) -> InputEventResult {
420        InputEventResult::EventIgnored
421    }
422
423    fn key_event(
424        self: Pin<&Self>,
425        _: &KeyEvent,
426        _window_adapter: &Rc<dyn WindowAdapter>,
427        _self_rc: &ItemRc,
428    ) -> KeyEventResult {
429        KeyEventResult::EventIgnored
430    }
431
432    fn focus_event(
433        self: Pin<&Self>,
434        _: &FocusEvent,
435        _window_adapter: &Rc<dyn WindowAdapter>,
436        _self_rc: &ItemRc,
437    ) -> FocusEventResult {
438        FocusEventResult::FocusIgnored
439    }
440
441    fn render(
442        self: Pin<&Self>,
443        backend: &mut ItemRendererRef,
444        self_rc: &ItemRc,
445        size: LogicalSize,
446    ) -> RenderingResult {
447        (*backend).draw_border_rectangle(self, self_rc, size, &self.cached_rendering_data);
448        RenderingResult::ContinueRenderingChildren
449    }
450
451    fn bounding_rect(
452        self: core::pin::Pin<&Self>,
453        _window_adapter: &Rc<dyn WindowAdapter>,
454        _self_rc: &ItemRc,
455        geometry: LogicalRect,
456    ) -> LogicalRect {
457        geometry
458    }
459
460    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
461        false
462    }
463}
464
465impl RenderBorderRectangle for BasicBorderRectangle {
466    fn background(self: Pin<&Self>) -> Brush {
467        self.background()
468    }
469    fn border_width(self: Pin<&Self>) -> LogicalLength {
470        self.border_width()
471    }
472    fn border_radius(self: Pin<&Self>) -> LogicalBorderRadius {
473        LogicalBorderRadius::from_length(self.border_radius())
474    }
475    fn border_color(self: Pin<&Self>) -> Brush {
476        self.border_color()
477    }
478}
479
480impl ItemConsts for BasicBorderRectangle {
481    const cached_rendering_data_offset: const_field_offset::FieldOffset<
482        BasicBorderRectangle,
483        CachedRenderingData,
484    > = BasicBorderRectangle::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
485}
486
487declare_item_vtable! {
488    fn slint_get_BasicBorderRectangleVTable() -> BasicBorderRectangleVTable for BasicBorderRectangle
489}
490
491#[repr(C)]
492#[derive(FieldOffsets, Default, SlintElement)]
493#[pin]
494/// The implementation of the `BorderRectangle` element
495pub struct BorderRectangle {
496    pub background: Property<Brush>,
497    pub border_width: Property<LogicalLength>,
498    pub border_radius: Property<LogicalLength>,
499    pub border_top_left_radius: Property<LogicalLength>,
500    pub border_top_right_radius: Property<LogicalLength>,
501    pub border_bottom_left_radius: Property<LogicalLength>,
502    pub border_bottom_right_radius: Property<LogicalLength>,
503    pub border_color: Property<Brush>,
504    pub cached_rendering_data: CachedRenderingData,
505}
506
507impl Item for BorderRectangle {
508    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
509
510    fn layout_info(
511        self: Pin<&Self>,
512        _orientation: Orientation,
513        _window_adapter: &Rc<dyn WindowAdapter>,
514        _self_rc: &ItemRc,
515    ) -> LayoutInfo {
516        LayoutInfo { stretch: 1., ..LayoutInfo::default() }
517    }
518
519    fn input_event_filter_before_children(
520        self: Pin<&Self>,
521        _: MouseEvent,
522        _window_adapter: &Rc<dyn WindowAdapter>,
523        _self_rc: &ItemRc,
524    ) -> InputEventFilterResult {
525        InputEventFilterResult::ForwardAndIgnore
526    }
527
528    fn input_event(
529        self: Pin<&Self>,
530        _: MouseEvent,
531        _window_adapter: &Rc<dyn WindowAdapter>,
532        _self_rc: &ItemRc,
533    ) -> InputEventResult {
534        InputEventResult::EventIgnored
535    }
536
537    fn key_event(
538        self: Pin<&Self>,
539        _: &KeyEvent,
540        _window_adapter: &Rc<dyn WindowAdapter>,
541        _self_rc: &ItemRc,
542    ) -> KeyEventResult {
543        KeyEventResult::EventIgnored
544    }
545
546    fn focus_event(
547        self: Pin<&Self>,
548        _: &FocusEvent,
549        _window_adapter: &Rc<dyn WindowAdapter>,
550        _self_rc: &ItemRc,
551    ) -> FocusEventResult {
552        FocusEventResult::FocusIgnored
553    }
554
555    fn render(
556        self: Pin<&Self>,
557        backend: &mut ItemRendererRef,
558        self_rc: &ItemRc,
559        size: LogicalSize,
560    ) -> RenderingResult {
561        (*backend).draw_border_rectangle(self, self_rc, size, &self.cached_rendering_data);
562        RenderingResult::ContinueRenderingChildren
563    }
564
565    fn bounding_rect(
566        self: core::pin::Pin<&Self>,
567        _window_adapter: &Rc<dyn WindowAdapter>,
568        _self_rc: &ItemRc,
569        geometry: LogicalRect,
570    ) -> LogicalRect {
571        geometry
572    }
573
574    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
575        false
576    }
577}
578
579impl RenderBorderRectangle for BorderRectangle {
580    fn background(self: Pin<&Self>) -> Brush {
581        self.background()
582    }
583    fn border_width(self: Pin<&Self>) -> LogicalLength {
584        self.border_width()
585    }
586    fn border_radius(self: Pin<&Self>) -> LogicalBorderRadius {
587        LogicalBorderRadius::from_lengths(
588            self.border_top_left_radius(),
589            self.border_top_right_radius(),
590            self.border_bottom_right_radius(),
591            self.border_bottom_left_radius(),
592        )
593    }
594    fn border_color(self: Pin<&Self>) -> Brush {
595        self.border_color()
596    }
597}
598
599impl ItemConsts for BorderRectangle {
600    const cached_rendering_data_offset: const_field_offset::FieldOffset<
601        BorderRectangle,
602        CachedRenderingData,
603    > = BorderRectangle::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
604}
605
606declare_item_vtable! {
607    fn slint_get_BorderRectangleVTable() -> BorderRectangleVTable for BorderRectangle
608}
609
610declare_item_vtable! {
611    fn slint_get_TouchAreaVTable() -> TouchAreaVTable for TouchArea
612}
613
614declare_item_vtable! {
615    fn slint_get_FocusScopeVTable() -> FocusScopeVTable for FocusScope
616}
617
618declare_item_vtable! {
619    fn slint_get_SwipeGestureHandlerVTable() -> SwipeGestureHandlerVTable for SwipeGestureHandler
620}
621
622#[repr(C)]
623#[derive(FieldOffsets, Default, SlintElement)]
624#[pin]
625/// The implementation of the `Clip` element
626pub struct Clip {
627    pub border_top_left_radius: Property<LogicalLength>,
628    pub border_top_right_radius: Property<LogicalLength>,
629    pub border_bottom_left_radius: Property<LogicalLength>,
630    pub border_bottom_right_radius: Property<LogicalLength>,
631    pub border_width: Property<LogicalLength>,
632    pub cached_rendering_data: CachedRenderingData,
633    pub clip: Property<bool>,
634}
635
636impl Item for Clip {
637    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
638
639    fn layout_info(
640        self: Pin<&Self>,
641        _orientation: Orientation,
642        _window_adapter: &Rc<dyn WindowAdapter>,
643        _self_rc: &ItemRc,
644    ) -> LayoutInfo {
645        LayoutInfo { stretch: 1., ..LayoutInfo::default() }
646    }
647
648    fn input_event_filter_before_children(
649        self: Pin<&Self>,
650        event: MouseEvent,
651        _window_adapter: &Rc<dyn WindowAdapter>,
652        self_rc: &ItemRc,
653    ) -> InputEventFilterResult {
654        if let Some(pos) = event.position() {
655            let geometry = self_rc.geometry();
656            if self.clip()
657                && (pos.x < 0 as Coord
658                    || pos.y < 0 as Coord
659                    || pos.x_length() > geometry.width_length()
660                    || pos.y_length() > geometry.height_length())
661            {
662                return InputEventFilterResult::Intercept;
663            }
664        }
665        InputEventFilterResult::ForwardAndIgnore
666    }
667
668    fn input_event(
669        self: Pin<&Self>,
670        _: MouseEvent,
671        _window_adapter: &Rc<dyn WindowAdapter>,
672        _self_rc: &ItemRc,
673    ) -> InputEventResult {
674        InputEventResult::EventIgnored
675    }
676
677    fn key_event(
678        self: Pin<&Self>,
679        _: &KeyEvent,
680        _window_adapter: &Rc<dyn WindowAdapter>,
681        _self_rc: &ItemRc,
682    ) -> KeyEventResult {
683        KeyEventResult::EventIgnored
684    }
685
686    fn focus_event(
687        self: Pin<&Self>,
688        _: &FocusEvent,
689        _window_adapter: &Rc<dyn WindowAdapter>,
690        _self_rc: &ItemRc,
691    ) -> FocusEventResult {
692        FocusEventResult::FocusIgnored
693    }
694
695    fn render(
696        self: Pin<&Self>,
697        backend: &mut ItemRendererRef,
698        self_rc: &ItemRc,
699        size: LogicalSize,
700    ) -> RenderingResult {
701        (*backend).visit_clip(self, self_rc, size)
702    }
703
704    fn bounding_rect(
705        self: core::pin::Pin<&Self>,
706        _window_adapter: &Rc<dyn WindowAdapter>,
707        _self_rc: &ItemRc,
708        geometry: LogicalRect,
709    ) -> LogicalRect {
710        geometry
711    }
712
713    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
714        self.clip()
715    }
716}
717
718impl Clip {
719    pub fn logical_border_radius(self: Pin<&Self>) -> LogicalBorderRadius {
720        LogicalBorderRadius::from_lengths(
721            self.border_top_left_radius(),
722            self.border_top_right_radius(),
723            self.border_bottom_right_radius(),
724            self.border_bottom_left_radius(),
725        )
726    }
727}
728
729impl ItemConsts for Clip {
730    const cached_rendering_data_offset: const_field_offset::FieldOffset<Clip, CachedRenderingData> =
731        Clip::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
732}
733
734declare_item_vtable! {
735    fn slint_get_ClipVTable() -> ClipVTable for Clip
736}
737
738#[repr(C)]
739#[derive(FieldOffsets, Default, SlintElement)]
740#[pin]
741/// The Opacity Item is not meant to be used directly by the .slint code, instead, the `opacity: xxx` or `visible: false` should be used
742pub struct Opacity {
743    // FIXME: this element shouldn't need these geometry property
744    pub opacity: Property<f32>,
745    pub cached_rendering_data: CachedRenderingData,
746}
747
748impl Item for Opacity {
749    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
750
751    fn layout_info(
752        self: Pin<&Self>,
753        _orientation: Orientation,
754        _window_adapter: &Rc<dyn WindowAdapter>,
755        _self_rc: &ItemRc,
756    ) -> LayoutInfo {
757        LayoutInfo { stretch: 1., ..LayoutInfo::default() }
758    }
759
760    fn input_event_filter_before_children(
761        self: Pin<&Self>,
762        _: MouseEvent,
763        _window_adapter: &Rc<dyn WindowAdapter>,
764        _self_rc: &ItemRc,
765    ) -> InputEventFilterResult {
766        InputEventFilterResult::ForwardAndIgnore
767    }
768
769    fn input_event(
770        self: Pin<&Self>,
771        _: MouseEvent,
772        _window_adapter: &Rc<dyn WindowAdapter>,
773        _self_rc: &ItemRc,
774    ) -> InputEventResult {
775        InputEventResult::EventIgnored
776    }
777
778    fn key_event(
779        self: Pin<&Self>,
780        _: &KeyEvent,
781        _window_adapter: &Rc<dyn WindowAdapter>,
782        _self_rc: &ItemRc,
783    ) -> KeyEventResult {
784        KeyEventResult::EventIgnored
785    }
786
787    fn focus_event(
788        self: Pin<&Self>,
789        _: &FocusEvent,
790        _window_adapter: &Rc<dyn WindowAdapter>,
791        _self_rc: &ItemRc,
792    ) -> FocusEventResult {
793        FocusEventResult::FocusIgnored
794    }
795
796    fn render(
797        self: Pin<&Self>,
798        backend: &mut ItemRendererRef,
799        self_rc: &ItemRc,
800        size: LogicalSize,
801    ) -> RenderingResult {
802        backend.visit_opacity(self, self_rc, size)
803    }
804
805    fn bounding_rect(
806        self: core::pin::Pin<&Self>,
807        _window_adapter: &Rc<dyn WindowAdapter>,
808        _self_rc: &ItemRc,
809        geometry: LogicalRect,
810    ) -> LogicalRect {
811        geometry
812    }
813
814    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
815        false
816    }
817}
818
819impl Opacity {
820    // This function determines the optimization opportunities for not having to render the
821    // children of the Opacity element into a layer:
822    //  *  The opacity item typically only one child (this is not guaranteed). If that item has
823    //     no children, then we can skip the layer and apply the opacity directly. This is not perfect though,
824    //     for example if the compiler inserts another synthetic element between the `Opacity` and the actual child,
825    //     then this check will apply a layer even though it might not actually be necessary.
826    //  * If the vale of the opacity is 1.0 then we don't need to do anything.
827    pub fn need_layer(self_rc: &ItemRc, opacity: f32) -> bool {
828        if opacity == 1.0 {
829            return false;
830        }
831
832        let opacity_child = match self_rc.first_child() {
833            Some(first_child) => first_child,
834            None => return false, // No children? Don't need a layer then.
835        };
836
837        if opacity_child.next_sibling().is_some() {
838            return true; // If the opacity item has more than one child, then we need a layer
839        }
840
841        // If the target of the opacity has any children then we need a layer
842        opacity_child.first_child().is_some()
843    }
844}
845
846impl ItemConsts for Opacity {
847    const cached_rendering_data_offset: const_field_offset::FieldOffset<
848        Opacity,
849        CachedRenderingData,
850    > = Opacity::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
851}
852
853declare_item_vtable! {
854    fn slint_get_OpacityVTable() -> OpacityVTable for Opacity
855}
856
857#[repr(C)]
858#[derive(FieldOffsets, Default, SlintElement)]
859#[pin]
860/// The Layer Item is not meant to be used directly by the .slint code, instead, the `layer: xxx` property should be used
861pub struct Layer {
862    pub cache_rendering_hint: Property<bool>,
863    pub cached_rendering_data: CachedRenderingData,
864}
865
866impl Item for Layer {
867    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
868
869    fn layout_info(
870        self: Pin<&Self>,
871        _orientation: Orientation,
872        _window_adapter: &Rc<dyn WindowAdapter>,
873        _self_rc: &ItemRc,
874    ) -> LayoutInfo {
875        LayoutInfo { stretch: 1., ..LayoutInfo::default() }
876    }
877
878    fn input_event_filter_before_children(
879        self: Pin<&Self>,
880        _: MouseEvent,
881        _window_adapter: &Rc<dyn WindowAdapter>,
882        _self_rc: &ItemRc,
883    ) -> InputEventFilterResult {
884        InputEventFilterResult::ForwardAndIgnore
885    }
886
887    fn input_event(
888        self: Pin<&Self>,
889        _: MouseEvent,
890        _window_adapter: &Rc<dyn WindowAdapter>,
891        _self_rc: &ItemRc,
892    ) -> InputEventResult {
893        InputEventResult::EventIgnored
894    }
895
896    fn key_event(
897        self: Pin<&Self>,
898        _: &KeyEvent,
899        _window_adapter: &Rc<dyn WindowAdapter>,
900        _self_rc: &ItemRc,
901    ) -> KeyEventResult {
902        KeyEventResult::EventIgnored
903    }
904
905    fn focus_event(
906        self: Pin<&Self>,
907        _: &FocusEvent,
908        _window_adapter: &Rc<dyn WindowAdapter>,
909        _self_rc: &ItemRc,
910    ) -> FocusEventResult {
911        FocusEventResult::FocusIgnored
912    }
913
914    fn render(
915        self: Pin<&Self>,
916        backend: &mut ItemRendererRef,
917        self_rc: &ItemRc,
918        size: LogicalSize,
919    ) -> RenderingResult {
920        backend.visit_layer(self, self_rc, size)
921    }
922
923    fn bounding_rect(
924        self: core::pin::Pin<&Self>,
925        _window_adapter: &Rc<dyn WindowAdapter>,
926        _self_rc: &ItemRc,
927        geometry: LogicalRect,
928    ) -> LogicalRect {
929        geometry
930    }
931
932    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
933        false
934    }
935}
936
937impl ItemConsts for Layer {
938    const cached_rendering_data_offset: const_field_offset::FieldOffset<
939        Layer,
940        CachedRenderingData,
941    > = Layer::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
942}
943
944declare_item_vtable! {
945    fn slint_get_LayerVTable() -> LayerVTable for Layer
946}
947
948#[repr(C)]
949#[derive(FieldOffsets, Default, SlintElement)]
950#[pin]
951/// The implementation of the `Rotate` element
952pub struct Rotate {
953    pub rotation_angle: Property<f32>,
954    pub rotation_origin_x: Property<LogicalLength>,
955    pub rotation_origin_y: Property<LogicalLength>,
956    pub cached_rendering_data: CachedRenderingData,
957}
958
959impl Item for Rotate {
960    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
961
962    fn layout_info(
963        self: Pin<&Self>,
964        _orientation: Orientation,
965        _window_adapter: &Rc<dyn WindowAdapter>,
966        _self_rc: &ItemRc,
967    ) -> LayoutInfo {
968        LayoutInfo { stretch: 1., ..LayoutInfo::default() }
969    }
970
971    fn input_event_filter_before_children(
972        self: Pin<&Self>,
973        _: MouseEvent,
974        _window_adapter: &Rc<dyn WindowAdapter>,
975        _self_rc: &ItemRc,
976    ) -> InputEventFilterResult {
977        InputEventFilterResult::ForwardAndIgnore
978    }
979
980    fn input_event(
981        self: Pin<&Self>,
982        _: MouseEvent,
983        _window_adapter: &Rc<dyn WindowAdapter>,
984        _self_rc: &ItemRc,
985    ) -> InputEventResult {
986        InputEventResult::EventIgnored
987    }
988
989    fn key_event(
990        self: Pin<&Self>,
991        _: &KeyEvent,
992        _window_adapter: &Rc<dyn WindowAdapter>,
993        _self_rc: &ItemRc,
994    ) -> KeyEventResult {
995        KeyEventResult::EventIgnored
996    }
997
998    fn focus_event(
999        self: Pin<&Self>,
1000        _: &FocusEvent,
1001        _window_adapter: &Rc<dyn WindowAdapter>,
1002        _self_rc: &ItemRc,
1003    ) -> FocusEventResult {
1004        FocusEventResult::FocusIgnored
1005    }
1006
1007    fn render(
1008        self: Pin<&Self>,
1009        backend: &mut ItemRendererRef,
1010        _self_rc: &ItemRc,
1011        _size: LogicalSize,
1012    ) -> RenderingResult {
1013        let origin =
1014            LogicalVector::from_lengths(self.rotation_origin_x(), self.rotation_origin_y());
1015        (*backend).translate(origin);
1016        (*backend).rotate(self.rotation_angle());
1017        (*backend).translate(-origin);
1018        RenderingResult::ContinueRenderingChildren
1019    }
1020
1021    fn bounding_rect(
1022        self: core::pin::Pin<&Self>,
1023        _window_adapter: &Rc<dyn WindowAdapter>,
1024        _self_rc: &ItemRc,
1025        geometry: LogicalRect,
1026    ) -> LogicalRect {
1027        geometry
1028    }
1029
1030    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
1031        false
1032    }
1033}
1034
1035impl ItemConsts for Rotate {
1036    const cached_rendering_data_offset: const_field_offset::FieldOffset<
1037        Rotate,
1038        CachedRenderingData,
1039    > = Rotate::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
1040}
1041
1042declare_item_vtable! {
1043    fn slint_get_RotateVTable() -> RotateVTable for Rotate
1044}
1045
1046declare_item_vtable! {
1047    fn slint_get_FlickableVTable() -> FlickableVTable for Flickable
1048}
1049
1050/// The implementation of the `PropertyAnimation` element
1051#[repr(C)]
1052#[derive(FieldOffsets, SlintElement, Clone, Debug)]
1053#[pin]
1054pub struct PropertyAnimation {
1055    #[rtti_field]
1056    pub delay: i32,
1057    #[rtti_field]
1058    pub duration: i32,
1059    #[rtti_field]
1060    pub iteration_count: f32,
1061    #[rtti_field]
1062    pub direction: AnimationDirection,
1063    #[rtti_field]
1064    pub easing: crate::animations::EasingCurve,
1065}
1066
1067impl Default for PropertyAnimation {
1068    fn default() -> Self {
1069        // Defaults for PropertyAnimation are defined here (for internal Rust code doing programmatic animations)
1070        // as well as in `builtins.slint` (for generated C++ and Rust code)
1071        Self {
1072            delay: 0,
1073            duration: 0,
1074            iteration_count: 1.,
1075            direction: Default::default(),
1076            easing: Default::default(),
1077        }
1078    }
1079}
1080
1081/// The implementation of the `Window` element
1082#[repr(C)]
1083#[derive(FieldOffsets, Default, SlintElement)]
1084#[pin]
1085pub struct WindowItem {
1086    pub width: Property<LogicalLength>,
1087    pub height: Property<LogicalLength>,
1088    pub background: Property<Brush>,
1089    pub title: Property<SharedString>,
1090    pub no_frame: Property<bool>,
1091    pub resize_border_width: Property<LogicalLength>,
1092    pub always_on_top: Property<bool>,
1093    pub full_screen: Property<bool>,
1094    pub icon: Property<crate::graphics::Image>,
1095    pub default_font_family: Property<SharedString>,
1096    pub default_font_size: Property<LogicalLength>,
1097    pub default_font_weight: Property<i32>,
1098    pub cached_rendering_data: CachedRenderingData,
1099}
1100
1101impl Item for WindowItem {
1102    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {
1103        #[cfg(feature = "std")]
1104        self.full_screen.set(std::env::var("SLINT_FULLSCREEN").is_ok());
1105    }
1106
1107    fn layout_info(
1108        self: Pin<&Self>,
1109        _orientation: Orientation,
1110        _window_adapter: &Rc<dyn WindowAdapter>,
1111        _self_rc: &ItemRc,
1112    ) -> LayoutInfo {
1113        LayoutInfo::default()
1114    }
1115
1116    fn input_event_filter_before_children(
1117        self: Pin<&Self>,
1118        _: MouseEvent,
1119        _window_adapter: &Rc<dyn WindowAdapter>,
1120        _self_rc: &ItemRc,
1121    ) -> InputEventFilterResult {
1122        InputEventFilterResult::ForwardAndIgnore
1123    }
1124
1125    fn input_event(
1126        self: Pin<&Self>,
1127        _event: MouseEvent,
1128        _window_adapter: &Rc<dyn WindowAdapter>,
1129        _self_rc: &ItemRc,
1130    ) -> InputEventResult {
1131        InputEventResult::EventIgnored
1132    }
1133
1134    fn key_event(
1135        self: Pin<&Self>,
1136        _: &KeyEvent,
1137        _window_adapter: &Rc<dyn WindowAdapter>,
1138        _self_rc: &ItemRc,
1139    ) -> KeyEventResult {
1140        KeyEventResult::EventIgnored
1141    }
1142
1143    fn focus_event(
1144        self: Pin<&Self>,
1145        _: &FocusEvent,
1146        _window_adapter: &Rc<dyn WindowAdapter>,
1147        _self_rc: &ItemRc,
1148    ) -> FocusEventResult {
1149        FocusEventResult::FocusIgnored
1150    }
1151
1152    fn render(
1153        self: Pin<&Self>,
1154        backend: &mut ItemRendererRef,
1155        self_rc: &ItemRc,
1156        size: LogicalSize,
1157    ) -> RenderingResult {
1158        backend.draw_window_background(self, self_rc, size, &self.cached_rendering_data);
1159        RenderingResult::ContinueRenderingChildren
1160    }
1161
1162    fn bounding_rect(
1163        self: core::pin::Pin<&Self>,
1164        _window_adapter: &Rc<dyn WindowAdapter>,
1165        _self_rc: &ItemRc,
1166        geometry: LogicalRect,
1167    ) -> LogicalRect {
1168        geometry
1169    }
1170
1171    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
1172        false
1173    }
1174}
1175
1176impl RenderRectangle for WindowItem {
1177    fn background(self: Pin<&Self>) -> Brush {
1178        self.background()
1179    }
1180}
1181
1182fn next_window_item(item: &ItemRc) -> Option<ItemRc> {
1183    let root_item_in_local_item_tree = ItemRc::new(item.item_tree().clone(), 0);
1184
1185    if root_item_in_local_item_tree.downcast::<crate::items::WindowItem>().is_some() {
1186        Some(root_item_in_local_item_tree)
1187    } else {
1188        root_item_in_local_item_tree
1189            .parent_item(crate::item_tree::ParentItemTraversalMode::FindAllParents)
1190            .and_then(|parent| next_window_item(&parent))
1191    }
1192}
1193
1194impl WindowItem {
1195    pub fn font_family(self: Pin<&Self>) -> Option<SharedString> {
1196        let maybe_family = self.default_font_family();
1197        if !maybe_family.is_empty() {
1198            Some(maybe_family)
1199        } else {
1200            None
1201        }
1202    }
1203
1204    pub fn font_size(self: Pin<&Self>) -> Option<LogicalLength> {
1205        let font_size = self.default_font_size();
1206        if font_size.get() <= 0 as Coord {
1207            None
1208        } else {
1209            Some(font_size)
1210        }
1211    }
1212
1213    pub fn font_weight(self: Pin<&Self>) -> Option<i32> {
1214        let font_weight = self.default_font_weight();
1215        if font_weight == 0 {
1216            None
1217        } else {
1218            Some(font_weight)
1219        }
1220    }
1221
1222    pub fn resolve_font_property<T>(
1223        self_rc: &ItemRc,
1224        property_fn: impl Fn(Pin<&Self>) -> Option<T>,
1225    ) -> Option<T> {
1226        let mut window_item_rc = self_rc.clone();
1227        loop {
1228            let window_item = window_item_rc.downcast::<Self>()?;
1229            if let Some(result) = property_fn(window_item.as_pin_ref()) {
1230                return Some(result);
1231            }
1232
1233            match window_item_rc
1234                .parent_item(crate::item_tree::ParentItemTraversalMode::FindAllParents)
1235                .and_then(|p| next_window_item(&p))
1236            {
1237                Some(item) => window_item_rc = item,
1238                None => return None,
1239            }
1240        }
1241    }
1242
1243    /// Creates a new FontRequest that uses the provide local font properties. If they're not set, i.e.
1244    /// the family is an empty string, or the weight is zero, the corresponding properties are fetched
1245    /// from the next parent WindowItem.
1246    pub fn resolved_font_request(
1247        self_rc: &crate::items::ItemRc,
1248        local_font_family: SharedString,
1249        local_font_weight: i32,
1250        local_font_size: LogicalLength,
1251        local_letter_spacing: LogicalLength,
1252        local_italic: bool,
1253    ) -> FontRequest {
1254        let Some(window_item_rc) = next_window_item(self_rc) else {
1255            return FontRequest::default();
1256        };
1257
1258        FontRequest {
1259            family: {
1260                if !local_font_family.is_empty() {
1261                    Some(local_font_family)
1262                } else {
1263                    crate::items::WindowItem::resolve_font_property(
1264                        &window_item_rc,
1265                        crate::items::WindowItem::font_family,
1266                    )
1267                }
1268            },
1269            weight: {
1270                if local_font_weight == 0 {
1271                    crate::items::WindowItem::resolve_font_property(
1272                        &window_item_rc,
1273                        crate::items::WindowItem::font_weight,
1274                    )
1275                } else {
1276                    Some(local_font_weight)
1277                }
1278            },
1279            pixel_size: {
1280                if local_font_size.get() == 0 as Coord {
1281                    crate::items::WindowItem::resolve_font_property(
1282                        &window_item_rc,
1283                        crate::items::WindowItem::font_size,
1284                    )
1285                } else {
1286                    Some(local_font_size)
1287                }
1288            },
1289            letter_spacing: Some(local_letter_spacing),
1290            italic: local_italic,
1291        }
1292    }
1293}
1294
1295impl ItemConsts for WindowItem {
1296    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
1297        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
1298}
1299
1300declare_item_vtable! {
1301    fn slint_get_WindowItemVTable() -> WindowItemVTable for WindowItem
1302}
1303
1304/// The implementation used for `ContextMenuArea` and `ContextMenuInternal` elements
1305#[repr(C)]
1306#[derive(FieldOffsets, Default, SlintElement)]
1307#[pin]
1308pub struct ContextMenu {
1309    //pub entries: Property<crate::model::ModelRc<MenuEntry>>,
1310    pub sub_menu: Callback<MenuEntryArg, MenuEntryModel>,
1311    pub activated: Callback<MenuEntryArg>,
1312    pub show: Callback<PointArg>,
1313    pub cached_rendering_data: CachedRenderingData,
1314    pub popup_id: Cell<Option<NonZeroU32>>,
1315    pub enabled: Property<bool>,
1316    #[cfg(target_os = "android")]
1317    long_press_timer: Cell<Option<crate::timers::Timer>>,
1318}
1319
1320impl Item for ContextMenu {
1321    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
1322
1323    fn layout_info(
1324        self: Pin<&Self>,
1325        _orientation: Orientation,
1326        _window_adapter: &Rc<dyn WindowAdapter>,
1327        _self_rc: &ItemRc,
1328    ) -> LayoutInfo {
1329        LayoutInfo::default()
1330    }
1331
1332    fn input_event_filter_before_children(
1333        self: Pin<&Self>,
1334        _: MouseEvent,
1335        _window_adapter: &Rc<dyn WindowAdapter>,
1336        _self_rc: &ItemRc,
1337    ) -> InputEventFilterResult {
1338        InputEventFilterResult::ForwardEvent
1339    }
1340
1341    fn input_event(
1342        self: Pin<&Self>,
1343        event: MouseEvent,
1344        _window_adapter: &Rc<dyn WindowAdapter>,
1345        _self_rc: &ItemRc,
1346    ) -> InputEventResult {
1347        if !self.enabled() {
1348            return InputEventResult::EventIgnored;
1349        }
1350        match event {
1351            MouseEvent::Pressed { position, button: PointerEventButton::Right, .. } => {
1352                self.show.call(&(crate::api::LogicalPosition::from_euclid(position),));
1353                InputEventResult::EventAccepted
1354            }
1355            #[cfg(target_os = "android")]
1356            MouseEvent::Pressed { position, button: PointerEventButton::Left, .. } => {
1357                let timer = crate::timers::Timer::default();
1358                let self_weak = _self_rc.downgrade();
1359                timer.start(
1360                    crate::timers::TimerMode::SingleShot,
1361                    WindowInner::from_pub(_window_adapter.window())
1362                        .ctx
1363                        .platform()
1364                        .long_press_interval(crate::InternalToken),
1365                    move || {
1366                        let Some(self_rc) = self_weak.upgrade() else { return };
1367                        let Some(self_) = self_rc.downcast::<ContextMenu>() else { return };
1368                        self_.show.call(&(crate::api::LogicalPosition::from_euclid(position),));
1369                    },
1370                );
1371                self.long_press_timer.set(Some(timer));
1372                InputEventResult::GrabMouse
1373            }
1374            #[cfg(target_os = "android")]
1375            MouseEvent::Released { .. } | MouseEvent::Exit => {
1376                if let Some(timer) = self.long_press_timer.take() {
1377                    timer.stop();
1378                }
1379                InputEventResult::EventIgnored
1380            }
1381            #[cfg(target_os = "android")]
1382            MouseEvent::Moved { .. } => InputEventResult::EventAccepted,
1383            _ => InputEventResult::EventIgnored,
1384        }
1385    }
1386
1387    fn key_event(
1388        self: Pin<&Self>,
1389        event: &KeyEvent,
1390        _window_adapter: &Rc<dyn WindowAdapter>,
1391        _self_rc: &ItemRc,
1392    ) -> KeyEventResult {
1393        if !self.enabled() {
1394            return KeyEventResult::EventIgnored;
1395        }
1396        if event.event_type == KeyEventType::KeyPressed
1397            && event.text.starts_with(crate::input::key_codes::Menu)
1398        {
1399            self.show.call(&(Default::default(),));
1400            KeyEventResult::EventAccepted
1401        } else {
1402            KeyEventResult::EventIgnored
1403        }
1404    }
1405
1406    fn focus_event(
1407        self: Pin<&Self>,
1408        _: &FocusEvent,
1409        _window_adapter: &Rc<dyn WindowAdapter>,
1410        _self_rc: &ItemRc,
1411    ) -> FocusEventResult {
1412        FocusEventResult::FocusIgnored
1413    }
1414
1415    fn render(
1416        self: Pin<&Self>,
1417        _backend: &mut ItemRendererRef,
1418        _self_rc: &ItemRc,
1419        _size: LogicalSize,
1420    ) -> RenderingResult {
1421        RenderingResult::ContinueRenderingChildren
1422    }
1423
1424    fn bounding_rect(
1425        self: core::pin::Pin<&Self>,
1426        _window_adapter: &Rc<dyn WindowAdapter>,
1427        _self_rc: &ItemRc,
1428        geometry: LogicalRect,
1429    ) -> LogicalRect {
1430        geometry
1431    }
1432
1433    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
1434        false
1435    }
1436}
1437
1438impl ContextMenu {
1439    pub fn close(self: Pin<&Self>, window_adapter: &Rc<dyn WindowAdapter>, _: &ItemRc) {
1440        if let Some(id) = self.popup_id.take() {
1441            WindowInner::from_pub(window_adapter.window()).close_popup(id);
1442        }
1443    }
1444
1445    pub fn is_open(self: Pin<&Self>, window_adapter: &Rc<dyn WindowAdapter>, _: &ItemRc) -> bool {
1446        self.popup_id.get().is_some_and(|id| {
1447            WindowInner::from_pub(window_adapter.window())
1448                .active_popups()
1449                .iter()
1450                .any(|p| p.popup_id == id)
1451        })
1452    }
1453}
1454
1455impl ItemConsts for ContextMenu {
1456    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
1457        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
1458}
1459
1460declare_item_vtable! {
1461    fn slint_get_ContextMenuVTable() -> ContextMenuVTable for ContextMenu
1462}
1463
1464#[cfg(feature = "ffi")]
1465#[unsafe(no_mangle)]
1466pub unsafe extern "C" fn slint_contextmenu_close(
1467    s: Pin<&ContextMenu>,
1468    window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,
1469    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,
1470    self_index: u32,
1471) {
1472    let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);
1473    let self_rc = ItemRc::new(self_component.clone(), self_index);
1474    s.close(window_adapter, &self_rc);
1475}
1476
1477#[cfg(feature = "ffi")]
1478#[unsafe(no_mangle)]
1479pub unsafe extern "C" fn slint_contextmenu_is_open(
1480    s: Pin<&ContextMenu>,
1481    window_adapter: *const crate::window::ffi::WindowAdapterRcOpaque,
1482    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,
1483    self_index: u32,
1484) -> bool {
1485    let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);
1486    let self_rc = ItemRc::new(self_component.clone(), self_index);
1487    s.is_open(window_adapter, &self_rc)
1488}
1489
1490/// The implementation of the `BoxShadow` element
1491#[repr(C)]
1492#[derive(FieldOffsets, Default, SlintElement)]
1493#[pin]
1494pub struct BoxShadow {
1495    pub border_radius: Property<LogicalLength>,
1496    // Shadow specific properties
1497    pub offset_x: Property<LogicalLength>,
1498    pub offset_y: Property<LogicalLength>,
1499    pub color: Property<Color>,
1500    pub blur: Property<LogicalLength>,
1501    pub cached_rendering_data: CachedRenderingData,
1502}
1503
1504impl Item for BoxShadow {
1505    fn init(self: Pin<&Self>, _self_rc: &ItemRc) {}
1506
1507    fn layout_info(
1508        self: Pin<&Self>,
1509        _orientation: Orientation,
1510        _window_adapter: &Rc<dyn WindowAdapter>,
1511        _self_rc: &ItemRc,
1512    ) -> LayoutInfo {
1513        LayoutInfo { stretch: 1., ..LayoutInfo::default() }
1514    }
1515
1516    fn input_event_filter_before_children(
1517        self: Pin<&Self>,
1518        _: MouseEvent,
1519        _window_adapter: &Rc<dyn WindowAdapter>,
1520        _self_rc: &ItemRc,
1521    ) -> InputEventFilterResult {
1522        InputEventFilterResult::ForwardAndIgnore
1523    }
1524
1525    fn input_event(
1526        self: Pin<&Self>,
1527        _event: MouseEvent,
1528        _window_adapter: &Rc<dyn WindowAdapter>,
1529        _self_rc: &ItemRc,
1530    ) -> InputEventResult {
1531        InputEventResult::EventIgnored
1532    }
1533
1534    fn key_event(
1535        self: Pin<&Self>,
1536        _: &KeyEvent,
1537        _window_adapter: &Rc<dyn WindowAdapter>,
1538        _self_rc: &ItemRc,
1539    ) -> KeyEventResult {
1540        KeyEventResult::EventIgnored
1541    }
1542
1543    fn focus_event(
1544        self: Pin<&Self>,
1545        _: &FocusEvent,
1546        _window_adapter: &Rc<dyn WindowAdapter>,
1547        _self_rc: &ItemRc,
1548    ) -> FocusEventResult {
1549        FocusEventResult::FocusIgnored
1550    }
1551
1552    fn render(
1553        self: Pin<&Self>,
1554        backend: &mut ItemRendererRef,
1555        self_rc: &ItemRc,
1556        size: LogicalSize,
1557    ) -> RenderingResult {
1558        (*backend).draw_box_shadow(self, self_rc, size);
1559        RenderingResult::ContinueRenderingChildren
1560    }
1561
1562    fn bounding_rect(
1563        self: core::pin::Pin<&Self>,
1564        _window_adapter: &Rc<dyn WindowAdapter>,
1565        _self_rc: &ItemRc,
1566        geometry: LogicalRect,
1567    ) -> LogicalRect {
1568        geometry
1569            .outer_rect(euclid::SideOffsets2D::from_length_all_same(self.blur()))
1570            .translate(LogicalVector::from_lengths(self.offset_x(), self.offset_y()))
1571    }
1572
1573    fn clips_children(self: core::pin::Pin<&Self>) -> bool {
1574        false
1575    }
1576}
1577
1578impl ItemConsts for BoxShadow {
1579    const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> =
1580        Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
1581}
1582
1583declare_item_vtable! {
1584    fn slint_get_BoxShadowVTable() -> BoxShadowVTable for BoxShadow
1585}
1586
1587declare_item_vtable! {
1588    fn slint_get_ComponentContainerVTable() -> ComponentContainerVTable for ComponentContainer
1589}
1590
1591declare_item_vtable! {
1592    fn slint_get_ComplexTextVTable() -> ComplexTextVTable for ComplexText
1593}
1594
1595declare_item_vtable! {
1596    fn slint_get_SimpleTextVTable() -> SimpleTextVTable for SimpleText
1597}
1598
1599declare_item_vtable! {
1600    fn slint_get_TextInputVTable() -> TextInputVTable for TextInput
1601}
1602
1603declare_item_vtable! {
1604    fn slint_get_ImageItemVTable() -> ImageItemVTable for ImageItem
1605}
1606
1607declare_item_vtable! {
1608    fn slint_get_ClippedImageVTable() -> ClippedImageVTable for ClippedImage
1609}
1610
1611#[cfg(feature = "std")]
1612declare_item_vtable! {
1613    fn slint_get_PathVTable() -> PathVTable for Path
1614}
1615
1616declare_item_vtable! {
1617    fn slint_get_MenuItemVTable() -> MenuItemVTable for MenuItem
1618}
1619
1620macro_rules! declare_enums {
1621    ($( $(#[$enum_doc:meta])* enum $Name:ident { $( $(#[$value_doc:meta])* $Value:ident,)* })*) => {
1622        $(
1623            #[derive(Copy, Clone, Debug, PartialEq, Eq, strum::EnumString, strum::Display, Hash)]
1624            #[repr(u32)]
1625            #[strum(serialize_all = "kebab-case")]
1626            $(#[$enum_doc])*
1627            pub enum $Name {
1628                $( $(#[$value_doc])* $Value),*
1629            }
1630
1631            impl Default for $Name {
1632                fn default() -> Self {
1633                    // Always return the first value
1634                    ($(Self::$Value,)*).0
1635                }
1636            }
1637        )*
1638    };
1639}
1640
1641i_slint_common::for_each_enums!(declare_enums);
1642
1643macro_rules! declare_builtin_structs {
1644    ($(
1645        $(#[$struct_attr:meta])*
1646        struct $Name:ident {
1647            @name = $inner_name:literal
1648            export {
1649                $( $(#[$pub_attr:meta])* $pub_field:ident : $pub_type:ty, )*
1650            }
1651            private {
1652                $( $(#[$pri_attr:meta])* $pri_field:ident : $pri_type:ty, )*
1653            }
1654        }
1655    )*) => {
1656        $(
1657            #[derive(Clone, Debug, Default, PartialEq)]
1658            #[repr(C)]
1659            $(#[$struct_attr])*
1660            pub struct $Name {
1661                $(
1662                    $(#[$pub_attr])*
1663                    pub $pub_field : $pub_type,
1664                )*
1665                $(
1666                    $(#[$pri_attr])*
1667                    pub $pri_field : $pri_type,
1668                )*
1669            }
1670        )*
1671    };
1672}
1673
1674i_slint_common::for_each_builtin_structs!(declare_builtin_structs);
1675
1676#[cfg(feature = "ffi")]
1677#[unsafe(no_mangle)]
1678pub unsafe extern "C" fn slint_item_absolute_position(
1679    self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>,
1680    self_index: u32,
1681) -> crate::lengths::LogicalPoint {
1682    let self_rc = ItemRc::new(self_component.clone(), self_index);
1683    self_rc.map_to_window(Default::default())
1684}