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