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