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