Skip to main content

slint_interpreter/
eval.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
4use crate::api::{SetPropertyError, Struct, Value};
5use crate::dynamic_item_tree::{CallbackHandler, InstanceRef};
6use core::ffi::c_void;
7use core::pin::Pin;
8use corelib::graphics::{
9    ConicGradientBrush, GradientStop, LinearGradientBrush, PathElement, RadialGradientBrush,
10};
11use corelib::input::FocusReason;
12use corelib::items::{ItemRc, ItemRef, PropertyAnimation, WindowItem};
13use corelib::menus::{Menu, MenuFromItemTree};
14use corelib::model::{Model, ModelExt, ModelRc, VecModel};
15use corelib::rtti::AnimatedBindingKind;
16use corelib::window::{WindowInner, WindowKind};
17use corelib::{Brush, Color, PathData, SharedString, SharedVector};
18use i_slint_compiler::diagnostics::Spanned;
19use i_slint_compiler::expression_tree::{
20    BuiltinFunction, Callable, EasingCurve, Expression, MinMaxOp, MouseCursorInner,
21    Path as ExprPath, PathElement as ExprPathElement,
22};
23use i_slint_compiler::langtype::{ConstantExpression, Type};
24use i_slint_compiler::namedreference::NamedReference;
25use i_slint_compiler::object_tree::ElementRc;
26use i_slint_core::api::ToSharedString;
27use i_slint_core::{self as corelib};
28use smol_str::SmolStr;
29use std::collections::HashMap;
30use std::rc::Rc;
31
32pub trait ErasedPropertyInfo {
33    fn get(&self, item: Pin<ItemRef>) -> Value;
34    fn set(
35        &self,
36        item: Pin<ItemRef>,
37        value: Value,
38        animation: Option<PropertyAnimation>,
39    ) -> Result<(), ()>;
40    fn set_binding(
41        &self,
42        item: Pin<ItemRef>,
43        binding: Box<dyn Fn() -> Value>,
44        animation: AnimatedBindingKind,
45    );
46    fn offset(&self) -> usize;
47
48    #[cfg(slint_debug_property)]
49    fn set_debug_name(&self, item: Pin<ItemRef>, name: String);
50
51    /// Safety: Property2 must be a (pinned) pointer to a `Property<T>`
52    /// where T is the same T as the one represented by this property.
53    unsafe fn link_two_ways(&self, item: Pin<ItemRef>, property2: *const c_void);
54
55    fn prepare_for_two_way_binding(&self, item: Pin<ItemRef>) -> Pin<Rc<corelib::Property<Value>>>;
56
57    fn link_two_way_with_map(
58        &self,
59        item: Pin<ItemRef>,
60        property2: Pin<Rc<corelib::Property<Value>>>,
61        map: Option<Rc<dyn corelib::rtti::TwoWayBindingMapping<Value>>>,
62    );
63
64    fn link_two_way_to_model_data(
65        &self,
66        item: Pin<ItemRef>,
67        getter: Box<dyn Fn() -> Option<Value>>,
68        setter: Box<dyn Fn(&Value)>,
69    );
70}
71
72impl<Item: vtable::HasStaticVTable<corelib::items::ItemVTable>> ErasedPropertyInfo
73    for &'static dyn corelib::rtti::PropertyInfo<Item, Value>
74{
75    fn get(&self, item: Pin<ItemRef>) -> Value {
76        (*self).get(ItemRef::downcast_pin(item).unwrap()).unwrap()
77    }
78    fn set(
79        &self,
80        item: Pin<ItemRef>,
81        value: Value,
82        animation: Option<PropertyAnimation>,
83    ) -> Result<(), ()> {
84        (*self).set(ItemRef::downcast_pin(item).unwrap(), value, animation)
85    }
86    fn set_binding(
87        &self,
88        item: Pin<ItemRef>,
89        binding: Box<dyn Fn() -> Value>,
90        animation: AnimatedBindingKind,
91    ) {
92        (*self).set_binding(ItemRef::downcast_pin(item).unwrap(), binding, animation).unwrap();
93    }
94    fn offset(&self) -> usize {
95        (*self).offset()
96    }
97    #[cfg(slint_debug_property)]
98    fn set_debug_name(&self, item: Pin<ItemRef>, name: String) {
99        (*self).set_debug_name(ItemRef::downcast_pin(item).unwrap(), name);
100    }
101    unsafe fn link_two_ways(&self, item: Pin<ItemRef>, property2: *const c_void) {
102        // Safety: ErasedPropertyInfo::link_two_ways and PropertyInfo::link_two_ways have the same safety requirement
103        unsafe { (*self).link_two_ways(ItemRef::downcast_pin(item).unwrap(), property2) }
104    }
105
106    fn prepare_for_two_way_binding(&self, item: Pin<ItemRef>) -> Pin<Rc<corelib::Property<Value>>> {
107        (*self).prepare_for_two_way_binding(ItemRef::downcast_pin(item).unwrap())
108    }
109
110    fn link_two_way_with_map(
111        &self,
112        item: Pin<ItemRef>,
113        property2: Pin<Rc<corelib::Property<Value>>>,
114        map: Option<Rc<dyn corelib::rtti::TwoWayBindingMapping<Value>>>,
115    ) {
116        (*self).link_two_way_with_map(ItemRef::downcast_pin(item).unwrap(), property2, map)
117    }
118
119    fn link_two_way_to_model_data(
120        &self,
121        item: Pin<ItemRef>,
122        getter: Box<dyn Fn() -> Option<Value>>,
123        setter: Box<dyn Fn(&Value)>,
124    ) {
125        (*self).link_two_way_to_model_data(ItemRef::downcast_pin(item).unwrap(), getter, setter)
126    }
127}
128
129pub trait ErasedCallbackInfo {
130    fn call(&self, item: Pin<ItemRef>, args: &[Value]) -> Value;
131    fn set_handler(&self, item: Pin<ItemRef>, handler: Box<dyn Fn(&[Value]) -> Value>);
132}
133
134impl<Item: vtable::HasStaticVTable<corelib::items::ItemVTable>> ErasedCallbackInfo
135    for &'static dyn corelib::rtti::CallbackInfo<Item, Value>
136{
137    fn call(&self, item: Pin<ItemRef>, args: &[Value]) -> Value {
138        (*self).call(ItemRef::downcast_pin(item).unwrap(), args).unwrap()
139    }
140
141    fn set_handler(&self, item: Pin<ItemRef>, handler: Box<dyn Fn(&[Value]) -> Value>) {
142        (*self).set_handler(ItemRef::downcast_pin(item).unwrap(), handler).unwrap()
143    }
144}
145
146impl corelib::rtti::ValueType for Value {}
147
148#[derive(Clone)]
149pub(crate) enum ComponentInstance<'a, 'id> {
150    InstanceRef(InstanceRef<'a, 'id>),
151    GlobalComponent(Pin<Rc<dyn crate::global_component::GlobalComponent>>),
152}
153
154/// The local variable needed for binding evaluation
155pub struct EvalLocalContext<'a, 'id> {
156    local_variables: HashMap<SmolStr, Value>,
157    function_arguments: Vec<Value>,
158    pub(crate) component_instance: InstanceRef<'a, 'id>,
159    /// When Some, a return statement was executed and one must stop evaluating
160    return_value: Option<Value>,
161}
162
163impl<'a, 'id> EvalLocalContext<'a, 'id> {
164    pub fn from_component_instance(component: InstanceRef<'a, 'id>) -> Self {
165        Self {
166            local_variables: Default::default(),
167            function_arguments: Default::default(),
168            component_instance: component,
169            return_value: None,
170        }
171    }
172
173    /// Create a context for a function and passing the arguments
174    pub fn from_function_arguments(
175        component: InstanceRef<'a, 'id>,
176        function_arguments: Vec<Value>,
177    ) -> Self {
178        Self {
179            component_instance: component,
180            function_arguments,
181            local_variables: Default::default(),
182            return_value: None,
183        }
184    }
185}
186
187/// Evaluate `expression` as a length / number and return the resulting f32.
188/// Caller's responsibility to only pass length-typed expressions.
189fn eval_to_f32(expression: &Expression, local_context: &mut EvalLocalContext) -> f32 {
190    match eval_expression(expression, local_context) {
191        Value::Number(n) => n as f32,
192        other => unreachable!("expected length-typed expression; got {other:?} for {expression:?}"),
193    }
194}
195
196/// Evaluate an expression and return a Value as the result of this expression
197pub fn eval_expression(expression: &Expression, local_context: &mut EvalLocalContext) -> Value {
198    if let Some(r) = &local_context.return_value {
199        return r.clone();
200    }
201    match expression {
202        Expression::Invalid => panic!("invalid expression while evaluating"),
203        Expression::Uncompiled(_) => panic!("uncompiled expression while evaluating"),
204        Expression::StringLiteral(s) => Value::String(s.as_str().into()),
205        Expression::NumberLiteral(n, _unit) => Value::Number(*n),
206        Expression::BoolLiteral(b) => Value::Bool(*b),
207        Expression::ElementReference(_) => todo!(
208            "Element references are only supported in the context of built-in function calls at the moment"
209        ),
210        Expression::PropertyReference(nr) => load_property_helper(
211            &ComponentInstance::InstanceRef(local_context.component_instance),
212            &nr.element(),
213            nr.name(),
214        )
215        .unwrap(),
216        Expression::RepeaterIndexReference { element } => load_property_helper(
217            &ComponentInstance::InstanceRef(local_context.component_instance),
218            &element.upgrade().unwrap().borrow().base_type.as_component().root_element,
219            crate::dynamic_item_tree::SPECIAL_PROPERTY_INDEX,
220        )
221        .unwrap(),
222        Expression::RepeaterModelReference { element } => {
223            let value = load_property_helper(
224                &ComponentInstance::InstanceRef(local_context.component_instance),
225                &element.upgrade().unwrap().borrow().base_type.as_component().root_element,
226                crate::dynamic_item_tree::SPECIAL_PROPERTY_MODEL_DATA,
227            )
228            .unwrap();
229            if matches!(value, Value::Void) {
230                // Uninitialized model data (because the model returned None) should still be initialized to the default value of the type
231                default_value_for_type(&expression.ty())
232            } else {
233                value
234            }
235        }
236        Expression::FunctionParameterReference { index, .. } => {
237            local_context.function_arguments[*index].clone()
238        }
239        Expression::StructFieldAccess { base, name } => {
240            if let Value::Struct(o) = eval_expression(base, local_context) {
241                o.get_field(name).cloned().unwrap_or(Value::Void)
242            } else {
243                Value::Void
244            }
245        }
246        Expression::ArrayIndex { array, index } => {
247            let array = eval_expression(array, local_context);
248            let index = eval_expression(index, local_context);
249            match (array, index) {
250                (Value::Model(model), Value::Number(index)) => model
251                    .row_data_tracked(index as isize as usize)
252                    .unwrap_or_else(|| default_value_for_type(&expression.ty())),
253                _ => Value::Void,
254            }
255        }
256        Expression::Cast { from, to } => cast_value(eval_expression(from, local_context), to),
257        Expression::CodeBlock(sub) => {
258            let mut v = Value::Void;
259            for e in sub {
260                v = eval_expression(e, local_context);
261                if let Some(r) = &local_context.return_value {
262                    return r.clone();
263                }
264            }
265            v
266        }
267        Expression::FunctionCall { function, arguments, source_location } => match &function {
268            Callable::Function(nr) => {
269                let is_item_member = nr
270                    .element()
271                    .borrow()
272                    .native_class()
273                    .is_some_and(|n| n.properties.contains_key(nr.name()));
274                if is_item_member {
275                    call_item_member_function(nr, local_context)
276                } else {
277                    let args = arguments
278                        .iter()
279                        .map(|e| eval_expression(e, local_context))
280                        .collect::<Vec<_>>();
281                    call_function(
282                        &ComponentInstance::InstanceRef(local_context.component_instance),
283                        &nr.element(),
284                        nr.name(),
285                        args,
286                    )
287                    .unwrap()
288                }
289            }
290            Callable::Callback(nr) => {
291                let args =
292                    arguments.iter().map(|e| eval_expression(e, local_context)).collect::<Vec<_>>();
293                invoke_callback(
294                    &ComponentInstance::InstanceRef(local_context.component_instance),
295                    &nr.element(),
296                    nr.name(),
297                    &args,
298                )
299                .unwrap()
300            }
301            Callable::Builtin(f) => {
302                call_builtin_function(f.clone(), arguments, local_context, source_location)
303            }
304        },
305        Expression::SelfAssignment { lhs, rhs, op, .. } => {
306            let rhs = eval_expression(rhs, local_context);
307            eval_assignment(lhs, *op, rhs, local_context);
308            Value::Void
309        }
310        Expression::BinaryExpression { lhs, rhs, op } => {
311            let lhs = eval_expression(lhs, local_context);
312            // && and || short circuit like in the generated code, or else side
313            // effects in the rhs would run in the interpreter only
314            match (op, &lhs) {
315                ('&', Value::Bool(false)) => return Value::Bool(false),
316                ('|', Value::Bool(true)) => return Value::Bool(true),
317                _ => {}
318            }
319            let rhs = eval_expression(rhs, local_context);
320
321            match (op, lhs, rhs) {
322                ('+', Value::String(mut a), Value::String(b)) => {
323                    a.push_str(b.as_str());
324                    Value::String(a)
325                }
326                ('+', Value::Number(a), Value::Number(b)) => Value::Number(a + b),
327                ('+', a @ Value::Struct(_), b @ Value::Struct(_)) => {
328                    let a: Option<corelib::layout::LayoutInfo> = a.try_into().ok();
329                    let b: Option<corelib::layout::LayoutInfo> = b.try_into().ok();
330                    if let (Some(a), Some(b)) = (a, b) {
331                        a.merge(&b).into()
332                    } else {
333                        panic!("unsupported {a:?} {op} {b:?}");
334                    }
335                }
336                ('-', Value::Number(a), Value::Number(b)) => Value::Number(a - b),
337                ('/', Value::Number(a), Value::Number(b)) => Value::Number(a / b),
338                ('*', Value::Number(a), Value::Number(b)) => Value::Number(a * b),
339                ('<', Value::Number(a), Value::Number(b)) => Value::Bool(a < b),
340                ('>', Value::Number(a), Value::Number(b)) => Value::Bool(a > b),
341                ('≤', Value::Number(a), Value::Number(b)) => Value::Bool(a <= b),
342                ('≥', Value::Number(a), Value::Number(b)) => Value::Bool(a >= b),
343                ('<', Value::String(a), Value::String(b)) => Value::Bool(a < b),
344                ('>', Value::String(a), Value::String(b)) => Value::Bool(a > b),
345                ('≤', Value::String(a), Value::String(b)) => Value::Bool(a <= b),
346                ('≥', Value::String(a), Value::String(b)) => Value::Bool(a >= b),
347                ('=', a, b) => Value::Bool(a == b),
348                ('!', a, b) => Value::Bool(a != b),
349                ('&', Value::Bool(a), Value::Bool(b)) => Value::Bool(a && b),
350                ('|', Value::Bool(a), Value::Bool(b)) => Value::Bool(a || b),
351                (op, lhs, rhs) => panic!("unsupported {lhs:?} {op} {rhs:?}"),
352            }
353        }
354        Expression::UnaryOp { sub, op } => {
355            let sub = eval_expression(sub, local_context);
356            eval_unary_op(sub, *op).unwrap_or_else(|sub| panic!("unsupported {op} {sub:?}"))
357        }
358        Expression::ImageReference { resource_ref, nine_slice, .. } => {
359            let mut image = match resource_ref {
360                i_slint_compiler::expression_tree::ImageReference::None => Ok(Default::default()),
361                i_slint_compiler::expression_tree::ImageReference::DataUri(data_uri) => {
362                    i_slint_compiler::data_uri::decode_data_uri(data_uri)
363                        .ok()
364                        .and_then(|(data, extension)| {
365                            corelib::graphics::load_image_from_data_uri(data_uri, &data, &extension)
366                                .ok()
367                        })
368                        .ok_or_else(Default::default)
369                }
370                i_slint_compiler::expression_tree::ImageReference::Url(url)
371                    if url.scheme() == "builtin" =>
372                {
373                    let path = std::path::Path::new(url.as_str());
374                    i_slint_compiler::fileaccess::load_file(path)
375                        .and_then(|virtual_file| virtual_file.builtin_contents)
376                        .map(|virtual_file| {
377                            let extension = path.extension().unwrap().to_str().unwrap();
378                            corelib::graphics::load_image_from_embedded_data(
379                                corelib::slice::Slice::from_slice(virtual_file),
380                                corelib::slice::Slice::from_slice(extension.as_bytes()),
381                            )
382                        })
383                        .ok_or_else(Default::default)
384                }
385                i_slint_compiler::expression_tree::ImageReference::Path(path) => {
386                    corelib::graphics::Image::load_from_path(std::path::Path::new(path))
387                }
388                i_slint_compiler::expression_tree::ImageReference::Url(url) => {
389                    #[cfg(target_arch = "wasm32")]
390                    {
391                        corelib::graphics::load_as_html_image(url.as_str())
392                    }
393                    // URL image references only work on the web, where the browser fetches them.
394                    #[cfg(not(target_arch = "wasm32"))]
395                    {
396                        let _ = url;
397                        Err(Default::default())
398                    }
399                }
400                i_slint_compiler::expression_tree::ImageReference::EmbeddedData { .. } => {
401                    todo!()
402                }
403                i_slint_compiler::expression_tree::ImageReference::EmbeddedTexture { .. } => {
404                    todo!()
405                }
406            }
407            .unwrap_or_else(|_| {
408                eprintln!("Could not load image {resource_ref:?}");
409                Default::default()
410            });
411            if let Some(n) = nine_slice {
412                image.set_nine_slice_edges(n[0], n[1], n[2], n[3]);
413            }
414            Value::Image(image)
415        }
416        Expression::Condition { condition, true_expr, false_expr } => {
417            match eval_expression(condition, local_context).try_into() as Result<bool, _> {
418                Ok(true) => eval_expression(true_expr, local_context),
419                Ok(false) => eval_expression(false_expr, local_context),
420                _ => local_context
421                    .return_value
422                    .clone()
423                    .expect("conditional expression did not evaluate to boolean"),
424            }
425        }
426        Expression::Array { values, .. } => {
427            Value::Model(ModelRc::new(corelib::model::SharedVectorModel::from(
428                values
429                    .iter()
430                    .map(|e| eval_expression(e, local_context))
431                    .collect::<SharedVector<_>>(),
432            )))
433        }
434        Expression::Struct { values, .. } => Value::Struct(
435            values
436                .iter()
437                .map(|(k, v)| (k.to_string(), eval_expression(v, local_context)))
438                .collect(),
439        ),
440        Expression::PathData(data) => Value::PathData(convert_path(data, local_context)),
441        Expression::StoreLocalVariable { name, value } => {
442            let value = eval_expression(value, local_context);
443            local_context.local_variables.insert(name.clone(), value);
444            Value::Void
445        }
446        Expression::ReadLocalVariable { name, .. } => {
447            local_context.local_variables.get(name).unwrap().clone()
448        }
449        Expression::EasingCurve(curve) => Value::EasingCurve(match curve {
450            EasingCurve::Linear => corelib::animations::EasingCurve::Linear,
451            EasingCurve::EaseInElastic => corelib::animations::EasingCurve::EaseInElastic,
452            EasingCurve::EaseOutElastic => corelib::animations::EasingCurve::EaseOutElastic,
453            EasingCurve::EaseInOutElastic => corelib::animations::EasingCurve::EaseInOutElastic,
454            EasingCurve::EaseInBounce => corelib::animations::EasingCurve::EaseInBounce,
455            EasingCurve::EaseOutBounce => corelib::animations::EasingCurve::EaseOutBounce,
456            EasingCurve::EaseInOutBounce => corelib::animations::EasingCurve::EaseInOutBounce,
457            EasingCurve::CubicBezier(a, b, c, d) => {
458                corelib::animations::EasingCurve::CubicBezier([*a, *b, *c, *d])
459            }
460        }),
461        Expression::MouseCursor(cursor) => Value::MouseCursorInner(match cursor {
462            MouseCursorInner::BuiltIn(cursor) => corelib::cursor::MouseCursorInner::BuiltIn(
463                eval_expression(cursor, local_context).try_into().unwrap(),
464            ),
465            MouseCursorInner::CustomMouseCursor { image, hotspot_x, hotspot_y } => {
466                let image = eval_expression(image, local_context).try_into().unwrap();
467                let hotspot_x = eval_expression(hotspot_x, local_context).try_into().unwrap();
468                let hotspot_y = eval_expression(hotspot_y, local_context).try_into().unwrap();
469
470                corelib::cursor::MouseCursorInner::CustomMouseCursor { image, hotspot_x, hotspot_y }
471            }
472        }),
473        Expression::LinearGradient { angle, stops } => {
474            let angle = eval_expression(angle, local_context);
475            Value::Brush(Brush::LinearGradient(LinearGradientBrush::new(
476                angle.try_into().unwrap(),
477                stops.iter().map(|(color, stop)| {
478                    let color = eval_expression(color, local_context).try_into().unwrap();
479                    let position = eval_expression(stop, local_context).try_into().unwrap();
480                    GradientStop { color, position }
481                }),
482            )))
483        }
484        Expression::RadialGradient { stops, center, radius } => {
485            let mut g = RadialGradientBrush::new_circle(stops.iter().map(|(color, stop)| {
486                let color = eval_expression(color, local_context).try_into().unwrap();
487                let position = eval_expression(stop, local_context).try_into().unwrap();
488                GradientStop { color, position }
489            }));
490            if let Some((cx, cy)) = center {
491                let cx: f32 = eval_expression(cx, local_context).try_into().unwrap();
492                let cy: f32 = eval_expression(cy, local_context).try_into().unwrap();
493                g = g.with_center(cx, cy);
494            }
495            if let Some(r) = radius {
496                let r: f32 = eval_expression(r, local_context).try_into().unwrap();
497                g = g.with_radius(r);
498            }
499            Value::Brush(Brush::RadialGradient(g))
500        }
501        Expression::ConicGradient { from_angle, stops, center } => {
502            let from_angle: f32 = eval_expression(from_angle, local_context).try_into().unwrap();
503            let mut g = ConicGradientBrush::new(
504                from_angle,
505                stops.iter().map(|(color, stop)| {
506                    let color = eval_expression(color, local_context).try_into().unwrap();
507                    let position = eval_expression(stop, local_context).try_into().unwrap();
508                    GradientStop { color, position }
509                }),
510            );
511            if let Some((cx, cy)) = center {
512                let cx: f32 = eval_expression(cx, local_context).try_into().unwrap();
513                let cy: f32 = eval_expression(cy, local_context).try_into().unwrap();
514                g = g.with_center(cx, cy);
515            }
516            Value::Brush(Brush::ConicGradient(g))
517        }
518        Expression::EnumerationValue(value) => {
519            Value::EnumerationValue(value.enumeration.name.to_string(), value.to_string())
520        }
521        Expression::Keys(ks) => {
522            let mut modifiers = i_slint_core::input::KeyboardModifiers::default();
523            modifiers.alt = ks.modifiers.alt;
524            modifiers.control = ks.modifiers.control;
525            modifiers.shift = ks.modifiers.shift;
526            modifiers.meta = ks.modifiers.meta;
527
528            Value::Keys(i_slint_core::input::make_keys(
529                SharedString::from(&*ks.key),
530                modifiers,
531                ks.ignore_shift,
532                ks.ignore_alt,
533            ))
534        }
535        Expression::ReturnStatement(x) => {
536            let val = x.as_ref().map_or(Value::Void, |x| eval_expression(x, local_context));
537            if local_context.return_value.is_none() {
538                local_context.return_value = Some(val);
539            }
540            local_context.return_value.clone().unwrap()
541        }
542        Expression::LayoutCacheAccess {
543            layout_cache_prop,
544            index,
545            repeater_index,
546            entries_per_item,
547        } => {
548            let cache = load_property_helper(
549                &ComponentInstance::InstanceRef(local_context.component_instance),
550                &layout_cache_prop.element(),
551                layout_cache_prop.name(),
552            )
553            .unwrap();
554            if let Value::LayoutCache(cache) = cache {
555                // Coordinate cache
556                if let Some(ri) = repeater_index {
557                    let offset: usize = eval_expression(ri, local_context).try_into().unwrap();
558                    Value::Number(
559                        cache
560                            .get((cache[*index] as usize) + offset * entries_per_item)
561                            .copied()
562                            .unwrap_or(0.)
563                            .into(),
564                    )
565                } else {
566                    Value::Number(cache[*index].into())
567                }
568            } else if let Value::ArrayOfU16(cache) = cache {
569                // Organized Data cache
570                if let Some(ri) = repeater_index {
571                    let offset: usize = eval_expression(ri, local_context).try_into().unwrap();
572                    Value::Number(
573                        cache
574                            .get((cache[*index] as usize) + offset * entries_per_item)
575                            .copied()
576                            .unwrap_or(0)
577                            .into(),
578                    )
579                } else {
580                    Value::Number(cache[*index].into())
581                }
582            } else {
583                panic!("invalid layout cache")
584            }
585        }
586        Expression::GridRepeaterCacheAccess {
587            layout_cache_prop,
588            index,
589            repeater_index,
590            stride,
591            child_offset,
592            inner_repeater_index,
593            entries_per_item,
594        } => {
595            let cache = load_property_helper(
596                &ComponentInstance::InstanceRef(local_context.component_instance),
597                &layout_cache_prop.element(),
598                layout_cache_prop.name(),
599            )
600            .unwrap();
601            if let Value::LayoutCache(cache) = cache {
602                // Coordinate cache
603                let row_idx: usize =
604                    eval_expression(repeater_index, local_context).try_into().unwrap();
605                let stride_val: usize = eval_expression(stride, local_context).try_into().unwrap();
606                if let Some(inner_ri) = inner_repeater_index {
607                    let inner_offset: usize =
608                        eval_expression(inner_ri, local_context).try_into().unwrap();
609                    let base = cache[*index] as usize;
610                    let data_idx = base
611                        + row_idx * stride_val
612                        + *child_offset
613                        + inner_offset * *entries_per_item;
614                    Value::Number(cache.get(data_idx).copied().unwrap_or(0.).into())
615                } else {
616                    let base = cache[*index] as usize;
617                    let data_idx = base + row_idx * stride_val + *child_offset;
618                    Value::Number(cache.get(data_idx).copied().unwrap_or(0.).into())
619                }
620            } else if let Value::ArrayOfU16(cache) = cache {
621                // Organized Data cache
622                let row_idx: usize =
623                    eval_expression(repeater_index, local_context).try_into().unwrap();
624                let stride_val: usize = eval_expression(stride, local_context).try_into().unwrap();
625                if let Some(inner_ri) = inner_repeater_index {
626                    let inner_offset: usize =
627                        eval_expression(inner_ri, local_context).try_into().unwrap();
628                    let base = cache[*index] as usize;
629                    let data_idx = base
630                        + row_idx * stride_val
631                        + *child_offset
632                        + inner_offset * *entries_per_item;
633                    Value::Number(cache.get(data_idx).copied().unwrap_or(0).into())
634                } else {
635                    let base = cache[*index] as usize;
636                    let data_idx = base + row_idx * stride_val + *child_offset;
637                    Value::Number(cache.get(data_idx).copied().unwrap_or(0).into())
638                }
639            } else {
640                panic!("invalid layout cache")
641            }
642        }
643        Expression::ComputeBoxLayoutInfo { layout, orientation, cross_axis_size } => {
644            let cross = cross_axis_size.as_deref().map(|e| eval_to_f32(e, local_context));
645            crate::eval_layout::compute_box_layout_info(layout, *orientation, local_context, cross)
646        }
647        Expression::ComputeGridLayoutInfo {
648            layout_organized_data_prop,
649            layout,
650            orientation,
651            cross_axis_size,
652        } => {
653            let cross = cross_axis_size.as_deref().map(|e| eval_to_f32(e, local_context));
654            let cache = load_property_helper(
655                &ComponentInstance::InstanceRef(local_context.component_instance),
656                &layout_organized_data_prop.element(),
657                layout_organized_data_prop.name(),
658            )
659            .unwrap();
660            if let Value::ArrayOfU16(organized_data) = cache {
661                crate::eval_layout::compute_grid_layout_info(
662                    layout,
663                    &organized_data,
664                    *orientation,
665                    local_context,
666                    cross,
667                )
668            } else {
669                panic!("invalid layout organized data cache")
670            }
671        }
672        Expression::OrganizeGridLayout(lay) => {
673            crate::eval_layout::organize_grid_layout(lay, local_context)
674        }
675        Expression::SolveBoxLayout(lay, o) => {
676            crate::eval_layout::solve_box_layout(lay, *o, local_context)
677        }
678        Expression::SolveGridLayout { layout_organized_data_prop, layout, orientation } => {
679            let cache = load_property_helper(
680                &ComponentInstance::InstanceRef(local_context.component_instance),
681                &layout_organized_data_prop.element(),
682                layout_organized_data_prop.name(),
683            )
684            .unwrap();
685            if let Value::ArrayOfU16(organized_data) = cache {
686                crate::eval_layout::solve_grid_layout(
687                    &organized_data,
688                    layout,
689                    *orientation,
690                    local_context,
691                )
692            } else {
693                panic!("invalid layout organized data cache")
694            }
695        }
696        Expression::SolveFlexboxLayout(layout) => {
697            crate::eval_layout::solve_flexbox_layout(layout, local_context)
698        }
699        Expression::ComputeFlexboxLayoutInfo { layout, orientation, cross_axis_size } => {
700            let cross = cross_axis_size.as_deref().map(|e| eval_to_f32(e, local_context));
701            crate::eval_layout::compute_flexbox_layout_info(
702                layout,
703                *orientation,
704                local_context,
705                cross,
706            )
707        }
708        Expression::MinMax { ty: _, op, lhs, rhs } => {
709            let Value::Number(lhs) = eval_expression(lhs, local_context) else {
710                return local_context
711                    .return_value
712                    .clone()
713                    .expect("minmax lhs expression did not evaluate to number");
714            };
715            let Value::Number(rhs) = eval_expression(rhs, local_context) else {
716                return local_context
717                    .return_value
718                    .clone()
719                    .expect("minmax rhs expression did not evaluate to number");
720            };
721            match op {
722                MinMaxOp::Min => Value::Number(lhs.min(rhs)),
723                MinMaxOp::Max => Value::Number(lhs.max(rhs)),
724            }
725        }
726        Expression::EmptyComponentFactory => Value::ComponentFactory(Default::default()),
727        Expression::EmptyDataTransfer => Value::DataTransfer(Default::default()),
728        Expression::DebugHook { expression, id: _id, .. } => {
729            #[cfg(feature = "internal")]
730            {
731                if let Some(hook_value) = crate::debug_hook::trigger_debug_hook(
732                    &local_context.component_instance,
733                    _id.clone(),
734                ) {
735                    return hook_value;
736                }
737            }
738
739            eval_expression(expression, local_context)
740        }
741    }
742}
743
744fn call_builtin_function(
745    f: BuiltinFunction,
746    arguments: &[Expression],
747    local_context: &mut EvalLocalContext,
748    source_location: &Option<i_slint_compiler::diagnostics::SourceLocation>,
749) -> Value {
750    match f {
751        BuiltinFunction::GetWindowScaleFactor => Value::Number(
752            local_context.component_instance.access_window(|window| window.scale_factor()) as _,
753        ),
754        BuiltinFunction::GetWindowDefaultFontSize => Value::Number({
755            let component = local_context.component_instance;
756            let item_comp = component.self_weak().get().unwrap().upgrade().unwrap();
757            WindowItem::resolved_default_font_size(vtable::VRc::into_dyn(item_comp)).get() as _
758        }),
759        BuiltinFunction::AnimationTick => {
760            Value::Number(i_slint_core::animations::animation_tick() as f64)
761        }
762        BuiltinFunction::Debug => {
763            use corelib::debug_log::*;
764
765            let to_print: SharedString =
766                eval_expression(&arguments[0], local_context).try_into().unwrap();
767            let location = source_location.as_ref().and_then(|location| {
768                location.source_file().map(|file| {
769                    let (line, column) = file.line_column(
770                        location.span.offset,
771                        i_slint_compiler::diagnostics::ByteFormat::Utf8,
772                    );
773                    let path = file.path().to_string_lossy();
774                    (line, column, path)
775                })
776            });
777            let location = location.as_ref().map(|(line, column, path)| LogMessageLocation {
778                path,
779                line: *line,
780                column: *column,
781            });
782            let root_weak =
783                vtable::VWeak::into_dyn(local_context.component_instance.root_weak().clone());
784            if let Some(root) = root_weak.upgrade()
785                && let Some(ctx) = corelib::window::context_for_root(&root)
786            {
787                ctx.dispatch_log_message(LogMessage::new(
788                    LogMessageSource::SlintCode,
789                    location,
790                    format_args!("{to_print}"),
791                ));
792            } else {
793                log_message(LogMessage::new(
794                    LogMessageSource::SlintCode,
795                    location,
796                    format_args!("{to_print}"),
797                ));
798            }
799            Value::Void
800        }
801        BuiltinFunction::DecimalSeparator => Value::String(
802            local_context
803                .component_instance
804                .access_window(|window| window.context().locale_decimal_separator())
805                .into(),
806        ),
807        BuiltinFunction::Mod => {
808            let mut to_num = |e| -> f64 { eval_expression(e, local_context).try_into().unwrap() };
809            Value::Number(to_num(&arguments[0]).rem_euclid(to_num(&arguments[1])))
810        }
811        BuiltinFunction::Round => {
812            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
813            Value::Number(x.round())
814        }
815        BuiltinFunction::Ceil => {
816            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
817            Value::Number(x.ceil())
818        }
819        BuiltinFunction::Floor => {
820            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
821            Value::Number(x.floor())
822        }
823        BuiltinFunction::Sqrt => {
824            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
825            Value::Number(x.sqrt())
826        }
827        BuiltinFunction::Abs => {
828            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
829            Value::Number(x.abs())
830        }
831        BuiltinFunction::Sin => {
832            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
833            Value::Number(x.to_radians().sin())
834        }
835        BuiltinFunction::Cos => {
836            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
837            Value::Number(x.to_radians().cos())
838        }
839        BuiltinFunction::Tan => {
840            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
841            Value::Number(x.to_radians().tan())
842        }
843        BuiltinFunction::ASin => {
844            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
845            Value::Number(x.asin().to_degrees())
846        }
847        BuiltinFunction::ACos => {
848            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
849            Value::Number(x.acos().to_degrees())
850        }
851        BuiltinFunction::ATan => {
852            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
853            Value::Number(x.atan().to_degrees())
854        }
855        BuiltinFunction::ATan2 => {
856            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
857            let y: f64 = eval_expression(&arguments[1], local_context).try_into().unwrap();
858            Value::Number(x.atan2(y).to_degrees())
859        }
860        BuiltinFunction::Log => {
861            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
862            let y: f64 = eval_expression(&arguments[1], local_context).try_into().unwrap();
863            Value::Number(x.log(y))
864        }
865        BuiltinFunction::Ln => {
866            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
867            Value::Number(x.ln())
868        }
869        BuiltinFunction::Pow => {
870            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
871            let y: f64 = eval_expression(&arguments[1], local_context).try_into().unwrap();
872            Value::Number(x.powf(y))
873        }
874        BuiltinFunction::Exp => {
875            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
876            Value::Number(x.exp())
877        }
878        BuiltinFunction::ToFixed => {
879            let n: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
880            let digits: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
881            let digits: usize = digits.max(0) as usize;
882            Value::String(i_slint_core::string::shared_string_from_number_fixed(n, digits))
883        }
884        BuiltinFunction::ToPrecision => {
885            let n: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
886            let precision: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
887            let precision: usize = precision.max(0) as usize;
888            Value::String(i_slint_core::string::shared_string_from_number_precision(n, precision))
889        }
890        BuiltinFunction::ToStringUnlocalized => {
891            let n: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
892            Value::String(i_slint_core::string::shared_string_from_number_unlocalized(n))
893        }
894        BuiltinFunction::SetFocusItem => {
895            if arguments.len() != 1 {
896                panic!("internal error: incorrect argument count to SetFocusItem")
897            }
898            let component = local_context.component_instance;
899            if let Expression::ElementReference(focus_item) = &arguments[0] {
900                generativity::make_guard!(guard);
901
902                let focus_item = focus_item.upgrade().unwrap();
903                let enclosing_component =
904                    enclosing_component_for_element(&focus_item, component, guard);
905                let description = enclosing_component.description;
906
907                let item_info = &description.items[focus_item.borrow().id.as_str()];
908
909                let focus_item_comp =
910                    enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
911
912                component.access_window(|window| {
913                    window.set_focus_item(
914                        &corelib::items::ItemRc::new(
915                            vtable::VRc::into_dyn(focus_item_comp),
916                            item_info.item_index(),
917                        ),
918                        true,
919                        FocusReason::Programmatic,
920                    )
921                });
922                Value::Void
923            } else {
924                panic!("internal error: argument to SetFocusItem must be an element")
925            }
926        }
927        BuiltinFunction::ClearFocusItem => {
928            if arguments.len() != 1 {
929                panic!("internal error: incorrect argument count to SetFocusItem")
930            }
931            let component = local_context.component_instance;
932            if let Expression::ElementReference(focus_item) = &arguments[0] {
933                generativity::make_guard!(guard);
934
935                let focus_item = focus_item.upgrade().unwrap();
936                let enclosing_component =
937                    enclosing_component_for_element(&focus_item, component, guard);
938                let description = enclosing_component.description;
939
940                let item_info = &description.items[focus_item.borrow().id.as_str()];
941
942                let focus_item_comp =
943                    enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
944
945                component.access_window(|window| {
946                    window.set_focus_item(
947                        &corelib::items::ItemRc::new(
948                            vtable::VRc::into_dyn(focus_item_comp),
949                            item_info.item_index(),
950                        ),
951                        false,
952                        FocusReason::Programmatic,
953                    )
954                });
955                Value::Void
956            } else {
957                panic!("internal error: argument to ClearFocusItem must be an element")
958            }
959        }
960        BuiltinFunction::ShowPopupWindow => {
961            if arguments.len() != 1 {
962                panic!("internal error: incorrect argument count to ShowPopupWindow")
963            }
964            let component = local_context.component_instance;
965            if let Expression::ElementReference(popup_window) = &arguments[0] {
966                let popup_window = popup_window.upgrade().unwrap();
967                let pop_comp = popup_window.borrow().enclosing_component.upgrade().unwrap();
968                let parent_component = {
969                    let parent_elem = pop_comp.parent_element().unwrap();
970                    parent_elem.borrow().enclosing_component.upgrade().unwrap()
971                };
972                let popup_list = parent_component.popup_windows.borrow();
973                let popup =
974                    popup_list.iter().find(|p| Rc::ptr_eq(&p.component, &pop_comp)).unwrap();
975
976                generativity::make_guard!(guard);
977                let enclosing_component =
978                    enclosing_component_for_element(&popup.parent_element, component, guard);
979                let parent_item_info = &enclosing_component.description.items
980                    [popup.parent_element.borrow().id.as_str()];
981                let parent_item_comp =
982                    enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
983                let parent_item = corelib::items::ItemRc::new(
984                    vtable::VRc::into_dyn(parent_item_comp),
985                    parent_item_info.item_index(),
986                );
987
988                let close_policy = Value::EnumerationValue(
989                    popup.close_policy.enumeration.name.to_string(),
990                    popup.close_policy.to_string(),
991                )
992                .try_into()
993                .expect("Invalid internal enumeration representation for close policy");
994                let popup_x = popup.x.clone();
995                let popup_y = popup.y.clone();
996
997                crate::dynamic_item_tree::show_popup(
998                    popup_window,
999                    enclosing_component,
1000                    popup,
1001                    move |instance_ref| {
1002                        let comp = ComponentInstance::InstanceRef(instance_ref);
1003                        let x = load_property_helper(&comp, &popup_x.element(), popup_x.name())
1004                            .unwrap();
1005                        let y = load_property_helper(&comp, &popup_y.element(), popup_y.name())
1006                            .unwrap();
1007                        corelib::api::LogicalPosition::new(
1008                            x.try_into().unwrap(),
1009                            y.try_into().unwrap(),
1010                        )
1011                    },
1012                    close_policy,
1013                    (*enclosing_component.self_weak().get().unwrap()).clone(),
1014                    component.window_adapter(),
1015                    &parent_item,
1016                );
1017                Value::Void
1018            } else {
1019                panic!("internal error: argument to ShowPopupWindow must be an element")
1020            }
1021        }
1022        BuiltinFunction::ClosePopupWindow => {
1023            let component = local_context.component_instance;
1024            if let Expression::ElementReference(popup_window) = &arguments[0] {
1025                let popup_window = popup_window.upgrade().unwrap();
1026                let pop_comp = popup_window.borrow().enclosing_component.upgrade().unwrap();
1027                let parent_component = {
1028                    let parent_elem = pop_comp.parent_element().unwrap();
1029                    parent_elem.borrow().enclosing_component.upgrade().unwrap()
1030                };
1031                let popup_list = parent_component.popup_windows.borrow();
1032                let popup =
1033                    popup_list.iter().find(|p| Rc::ptr_eq(&p.component, &pop_comp)).unwrap();
1034
1035                generativity::make_guard!(guard);
1036                let enclosing_component =
1037                    enclosing_component_for_element(&popup.parent_element, component, guard);
1038                crate::dynamic_item_tree::close_popup(
1039                    popup_window,
1040                    enclosing_component,
1041                    enclosing_component.window_adapter(),
1042                );
1043
1044                Value::Void
1045            } else {
1046                panic!("internal error: argument to ClosePopupWindow must be an element")
1047            }
1048        }
1049        BuiltinFunction::ShowPopupMenu | BuiltinFunction::ShowPopupMenuInternal => {
1050            let [Expression::ElementReference(element), entries, position] = arguments else {
1051                panic!("internal error: incorrect argument count to ShowPopupMenu")
1052            };
1053            let position = eval_expression(position, local_context)
1054                .try_into()
1055                .expect("internal error: popup menu position argument should be a point");
1056
1057            let component = local_context.component_instance;
1058            let elem = element.upgrade().unwrap();
1059            generativity::make_guard!(guard);
1060            let enclosing_component = enclosing_component_for_element(&elem, component, guard);
1061            let description = enclosing_component.description;
1062            let item_info = &description.items[elem.borrow().id.as_str()];
1063            let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
1064            let item_tree = vtable::VRc::into_dyn(item_comp);
1065            let item_rc = corelib::items::ItemRc::new(item_tree.clone(), item_info.item_index());
1066
1067            generativity::make_guard!(guard);
1068            let compiled = enclosing_component.description.popup_menu_description.unerase(guard);
1069            let extra_data = enclosing_component
1070                .description
1071                .extra_data_offset
1072                .apply(enclosing_component.as_ref());
1073            let inst = crate::dynamic_item_tree::instantiate(
1074                compiled.clone(),
1075                Some((*enclosing_component.self_weak().get().unwrap()).clone()),
1076                None,
1077                Some(&crate::dynamic_item_tree::WindowOptions::UseExistingWindow(
1078                    component.window_adapter(),
1079                )),
1080                extra_data.globals.get().unwrap().clone(),
1081            );
1082
1083            generativity::make_guard!(guard);
1084            let inst_ref = inst.unerase(guard);
1085            if let Expression::ElementReference(e) = entries {
1086                let menu_item_tree =
1087                    e.upgrade().unwrap().borrow().enclosing_component.upgrade().unwrap();
1088                let menu_item_tree = crate::dynamic_item_tree::make_menu_item_tree(
1089                    &menu_item_tree,
1090                    &enclosing_component,
1091                    None,
1092                    None,
1093                );
1094
1095                if component.access_window(|window| {
1096                    window.show_native_popup_menu(
1097                        vtable::VRc::into_dyn(menu_item_tree.clone()),
1098                        position,
1099                        &item_rc,
1100                    )
1101                }) {
1102                    return Value::Void;
1103                }
1104
1105                let (entries, sub_menu, activated) = menu_item_tree_properties(menu_item_tree);
1106
1107                compiled.set_binding(inst_ref.borrow(), "entries", entries).unwrap();
1108                compiled.set_callback_handler(inst_ref.borrow(), "sub-menu", sub_menu).unwrap();
1109                compiled.set_callback_handler(inst_ref.borrow(), "activated", activated).unwrap();
1110            } else {
1111                let entries = eval_expression(entries, local_context);
1112                compiled.set_property(inst_ref.borrow(), "entries", entries).unwrap();
1113                let item_weak = item_rc.downgrade();
1114                compiled
1115                    .set_callback_handler(
1116                        inst_ref.borrow(),
1117                        "sub-menu",
1118                        Box::new(move |args: &[Value]| -> Value {
1119                            item_weak
1120                                .upgrade()
1121                                .unwrap()
1122                                .downcast::<corelib::items::ContextMenu>()
1123                                .unwrap()
1124                                .sub_menu
1125                                .call(&(args[0].clone().try_into().unwrap(),))
1126                                .into()
1127                        }),
1128                    )
1129                    .unwrap();
1130                let item_weak = item_rc.downgrade();
1131                compiled
1132                    .set_callback_handler(
1133                        inst_ref.borrow(),
1134                        "activated",
1135                        Box::new(move |args: &[Value]| -> Value {
1136                            item_weak
1137                                .upgrade()
1138                                .unwrap()
1139                                .downcast::<corelib::items::ContextMenu>()
1140                                .unwrap()
1141                                .activated
1142                                .call(&(args[0].clone().try_into().unwrap(),));
1143                            Value::Void
1144                        }),
1145                    )
1146                    .unwrap();
1147            }
1148            let item_weak = item_rc.downgrade();
1149            compiled
1150                .set_callback_handler(
1151                    inst_ref.borrow(),
1152                    "close-popup",
1153                    Box::new(move |_args: &[Value]| -> Value {
1154                        let Some(item_rc) = item_weak.upgrade() else { return Value::Void };
1155                        if let Some(id) = item_rc
1156                            .downcast::<corelib::items::ContextMenu>()
1157                            .unwrap()
1158                            .popup_id
1159                            .take()
1160                        {
1161                            WindowInner::from_pub(item_rc.window_adapter().unwrap().window())
1162                                .close_popup(id);
1163                        }
1164                        Value::Void
1165                    }),
1166                )
1167                .unwrap();
1168            component.access_window(|window| {
1169                let context_menu_elem = item_rc.downcast::<corelib::items::ContextMenu>().unwrap();
1170                if let Some(old_id) = context_menu_elem.popup_id.take() {
1171                    window.close_popup(old_id)
1172                }
1173                let id = window.show_popup(
1174                    &vtable::VRc::into_dyn(inst.clone()),
1175                    Box::new(move || position),
1176                    corelib::items::PopupClosePolicy::CloseOnClickOutside,
1177                    &item_rc,
1178                    WindowKind::Menu,
1179                    Box::new(|_| {}),
1180                );
1181                context_menu_elem.popup_id.set(Some(id));
1182            });
1183            inst.run_setup_code();
1184            Value::Void
1185        }
1186        BuiltinFunction::SetSelectionOffsets => {
1187            if arguments.len() != 3 {
1188                panic!("internal error: incorrect argument count to select range function call")
1189            }
1190            let component = local_context.component_instance;
1191            if let Expression::ElementReference(element) = &arguments[0] {
1192                generativity::make_guard!(guard);
1193
1194                let elem = element.upgrade().unwrap();
1195                let enclosing_component = enclosing_component_for_element(&elem, component, guard);
1196                let description = enclosing_component.description;
1197                let item_info = &description.items[elem.borrow().id.as_str()];
1198                let item_ref =
1199                    unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
1200
1201                let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
1202                let item_rc = corelib::items::ItemRc::new(
1203                    vtable::VRc::into_dyn(item_comp),
1204                    item_info.item_index(),
1205                );
1206
1207                let window_adapter = component.window_adapter();
1208
1209                // TODO: Make this generic through RTTI
1210                if let Some(textinput) =
1211                    ItemRef::downcast_pin::<corelib::items::TextInput>(item_ref)
1212                {
1213                    let start: i32 =
1214                        eval_expression(&arguments[1], local_context).try_into().expect(
1215                            "internal error: second argument to set-selection-offsets must be an integer",
1216                        );
1217                    let end: i32 = eval_expression(&arguments[2], local_context).try_into().expect(
1218                        "internal error: third argument to set-selection-offsets must be an integer",
1219                    );
1220
1221                    textinput.set_selection_offsets(&window_adapter, &item_rc, start, end);
1222                } else {
1223                    panic!(
1224                        "internal error: member function called on element that doesn't have it: {}",
1225                        elem.borrow().original_name()
1226                    )
1227                }
1228
1229                Value::Void
1230            } else {
1231                panic!("internal error: first argument to set-selection-offsets must be an element")
1232            }
1233        }
1234        BuiltinFunction::ItemFontMetrics => {
1235            if arguments.len() != 1 {
1236                panic!(
1237                    "internal error: incorrect argument count to item font metrics function call"
1238                )
1239            }
1240            let component = local_context.component_instance;
1241            if let Expression::ElementReference(element) = &arguments[0] {
1242                generativity::make_guard!(guard);
1243
1244                let elem = element.upgrade().unwrap();
1245                let enclosing_component = enclosing_component_for_element(&elem, component, guard);
1246                let description = enclosing_component.description;
1247                let item_info = &description.items[elem.borrow().id.as_str()];
1248                let item_ref =
1249                    unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
1250                let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
1251                let item_rc = corelib::items::ItemRc::new(
1252                    vtable::VRc::into_dyn(item_comp),
1253                    item_info.item_index(),
1254                );
1255                let window_adapter = component.window_adapter();
1256                let metrics = i_slint_core::items::slint_text_item_fontmetrics(
1257                    &window_adapter,
1258                    item_ref,
1259                    &item_rc,
1260                );
1261                metrics.into()
1262            } else {
1263                panic!("internal error: argument to item-font-metrics must be an element")
1264            }
1265        }
1266        BuiltinFunction::StringIsFloat => {
1267            if arguments.len() != 1 {
1268                panic!("internal error: incorrect argument count to StringIsFloat")
1269            }
1270            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
1271                Value::Bool(<f64 as core::str::FromStr>::from_str(s.as_str()).is_ok())
1272            } else {
1273                panic!("Argument not a string");
1274            }
1275        }
1276        BuiltinFunction::StringToFloat => {
1277            if arguments.len() != 1 {
1278                panic!("internal error: incorrect argument count to StringToFloat")
1279            }
1280            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
1281                Value::Number(core::str::FromStr::from_str(s.as_str()).unwrap_or(0.))
1282            } else {
1283                panic!("Argument not a string");
1284            }
1285        }
1286        BuiltinFunction::StringIsEmpty => {
1287            if arguments.len() != 1 {
1288                panic!("internal error: incorrect argument count to StringIsEmpty")
1289            }
1290            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
1291                Value::Bool(s.is_empty())
1292            } else {
1293                panic!("Argument not a string");
1294            }
1295        }
1296        BuiltinFunction::StringCharacterCount => {
1297            if arguments.len() != 1 {
1298                panic!("internal error: incorrect argument count to StringCharacterCount")
1299            }
1300            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
1301                Value::Number(
1302                    unicode_segmentation::UnicodeSegmentation::graphemes(s.as_str(), true).count()
1303                        as f64,
1304                )
1305            } else {
1306                panic!("Argument not a string");
1307            }
1308        }
1309        BuiltinFunction::StringToLowercase => {
1310            if arguments.len() != 1 {
1311                panic!("internal error: incorrect argument count to StringToLowercase")
1312            }
1313            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
1314                Value::String(s.to_lowercase().into())
1315            } else {
1316                panic!("Argument not a string");
1317            }
1318        }
1319        BuiltinFunction::StringToUppercase => {
1320            if arguments.len() != 1 {
1321                panic!("internal error: incorrect argument count to StringToUppercase")
1322            }
1323            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
1324                Value::String(s.to_uppercase().into())
1325            } else {
1326                panic!("Argument not a string");
1327            }
1328        }
1329        BuiltinFunction::StringStartsWith => {
1330            if arguments.len() != 2 {
1331                panic!("internal error: incorrect argument count to StringStartsWith")
1332            }
1333            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
1334                if let Value::String(pat) = eval_expression(&arguments[1], local_context) {
1335                    Value::Bool(s.starts_with(pat.as_str()))
1336                } else {
1337                    panic!("Second argument not a string");
1338                }
1339            } else {
1340                panic!("First argument not a string");
1341            }
1342        }
1343        BuiltinFunction::StringEndsWith => {
1344            if arguments.len() != 2 {
1345                panic!("internal error: incorrect argument count to StringEndsWith")
1346            }
1347            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
1348                if let Value::String(pat) = eval_expression(&arguments[1], local_context) {
1349                    Value::Bool(s.ends_with(pat.as_str()))
1350                } else {
1351                    panic!("Second argument not a string");
1352                }
1353            } else {
1354                panic!("First argument not a string");
1355            }
1356        }
1357        BuiltinFunction::KeysToString => {
1358            if arguments.len() != 1 {
1359                panic!("internal error: incorrect argument count to KeysToString")
1360            }
1361            let Value::Keys(keys) = eval_expression(&arguments[0], local_context) else {
1362                panic!("Argument is not of type keys");
1363            };
1364            Value::String(ToSharedString::to_shared_string(&keys))
1365        }
1366        BuiltinFunction::ColorRgbaStruct => {
1367            if arguments.len() != 1 {
1368                panic!("internal error: incorrect argument count to ColorRGBAComponents")
1369            }
1370            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
1371                let color = brush.color();
1372                let values = IntoIterator::into_iter([
1373                    ("red".to_string(), Value::Number(color.red().into())),
1374                    ("green".to_string(), Value::Number(color.green().into())),
1375                    ("blue".to_string(), Value::Number(color.blue().into())),
1376                    ("alpha".to_string(), Value::Number(color.alpha().into())),
1377                ])
1378                .collect();
1379                Value::Struct(values)
1380            } else {
1381                panic!("First argument not a color");
1382            }
1383        }
1384        BuiltinFunction::ColorHsvaStruct => {
1385            if arguments.len() != 1 {
1386                panic!("internal error: incorrect argument count to ColorHSVAComponents")
1387            }
1388            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
1389                let color = brush.color().to_hsva();
1390                let values = IntoIterator::into_iter([
1391                    ("hue".to_string(), Value::Number(color.hue.into())),
1392                    ("saturation".to_string(), Value::Number(color.saturation.into())),
1393                    ("value".to_string(), Value::Number(color.value.into())),
1394                    ("alpha".to_string(), Value::Number(color.alpha.into())),
1395                ])
1396                .collect();
1397                Value::Struct(values)
1398            } else {
1399                panic!("First argument not a color");
1400            }
1401        }
1402        BuiltinFunction::ColorOklchStruct => {
1403            if arguments.len() != 1 {
1404                panic!("internal error: incorrect argument count to ColorOklchStruct")
1405            }
1406            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
1407                let color = brush.color().to_oklch();
1408                let values = IntoIterator::into_iter([
1409                    ("lightness".to_string(), Value::Number(color.lightness.into())),
1410                    ("chroma".to_string(), Value::Number(color.chroma.into())),
1411                    ("hue".to_string(), Value::Number(color.hue.into())),
1412                    ("alpha".to_string(), Value::Number(color.alpha.into())),
1413                ])
1414                .collect();
1415                Value::Struct(values)
1416            } else {
1417                panic!("First argument not a color");
1418            }
1419        }
1420        BuiltinFunction::ColorBrighter => {
1421            if arguments.len() != 2 {
1422                panic!("internal error: incorrect argument count to ColorBrighter")
1423            }
1424            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
1425                if let Value::Number(factor) = eval_expression(&arguments[1], local_context) {
1426                    brush.brighter(factor as _).into()
1427                } else {
1428                    panic!("Second argument not a number");
1429                }
1430            } else {
1431                panic!("First argument not a color");
1432            }
1433        }
1434        BuiltinFunction::ColorDarker => {
1435            if arguments.len() != 2 {
1436                panic!("internal error: incorrect argument count to ColorDarker")
1437            }
1438            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
1439                if let Value::Number(factor) = eval_expression(&arguments[1], local_context) {
1440                    brush.darker(factor as _).into()
1441                } else {
1442                    panic!("Second argument not a number");
1443                }
1444            } else {
1445                panic!("First argument not a color");
1446            }
1447        }
1448        BuiltinFunction::ColorTransparentize => {
1449            if arguments.len() != 2 {
1450                panic!("internal error: incorrect argument count to ColorFaded")
1451            }
1452            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
1453                if let Value::Number(factor) = eval_expression(&arguments[1], local_context) {
1454                    brush.transparentize(factor as _).into()
1455                } else {
1456                    panic!("Second argument not a number");
1457                }
1458            } else {
1459                panic!("First argument not a color");
1460            }
1461        }
1462        BuiltinFunction::ColorMix => {
1463            if arguments.len() != 3 {
1464                panic!("internal error: incorrect argument count to ColorMix")
1465            }
1466
1467            let arg0 = eval_expression(&arguments[0], local_context);
1468            let arg1 = eval_expression(&arguments[1], local_context);
1469            let arg2 = eval_expression(&arguments[2], local_context);
1470
1471            if !matches!(arg0, Value::Brush(Brush::SolidColor(_))) {
1472                panic!("First argument not a color");
1473            }
1474            if !matches!(arg1, Value::Brush(Brush::SolidColor(_))) {
1475                panic!("Second argument not a color");
1476            }
1477            if !matches!(arg2, Value::Number(_)) {
1478                panic!("Third argument not a number");
1479            }
1480
1481            let (
1482                Value::Brush(Brush::SolidColor(color_a)),
1483                Value::Brush(Brush::SolidColor(color_b)),
1484                Value::Number(factor),
1485            ) = (arg0, arg1, arg2)
1486            else {
1487                unreachable!()
1488            };
1489
1490            color_a.mix(&color_b, factor as _).into()
1491        }
1492        BuiltinFunction::ColorWithAlpha => {
1493            if arguments.len() != 2 {
1494                panic!("internal error: incorrect argument count to ColorWithAlpha")
1495            }
1496            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
1497                if let Value::Number(factor) = eval_expression(&arguments[1], local_context) {
1498                    brush.with_alpha(factor as _).into()
1499                } else {
1500                    panic!("Second argument not a number");
1501                }
1502            } else {
1503                panic!("First argument not a color");
1504            }
1505        }
1506        BuiltinFunction::ImageSize => {
1507            if arguments.len() != 1 {
1508                panic!("internal error: incorrect argument count to ImageSize")
1509            }
1510            if let Value::Image(img) = eval_expression(&arguments[0], local_context) {
1511                let size = img.size();
1512                let values = IntoIterator::into_iter([
1513                    ("width".to_string(), Value::Number(size.width as f64)),
1514                    ("height".to_string(), Value::Number(size.height as f64)),
1515                ])
1516                .collect();
1517                Value::Struct(values)
1518            } else {
1519                panic!("First argument not an image");
1520            }
1521        }
1522        BuiltinFunction::ArrayLength => {
1523            if arguments.len() != 1 {
1524                panic!("internal error: incorrect argument count to ArrayLength")
1525            }
1526            match eval_expression(&arguments[0], local_context) {
1527                Value::Model(model) => {
1528                    model.model_tracker().track_row_count_changes();
1529                    Value::Number(model.row_count() as f64)
1530                }
1531                _ => {
1532                    panic!("First argument not an array: {:?}", arguments[0]);
1533                }
1534            }
1535        }
1536        BuiltinFunction::ArrayPush => {
1537            if arguments.len() != 2 {
1538                panic!("internal error: incorrect argument count to ArrayPush")
1539            }
1540
1541            let model = match eval_expression(&arguments[0], local_context) {
1542                Value::Model(m) => m,
1543                _ => panic!("First argument not an array: {:?}", arguments[0]),
1544            };
1545            let value = eval_expression(&arguments[1], local_context);
1546
1547            model.push_row(value);
1548
1549            Value::Void
1550        }
1551        BuiltinFunction::ArrayRemove => {
1552            if arguments.len() != 2 {
1553                panic!("internal error: incorrect argument count to ArrayRemove")
1554            }
1555
1556            let model = match eval_expression(&arguments[0], local_context) {
1557                Value::Model(m) => m,
1558                _ => panic!("First argument not an array: {:?}", arguments[0]),
1559            };
1560            let index = match eval_expression(&arguments[1], local_context) {
1561                Value::Number(i) => i,
1562                _ => panic!("Second argument not an integer: {:?}", arguments[1]),
1563            };
1564
1565            model.remove_row(index as isize);
1566
1567            Value::Void
1568        }
1569
1570        BuiltinFunction::ArrayInsert => {
1571            if arguments.len() != 3 {
1572                panic!("internal error: incorrect argument count to ArrayInsert")
1573            }
1574
1575            let model = match eval_expression(&arguments[0], local_context) {
1576                Value::Model(m) => m,
1577                _ => panic!("First argument not an array: {:?}", arguments[0]),
1578            };
1579            let index = match eval_expression(&arguments[1], local_context) {
1580                Value::Number(i) => i,
1581                _ => panic!("Second argument not an integer: {:?}", arguments[1]),
1582            };
1583
1584            let value = eval_expression(&arguments[2], local_context);
1585            model.insert_row(index as isize, value);
1586
1587            Value::Void
1588        }
1589        BuiltinFunction::Rgb => {
1590            let r: i32 = eval_expression(&arguments[0], local_context).try_into().unwrap();
1591            let g: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
1592            let b: i32 = eval_expression(&arguments[2], local_context).try_into().unwrap();
1593            let a: f32 = eval_expression(&arguments[3], local_context).try_into().unwrap();
1594            let r: u8 = r.clamp(0, 255) as u8;
1595            let g: u8 = g.clamp(0, 255) as u8;
1596            let b: u8 = b.clamp(0, 255) as u8;
1597            let a: u8 = (255. * a).clamp(0., 255.) as u8;
1598            Value::Brush(Brush::SolidColor(Color::from_argb_u8(a, r, g, b)))
1599        }
1600        BuiltinFunction::Hsv => {
1601            let h: f32 = eval_expression(&arguments[0], local_context).try_into().unwrap();
1602            let s: f32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
1603            let v: f32 = eval_expression(&arguments[2], local_context).try_into().unwrap();
1604            let a: f32 = eval_expression(&arguments[3], local_context).try_into().unwrap();
1605            let a = (1. * a).clamp(0., 1.);
1606            Value::Brush(Brush::SolidColor(Color::from_hsva(h, s, v, a)))
1607        }
1608        BuiltinFunction::Oklch => {
1609            let l: f32 = eval_expression(&arguments[0], local_context).try_into().unwrap();
1610            let c: f32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
1611            let h: f32 = eval_expression(&arguments[2], local_context).try_into().unwrap();
1612            let a: f32 = eval_expression(&arguments[3], local_context).try_into().unwrap();
1613            let l = l.clamp(0., 1.);
1614            let c = c.max(0.);
1615            let a = a.clamp(0., 1.);
1616            Value::Brush(Brush::SolidColor(Color::from_oklch(l, c, h, a)))
1617        }
1618        BuiltinFunction::ColorScheme => {
1619            let root_weak =
1620                vtable::VWeak::into_dyn(local_context.component_instance.root_weak().clone());
1621            let root = root_weak.upgrade().unwrap();
1622            corelib::window::context_for_root(&root)
1623                .map_or(corelib::items::ColorScheme::Unknown, |ctx| ctx.color_scheme(Some(&root)))
1624                .into()
1625        }
1626        BuiltinFunction::AccentColor => {
1627            let root_weak =
1628                vtable::VWeak::into_dyn(local_context.component_instance.root_weak().clone());
1629            let root = root_weak.upgrade().unwrap();
1630            Value::Brush(corelib::Brush::SolidColor(corelib::window::accent_color(&root)))
1631        }
1632        BuiltinFunction::SupportsNativeMenuBar => local_context
1633            .component_instance
1634            .window_adapter()
1635            .internal(corelib::InternalToken)
1636            .is_some_and(|x| x.supports_native_menu_bar())
1637            .into(),
1638        BuiltinFunction::SetupMenuBar => {
1639            let component = local_context.component_instance;
1640            let [
1641                Expression::PropertyReference(entries_nr),
1642                Expression::PropertyReference(sub_menu_nr),
1643                Expression::PropertyReference(activated_nr),
1644                Expression::ElementReference(item_tree_root),
1645                Expression::BoolLiteral(no_native),
1646                condition,
1647                visible,
1648                ..,
1649            ] = arguments
1650            else {
1651                panic!("internal error: incorrect argument count to SetupMenuBar")
1652            };
1653
1654            let menu_item_tree =
1655                item_tree_root.upgrade().unwrap().borrow().enclosing_component.upgrade().unwrap();
1656            let menu_item_tree = crate::dynamic_item_tree::make_menu_item_tree(
1657                &menu_item_tree,
1658                &component,
1659                Some(condition),
1660                Some(visible),
1661            );
1662
1663            let window_adapter = component.window_adapter();
1664            let window_inner = WindowInner::from_pub(window_adapter.window());
1665            let menubar = vtable::VRc::into_dyn(vtable::VRc::clone(&menu_item_tree));
1666            window_inner.setup_menubar_shortcuts(vtable::VRc::clone(&menubar));
1667
1668            if !no_native && window_inner.supports_native_menu_bar() {
1669                window_inner.setup_menubar(menubar);
1670                return Value::Void;
1671            }
1672
1673            let (entries, sub_menu, activated) = menu_item_tree_properties(menu_item_tree);
1674
1675            assert_eq!(
1676                entries_nr.element().borrow().id,
1677                component.description.original.root_element.borrow().id,
1678                "entries need to be in the main element"
1679            );
1680            local_context
1681                .component_instance
1682                .description
1683                .set_binding(component.borrow(), entries_nr.name(), entries)
1684                .unwrap();
1685            let i = &ComponentInstance::InstanceRef(local_context.component_instance);
1686            set_callback_handler(i, &sub_menu_nr.element(), sub_menu_nr.name(), sub_menu).unwrap();
1687            set_callback_handler(i, &activated_nr.element(), activated_nr.name(), activated)
1688                .unwrap();
1689
1690            Value::Void
1691        }
1692        BuiltinFunction::SetupSystemTrayIcon => {
1693            let [
1694                Expression::ElementReference(system_tray_elem),
1695                Expression::ElementReference(item_tree_root),
1696                rest @ ..,
1697            ] = arguments
1698            else {
1699                panic!("internal error: incorrect argument count to SetupSystemTrayIcon")
1700            };
1701
1702            let component = local_context.component_instance;
1703            let elem = system_tray_elem.upgrade().unwrap();
1704            generativity::make_guard!(guard);
1705            let enclosing_component = enclosing_component_for_element(&elem, component, guard);
1706            let description = enclosing_component.description;
1707            let item_info = &description.items[elem.borrow().id.as_str()];
1708            let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
1709            let item_tree = vtable::VRc::into_dyn(item_comp);
1710            let item_rc = corelib::items::ItemRc::new(item_tree.clone(), item_info.item_index());
1711
1712            let menu_item_tree_component =
1713                item_tree_root.upgrade().unwrap().borrow().enclosing_component.upgrade().unwrap();
1714            let menu_vrc = crate::dynamic_item_tree::make_menu_item_tree(
1715                &menu_item_tree_component,
1716                &enclosing_component,
1717                rest.first(),
1718                None,
1719            );
1720
1721            let system_tray =
1722                item_rc.downcast::<corelib::items::SystemTrayIcon>().expect("SystemTrayIcon item");
1723            system_tray.as_pin_ref().set_menu(&item_rc, vtable::VRc::into_dyn(menu_vrc));
1724
1725            Value::Void
1726        }
1727        BuiltinFunction::MonthDayCount => {
1728            let m: u32 = eval_expression(&arguments[0], local_context).try_into().unwrap();
1729            let y: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
1730            Value::Number(i_slint_core::date_time::month_day_count(m, y).unwrap_or(0) as f64)
1731        }
1732        BuiltinFunction::MonthOffset => {
1733            let m: u32 = eval_expression(&arguments[0], local_context).try_into().unwrap();
1734            let y: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
1735
1736            Value::Number(i_slint_core::date_time::month_offset(m, y) as f64)
1737        }
1738        BuiltinFunction::FormatDate => {
1739            let f: SharedString = eval_expression(&arguments[0], local_context).try_into().unwrap();
1740            let d: u32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
1741            let m: u32 = eval_expression(&arguments[2], local_context).try_into().unwrap();
1742            let y: i32 = eval_expression(&arguments[3], local_context).try_into().unwrap();
1743
1744            Value::String(i_slint_core::date_time::format_date(&f, d, m, y))
1745        }
1746        BuiltinFunction::DateNow => Value::Model(ModelRc::new(VecModel::from(
1747            i_slint_core::date_time::date_now()
1748                .into_iter()
1749                .map(|x| Value::Number(x as f64))
1750                .collect::<Vec<_>>(),
1751        ))),
1752        BuiltinFunction::ValidDate => {
1753            let d: SharedString = eval_expression(&arguments[0], local_context).try_into().unwrap();
1754            let f: SharedString = eval_expression(&arguments[1], local_context).try_into().unwrap();
1755            Value::Bool(i_slint_core::date_time::parse_date(d.as_str(), f.as_str()).is_some())
1756        }
1757        BuiltinFunction::ParseDate => {
1758            let d: SharedString = eval_expression(&arguments[0], local_context).try_into().unwrap();
1759            let f: SharedString = eval_expression(&arguments[1], local_context).try_into().unwrap();
1760
1761            Value::Model(ModelRc::new(
1762                i_slint_core::date_time::parse_date(d.as_str(), f.as_str())
1763                    .map(|x| {
1764                        VecModel::from(
1765                            x.into_iter().map(|x| Value::Number(x as f64)).collect::<Vec<_>>(),
1766                        )
1767                    })
1768                    .unwrap_or_default(),
1769            ))
1770        }
1771        BuiltinFunction::TextInputFocused => Value::Bool(
1772            local_context.component_instance.access_window(|window| window.text_input_focused())
1773                as _,
1774        ),
1775        BuiltinFunction::SetTextInputFocused => {
1776            local_context.component_instance.access_window(|window| {
1777                window.set_text_input_focused(
1778                    eval_expression(&arguments[0], local_context).try_into().unwrap(),
1779                )
1780            });
1781            Value::Void
1782        }
1783        BuiltinFunction::ImplicitLayoutInfo(orient) => {
1784            let component = local_context.component_instance;
1785            if let [Expression::ElementReference(item), constraint_expr] = arguments {
1786                generativity::make_guard!(guard);
1787
1788                let constraint: f32 =
1789                    eval_expression(constraint_expr, local_context).try_into().unwrap_or(-1.);
1790
1791                let item = item.upgrade().unwrap();
1792                let enclosing_component = enclosing_component_for_element(&item, component, guard);
1793                let description = enclosing_component.description;
1794                let item_info = &description.items[item.borrow().id.as_str()];
1795                let item_ref =
1796                    unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
1797                let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
1798                let window_adapter = component.window_adapter();
1799                item_ref
1800                    .as_ref()
1801                    .layout_info(
1802                        crate::eval_layout::to_runtime(orient),
1803                        constraint,
1804                        &window_adapter,
1805                        &ItemRc::new(vtable::VRc::into_dyn(item_comp), item_info.item_index()),
1806                    )
1807                    .into()
1808            } else {
1809                panic!("internal error: incorrect arguments to ImplicitLayoutInfo {arguments:?}");
1810            }
1811        }
1812        BuiltinFunction::ItemAbsolutePosition => {
1813            if arguments.len() != 1 {
1814                panic!("internal error: incorrect argument count to ItemAbsolutePosition")
1815            }
1816
1817            let component = local_context.component_instance;
1818
1819            if let Expression::ElementReference(item) = &arguments[0] {
1820                generativity::make_guard!(guard);
1821
1822                let item = item.upgrade().unwrap();
1823                let enclosing_component = enclosing_component_for_element(&item, component, guard);
1824                let description = enclosing_component.description;
1825
1826                let item_info = &description.items[item.borrow().id.as_str()];
1827
1828                let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
1829
1830                let item_rc = corelib::items::ItemRc::new(
1831                    vtable::VRc::into_dyn(item_comp),
1832                    item_info.item_index(),
1833                );
1834
1835                // Map the item's own geometry origin through the ancestor transforms so the
1836                // result is the item's absolute position (not its parent's).
1837                item_rc.map_to_window(item_rc.geometry().origin).to_untyped().into()
1838            } else {
1839                panic!("internal error: argument to SetFocusItem must be an element")
1840            }
1841        }
1842        BuiltinFunction::RegisterCustomFontByPath => {
1843            if arguments.len() != 1 {
1844                panic!("internal error: incorrect argument count to RegisterCustomFontByPath")
1845            }
1846            let component = local_context.component_instance;
1847            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
1848                // If the window adapter can't be created, log and skip the registration
1849                // instead of panicking: the same error resurfaces when the window is
1850                // actually used.
1851                let result = component.try_window_adapter().map_err(|e| e.to_string()).and_then(
1852                    |window_adapter| {
1853                        window_adapter
1854                            .renderer()
1855                            .register_font_from_path(&std::path::PathBuf::from(s.as_str()))
1856                            .map_err(|e| format!("Cannot load custom font {}: {e}", s.as_str()))
1857                    },
1858                );
1859                if let Err(err) = result {
1860                    corelib::debug_log!("{err}");
1861                }
1862                Value::Void
1863            } else {
1864                panic!("Argument not a string");
1865            }
1866        }
1867        BuiltinFunction::RegisterCustomFontByMemory | BuiltinFunction::RegisterBitmapFont => {
1868            unimplemented!()
1869        }
1870        BuiltinFunction::Translate => {
1871            let original: SharedString =
1872                eval_expression(&arguments[0], local_context).try_into().unwrap();
1873            let context: SharedString =
1874                eval_expression(&arguments[1], local_context).try_into().unwrap();
1875            let domain: SharedString =
1876                eval_expression(&arguments[2], local_context).try_into().unwrap();
1877            let args = eval_expression(&arguments[3], local_context);
1878            let Value::Model(args) = args else { panic!("Args to translate not a model {args:?}") };
1879            struct StringModelWrapper(ModelRc<Value>);
1880            impl corelib::translations::FormatArgs for StringModelWrapper {
1881                type Output<'a> = SharedString;
1882                fn from_index(&self, index: usize) -> Option<SharedString> {
1883                    self.0.row_data(index).map(|x| x.try_into().unwrap())
1884                }
1885            }
1886            Value::String(corelib::translations::translate(
1887                &original,
1888                &context,
1889                &domain,
1890                &StringModelWrapper(args),
1891                eval_expression(&arguments[4], local_context).try_into().unwrap(),
1892                &SharedString::try_from(eval_expression(&arguments[5], local_context)).unwrap(),
1893            ))
1894        }
1895        BuiltinFunction::Use24HourFormat => Value::Bool(corelib::date_time::use_24_hour_format()),
1896        BuiltinFunction::UpdateTimers => {
1897            crate::dynamic_item_tree::update_timers(local_context.component_instance);
1898            Value::Void
1899        }
1900        BuiltinFunction::DetectOperatingSystem => i_slint_core::detect_operating_system().into(),
1901        // start and stop are unreachable because they are lowered to simple assignment of running
1902        BuiltinFunction::StartTimer => unreachable!(),
1903        BuiltinFunction::StopTimer => unreachable!(),
1904        BuiltinFunction::RestartTimer => {
1905            if let [Expression::ElementReference(timer_element)] = arguments {
1906                crate::dynamic_item_tree::restart_timer(
1907                    timer_element.clone(),
1908                    local_context.component_instance,
1909                );
1910
1911                Value::Void
1912            } else {
1913                panic!("internal error: argument to RestartTimer must be an element")
1914            }
1915        }
1916        BuiltinFunction::OpenUrl => {
1917            let url: SharedString =
1918                eval_expression(&arguments[0], local_context).try_into().unwrap();
1919            let window_adapter = local_context.component_instance.window_adapter();
1920            Value::Bool(corelib::open_url(&url, window_adapter.window()).is_ok())
1921        }
1922        BuiltinFunction::MacosBringAllWindowsToFront => {
1923            corelib::macos_bring_all_windows_to_front();
1924            Value::Void
1925        }
1926        BuiltinFunction::ParseMarkdown => {
1927            let format_string: SharedString =
1928                eval_expression(&arguments[0], local_context).try_into().unwrap();
1929            let args: ModelRc<corelib::styled_text::StyledText> =
1930                eval_expression(&arguments[1], local_context).try_into().unwrap();
1931            Value::StyledText(corelib::styled_text::parse_markdown(
1932                &format_string,
1933                &args.iter().collect::<Vec<_>>(),
1934            ))
1935        }
1936        BuiltinFunction::StringToStyledText => {
1937            let string: SharedString =
1938                eval_expression(&arguments[0], local_context).try_into().unwrap();
1939            Value::StyledText(corelib::styled_text::string_to_styled_text(string.to_string()))
1940        }
1941        BuiltinFunction::ColorToStyledText => {
1942            let color: corelib::Color =
1943                eval_expression(&arguments[0], local_context).try_into().unwrap();
1944            Value::StyledText(corelib::styled_text::color_to_styled_text(color))
1945        }
1946    }
1947}
1948
1949fn call_item_member_function(nr: &NamedReference, local_context: &mut EvalLocalContext) -> Value {
1950    let component = local_context.component_instance;
1951    let elem = nr.element();
1952    let name = nr.name().as_str();
1953    generativity::make_guard!(guard);
1954    let enclosing_component = enclosing_component_for_element(&elem, component, guard);
1955    let description = enclosing_component.description;
1956    let item_info = &description.items[elem.borrow().id.as_str()];
1957    let item_ref = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
1958
1959    let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
1960    let item_rc =
1961        corelib::items::ItemRc::new(vtable::VRc::into_dyn(item_comp), item_info.item_index());
1962
1963    let window_adapter = component.window_adapter();
1964
1965    // TODO: Make this generic through RTTI
1966    if let Some(textinput) = ItemRef::downcast_pin::<corelib::items::TextInput>(item_ref) {
1967        match name {
1968            "select-all" => textinput.select_all(&window_adapter, &item_rc),
1969            "clear-selection" => textinput.clear_selection(&window_adapter, &item_rc),
1970            "cut" => textinput.cut(&window_adapter, &item_rc),
1971            "copy" => textinput.copy(&window_adapter, &item_rc),
1972            "paste" => textinput.paste(&window_adapter, &item_rc),
1973            "undo" => textinput.undo(&window_adapter, &item_rc),
1974            "redo" => textinput.redo(&window_adapter, &item_rc),
1975            _ => panic!("internal: Unknown member function {name} called on TextInput"),
1976        }
1977    } else if let Some(s) = ItemRef::downcast_pin::<corelib::items::SwipeGestureHandler>(item_ref) {
1978        match name {
1979            "cancel" => s.cancel(&window_adapter, &item_rc),
1980            _ => panic!("internal: Unknown member function {name} called on SwipeGestureHandler"),
1981        }
1982    } else if let Some(s) = ItemRef::downcast_pin::<corelib::items::ContextMenu>(item_ref) {
1983        match name {
1984            "close" => s.close(&window_adapter, &item_rc),
1985            "is-open" => return Value::Bool(s.is_open(&window_adapter, &item_rc)),
1986            _ => {
1987                panic!("internal: Unknown member function {name} called on ContextMenu")
1988            }
1989        }
1990    } else if let Some(s) = ItemRef::downcast_pin::<corelib::items::WindowItem>(item_ref) {
1991        match name {
1992            "hide" => s.hide(&window_adapter, &item_rc),
1993            "close" => return Value::Bool(s.close(&window_adapter, &item_rc)),
1994            _ => {
1995                panic!("internal: Unknown member function {name} called on WindowItem")
1996            }
1997        }
1998    } else {
1999        panic!(
2000            "internal error: member function {name} called on element that doesn't have it: {}",
2001            elem.borrow().original_name()
2002        )
2003    }
2004
2005    Value::Void
2006}
2007
2008fn eval_assignment(lhs: &Expression, op: char, rhs: Value, local_context: &mut EvalLocalContext) {
2009    let eval = |lhs| match (lhs, &rhs, op) {
2010        (Value::String(ref mut a), Value::String(b), '+') => {
2011            a.push_str(b.as_str());
2012            Value::String(a.clone())
2013        }
2014        (Value::Number(a), Value::Number(b), '+') => Value::Number(a + b),
2015        (Value::Number(a), Value::Number(b), '-') => Value::Number(a - b),
2016        (Value::Number(a), Value::Number(b), '/') => Value::Number(a / b),
2017        (Value::Number(a), Value::Number(b), '*') => Value::Number(a * b),
2018        (lhs, rhs, op) => panic!("unsupported {lhs:?} {op} {rhs:?}"),
2019    };
2020    match lhs {
2021        Expression::PropertyReference(nr) => {
2022            let element = nr.element();
2023            generativity::make_guard!(guard);
2024            let enclosing_component = enclosing_component_instance_for_element(
2025                &element,
2026                &ComponentInstance::InstanceRef(local_context.component_instance),
2027                guard,
2028            );
2029
2030            match enclosing_component {
2031                ComponentInstance::InstanceRef(enclosing_component) => {
2032                    if op == '=' {
2033                        store_property(enclosing_component, &element, nr.name(), rhs).unwrap();
2034                        return;
2035                    }
2036
2037                    let component = element.borrow().enclosing_component.upgrade().unwrap();
2038                    if element.borrow().id == component.root_element.borrow().id
2039                        && let Some(x) =
2040                            enclosing_component.description.custom_properties.get(nr.name())
2041                    {
2042                        unsafe {
2043                            let p =
2044                                Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset));
2045                            x.prop.set(p, eval(x.prop.get(p).unwrap()), None).unwrap();
2046                        }
2047                        return;
2048                    }
2049                    let item_info =
2050                        &enclosing_component.description.items[element.borrow().id.as_str()];
2051                    let item =
2052                        unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
2053                    let p = &item_info.rtti.properties[nr.name().as_str()];
2054                    p.set(item, eval(p.get(item)), None).unwrap();
2055                }
2056                ComponentInstance::GlobalComponent(global) => {
2057                    let val = if op == '=' {
2058                        rhs
2059                    } else {
2060                        eval(global.as_ref().get_property(nr.name()).unwrap())
2061                    };
2062                    global.as_ref().set_property(nr.name(), val).unwrap();
2063                }
2064            }
2065        }
2066        Expression::StructFieldAccess { base, name } => {
2067            if let Value::Struct(mut o) = eval_expression(base, local_context) {
2068                let mut r = o.get_field(name).unwrap().clone();
2069                r = if op == '=' { rhs } else { eval(std::mem::take(&mut r)) };
2070                o.set_field(name.to_string(), r);
2071                eval_assignment(base, '=', Value::Struct(o), local_context)
2072            }
2073        }
2074        Expression::RepeaterModelReference { element } => {
2075            let element = element.upgrade().unwrap();
2076            let component_instance = local_context.component_instance;
2077            generativity::make_guard!(g1);
2078            let enclosing_component =
2079                enclosing_component_for_element(&element, component_instance, g1);
2080            // we need a 'static Repeater component in order to call model_set_row_data, so get it.
2081            // Safety: This is the only 'static Id in scope.
2082            let static_guard =
2083                unsafe { generativity::Guard::new(generativity::Id::<'static>::new()) };
2084            let repeater = crate::dynamic_item_tree::get_repeater_by_name(
2085                enclosing_component,
2086                element.borrow().id.as_str(),
2087                static_guard,
2088            );
2089            repeater.0.model_set_row_data(
2090                eval_expression(
2091                    &Expression::RepeaterIndexReference { element: Rc::downgrade(&element) },
2092                    local_context,
2093                )
2094                .try_into()
2095                .unwrap(),
2096                if op == '=' {
2097                    rhs
2098                } else {
2099                    eval(eval_expression(
2100                        &Expression::RepeaterModelReference { element: Rc::downgrade(&element) },
2101                        local_context,
2102                    ))
2103                },
2104            )
2105        }
2106        Expression::ArrayIndex { array, index } => {
2107            let array = eval_expression(array, local_context);
2108            let index = eval_expression(index, local_context);
2109            match (array, index) {
2110                (Value::Model(model), Value::Number(index)) => {
2111                    if index >= 0. && (index as usize) < model.row_count() {
2112                        let index = index as usize;
2113                        if op == '=' {
2114                            model.set_row_data(index, rhs);
2115                        } else {
2116                            model.set_row_data(
2117                                index,
2118                                eval(
2119                                    model
2120                                        .row_data(index)
2121                                        .unwrap_or_else(|| default_value_for_type(&lhs.ty())),
2122                                ),
2123                            );
2124                        }
2125                    }
2126                }
2127                _ => {
2128                    eprintln!("Attempting to write into an array that cannot be written");
2129                }
2130            }
2131        }
2132        _ => panic!("typechecking should make sure this was a PropertyReference"),
2133    }
2134}
2135
2136pub fn load_property(component: InstanceRef, element: &ElementRc, name: &str) -> Result<Value, ()> {
2137    load_property_helper(&ComponentInstance::InstanceRef(component), element, name)
2138}
2139
2140fn load_property_helper(
2141    component_instance: &ComponentInstance,
2142    element: &ElementRc,
2143    name: &str,
2144) -> Result<Value, ()> {
2145    generativity::make_guard!(guard);
2146    match enclosing_component_instance_for_element(element, component_instance, guard) {
2147        ComponentInstance::InstanceRef(enclosing_component) => {
2148            let element = element.borrow();
2149            if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id
2150            {
2151                if let Some(x) = enclosing_component.description.custom_properties.get(name) {
2152                    return unsafe {
2153                        x.prop.get(Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset)))
2154                    };
2155                } else if enclosing_component.description.original.is_global() {
2156                    return Err(());
2157                }
2158            };
2159            let item_info = enclosing_component
2160                .description
2161                .items
2162                .get(element.id.as_str())
2163                .unwrap_or_else(|| panic!("Unknown element for {}.{}", element.id, name));
2164            core::mem::drop(element);
2165            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
2166            Ok(item_info.rtti.properties.get(name).ok_or(())?.get(item))
2167        }
2168        ComponentInstance::GlobalComponent(glob) => glob.as_ref().get_property(name),
2169    }
2170}
2171
2172pub fn store_property(
2173    component_instance: InstanceRef,
2174    element: &ElementRc,
2175    name: &str,
2176    mut value: Value,
2177) -> Result<(), SetPropertyError> {
2178    generativity::make_guard!(guard);
2179    match enclosing_component_instance_for_element(
2180        element,
2181        &ComponentInstance::InstanceRef(component_instance),
2182        guard,
2183    ) {
2184        ComponentInstance::InstanceRef(enclosing_component) => {
2185            let maybe_animation = match element.borrow().bindings.get(name) {
2186                Some(b) => crate::dynamic_item_tree::animation_for_property(
2187                    enclosing_component,
2188                    &b.borrow().animation,
2189                ),
2190                None => {
2191                    crate::dynamic_item_tree::animation_for_property(enclosing_component, &None)
2192                }
2193            };
2194
2195            let component = element.borrow().enclosing_component.upgrade().unwrap();
2196            if element.borrow().id == component.root_element.borrow().id {
2197                if let Some(x) = enclosing_component.description.custom_properties.get(name) {
2198                    if let Some(orig_decl) = enclosing_component
2199                        .description
2200                        .original
2201                        .root_element
2202                        .borrow()
2203                        .property_declarations
2204                        .get(name)
2205                    {
2206                        // Do an extra type checking because PropertyInfo::set won't do it for custom structures or array
2207                        if !check_value_type(&mut value, &orig_decl.property_type) {
2208                            return Err(SetPropertyError::WrongType);
2209                        }
2210                    }
2211                    unsafe {
2212                        let p = Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset));
2213                        return x
2214                            .prop
2215                            .set(p, value, maybe_animation.as_animation())
2216                            .map_err(|()| SetPropertyError::WrongType);
2217                    }
2218                } else if enclosing_component.description.original.is_global() {
2219                    return Err(SetPropertyError::NoSuchProperty);
2220                }
2221            };
2222            let item_info = &enclosing_component.description.items[element.borrow().id.as_str()];
2223            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
2224            let p = &item_info.rtti.properties.get(name).ok_or(SetPropertyError::NoSuchProperty)?;
2225            p.set(item, value, maybe_animation.as_animation())
2226                .map_err(|()| SetPropertyError::WrongType)?;
2227        }
2228        ComponentInstance::GlobalComponent(glob) => {
2229            glob.as_ref().set_property(name, value)?;
2230        }
2231    }
2232    Ok(())
2233}
2234
2235/// Return true if the Value can be used for a property of the given type
2236fn check_value_type(value: &mut Value, ty: &Type) -> bool {
2237    match ty {
2238        Type::Void => true,
2239        Type::Invalid
2240        | Type::InferredProperty
2241        | Type::InferredCallback
2242        | Type::Callback { .. }
2243        | Type::Function { .. }
2244        | Type::ElementReference => panic!("not valid property type"),
2245        Type::Float32 => matches!(value, Value::Number(_)),
2246        Type::Int32 => matches!(value, Value::Number(_)),
2247        Type::String => matches!(value, Value::String(_)),
2248        Type::Color => matches!(value, Value::Brush(_)),
2249        Type::UnitProduct(_)
2250        | Type::Duration
2251        | Type::PhysicalLength
2252        | Type::LogicalLength
2253        | Type::Rem
2254        | Type::Angle
2255        | Type::Percent => matches!(value, Value::Number(_)),
2256        Type::Image => matches!(value, Value::Image(_)),
2257        Type::Bool => matches!(value, Value::Bool(_)),
2258        Type::Model => {
2259            matches!(value, Value::Model(_) | Value::Bool(_) | Value::Number(_))
2260        }
2261        Type::PathData => matches!(value, Value::PathData(_)),
2262        Type::Easing => matches!(value, Value::EasingCurve(_)),
2263        Type::MouseCursor => matches!(value, Value::MouseCursorInner(_)),
2264        Type::Brush => matches!(value, Value::Brush(_)),
2265        Type::Array(inner) => {
2266            matches!(value, Value::Model(m) if m.iter().all(|mut v| check_value_type(&mut v, inner)))
2267        }
2268        Type::Struct(s) => {
2269            let Value::Struct(str) = value else { return false };
2270            if !str
2271                .0
2272                .iter_mut()
2273                .all(|(k, v)| s.fields.get(k).is_some_and(|ty| check_value_type(v, ty)))
2274            {
2275                return false;
2276            }
2277            for k in s.fields.keys() {
2278                str.0.entry(k.clone()).or_insert_with(|| default_value_for_struct_field(s, k));
2279            }
2280            true
2281        }
2282        Type::Enumeration(en) => {
2283            matches!(value, Value::EnumerationValue(name, _) if name == en.name.as_str())
2284        }
2285        Type::Keys => matches!(value, Value::Keys(_)),
2286        Type::LayoutCache => matches!(value, Value::LayoutCache(_)),
2287        Type::ArrayOfU16 => matches!(value, Value::ArrayOfU16(_)),
2288        Type::ComponentFactory => matches!(value, Value::ComponentFactory(_)),
2289        Type::StyledText => matches!(value, Value::StyledText(_)),
2290        Type::DataTransfer => matches!(value, Value::DataTransfer(_)),
2291    }
2292}
2293
2294pub(crate) fn invoke_callback(
2295    component_instance: &ComponentInstance,
2296    element: &ElementRc,
2297    callback_name: &SmolStr,
2298    args: &[Value],
2299) -> Option<Value> {
2300    generativity::make_guard!(guard);
2301    match enclosing_component_instance_for_element(element, component_instance, guard) {
2302        ComponentInstance::InstanceRef(enclosing_component) => {
2303            // Keep the component alive while the callback runs: the callback may close the popup
2304            // that owns this callback, and Callback::call() restores the handler after returning.
2305            let _component_guard = enclosing_component
2306                .self_weak()
2307                .get()
2308                .expect("component self weak must be initialized before invoking callbacks")
2309                .upgrade()
2310                .expect("component must be alive while invoking callbacks");
2311            let description = enclosing_component.description;
2312            let element = element.borrow();
2313            if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id
2314            {
2315                if let Some(callback_offset) = description.custom_callbacks.get(callback_name) {
2316                    if let Some(tracker_offset) = description.callback_trackers.get(callback_name) {
2317                        tracker_offset.apply_pin(enclosing_component.instance).get();
2318                    }
2319                    let callback = callback_offset.apply(&*enclosing_component.instance);
2320                    let res = callback.call(args);
2321                    return Some(if res != Value::Void {
2322                        res
2323                    } else if let Some(Type::Callback(callback)) = description
2324                        .original
2325                        .root_element
2326                        .borrow()
2327                        .property_declarations
2328                        .get(callback_name)
2329                        .map(|d| &d.property_type)
2330                    {
2331                        // If the callback was not set, the return value will be Value::Void, but we need
2332                        // to make sure that the value is actually of the right type as returned by the
2333                        // callback, otherwise we will get panics later
2334                        default_value_for_type(&callback.return_type)
2335                    } else {
2336                        res
2337                    });
2338                } else if enclosing_component.description.original.is_global() {
2339                    return None;
2340                }
2341            };
2342            let item_info = &description.items[element.id.as_str()];
2343            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
2344            item_info
2345                .rtti
2346                .callbacks
2347                .get(callback_name.as_str())
2348                .map(|callback| callback.call(item, args))
2349        }
2350        ComponentInstance::GlobalComponent(global) => {
2351            Some(global.as_ref().invoke_callback(callback_name, args).unwrap())
2352        }
2353    }
2354}
2355
2356pub(crate) fn set_callback_handler(
2357    component_instance: &ComponentInstance,
2358    element: &ElementRc,
2359    callback_name: &str,
2360    handler: CallbackHandler,
2361) -> Result<(), ()> {
2362    generativity::make_guard!(guard);
2363    match enclosing_component_instance_for_element(element, component_instance, guard) {
2364        ComponentInstance::InstanceRef(enclosing_component) => {
2365            let description = enclosing_component.description;
2366            let element = element.borrow();
2367            if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id
2368            {
2369                if let Some(callback_offset) = description.custom_callbacks.get(callback_name) {
2370                    let callback = callback_offset.apply(&*enclosing_component.instance);
2371                    callback.set_handler(handler);
2372                    if let Some(tracker_offset) = description.callback_trackers.get(callback_name) {
2373                        tracker_offset.apply_pin(enclosing_component.instance).mark_dirty();
2374                    }
2375                    return Ok(());
2376                } else if enclosing_component.description.original.is_global() {
2377                    return Err(());
2378                }
2379            };
2380            let item_info = &description.items[element.id.as_str()];
2381            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
2382            if let Some(callback) = item_info.rtti.callbacks.get(callback_name) {
2383                callback.set_handler(item, handler);
2384                Ok(())
2385            } else {
2386                Err(())
2387            }
2388        }
2389        ComponentInstance::GlobalComponent(global) => {
2390            global.as_ref().set_callback_handler(callback_name, handler)
2391        }
2392    }
2393}
2394
2395/// Invoke the function.
2396///
2397/// Return None if the function don't exist
2398pub(crate) fn call_function(
2399    component_instance: &ComponentInstance,
2400    element: &ElementRc,
2401    function_name: &str,
2402    args: Vec<Value>,
2403) -> Option<Value> {
2404    generativity::make_guard!(guard);
2405    match enclosing_component_instance_for_element(element, component_instance, guard) {
2406        ComponentInstance::InstanceRef(c) => {
2407            // Keep the component alive while the function runs: the function may close the popup
2408            // that owns this function or callbacks it invokes.
2409            let _component_guard = c
2410                .self_weak()
2411                .get()
2412                .expect("component self weak must be initialized before invoking functions")
2413                .upgrade()
2414                .expect("component must be alive while invoking functions");
2415            let mut ctx = EvalLocalContext::from_function_arguments(c, args);
2416            eval_expression(
2417                &element.borrow().bindings.get(function_name)?.borrow().expression,
2418                &mut ctx,
2419            )
2420            .into()
2421        }
2422        ComponentInstance::GlobalComponent(g) => g.as_ref().eval_function(function_name, args).ok(),
2423    }
2424}
2425
2426/// Return the component instance which hold the given element.
2427/// Does not take in account the global component.
2428pub fn enclosing_component_for_element<'a, 'old_id, 'new_id>(
2429    element: &'a ElementRc,
2430    component: InstanceRef<'a, 'old_id>,
2431    _guard: generativity::Guard<'new_id>,
2432) -> InstanceRef<'a, 'new_id> {
2433    let enclosing = &element.borrow().enclosing_component.upgrade().unwrap();
2434    if Rc::ptr_eq(enclosing, &component.description.original) {
2435        // Safety: new_id is an unique id
2436        unsafe {
2437            std::mem::transmute::<InstanceRef<'a, 'old_id>, InstanceRef<'a, 'new_id>>(component)
2438        }
2439    } else {
2440        assert!(!enclosing.is_global());
2441        // Safety: this is the only place we use this 'static lifetime in this function and nothing is returned with it
2442        // For some reason we can't make a new guard here because the compiler thinks we are returning that
2443        // (it assumes that the 'id must outlive 'a , which is not true)
2444        let static_guard = unsafe { generativity::Guard::new(generativity::Id::<'static>::new()) };
2445
2446        let parent_instance = component
2447            .parent_instance(static_guard)
2448            .expect("accessing deleted parent (issue #6426)");
2449        enclosing_component_for_element(element, parent_instance, _guard)
2450    }
2451}
2452
2453/// Return the component instance which hold the given element.
2454/// The difference with enclosing_component_for_element is that it takes the GlobalComponent into account.
2455pub(crate) fn enclosing_component_instance_for_element<'a, 'new_id>(
2456    element: &'a ElementRc,
2457    component_instance: &ComponentInstance<'a, '_>,
2458    guard: generativity::Guard<'new_id>,
2459) -> ComponentInstance<'a, 'new_id> {
2460    let enclosing = &element.borrow().enclosing_component.upgrade().unwrap();
2461    match component_instance {
2462        ComponentInstance::InstanceRef(component) => {
2463            if enclosing.is_global() && !Rc::ptr_eq(enclosing, &component.description.original) {
2464                ComponentInstance::GlobalComponent(
2465                    component
2466                        .description
2467                        .extra_data_offset
2468                        .apply(component.instance.get_ref())
2469                        .globals
2470                        .get()
2471                        .unwrap()
2472                        .get(enclosing.root_element.borrow().id.as_str())
2473                        .unwrap(),
2474                )
2475            } else {
2476                ComponentInstance::InstanceRef(enclosing_component_for_element(
2477                    element, *component, guard,
2478                ))
2479            }
2480        }
2481        ComponentInstance::GlobalComponent(global) => {
2482            //assert!(Rc::ptr_eq(enclosing, &global.component));
2483            ComponentInstance::GlobalComponent(global.clone())
2484        }
2485    }
2486}
2487
2488pub fn new_struct_with_bindings<ElementType: 'static + Default + corelib::rtti::BuiltinItem>(
2489    bindings: &i_slint_compiler::object_tree::BindingsMap,
2490    local_context: &mut EvalLocalContext,
2491) -> ElementType {
2492    let mut element = ElementType::default();
2493    for (prop, info) in ElementType::fields::<Value>().into_iter() {
2494        if let Some(binding) = &bindings.get(prop) {
2495            let value = eval_expression(&binding.borrow(), local_context);
2496            info.set_field(&mut element, value).unwrap();
2497        }
2498    }
2499    element
2500}
2501
2502fn convert_from_lyon_path<'a>(
2503    events_it: impl IntoIterator<Item = &'a i_slint_compiler::expression_tree::Expression>,
2504    points_it: impl IntoIterator<Item = &'a i_slint_compiler::expression_tree::Expression>,
2505    local_context: &mut EvalLocalContext,
2506) -> PathData {
2507    let events = events_it
2508        .into_iter()
2509        .map(|event_expr| eval_expression(event_expr, local_context).try_into().unwrap())
2510        .collect::<SharedVector<_>>();
2511
2512    let points = points_it
2513        .into_iter()
2514        .map(|point_expr| {
2515            let point_value = eval_expression(point_expr, local_context);
2516            let point_struct: Struct = point_value.try_into().unwrap();
2517            let mut point = i_slint_core::graphics::Point::default();
2518            let x: f64 = point_struct.get_field("x").unwrap().clone().try_into().unwrap();
2519            let y: f64 = point_struct.get_field("y").unwrap().clone().try_into().unwrap();
2520            point.x = x as _;
2521            point.y = y as _;
2522            point
2523        })
2524        .collect::<SharedVector<_>>();
2525
2526    PathData::Events(events, points)
2527}
2528
2529pub fn convert_path(path: &ExprPath, local_context: &mut EvalLocalContext) -> PathData {
2530    match path {
2531        ExprPath::Elements(elements) => PathData::Elements(
2532            elements
2533                .iter()
2534                .map(|element| convert_path_element(element, local_context))
2535                .collect::<SharedVector<PathElement>>(),
2536        ),
2537        ExprPath::Events(events, points) => {
2538            convert_from_lyon_path(events.iter(), points.iter(), local_context)
2539        }
2540        ExprPath::Commands(commands) => {
2541            if let Value::String(commands) = eval_expression(commands, local_context) {
2542                PathData::Commands(commands)
2543            } else {
2544                panic!("binding to path commands does not evaluate to string");
2545            }
2546        }
2547    }
2548}
2549
2550fn convert_path_element(
2551    expr_element: &ExprPathElement,
2552    local_context: &mut EvalLocalContext,
2553) -> PathElement {
2554    match expr_element.element_type.native_class.class_name.as_str() {
2555        "MoveTo" => {
2556            PathElement::MoveTo(new_struct_with_bindings(&expr_element.bindings, local_context))
2557        }
2558        "LineTo" => {
2559            PathElement::LineTo(new_struct_with_bindings(&expr_element.bindings, local_context))
2560        }
2561        "ArcTo" => {
2562            PathElement::ArcTo(new_struct_with_bindings(&expr_element.bindings, local_context))
2563        }
2564        "CubicTo" => {
2565            PathElement::CubicTo(new_struct_with_bindings(&expr_element.bindings, local_context))
2566        }
2567        "QuadraticTo" => PathElement::QuadraticTo(new_struct_with_bindings(
2568            &expr_element.bindings,
2569            local_context,
2570        )),
2571        "Close" => PathElement::Close,
2572        _ => panic!(
2573            "Cannot create unsupported path element {}",
2574            expr_element.element_type.native_class.class_name
2575        ),
2576    }
2577}
2578
2579/// Create a value suitable as the default value of a given type
2580pub fn default_value_for_type(ty: &Type) -> Value {
2581    match ty {
2582        Type::Float32 | Type::Int32 => Value::Number(0.),
2583        Type::String => Value::String(Default::default()),
2584        Type::Color | Type::Brush => Value::Brush(Default::default()),
2585        Type::Duration | Type::Angle | Type::PhysicalLength | Type::LogicalLength | Type::Rem => {
2586            Value::Number(0.)
2587        }
2588        Type::Image => Value::Image(Default::default()),
2589        Type::Bool => Value::Bool(false),
2590        Type::Callback { .. } => Value::Void,
2591        Type::Struct(s) => Value::Struct(
2592            s.fields
2593                .keys()
2594                .map(|n| (n.to_string(), default_value_for_struct_field(s, n)))
2595                .collect::<Struct>(),
2596        ),
2597        Type::Array(_) | Type::Model => Value::Model(Default::default()),
2598        Type::Percent => Value::Number(0.),
2599        Type::Enumeration(e) => Value::EnumerationValue(
2600            e.name.to_string(),
2601            e.values.get(e.default_value).unwrap().to_string(),
2602        ),
2603        Type::Keys => Value::Keys(Default::default()),
2604        Type::DataTransfer => Value::DataTransfer(Default::default()),
2605        Type::Easing => Value::EasingCurve(Default::default()),
2606        Type::MouseCursor => Value::MouseCursorInner(Default::default()),
2607        Type::Void | Type::Invalid => Value::Void,
2608        Type::UnitProduct(_) => Value::Number(0.),
2609        Type::PathData => Value::PathData(Default::default()),
2610        Type::LayoutCache => Value::LayoutCache(Default::default()),
2611        Type::ArrayOfU16 => Value::ArrayOfU16(Default::default()),
2612        Type::ComponentFactory => Value::ComponentFactory(Default::default()),
2613        Type::InferredProperty
2614        | Type::InferredCallback
2615        | Type::ElementReference
2616        | Type::Function { .. } => {
2617            panic!("There can't be such property")
2618        }
2619        Type::StyledText => Value::StyledText(Default::default()),
2620    }
2621}
2622
2623/// Create a value for the default of a struct field:
2624/// the user-declared default value (`struct Foo { bar: int = 42 }`) if there is one,
2625/// otherwise the default value for the field's type.
2626pub fn default_value_for_struct_field(
2627    s: &i_slint_compiler::langtype::Struct,
2628    field_name: &str,
2629) -> Value {
2630    match s.field_defaults.get(field_name) {
2631        Some(expr) => eval_constant_expression(expr),
2632        None => default_value_for_type(
2633            s.fields.get(field_name).expect("default value requested for unknown struct field"),
2634        ),
2635    }
2636}
2637
2638/// Convert a value to the given type, as [`Expression::Cast`] does
2639fn cast_value(value: Value, to: &Type) -> Value {
2640    match (value, to) {
2641        (Value::Number(n), Type::Int32) => Value::Number(n.trunc()),
2642        (Value::Number(n), Type::String) => {
2643            Value::String(i_slint_core::string::shared_string_from_number(n))
2644        }
2645        (Value::Number(n), Type::Color) => Color::from_argb_encoded(n as u32).into(),
2646        (Value::Brush(brush), Type::Color) => brush.color().into(),
2647        (Value::EnumerationValue(_, val), Type::String) => Value::String(val.into()),
2648        (v, _) => v,
2649    }
2650}
2651
2652/// Apply a unary operator to a value; returns the unmodified value as the error
2653/// for unsupported combinations
2654fn eval_unary_op(sub: Value, op: char) -> Result<Value, Value> {
2655    match (sub, op) {
2656        (Value::Number(a), '+') => Ok(Value::Number(a)),
2657        (Value::Number(a), '-') => Ok(Value::Number(-a)),
2658        (Value::Bool(a), '!') => Ok(Value::Bool(!a)),
2659        (sub, _) => Err(sub),
2660    }
2661}
2662
2663/// Evaluate a constant expression as stored in [`i_slint_compiler::langtype::Struct::field_defaults`],
2664/// which needs no evaluation context.
2665/// Mirrors [`eval_expression`] for the corresponding expressions.
2666fn eval_constant_expression(expr: &ConstantExpression) -> Value {
2667    match expr {
2668        ConstantExpression::StringLiteral(s) => Value::String(s.as_str().into()),
2669        ConstantExpression::NumberLiteral(n, _unit) => Value::Number(*n),
2670        ConstantExpression::BoolLiteral(b) => Value::Bool(*b),
2671        ConstantExpression::EnumerationValue(value) => {
2672            Value::EnumerationValue(value.enumeration.name.to_string(), value.to_string())
2673        }
2674        ConstantExpression::Cast { from, to } => cast_value(eval_constant_expression(from), to),
2675        ConstantExpression::UnaryOp { sub, op } => {
2676            // The resolver only accepts the unary operators on matching operand types
2677            eval_unary_op(eval_constant_expression(sub), *op)
2678                .unwrap_or_else(|sub| panic!("unsupported {op} {sub:?}"))
2679        }
2680        ConstantExpression::Struct { values, .. } => Value::Struct(
2681            values
2682                .iter()
2683                .map(|(k, v)| (k.to_string(), eval_constant_expression(v)))
2684                .collect::<Struct>(),
2685        ),
2686        ConstantExpression::Array { values, .. } => {
2687            Value::Model(ModelRc::new(corelib::model::SharedVectorModel::from(
2688                values.iter().map(eval_constant_expression).collect::<SharedVector<_>>(),
2689            )))
2690        }
2691    }
2692}
2693
2694fn menu_item_tree_properties(
2695    context_menu_item_tree: vtable::VRc<i_slint_core::menus::MenuVTable, MenuFromItemTree>,
2696) -> (Box<dyn Fn() -> Value>, CallbackHandler, CallbackHandler) {
2697    let context_menu_item_tree_ = context_menu_item_tree.clone();
2698    let entries = Box::new(move || {
2699        let mut entries = SharedVector::default();
2700        context_menu_item_tree_.sub_menu(None, &mut entries);
2701        Value::Model(ModelRc::new(VecModel::from(
2702            entries.into_iter().map(Value::from).collect::<Vec<_>>(),
2703        )))
2704    });
2705    let context_menu_item_tree_ = context_menu_item_tree.clone();
2706    let sub_menu = Box::new(move |args: &[Value]| -> Value {
2707        let mut entries = SharedVector::default();
2708        context_menu_item_tree_.sub_menu(Some(&args[0].clone().try_into().unwrap()), &mut entries);
2709        Value::Model(ModelRc::new(VecModel::from(
2710            entries.into_iter().map(Value::from).collect::<Vec<_>>(),
2711        )))
2712    });
2713    let activated = Box::new(move |args: &[Value]| -> Value {
2714        context_menu_item_tree.activate(&args[0].clone().try_into().unwrap());
2715        Value::Void
2716    });
2717    (entries, sub_menu, activated)
2718}