Skip to main content

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