i_slint_core/
items.rs

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