Skip to main content

slint_interpreter/
erased.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4//! Trait object for manipulating native items without knowing their type.
5//!
6//! Every item, property and callback is heap-allocated in its own `Pin<Rc<…>>`.
7//! The trait methods dispatch by name to the item's `rtti::BuiltinItem` metadata.
8
9use crate::Value;
10use core::pin::Pin;
11use i_slint_core::graphics::Brush;
12use i_slint_core::items::{ItemVTable, PropertyAnimation};
13use i_slint_core::properties::InterpolatedPropertyValue;
14use i_slint_core::rtti::{AnimatedBindingKind, TwoWayBindingMapping};
15use i_slint_core::{Callback, Property};
16use std::rc::Rc;
17use vtable::VRef;
18
19/// Erased access to a boxed native item such as `Rectangle`, `Text` or `TouchArea`.
20pub trait ErasedItem {
21    fn get_property(self: Pin<&Self>, name: &str) -> Result<Value, ()>;
22
23    fn set_property(
24        self: Pin<&Self>,
25        name: &str,
26        value: Value,
27        animation: Option<PropertyAnimation>,
28    ) -> Result<(), ()>;
29
30    fn set_property_binding(
31        self: Pin<&Self>,
32        name: &str,
33        binding: Box<dyn Fn() -> Value>,
34        animation: AnimatedBindingKind,
35    ) -> Result<(), ()>;
36
37    fn prepare_property_for_two_way_binding(
38        self: Pin<&Self>,
39        name: &str,
40    ) -> Option<Pin<Rc<Property<Value>>>>;
41
42    fn link_property_two_way_with_map(
43        self: Pin<&Self>,
44        name: &str,
45        other: Pin<Rc<Property<Value>>>,
46        mapper: Option<Rc<dyn TwoWayBindingMapping<Value>>>,
47    );
48
49    fn call_callback(self: Pin<&Self>, name: &str, args: &[Value]) -> Result<Value, ()>;
50
51    fn set_callback_handler(
52        self: Pin<&Self>,
53        name: &str,
54        handler: Box<dyn Fn(&[Value]) -> Value>,
55    ) -> Result<(), ()>;
56
57    /// Write a plain (non-`Property`) field, e.g. the fields updated by layouts.
58    fn set_field(self: Pin<&Self>, name: &str, value: Value) -> Result<(), ()>;
59
60    fn as_item_ref(self: Pin<&Self>) -> Pin<VRef<'_, ItemVTable>>;
61}
62
63pub type ErasedItemRc = Pin<Rc<dyn ErasedItem>>;
64
65/// A sub-component's own `Property<Value>`.
66pub type SubComponentProperty = Pin<Rc<Property<Value>>>;
67
68/// A sub-component's own callback, with a `Vec<Value>` argument tuple.
69pub type SubComponentCallback = Pin<Rc<Callback<[Value], Value>>>;
70
71/// Animated bindings on sub-component properties need `Value` to support
72/// interpolation. Numeric and brush variants interpolate; everything else
73/// snaps. Numbers interpolate in `f32` because animated numeric properties
74/// are `f32`-based — an `f64` blend would leak rounding noise like
75/// `99.50000001117587` instead of `99.5`.
76impl InterpolatedPropertyValue for Value {
77    fn interpolate(&self, target: &Self, t: f32) -> Self {
78        match (self, target) {
79            (Value::Number(a), Value::Number(b)) => {
80                let (a, b) = (*a as f32, *b as f32);
81                Value::Number((a + (b - a) * t) as f64)
82            }
83            (Value::Brush(a), Value::Brush(b)) => Value::Brush(Brush::interpolate(a, b, t)),
84            _ => target.clone(),
85        }
86    }
87}