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