1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
2 | // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial |
3 | |
4 | // cSpell: ignore nesw |
5 | |
6 | /*! |
7 | This module contains the builtin items, either in this file or in sub-modules. |
8 | |
9 | When 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_component.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 | |
23 | use crate::graphics::{Brush, Color, Point}; |
24 | use crate::input::{ |
25 | FocusEvent, FocusEventResult, InputEventFilterResult, InputEventResult, KeyEventResult, |
26 | KeyEventType, MouseEvent, |
27 | }; |
28 | use crate::item_rendering::{CachedRenderingData, RenderBorderRectangle}; |
29 | pub use crate::item_tree::ItemRc; |
30 | use crate::layout::LayoutInfo; |
31 | use crate::lengths::{ |
32 | LogicalBorderRadius, LogicalLength, LogicalPoint, LogicalRect, LogicalSize, LogicalVector, |
33 | PointLengths, RectLengths, |
34 | }; |
35 | #[cfg (feature = "rtti" )] |
36 | use crate::rtti::*; |
37 | use crate::window::{WindowAdapter, WindowAdapterRc, WindowInner}; |
38 | use crate::{Callback, Coord, Property, SharedString}; |
39 | use alloc::rc::Rc; |
40 | use const_field_offset::FieldOffsets; |
41 | use core::cell::Cell; |
42 | use core::pin::Pin; |
43 | use i_slint_core_macros::*; |
44 | use vtable::*; |
45 | |
46 | mod component_container; |
47 | pub use self::component_container::*; |
48 | mod flickable; |
49 | pub use flickable::*; |
50 | mod text; |
51 | pub use text::*; |
52 | mod image; |
53 | pub use self::image::*; |
54 | #[cfg (feature = "std" )] |
55 | mod path; |
56 | #[cfg (feature = "std" )] |
57 | pub use path::*; |
58 | |
59 | /// Alias for `&mut dyn ItemRenderer`. Required so cbindgen generates the ItemVTable |
60 | /// despite the presence of trait object |
61 | type ItemRendererRef<'a> = &'a mut dyn crate::item_rendering::ItemRenderer; |
62 | |
63 | /// Workarounds for cbindgen |
64 | pub type VoidArg = (); |
65 | pub type KeyEventArg = (KeyEvent,); |
66 | type PointerEventArg = (PointerEvent,); |
67 | type PointerScrollEventArg = (PointerScrollEvent,); |
68 | type PointArg = (Point,); |
69 | |
70 | #[cfg (all(feature = "ffi" , windows))] |
71 | #[macro_export ] |
72 | macro_rules! declare_item_vtable { |
73 | (fn $getter:ident() -> $item_vtable_ty:ident for $item_ty:ty) => { |
74 | ItemVTable_static! { |
75 | #[no_mangle] |
76 | pub static $item_vtable_ty for $item_ty |
77 | } |
78 | #[no_mangle] |
79 | pub extern "C" fn $getter() -> *const ItemVTable { |
80 | use vtable::HasStaticVTable; |
81 | <$item_ty>::static_vtable() |
82 | } |
83 | }; |
84 | } |
85 | #[cfg (not(all(feature = "ffi" , windows)))] |
86 | #[macro_export ] |
87 | macro_rules! declare_item_vtable { |
88 | (fn $getter:ident() -> $item_vtable_ty:ident for $item_ty:ty) => { |
89 | ItemVTable_static! { |
90 | #[no_mangle] |
91 | pub static $item_vtable_ty for $item_ty |
92 | } |
93 | }; |
94 | } |
95 | |
96 | /// Returned by the `render()` function on items to indicate whether the rendering of |
97 | /// children should be handled by the caller, of if the item took care of that (for example |
98 | /// through layer indirection) |
99 | #[repr (C)] |
100 | #[derive (Default)] |
101 | pub enum RenderingResult { |
102 | #[default] |
103 | ContinueRenderingChildren, |
104 | ContinueRenderingWithoutChildren, |
105 | } |
106 | |
107 | /// Items are the nodes in the render tree. |
108 | #[vtable ] |
109 | #[repr (C)] |
110 | pub struct ItemVTable { |
111 | /// This function is called by the run-time after the memory for the item |
112 | /// has been allocated and initialized. It will be called before any user specified |
113 | /// bindings are set. |
114 | pub init: extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, my_item: &ItemRc), |
115 | |
116 | /// offset in bytes from the *const ItemImpl. |
117 | /// isize::MAX means None |
118 | #[allow (non_upper_case_globals)] |
119 | #[field_offset(CachedRenderingData)] |
120 | pub cached_rendering_data_offset: usize, |
121 | |
122 | /// We would need max/min/preferred size, and all layout info |
123 | pub layout_info: extern "C" fn( |
124 | core::pin::Pin<VRef<ItemVTable>>, |
125 | orientation: Orientation, |
126 | window_adapter: &WindowAdapterRc, |
127 | ) -> LayoutInfo, |
128 | |
129 | /// Event handler for mouse and touch event. This function is called before being called on children. |
130 | /// Then, depending on the return value, it is called for the children, and their children, then |
131 | /// [`Self::input_event`] is called on the children, and finally [`Self::input_event`] is called |
132 | /// on this item again. |
133 | pub input_event_filter_before_children: extern "C" fn( |
134 | core::pin::Pin<VRef<ItemVTable>>, |
135 | MouseEvent, |
136 | window_adapter: &WindowAdapterRc, |
137 | self_rc: &ItemRc, |
138 | ) -> InputEventFilterResult, |
139 | |
140 | /// Handle input event for mouse and touch event |
141 | pub input_event: extern "C" fn( |
142 | core::pin::Pin<VRef<ItemVTable>>, |
143 | MouseEvent, |
144 | window_adapter: &WindowAdapterRc, |
145 | self_rc: &ItemRc, |
146 | ) -> InputEventResult, |
147 | |
148 | pub focus_event: extern "C" fn( |
149 | core::pin::Pin<VRef<ItemVTable>>, |
150 | &FocusEvent, |
151 | window_adapter: &WindowAdapterRc, |
152 | self_rc: &ItemRc, |
153 | ) -> FocusEventResult, |
154 | |
155 | pub key_event: extern "C" fn( |
156 | core::pin::Pin<VRef<ItemVTable>>, |
157 | &KeyEvent, |
158 | window_adapter: &WindowAdapterRc, |
159 | self_rc: &ItemRc, |
160 | ) -> KeyEventResult, |
161 | |
162 | pub render: extern "C" fn( |
163 | core::pin::Pin<VRef<ItemVTable>>, |
164 | backend: &mut ItemRendererRef, |
165 | self_rc: &ItemRc, |
166 | size: LogicalSize, |
167 | ) -> RenderingResult, |
168 | } |
169 | |
170 | /// Alias for `vtable::VRef<ItemVTable>` which represent a pointer to a `dyn Item` with |
171 | /// the associated vtable |
172 | pub type ItemRef<'a> = vtable::VRef<'a, ItemVTable>; |
173 | |
174 | #[repr (C)] |
175 | #[derive (FieldOffsets, Default, SlintElement)] |
176 | #[pin] |
177 | /// The implementation of an empty items that does nothing |
178 | pub struct Empty { |
179 | pub cached_rendering_data: CachedRenderingData, |
180 | } |
181 | |
182 | impl Item for Empty { |
183 | fn init(self: Pin<&Self>, _self_rc: &ItemRc) {} |
184 | |
185 | fn layout_info( |
186 | self: Pin<&Self>, |
187 | _orientation: Orientation, |
188 | _window_adapter: &Rc<dyn WindowAdapter>, |
189 | ) -> LayoutInfo { |
190 | LayoutInfo { stretch: 1., ..LayoutInfo::default() } |
191 | } |
192 | |
193 | fn input_event_filter_before_children( |
194 | self: Pin<&Self>, |
195 | _: MouseEvent, |
196 | _window_adapter: &Rc<dyn WindowAdapter>, |
197 | _self_rc: &ItemRc, |
198 | ) -> InputEventFilterResult { |
199 | InputEventFilterResult::ForwardAndIgnore |
200 | } |
201 | |
202 | fn input_event( |
203 | self: Pin<&Self>, |
204 | _: MouseEvent, |
205 | _window_adapter: &Rc<dyn WindowAdapter>, |
206 | _self_rc: &ItemRc, |
207 | ) -> InputEventResult { |
208 | InputEventResult::EventIgnored |
209 | } |
210 | |
211 | fn key_event( |
212 | self: Pin<&Self>, |
213 | _: &KeyEvent, |
214 | _window_adapter: &Rc<dyn WindowAdapter>, |
215 | _self_rc: &ItemRc, |
216 | ) -> KeyEventResult { |
217 | KeyEventResult::EventIgnored |
218 | } |
219 | |
220 | fn focus_event( |
221 | self: Pin<&Self>, |
222 | _: &FocusEvent, |
223 | _window_adapter: &Rc<dyn WindowAdapter>, |
224 | _self_rc: &ItemRc, |
225 | ) -> FocusEventResult { |
226 | FocusEventResult::FocusIgnored |
227 | } |
228 | |
229 | fn render( |
230 | self: Pin<&Self>, |
231 | _backend: &mut ItemRendererRef, |
232 | _self_rc: &ItemRc, |
233 | _size: LogicalSize, |
234 | ) -> RenderingResult { |
235 | RenderingResult::ContinueRenderingChildren |
236 | } |
237 | } |
238 | |
239 | impl ItemConsts for Empty { |
240 | const cached_rendering_data_offset: const_field_offset::FieldOffset< |
241 | Empty, |
242 | CachedRenderingData, |
243 | > = Empty::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection(); |
244 | } |
245 | |
246 | declare_item_vtable! { |
247 | fn slint_get_EmptyVTable() -> EmptyVTable for Empty |
248 | } |
249 | |
250 | #[repr (C)] |
251 | #[derive (FieldOffsets, Default, SlintElement)] |
252 | #[pin] |
253 | /// The implementation of the `Rectangle` element |
254 | pub struct Rectangle { |
255 | pub background: Property<Brush>, |
256 | pub cached_rendering_data: CachedRenderingData, |
257 | } |
258 | |
259 | impl Item for Rectangle { |
260 | fn init(self: Pin<&Self>, _self_rc: &ItemRc) {} |
261 | |
262 | fn layout_info( |
263 | self: Pin<&Self>, |
264 | _orientation: Orientation, |
265 | _window_adapter: &Rc<dyn WindowAdapter>, |
266 | ) -> LayoutInfo { |
267 | LayoutInfo { stretch: 1., ..LayoutInfo::default() } |
268 | } |
269 | |
270 | fn input_event_filter_before_children( |
271 | self: Pin<&Self>, |
272 | _: MouseEvent, |
273 | _window_adapter: &Rc<dyn WindowAdapter>, |
274 | _self_rc: &ItemRc, |
275 | ) -> InputEventFilterResult { |
276 | InputEventFilterResult::ForwardAndIgnore |
277 | } |
278 | |
279 | fn input_event( |
280 | self: Pin<&Self>, |
281 | _: MouseEvent, |
282 | _window_adapter: &Rc<dyn WindowAdapter>, |
283 | _self_rc: &ItemRc, |
284 | ) -> InputEventResult { |
285 | InputEventResult::EventIgnored |
286 | } |
287 | |
288 | fn key_event( |
289 | self: Pin<&Self>, |
290 | _: &KeyEvent, |
291 | _window_adapter: &Rc<dyn WindowAdapter>, |
292 | _self_rc: &ItemRc, |
293 | ) -> KeyEventResult { |
294 | KeyEventResult::EventIgnored |
295 | } |
296 | |
297 | fn focus_event( |
298 | self: Pin<&Self>, |
299 | _: &FocusEvent, |
300 | _window_adapter: &Rc<dyn WindowAdapter>, |
301 | _self_rc: &ItemRc, |
302 | ) -> FocusEventResult { |
303 | FocusEventResult::FocusIgnored |
304 | } |
305 | |
306 | fn render( |
307 | self: Pin<&Self>, |
308 | backend: &mut ItemRendererRef, |
309 | self_rc: &ItemRc, |
310 | size: LogicalSize, |
311 | ) -> RenderingResult { |
312 | (*backend).draw_rectangle(self, self_rc, size); |
313 | RenderingResult::ContinueRenderingChildren |
314 | } |
315 | } |
316 | |
317 | impl ItemConsts for Rectangle { |
318 | const cached_rendering_data_offset: const_field_offset::FieldOffset< |
319 | Rectangle, |
320 | CachedRenderingData, |
321 | > = Rectangle::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection(); |
322 | } |
323 | |
324 | declare_item_vtable! { |
325 | fn slint_get_RectangleVTable() -> RectangleVTable for Rectangle |
326 | } |
327 | |
328 | #[repr (C)] |
329 | #[derive (FieldOffsets, Default, SlintElement)] |
330 | #[pin] |
331 | /// The implementation of the `BasicBorderRectangle` element |
332 | pub struct BasicBorderRectangle { |
333 | pub background: Property<Brush>, |
334 | pub border_width: Property<LogicalLength>, |
335 | pub border_radius: Property<LogicalLength>, |
336 | pub border_color: Property<Brush>, |
337 | pub cached_rendering_data: CachedRenderingData, |
338 | } |
339 | |
340 | impl Item for BasicBorderRectangle { |
341 | fn init(self: Pin<&Self>, _self_rc: &ItemRc) {} |
342 | |
343 | fn layout_info( |
344 | self: Pin<&Self>, |
345 | _orientation: Orientation, |
346 | _window_adapter: &Rc<dyn WindowAdapter>, |
347 | ) -> LayoutInfo { |
348 | LayoutInfo { stretch: 1., ..LayoutInfo::default() } |
349 | } |
350 | |
351 | fn input_event_filter_before_children( |
352 | self: Pin<&Self>, |
353 | _: MouseEvent, |
354 | _window_adapter: &Rc<dyn WindowAdapter>, |
355 | _self_rc: &ItemRc, |
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 | ) -> InputEventResult { |
366 | InputEventResult::EventIgnored |
367 | } |
368 | |
369 | fn key_event( |
370 | self: Pin<&Self>, |
371 | _: &KeyEvent, |
372 | _window_adapter: &Rc<dyn WindowAdapter>, |
373 | _self_rc: &ItemRc, |
374 | ) -> KeyEventResult { |
375 | KeyEventResult::EventIgnored |
376 | } |
377 | |
378 | fn focus_event( |
379 | self: Pin<&Self>, |
380 | _: &FocusEvent, |
381 | _window_adapter: &Rc<dyn WindowAdapter>, |
382 | _self_rc: &ItemRc, |
383 | ) -> FocusEventResult { |
384 | FocusEventResult::FocusIgnored |
385 | } |
386 | |
387 | fn render( |
388 | self: Pin<&Self>, |
389 | backend: &mut ItemRendererRef, |
390 | self_rc: &ItemRc, |
391 | size: LogicalSize, |
392 | ) -> RenderingResult { |
393 | (*backend).draw_border_rectangle(self, self_rc, size, &self.cached_rendering_data); |
394 | RenderingResult::ContinueRenderingChildren |
395 | } |
396 | } |
397 | |
398 | impl RenderBorderRectangle for BasicBorderRectangle { |
399 | fn background(self: Pin<&Self>) -> Brush { |
400 | self.background() |
401 | } |
402 | fn border_width(self: Pin<&Self>) -> LogicalLength { |
403 | self.border_width() |
404 | } |
405 | fn border_radius(self: Pin<&Self>) -> LogicalBorderRadius { |
406 | LogicalBorderRadius::from_length(self.border_radius()) |
407 | } |
408 | fn border_color(self: Pin<&Self>) -> Brush { |
409 | self.border_color() |
410 | } |
411 | } |
412 | |
413 | impl ItemConsts for BasicBorderRectangle { |
414 | const cached_rendering_data_offset: const_field_offset::FieldOffset< |
415 | BasicBorderRectangle, |
416 | CachedRenderingData, |
417 | > = BasicBorderRectangle::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection(); |
418 | } |
419 | |
420 | declare_item_vtable! { |
421 | fn slint_get_BasicBorderRectangleVTable() -> BasicBorderRectangleVTable for BasicBorderRectangle |
422 | } |
423 | |
424 | #[repr (C)] |
425 | #[derive (FieldOffsets, Default, SlintElement)] |
426 | #[pin] |
427 | /// The implementation of the `BorderRectangle` element |
428 | pub struct BorderRectangle { |
429 | pub background: Property<Brush>, |
430 | pub border_width: Property<LogicalLength>, |
431 | pub border_radius: Property<LogicalLength>, |
432 | pub border_top_left_radius: Property<LogicalLength>, |
433 | pub border_top_right_radius: Property<LogicalLength>, |
434 | pub border_bottom_left_radius: Property<LogicalLength>, |
435 | pub border_bottom_right_radius: Property<LogicalLength>, |
436 | pub border_color: Property<Brush>, |
437 | pub cached_rendering_data: CachedRenderingData, |
438 | } |
439 | |
440 | impl Item for BorderRectangle { |
441 | fn init(self: Pin<&Self>, _self_rc: &ItemRc) {} |
442 | |
443 | fn layout_info( |
444 | self: Pin<&Self>, |
445 | _orientation: Orientation, |
446 | _window_adapter: &Rc<dyn WindowAdapter>, |
447 | ) -> LayoutInfo { |
448 | LayoutInfo { stretch: 1., ..LayoutInfo::default() } |
449 | } |
450 | |
451 | fn input_event_filter_before_children( |
452 | self: Pin<&Self>, |
453 | _: MouseEvent, |
454 | _window_adapter: &Rc<dyn WindowAdapter>, |
455 | _self_rc: &ItemRc, |
456 | ) -> InputEventFilterResult { |
457 | InputEventFilterResult::ForwardAndIgnore |
458 | } |
459 | |
460 | fn input_event( |
461 | self: Pin<&Self>, |
462 | _: MouseEvent, |
463 | _window_adapter: &Rc<dyn WindowAdapter>, |
464 | _self_rc: &ItemRc, |
465 | ) -> InputEventResult { |
466 | InputEventResult::EventIgnored |
467 | } |
468 | |
469 | fn key_event( |
470 | self: Pin<&Self>, |
471 | _: &KeyEvent, |
472 | _window_adapter: &Rc<dyn WindowAdapter>, |
473 | _self_rc: &ItemRc, |
474 | ) -> KeyEventResult { |
475 | KeyEventResult::EventIgnored |
476 | } |
477 | |
478 | fn focus_event( |
479 | self: Pin<&Self>, |
480 | _: &FocusEvent, |
481 | _window_adapter: &Rc<dyn WindowAdapter>, |
482 | _self_rc: &ItemRc, |
483 | ) -> FocusEventResult { |
484 | FocusEventResult::FocusIgnored |
485 | } |
486 | |
487 | fn render( |
488 | self: Pin<&Self>, |
489 | backend: &mut ItemRendererRef, |
490 | self_rc: &ItemRc, |
491 | size: LogicalSize, |
492 | ) -> RenderingResult { |
493 | (*backend).draw_border_rectangle(self, self_rc, size, &self.cached_rendering_data); |
494 | RenderingResult::ContinueRenderingChildren |
495 | } |
496 | } |
497 | |
498 | impl RenderBorderRectangle for BorderRectangle { |
499 | fn background(self: Pin<&Self>) -> Brush { |
500 | self.background() |
501 | } |
502 | fn border_width(self: Pin<&Self>) -> LogicalLength { |
503 | self.border_width() |
504 | } |
505 | fn border_radius(self: Pin<&Self>) -> LogicalBorderRadius { |
506 | LogicalBorderRadius::from_lengths( |
507 | self.border_top_left_radius(), |
508 | self.border_top_right_radius(), |
509 | self.border_bottom_right_radius(), |
510 | self.border_bottom_left_radius(), |
511 | ) |
512 | } |
513 | fn border_color(self: Pin<&Self>) -> Brush { |
514 | self.border_color() |
515 | } |
516 | } |
517 | |
518 | impl ItemConsts for BorderRectangle { |
519 | const cached_rendering_data_offset: const_field_offset::FieldOffset< |
520 | BorderRectangle, |
521 | CachedRenderingData, |
522 | > = BorderRectangle::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection(); |
523 | } |
524 | |
525 | declare_item_vtable! { |
526 | fn slint_get_BorderRectangleVTable() -> BorderRectangleVTable for BorderRectangle |
527 | } |
528 | |
529 | /// The implementation of the `TouchArea` element |
530 | #[repr (C)] |
531 | #[derive (FieldOffsets, SlintElement, Default)] |
532 | #[pin] |
533 | pub struct TouchArea { |
534 | pub enabled: Property<bool>, |
535 | /// FIXME: We should annotate this as an "output" property. |
536 | pub pressed: Property<bool>, |
537 | pub has_hover: Property<bool>, |
538 | /// FIXME: there should be just one property for the point instead of two. |
539 | /// Could even be merged with pressed in a `Property<Option<Point>>` (of course, in the |
540 | /// implementation item only, for the compiler it would stay separate properties) |
541 | pub pressed_x: Property<LogicalLength>, |
542 | pub pressed_y: Property<LogicalLength>, |
543 | /// FIXME: should maybe be as parameter to the mouse event instead. Or at least just one property |
544 | pub mouse_x: Property<LogicalLength>, |
545 | pub mouse_y: Property<LogicalLength>, |
546 | pub mouse_cursor: Property<MouseCursor>, |
547 | pub clicked: Callback<VoidArg>, |
548 | pub double_clicked: Callback<VoidArg>, |
549 | pub moved: Callback<VoidArg>, |
550 | pub pointer_event: Callback<PointerEventArg>, |
551 | pub scroll_event: Callback<PointerScrollEventArg, EventResult>, |
552 | /// FIXME: remove this |
553 | pub cached_rendering_data: CachedRenderingData, |
554 | /// true when we are currently grabbing the mouse |
555 | grabbed: Cell<bool>, |
556 | } |
557 | |
558 | impl Item for TouchArea { |
559 | fn init(self: Pin<&Self>, _self_rc: &ItemRc) {} |
560 | |
561 | fn layout_info( |
562 | self: Pin<&Self>, |
563 | _orientation: Orientation, |
564 | _window_adapter: &Rc<dyn WindowAdapter>, |
565 | ) -> LayoutInfo { |
566 | LayoutInfo { stretch: 1., ..LayoutInfo::default() } |
567 | } |
568 | |
569 | fn input_event_filter_before_children( |
570 | self: Pin<&Self>, |
571 | event: MouseEvent, |
572 | window_adapter: &Rc<dyn WindowAdapter>, |
573 | _self_rc: &ItemRc, |
574 | ) -> InputEventFilterResult { |
575 | if !self.enabled() { |
576 | return InputEventFilterResult::ForwardAndIgnore; |
577 | } |
578 | if let Some(pos) = event.position() { |
579 | Self::FIELD_OFFSETS.mouse_x.apply_pin(self).set(pos.x_length()); |
580 | Self::FIELD_OFFSETS.mouse_y.apply_pin(self).set(pos.y_length()); |
581 | } |
582 | let hovering = !matches!(event, MouseEvent::Exit); |
583 | Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(hovering); |
584 | if hovering { |
585 | if let Some(x) = window_adapter.internal(crate::InternalToken) { |
586 | x.set_mouse_cursor(self.mouse_cursor()); |
587 | } |
588 | } |
589 | InputEventFilterResult::ForwardAndInterceptGrab |
590 | } |
591 | |
592 | fn input_event( |
593 | self: Pin<&Self>, |
594 | event: MouseEvent, |
595 | window_adapter: &Rc<dyn WindowAdapter>, |
596 | self_rc: &ItemRc, |
597 | ) -> InputEventResult { |
598 | if matches!(event, MouseEvent::Exit) { |
599 | Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(false); |
600 | if let Some(x) = window_adapter.internal(crate::InternalToken) { |
601 | x.set_mouse_cursor(MouseCursor::Default); |
602 | } |
603 | } |
604 | if !self.enabled() { |
605 | return InputEventResult::EventIgnored; |
606 | } |
607 | |
608 | match event { |
609 | MouseEvent::Pressed { position, button, .. } => { |
610 | self.grabbed.set(true); |
611 | if button == PointerEventButton::Left { |
612 | Self::FIELD_OFFSETS.pressed_x.apply_pin(self).set(position.x_length()); |
613 | Self::FIELD_OFFSETS.pressed_y.apply_pin(self).set(position.y_length()); |
614 | Self::FIELD_OFFSETS.pressed.apply_pin(self).set(true); |
615 | } |
616 | Self::FIELD_OFFSETS.pointer_event.apply_pin(self).call(&(PointerEvent { |
617 | button, |
618 | kind: PointerEventKind::Down, |
619 | modifiers: window_adapter.window().0.modifiers.get().into(), |
620 | },)); |
621 | |
622 | InputEventResult::GrabMouse |
623 | } |
624 | MouseEvent::Exit => { |
625 | Self::FIELD_OFFSETS.pressed.apply_pin(self).set(false); |
626 | if self.grabbed.replace(false) { |
627 | Self::FIELD_OFFSETS.pointer_event.apply_pin(self).call(&(PointerEvent { |
628 | button: PointerEventButton::Other, |
629 | kind: PointerEventKind::Cancel, |
630 | modifiers: window_adapter.window().0.modifiers.get().into(), |
631 | },)); |
632 | } |
633 | |
634 | InputEventResult::EventAccepted |
635 | } |
636 | |
637 | MouseEvent::Released { button, position, click_count } => { |
638 | let geometry = self_rc.geometry(); |
639 | if button == PointerEventButton::Left |
640 | && LogicalRect::new(LogicalPoint::default(), geometry.size).contains(position) |
641 | && self.pressed() |
642 | { |
643 | Self::FIELD_OFFSETS.clicked.apply_pin(self).call(&()); |
644 | if (click_count % 2) == 1 { |
645 | Self::FIELD_OFFSETS.double_clicked.apply_pin(self).call(&()) |
646 | } |
647 | } |
648 | |
649 | self.grabbed.set(false); |
650 | if button == PointerEventButton::Left { |
651 | Self::FIELD_OFFSETS.pressed.apply_pin(self).set(false); |
652 | } |
653 | Self::FIELD_OFFSETS.pointer_event.apply_pin(self).call(&(PointerEvent { |
654 | button, |
655 | kind: PointerEventKind::Up, |
656 | modifiers: window_adapter.window().0.modifiers.get().into(), |
657 | },)); |
658 | |
659 | InputEventResult::EventAccepted |
660 | } |
661 | MouseEvent::Moved { .. } => { |
662 | Self::FIELD_OFFSETS.pointer_event.apply_pin(self).call(&(PointerEvent { |
663 | button: PointerEventButton::Other, |
664 | kind: PointerEventKind::Move, |
665 | modifiers: window_adapter.window().0.modifiers.get().into(), |
666 | },)); |
667 | return if self.grabbed.get() { |
668 | Self::FIELD_OFFSETS.moved.apply_pin(self).call(&()); |
669 | InputEventResult::GrabMouse |
670 | } else { |
671 | InputEventResult::EventAccepted |
672 | }; |
673 | } |
674 | MouseEvent::Wheel { delta_x, delta_y, .. } => { |
675 | let modifiers = window_adapter.window().0.modifiers.get().into(); |
676 | let r = Self::FIELD_OFFSETS |
677 | .scroll_event |
678 | .apply_pin(self) |
679 | .call(&(PointerScrollEvent { delta_x, delta_y, modifiers },)); |
680 | if self.grabbed.get() { |
681 | InputEventResult::GrabMouse |
682 | } else { |
683 | match r { |
684 | EventResult::Reject => { |
685 | // We are ignoring the event, so we will be removed from the item_stack, |
686 | // therefore we must remove the has_hover flag as there might be a scroll under us. |
687 | // It will be put back later. |
688 | Self::FIELD_OFFSETS.has_hover.apply_pin(self).set(false); |
689 | InputEventResult::EventIgnored |
690 | } |
691 | EventResult::Accept => InputEventResult::EventAccepted, |
692 | } |
693 | } |
694 | } |
695 | } |
696 | } |
697 | |
698 | fn key_event( |
699 | self: Pin<&Self>, |
700 | _: &KeyEvent, |
701 | _window_adapter: &Rc<dyn WindowAdapter>, |
702 | _self_rc: &ItemRc, |
703 | ) -> KeyEventResult { |
704 | KeyEventResult::EventIgnored |
705 | } |
706 | |
707 | fn focus_event( |
708 | self: Pin<&Self>, |
709 | _: &FocusEvent, |
710 | _window_adapter: &Rc<dyn WindowAdapter>, |
711 | _self_rc: &ItemRc, |
712 | ) -> FocusEventResult { |
713 | FocusEventResult::FocusIgnored |
714 | } |
715 | |
716 | fn render( |
717 | self: Pin<&Self>, |
718 | _backend: &mut ItemRendererRef, |
719 | _self_rc: &ItemRc, |
720 | _size: LogicalSize, |
721 | ) -> RenderingResult { |
722 | RenderingResult::ContinueRenderingChildren |
723 | } |
724 | } |
725 | |
726 | impl ItemConsts for TouchArea { |
727 | const cached_rendering_data_offset: const_field_offset::FieldOffset< |
728 | TouchArea, |
729 | CachedRenderingData, |
730 | > = TouchArea::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection(); |
731 | } |
732 | |
733 | declare_item_vtable! { |
734 | fn slint_get_TouchAreaVTable() -> TouchAreaVTable for TouchArea |
735 | } |
736 | |
737 | /// A runtime item that exposes key |
738 | #[repr (C)] |
739 | #[derive (FieldOffsets, Default, SlintElement)] |
740 | #[pin] |
741 | pub struct FocusScope { |
742 | pub enabled: Property<bool>, |
743 | pub has_focus: Property<bool>, |
744 | pub key_pressed: Callback<KeyEventArg, EventResult>, |
745 | pub key_released: Callback<KeyEventArg, EventResult>, |
746 | pub focus_changed_event: Callback<VoidArg>, |
747 | /// FIXME: remove this |
748 | pub cached_rendering_data: CachedRenderingData, |
749 | } |
750 | |
751 | impl Item for FocusScope { |
752 | fn init(self: Pin<&Self>, _self_rc: &ItemRc) {} |
753 | |
754 | fn layout_info( |
755 | self: Pin<&Self>, |
756 | _orientation: Orientation, |
757 | _window_adapter: &Rc<dyn WindowAdapter>, |
758 | ) -> LayoutInfo { |
759 | LayoutInfo { stretch: 1., ..LayoutInfo::default() } |
760 | } |
761 | |
762 | fn input_event_filter_before_children( |
763 | self: Pin<&Self>, |
764 | _: MouseEvent, |
765 | _window_adapter: &Rc<dyn WindowAdapter>, |
766 | _self_rc: &ItemRc, |
767 | ) -> InputEventFilterResult { |
768 | InputEventFilterResult::ForwardEvent |
769 | } |
770 | |
771 | fn input_event( |
772 | self: Pin<&Self>, |
773 | event: MouseEvent, |
774 | window_adapter: &Rc<dyn WindowAdapter>, |
775 | self_rc: &ItemRc, |
776 | ) -> InputEventResult { |
777 | if self.enabled() && matches!(event, MouseEvent::Pressed { .. }) && !self.has_focus() { |
778 | WindowInner::from_pub(window_adapter.window()).set_focus_item(self_rc); |
779 | InputEventResult::EventAccepted |
780 | } else { |
781 | InputEventResult::EventIgnored |
782 | } |
783 | } |
784 | |
785 | fn key_event( |
786 | self: Pin<&Self>, |
787 | event: &KeyEvent, |
788 | _window_adapter: &Rc<dyn WindowAdapter>, |
789 | _self_rc: &ItemRc, |
790 | ) -> KeyEventResult { |
791 | let r = match event.event_type { |
792 | KeyEventType::KeyPressed => { |
793 | Self::FIELD_OFFSETS.key_pressed.apply_pin(self).call(&(event.clone(),)) |
794 | } |
795 | KeyEventType::KeyReleased => { |
796 | Self::FIELD_OFFSETS.key_released.apply_pin(self).call(&(event.clone(),)) |
797 | } |
798 | KeyEventType::UpdateComposition | KeyEventType::CommitComposition => { |
799 | EventResult::Reject |
800 | } |
801 | }; |
802 | match r { |
803 | EventResult::Accept => KeyEventResult::EventAccepted, |
804 | EventResult::Reject => KeyEventResult::EventIgnored, |
805 | } |
806 | } |
807 | |
808 | fn focus_event( |
809 | self: Pin<&Self>, |
810 | event: &FocusEvent, |
811 | _window_adapter: &Rc<dyn WindowAdapter>, |
812 | _self_rc: &ItemRc, |
813 | ) -> FocusEventResult { |
814 | if !self.enabled() { |
815 | return FocusEventResult::FocusIgnored; |
816 | } |
817 | |
818 | match event { |
819 | FocusEvent::FocusIn | FocusEvent::WindowReceivedFocus => { |
820 | self.has_focus.set(true); |
821 | Self::FIELD_OFFSETS.focus_changed_event.apply_pin(self).call(&()); |
822 | } |
823 | FocusEvent::FocusOut | FocusEvent::WindowLostFocus => { |
824 | self.has_focus.set(false); |
825 | Self::FIELD_OFFSETS.focus_changed_event.apply_pin(self).call(&()); |
826 | } |
827 | } |
828 | FocusEventResult::FocusAccepted |
829 | } |
830 | |
831 | fn render( |
832 | self: Pin<&Self>, |
833 | _backend: &mut ItemRendererRef, |
834 | _self_rc: &ItemRc, |
835 | _size: LogicalSize, |
836 | ) -> RenderingResult { |
837 | RenderingResult::ContinueRenderingChildren |
838 | } |
839 | } |
840 | |
841 | impl ItemConsts for FocusScope { |
842 | const cached_rendering_data_offset: const_field_offset::FieldOffset< |
843 | FocusScope, |
844 | CachedRenderingData, |
845 | > = FocusScope::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection(); |
846 | } |
847 | |
848 | declare_item_vtable! { |
849 | fn slint_get_FocusScopeVTable() -> FocusScopeVTable for FocusScope |
850 | } |
851 | |
852 | #[repr (C)] |
853 | #[derive (FieldOffsets, Default, SlintElement)] |
854 | #[pin] |
855 | /// The implementation of the `Clip` element |
856 | pub struct Clip { |
857 | pub border_top_left_radius: Property<LogicalLength>, |
858 | pub border_top_right_radius: Property<LogicalLength>, |
859 | pub border_bottom_left_radius: Property<LogicalLength>, |
860 | pub border_bottom_right_radius: Property<LogicalLength>, |
861 | pub border_width: Property<LogicalLength>, |
862 | pub cached_rendering_data: CachedRenderingData, |
863 | pub clip: Property<bool>, |
864 | } |
865 | |
866 | impl Item for Clip { |
867 | fn init(self: Pin<&Self>, _self_rc: &ItemRc) {} |
868 | |
869 | fn layout_info( |
870 | self: Pin<&Self>, |
871 | _orientation: Orientation, |
872 | _window_adapter: &Rc<dyn WindowAdapter>, |
873 | ) -> LayoutInfo { |
874 | LayoutInfo { stretch: 1., ..LayoutInfo::default() } |
875 | } |
876 | |
877 | fn input_event_filter_before_children( |
878 | self: Pin<&Self>, |
879 | event: MouseEvent, |
880 | _window_adapter: &Rc<dyn WindowAdapter>, |
881 | self_rc: &ItemRc, |
882 | ) -> InputEventFilterResult { |
883 | if let Some(pos) = event.position() { |
884 | let geometry = self_rc.geometry(); |
885 | if self.clip() |
886 | && (pos.x < 0 as Coord |
887 | || pos.y < 0 as Coord |
888 | || pos.x_length() > geometry.width_length() |
889 | || pos.y_length() > geometry.height_length()) |
890 | { |
891 | return InputEventFilterResult::Intercept; |
892 | } |
893 | } |
894 | InputEventFilterResult::ForwardAndIgnore |
895 | } |
896 | |
897 | fn input_event( |
898 | self: Pin<&Self>, |
899 | _: MouseEvent, |
900 | _window_adapter: &Rc<dyn WindowAdapter>, |
901 | _self_rc: &ItemRc, |
902 | ) -> InputEventResult { |
903 | InputEventResult::EventIgnored |
904 | } |
905 | |
906 | fn key_event( |
907 | self: Pin<&Self>, |
908 | _: &KeyEvent, |
909 | _window_adapter: &Rc<dyn WindowAdapter>, |
910 | _self_rc: &ItemRc, |
911 | ) -> KeyEventResult { |
912 | KeyEventResult::EventIgnored |
913 | } |
914 | |
915 | fn focus_event( |
916 | self: Pin<&Self>, |
917 | _: &FocusEvent, |
918 | _window_adapter: &Rc<dyn WindowAdapter>, |
919 | _self_rc: &ItemRc, |
920 | ) -> FocusEventResult { |
921 | FocusEventResult::FocusIgnored |
922 | } |
923 | |
924 | fn render( |
925 | self: Pin<&Self>, |
926 | backend: &mut ItemRendererRef, |
927 | self_rc: &ItemRc, |
928 | size: LogicalSize, |
929 | ) -> RenderingResult { |
930 | (*backend).visit_clip(self, self_rc, size) |
931 | } |
932 | } |
933 | |
934 | impl Clip { |
935 | pub fn logical_border_radius(self: Pin<&Self>) -> LogicalBorderRadius { |
936 | LogicalBorderRadius::from_lengths( |
937 | self.border_top_left_radius(), |
938 | self.border_top_right_radius(), |
939 | self.border_bottom_right_radius(), |
940 | self.border_bottom_left_radius(), |
941 | ) |
942 | } |
943 | } |
944 | |
945 | impl ItemConsts for Clip { |
946 | const cached_rendering_data_offset: const_field_offset::FieldOffset<Clip, CachedRenderingData> = |
947 | Clip::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection(); |
948 | } |
949 | |
950 | declare_item_vtable! { |
951 | fn slint_get_ClipVTable() -> ClipVTable for Clip |
952 | } |
953 | |
954 | #[repr (C)] |
955 | #[derive (FieldOffsets, Default, SlintElement)] |
956 | #[pin] |
957 | /// The Opacity Item is not meant to be used directly by the .slint code, instead, the `opacity: xxx` or `visible: false` should be used |
958 | pub struct Opacity { |
959 | // FIXME: this element shouldn't need these geometry property |
960 | pub opacity: Property<f32>, |
961 | pub cached_rendering_data: CachedRenderingData, |
962 | } |
963 | |
964 | impl Item for Opacity { |
965 | fn init(self: Pin<&Self>, _self_rc: &ItemRc) {} |
966 | |
967 | fn layout_info( |
968 | self: Pin<&Self>, |
969 | _orientation: Orientation, |
970 | _window_adapter: &Rc<dyn WindowAdapter>, |
971 | ) -> LayoutInfo { |
972 | LayoutInfo { stretch: 1., ..LayoutInfo::default() } |
973 | } |
974 | |
975 | fn input_event_filter_before_children( |
976 | self: Pin<&Self>, |
977 | _: MouseEvent, |
978 | _window_adapter: &Rc<dyn WindowAdapter>, |
979 | _self_rc: &ItemRc, |
980 | ) -> InputEventFilterResult { |
981 | InputEventFilterResult::ForwardAndIgnore |
982 | } |
983 | |
984 | fn input_event( |
985 | self: Pin<&Self>, |
986 | _: MouseEvent, |
987 | _window_adapter: &Rc<dyn WindowAdapter>, |
988 | _self_rc: &ItemRc, |
989 | ) -> InputEventResult { |
990 | InputEventResult::EventIgnored |
991 | } |
992 | |
993 | fn key_event( |
994 | self: Pin<&Self>, |
995 | _: &KeyEvent, |
996 | _window_adapter: &Rc<dyn WindowAdapter>, |
997 | _self_rc: &ItemRc, |
998 | ) -> KeyEventResult { |
999 | KeyEventResult::EventIgnored |
1000 | } |
1001 | |
1002 | fn focus_event( |
1003 | self: Pin<&Self>, |
1004 | _: &FocusEvent, |
1005 | _window_adapter: &Rc<dyn WindowAdapter>, |
1006 | _self_rc: &ItemRc, |
1007 | ) -> FocusEventResult { |
1008 | FocusEventResult::FocusIgnored |
1009 | } |
1010 | |
1011 | fn render( |
1012 | self: Pin<&Self>, |
1013 | backend: &mut ItemRendererRef, |
1014 | self_rc: &ItemRc, |
1015 | size: LogicalSize, |
1016 | ) -> RenderingResult { |
1017 | backend.visit_opacity(self, self_rc, size) |
1018 | } |
1019 | } |
1020 | |
1021 | impl Opacity { |
1022 | // This function determines the optimization opportunities for not having to render the |
1023 | // children of the Opacity element into a layer: |
1024 | // * The opacity item typically only one child (this is not guaranteed). If that item has |
1025 | // no children, then we can skip the layer and apply the opacity directly. This is not perfect though, |
1026 | // for example if the compiler inserts another synthetic element between the `Opacity` and the actual child, |
1027 | // then this check will apply a layer even though it might not actually be necessary. |
1028 | // * If the vale of the opacity is 1.0 then we don't need to do anything. |
1029 | pub fn need_layer(self_rc: &ItemRc, opacity: f32) -> bool { |
1030 | if opacity == 1.0 { |
1031 | return false; |
1032 | } |
1033 | |
1034 | let opacity_child = match self_rc.first_child() { |
1035 | Some(first_child) => first_child, |
1036 | None => return false, // No children? Don't need a layer then. |
1037 | }; |
1038 | |
1039 | if opacity_child.next_sibling().is_some() { |
1040 | return true; // If the opacity item has more than one child, then we need a layer |
1041 | } |
1042 | |
1043 | // If the target of the opacity has any children then we need a layer |
1044 | opacity_child.first_child().is_some() |
1045 | } |
1046 | } |
1047 | |
1048 | impl ItemConsts for Opacity { |
1049 | const cached_rendering_data_offset: const_field_offset::FieldOffset< |
1050 | Opacity, |
1051 | CachedRenderingData, |
1052 | > = Opacity::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection(); |
1053 | } |
1054 | |
1055 | declare_item_vtable! { |
1056 | fn slint_get_OpacityVTable() -> OpacityVTable for Opacity |
1057 | } |
1058 | |
1059 | #[repr (C)] |
1060 | #[derive (FieldOffsets, Default, SlintElement)] |
1061 | #[pin] |
1062 | /// The Layer Item is not meant to be used directly by the .slint code, instead, the `layer: xxx` property should be used |
1063 | pub struct Layer { |
1064 | pub cache_rendering_hint: Property<bool>, |
1065 | pub cached_rendering_data: CachedRenderingData, |
1066 | } |
1067 | |
1068 | impl Item for Layer { |
1069 | fn init(self: Pin<&Self>, _self_rc: &ItemRc) {} |
1070 | |
1071 | fn layout_info( |
1072 | self: Pin<&Self>, |
1073 | _orientation: Orientation, |
1074 | _window_adapter: &Rc<dyn WindowAdapter>, |
1075 | ) -> LayoutInfo { |
1076 | LayoutInfo { stretch: 1., ..LayoutInfo::default() } |
1077 | } |
1078 | |
1079 | fn input_event_filter_before_children( |
1080 | self: Pin<&Self>, |
1081 | _: MouseEvent, |
1082 | _window_adapter: &Rc<dyn WindowAdapter>, |
1083 | _self_rc: &ItemRc, |
1084 | ) -> InputEventFilterResult { |
1085 | InputEventFilterResult::ForwardAndIgnore |
1086 | } |
1087 | |
1088 | fn input_event( |
1089 | self: Pin<&Self>, |
1090 | _: MouseEvent, |
1091 | _window_adapter: &Rc<dyn WindowAdapter>, |
1092 | _self_rc: &ItemRc, |
1093 | ) -> InputEventResult { |
1094 | InputEventResult::EventIgnored |
1095 | } |
1096 | |
1097 | fn key_event( |
1098 | self: Pin<&Self>, |
1099 | _: &KeyEvent, |
1100 | _window_adapter: &Rc<dyn WindowAdapter>, |
1101 | _self_rc: &ItemRc, |
1102 | ) -> KeyEventResult { |
1103 | KeyEventResult::EventIgnored |
1104 | } |
1105 | |
1106 | fn focus_event( |
1107 | self: Pin<&Self>, |
1108 | _: &FocusEvent, |
1109 | _window_adapter: &Rc<dyn WindowAdapter>, |
1110 | _self_rc: &ItemRc, |
1111 | ) -> FocusEventResult { |
1112 | FocusEventResult::FocusIgnored |
1113 | } |
1114 | |
1115 | fn render( |
1116 | self: Pin<&Self>, |
1117 | backend: &mut ItemRendererRef, |
1118 | self_rc: &ItemRc, |
1119 | size: LogicalSize, |
1120 | ) -> RenderingResult { |
1121 | backend.visit_layer(self, self_rc, size) |
1122 | } |
1123 | } |
1124 | |
1125 | impl ItemConsts for Layer { |
1126 | const cached_rendering_data_offset: const_field_offset::FieldOffset< |
1127 | Layer, |
1128 | CachedRenderingData, |
1129 | > = Layer::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection(); |
1130 | } |
1131 | |
1132 | declare_item_vtable! { |
1133 | fn slint_get_LayerVTable() -> LayerVTable for Layer |
1134 | } |
1135 | |
1136 | #[repr (C)] |
1137 | #[derive (FieldOffsets, Default, SlintElement)] |
1138 | #[pin] |
1139 | /// The implementation of the `Rotate` element |
1140 | pub struct Rotate { |
1141 | pub rotation_angle: Property<f32>, |
1142 | pub rotation_origin_x: Property<LogicalLength>, |
1143 | pub rotation_origin_y: Property<LogicalLength>, |
1144 | pub cached_rendering_data: CachedRenderingData, |
1145 | } |
1146 | |
1147 | impl Item for Rotate { |
1148 | fn init(self: Pin<&Self>, _self_rc: &ItemRc) {} |
1149 | |
1150 | fn layout_info( |
1151 | self: Pin<&Self>, |
1152 | _orientation: Orientation, |
1153 | _window_adapter: &Rc<dyn WindowAdapter>, |
1154 | ) -> LayoutInfo { |
1155 | LayoutInfo { stretch: 1., ..LayoutInfo::default() } |
1156 | } |
1157 | |
1158 | fn input_event_filter_before_children( |
1159 | self: Pin<&Self>, |
1160 | _: MouseEvent, |
1161 | _window_adapter: &Rc<dyn WindowAdapter>, |
1162 | _self_rc: &ItemRc, |
1163 | ) -> InputEventFilterResult { |
1164 | InputEventFilterResult::ForwardAndIgnore |
1165 | } |
1166 | |
1167 | fn input_event( |
1168 | self: Pin<&Self>, |
1169 | _: MouseEvent, |
1170 | _window_adapter: &Rc<dyn WindowAdapter>, |
1171 | _self_rc: &ItemRc, |
1172 | ) -> InputEventResult { |
1173 | InputEventResult::EventIgnored |
1174 | } |
1175 | |
1176 | fn key_event( |
1177 | self: Pin<&Self>, |
1178 | _: &KeyEvent, |
1179 | _window_adapter: &Rc<dyn WindowAdapter>, |
1180 | _self_rc: &ItemRc, |
1181 | ) -> KeyEventResult { |
1182 | KeyEventResult::EventIgnored |
1183 | } |
1184 | |
1185 | fn focus_event( |
1186 | self: Pin<&Self>, |
1187 | _: &FocusEvent, |
1188 | _window_adapter: &Rc<dyn WindowAdapter>, |
1189 | _self_rc: &ItemRc, |
1190 | ) -> FocusEventResult { |
1191 | FocusEventResult::FocusIgnored |
1192 | } |
1193 | |
1194 | fn render( |
1195 | self: Pin<&Self>, |
1196 | backend: &mut ItemRendererRef, |
1197 | _self_rc: &ItemRc, |
1198 | _size: LogicalSize, |
1199 | ) -> RenderingResult { |
1200 | let origin = |
1201 | LogicalVector::from_lengths(self.rotation_origin_x(), self.rotation_origin_y()); |
1202 | (*backend).translate(origin); |
1203 | (*backend).rotate(self.rotation_angle()); |
1204 | (*backend).translate(-origin); |
1205 | RenderingResult::ContinueRenderingChildren |
1206 | } |
1207 | } |
1208 | |
1209 | impl ItemConsts for Rotate { |
1210 | const cached_rendering_data_offset: const_field_offset::FieldOffset< |
1211 | Rotate, |
1212 | CachedRenderingData, |
1213 | > = Rotate::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection(); |
1214 | } |
1215 | |
1216 | declare_item_vtable! { |
1217 | fn slint_get_RotateVTable() -> RotateVTable for Rotate |
1218 | } |
1219 | |
1220 | declare_item_vtable! { |
1221 | fn slint_get_FlickableVTable() -> FlickableVTable for Flickable |
1222 | } |
1223 | |
1224 | /// The implementation of the `PropertyAnimation` element |
1225 | #[repr (C)] |
1226 | #[derive (FieldOffsets, SlintElement, Clone, Debug)] |
1227 | #[pin] |
1228 | pub struct PropertyAnimation { |
1229 | #[rtti_field] |
1230 | pub delay: i32, |
1231 | #[rtti_field] |
1232 | pub duration: i32, |
1233 | #[rtti_field] |
1234 | pub iteration_count: f32, |
1235 | #[rtti_field] |
1236 | pub easing: crate::animations::EasingCurve, |
1237 | } |
1238 | |
1239 | impl Default for PropertyAnimation { |
1240 | fn default() -> Self { |
1241 | // Defaults for PropertyAnimation are defined here (for internal Rust code doing programmatic animations) |
1242 | // as well as in `builtins.slint` (for generated C++ and Rust code) |
1243 | Self { delay: 0, duration: 0, iteration_count: 1., easing: Default::default() } |
1244 | } |
1245 | } |
1246 | |
1247 | /// The implementation of the `Window` element |
1248 | #[repr (C)] |
1249 | #[derive (FieldOffsets, Default, SlintElement)] |
1250 | #[pin] |
1251 | pub struct WindowItem { |
1252 | pub width: Property<LogicalLength>, |
1253 | pub height: Property<LogicalLength>, |
1254 | pub background: Property<Brush>, |
1255 | pub title: Property<SharedString>, |
1256 | pub no_frame: Property<bool>, |
1257 | pub always_on_top: 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 | |
1265 | impl Item for WindowItem { |
1266 | fn init(self: Pin<&Self>, _self_rc: &ItemRc) {} |
1267 | |
1268 | fn layout_info( |
1269 | self: Pin<&Self>, |
1270 | _orientation: Orientation, |
1271 | _window_adapter: &Rc<dyn WindowAdapter>, |
1272 | ) -> LayoutInfo { |
1273 | LayoutInfo::default() |
1274 | } |
1275 | |
1276 | fn input_event_filter_before_children( |
1277 | self: Pin<&Self>, |
1278 | _: MouseEvent, |
1279 | _window_adapter: &Rc<dyn WindowAdapter>, |
1280 | _self_rc: &ItemRc, |
1281 | ) -> InputEventFilterResult { |
1282 | InputEventFilterResult::ForwardAndIgnore |
1283 | } |
1284 | |
1285 | fn input_event( |
1286 | self: Pin<&Self>, |
1287 | _event: MouseEvent, |
1288 | _window_adapter: &Rc<dyn WindowAdapter>, |
1289 | _self_rc: &ItemRc, |
1290 | ) -> InputEventResult { |
1291 | InputEventResult::EventIgnored |
1292 | } |
1293 | |
1294 | fn key_event( |
1295 | self: Pin<&Self>, |
1296 | _: &KeyEvent, |
1297 | _window_adapter: &Rc<dyn WindowAdapter>, |
1298 | _self_rc: &ItemRc, |
1299 | ) -> KeyEventResult { |
1300 | KeyEventResult::EventIgnored |
1301 | } |
1302 | |
1303 | fn focus_event( |
1304 | self: Pin<&Self>, |
1305 | _: &FocusEvent, |
1306 | _window_adapter: &Rc<dyn WindowAdapter>, |
1307 | _self_rc: &ItemRc, |
1308 | ) -> FocusEventResult { |
1309 | FocusEventResult::FocusIgnored |
1310 | } |
1311 | |
1312 | fn render( |
1313 | self: Pin<&Self>, |
1314 | _backend: &mut ItemRendererRef, |
1315 | _self_rc: &ItemRc, |
1316 | _size: LogicalSize, |
1317 | ) -> RenderingResult { |
1318 | RenderingResult::ContinueRenderingChildren |
1319 | } |
1320 | } |
1321 | |
1322 | impl WindowItem { |
1323 | pub fn font_family(self: Pin<&Self>) -> Option<SharedString> { |
1324 | let maybe_family = self.default_font_family(); |
1325 | if !maybe_family.is_empty() { |
1326 | Some(maybe_family) |
1327 | } else { |
1328 | None |
1329 | } |
1330 | } |
1331 | |
1332 | pub fn font_size(self: Pin<&Self>) -> Option<LogicalLength> { |
1333 | let font_size = self.default_font_size(); |
1334 | if font_size.get() <= 0 as Coord { |
1335 | None |
1336 | } else { |
1337 | Some(font_size) |
1338 | } |
1339 | } |
1340 | |
1341 | pub fn font_weight(self: Pin<&Self>) -> Option<i32> { |
1342 | let font_weight = self.default_font_weight(); |
1343 | if font_weight == 0 { |
1344 | None |
1345 | } else { |
1346 | Some(font_weight) |
1347 | } |
1348 | } |
1349 | } |
1350 | |
1351 | impl ItemConsts for WindowItem { |
1352 | const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> = |
1353 | Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection(); |
1354 | } |
1355 | |
1356 | declare_item_vtable! { |
1357 | fn slint_get_WindowItemVTable() -> WindowItemVTable for WindowItem |
1358 | } |
1359 | |
1360 | /// The implementation of the `BoxShadow` element |
1361 | #[repr (C)] |
1362 | #[derive (FieldOffsets, Default, SlintElement)] |
1363 | #[pin] |
1364 | pub struct BoxShadow { |
1365 | pub border_radius: Property<LogicalLength>, |
1366 | // Shadow specific properties |
1367 | pub offset_x: Property<LogicalLength>, |
1368 | pub offset_y: Property<LogicalLength>, |
1369 | pub color: Property<Color>, |
1370 | pub blur: Property<LogicalLength>, |
1371 | pub cached_rendering_data: CachedRenderingData, |
1372 | } |
1373 | |
1374 | impl Item for BoxShadow { |
1375 | fn init(self: Pin<&Self>, _self_rc: &ItemRc) {} |
1376 | |
1377 | fn layout_info( |
1378 | self: Pin<&Self>, |
1379 | _orientation: Orientation, |
1380 | _window_adapter: &Rc<dyn WindowAdapter>, |
1381 | ) -> LayoutInfo { |
1382 | LayoutInfo { stretch: 1., ..LayoutInfo::default() } |
1383 | } |
1384 | |
1385 | fn input_event_filter_before_children( |
1386 | self: Pin<&Self>, |
1387 | _: MouseEvent, |
1388 | _window_adapter: &Rc<dyn WindowAdapter>, |
1389 | _self_rc: &ItemRc, |
1390 | ) -> InputEventFilterResult { |
1391 | InputEventFilterResult::ForwardAndIgnore |
1392 | } |
1393 | |
1394 | fn input_event( |
1395 | self: Pin<&Self>, |
1396 | _event: MouseEvent, |
1397 | _window_adapter: &Rc<dyn WindowAdapter>, |
1398 | _self_rc: &ItemRc, |
1399 | ) -> InputEventResult { |
1400 | InputEventResult::EventIgnored |
1401 | } |
1402 | |
1403 | fn key_event( |
1404 | self: Pin<&Self>, |
1405 | _: &KeyEvent, |
1406 | _window_adapter: &Rc<dyn WindowAdapter>, |
1407 | _self_rc: &ItemRc, |
1408 | ) -> KeyEventResult { |
1409 | KeyEventResult::EventIgnored |
1410 | } |
1411 | |
1412 | fn focus_event( |
1413 | self: Pin<&Self>, |
1414 | _: &FocusEvent, |
1415 | _window_adapter: &Rc<dyn WindowAdapter>, |
1416 | _self_rc: &ItemRc, |
1417 | ) -> FocusEventResult { |
1418 | FocusEventResult::FocusIgnored |
1419 | } |
1420 | |
1421 | fn render( |
1422 | self: Pin<&Self>, |
1423 | backend: &mut ItemRendererRef, |
1424 | self_rc: &ItemRc, |
1425 | size: LogicalSize, |
1426 | ) -> RenderingResult { |
1427 | (*backend).draw_box_shadow(self, self_rc, size); |
1428 | RenderingResult::ContinueRenderingChildren |
1429 | } |
1430 | } |
1431 | |
1432 | impl ItemConsts for BoxShadow { |
1433 | const cached_rendering_data_offset: const_field_offset::FieldOffset<Self, CachedRenderingData> = |
1434 | Self::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection(); |
1435 | } |
1436 | |
1437 | declare_item_vtable! { |
1438 | fn slint_get_BoxShadowVTable() -> BoxShadowVTable for BoxShadow |
1439 | } |
1440 | |
1441 | declare_item_vtable! { |
1442 | fn slint_get_ComponentContainerVTable() -> ComponentContainerVTable for ComponentContainer |
1443 | } |
1444 | |
1445 | declare_item_vtable! { |
1446 | fn slint_get_TextVTable() -> TextVTable for Text |
1447 | } |
1448 | |
1449 | declare_item_vtable! { |
1450 | fn slint_get_TextInputVTable() -> TextInputVTable for TextInput |
1451 | } |
1452 | |
1453 | declare_item_vtable! { |
1454 | fn slint_get_ImageItemVTable() -> ImageItemVTable for ImageItem |
1455 | } |
1456 | |
1457 | declare_item_vtable! { |
1458 | fn slint_get_ClippedImageVTable() -> ClippedImageVTable for ClippedImage |
1459 | } |
1460 | |
1461 | #[cfg (feature = "std" )] |
1462 | declare_item_vtable! { |
1463 | fn slint_get_PathVTable() -> PathVTable for Path |
1464 | } |
1465 | |
1466 | macro_rules! declare_enums { |
1467 | ($( $(#[$enum_doc:meta])* enum $Name:ident { $( $(#[$value_doc:meta])* $Value:ident,)* })*) => { |
1468 | $( |
1469 | #[derive(Copy, Clone, Debug, PartialEq, Eq, strum::EnumString, strum::Display, Hash)] |
1470 | #[repr(u32)] |
1471 | #[strum(serialize_all = "kebab-case" )] |
1472 | $(#[$enum_doc])* |
1473 | pub enum $Name { |
1474 | $( $(#[$value_doc])* $Value),* |
1475 | } |
1476 | |
1477 | impl Default for $Name { |
1478 | fn default() -> Self { |
1479 | // Always return the first value |
1480 | ($(Self::$Value,)*).0 |
1481 | } |
1482 | } |
1483 | )* |
1484 | }; |
1485 | } |
1486 | |
1487 | i_slint_common::for_each_enums!(declare_enums); |
1488 | |
1489 | macro_rules! declare_builtin_structs { |
1490 | ($( |
1491 | $(#[$struct_attr:meta])* |
1492 | struct $Name:ident { |
1493 | @name = $inner_name:literal |
1494 | export { |
1495 | $( $(#[$pub_attr:meta])* $pub_field:ident : $pub_type:ty, )* |
1496 | } |
1497 | private { |
1498 | $( $(#[$pri_attr:meta])* $pri_field:ident : $pri_type:ty, )* |
1499 | } |
1500 | } |
1501 | )*) => { |
1502 | $( |
1503 | #[derive(Clone, Debug, Default, PartialEq)] |
1504 | #[repr(C)] |
1505 | $(#[$struct_attr])* |
1506 | pub struct $Name { |
1507 | $( |
1508 | $(#[$pub_attr])* |
1509 | pub $pub_field : $pub_type, |
1510 | )* |
1511 | $( |
1512 | $(#[$pri_attr])* |
1513 | pub $pri_field : $pri_type, |
1514 | )* |
1515 | } |
1516 | )* |
1517 | }; |
1518 | } |
1519 | |
1520 | i_slint_common::for_each_builtin_structs!(declare_builtin_structs); |
1521 | |
1522 | #[cfg (feature = "ffi" )] |
1523 | #[no_mangle ] |
1524 | pub unsafe extern "C" fn slint_item_absolute_position( |
1525 | self_component: &vtable::VRc<crate::item_tree::ItemTreeVTable>, |
1526 | self_index: u32, |
1527 | ) -> LogicalPoint { |
1528 | let self_rc: ItemRc = ItemRc::new(item_tree:self_component.clone(), self_index); |
1529 | self_rc.map_to_window(Default::default()) |
1530 | } |
1531 | |