slint_interpreter/
eval.rs

1// Copyright © SixtyFPS GmbH <[email protected]>
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::pin::Pin;
7use corelib::graphics::{
8    ConicGradientBrush, GradientStop, LinearGradientBrush, PathElement, RadialGradientBrush,
9};
10use corelib::items::{ColorScheme, ItemRef, PropertyAnimation};
11use corelib::menus::{Menu, MenuFromItemTree};
12use corelib::model::{Model, ModelExt, ModelRc, VecModel};
13use corelib::rtti::AnimatedBindingKind;
14use corelib::window::WindowInner;
15use corelib::{Brush, Color, PathData, SharedString, SharedVector};
16use i_slint_compiler::expression_tree::{
17    BuiltinFunction, Callable, EasingCurve, Expression, MinMaxOp, Path as ExprPath,
18    PathElement as ExprPathElement,
19};
20use i_slint_compiler::langtype::Type;
21use i_slint_compiler::namedreference::NamedReference;
22use i_slint_compiler::object_tree::ElementRc;
23use i_slint_core as corelib;
24use i_slint_core::input::FocusReason;
25use i_slint_core::items::{ItemRc, WindowItem};
26use smol_str::SmolStr;
27use std::collections::HashMap;
28use std::rc::Rc;
29
30pub trait ErasedPropertyInfo {
31    fn get(&self, item: Pin<ItemRef>) -> Value;
32    fn set(
33        &self,
34        item: Pin<ItemRef>,
35        value: Value,
36        animation: Option<PropertyAnimation>,
37    ) -> Result<(), ()>;
38    fn set_binding(
39        &self,
40        item: Pin<ItemRef>,
41        binding: Box<dyn Fn() -> Value>,
42        animation: AnimatedBindingKind,
43    );
44    fn offset(&self) -> usize;
45
46    /// Safety: Property2 must be a (pinned) pointer to a `Property<T>`
47    /// where T is the same T as the one represented by this property.
48    unsafe fn link_two_ways(&self, item: Pin<ItemRef>, property2: *const ());
49}
50
51impl<Item: vtable::HasStaticVTable<corelib::items::ItemVTable>> ErasedPropertyInfo
52    for &'static dyn corelib::rtti::PropertyInfo<Item, Value>
53{
54    fn get(&self, item: Pin<ItemRef>) -> Value {
55        (*self).get(ItemRef::downcast_pin(item).unwrap()).unwrap()
56    }
57    fn set(
58        &self,
59        item: Pin<ItemRef>,
60        value: Value,
61        animation: Option<PropertyAnimation>,
62    ) -> Result<(), ()> {
63        (*self).set(ItemRef::downcast_pin(item).unwrap(), value, animation)
64    }
65    fn set_binding(
66        &self,
67        item: Pin<ItemRef>,
68        binding: Box<dyn Fn() -> Value>,
69        animation: AnimatedBindingKind,
70    ) {
71        (*self).set_binding(ItemRef::downcast_pin(item).unwrap(), binding, animation).unwrap();
72    }
73    fn offset(&self) -> usize {
74        (*self).offset()
75    }
76    unsafe fn link_two_ways(&self, item: Pin<ItemRef>, property2: *const ()) {
77        // Safety: ErasedPropertyInfo::link_two_ways and PropertyInfo::link_two_ways have the same safety requirement
78        (*self).link_two_ways(ItemRef::downcast_pin(item).unwrap(), property2)
79    }
80}
81
82pub trait ErasedCallbackInfo {
83    fn call(&self, item: Pin<ItemRef>, args: &[Value]) -> Value;
84    fn set_handler(&self, item: Pin<ItemRef>, handler: Box<dyn Fn(&[Value]) -> Value>);
85}
86
87impl<Item: vtable::HasStaticVTable<corelib::items::ItemVTable>> ErasedCallbackInfo
88    for &'static dyn corelib::rtti::CallbackInfo<Item, Value>
89{
90    fn call(&self, item: Pin<ItemRef>, args: &[Value]) -> Value {
91        (*self).call(ItemRef::downcast_pin(item).unwrap(), args).unwrap()
92    }
93
94    fn set_handler(&self, item: Pin<ItemRef>, handler: Box<dyn Fn(&[Value]) -> Value>) {
95        (*self).set_handler(ItemRef::downcast_pin(item).unwrap(), handler).unwrap()
96    }
97}
98
99impl corelib::rtti::ValueType for Value {}
100
101#[derive(Clone)]
102pub(crate) enum ComponentInstance<'a, 'id> {
103    InstanceRef(InstanceRef<'a, 'id>),
104    GlobalComponent(Pin<Rc<dyn crate::global_component::GlobalComponent>>),
105}
106
107/// The local variable needed for binding evaluation
108pub struct EvalLocalContext<'a, 'id> {
109    local_variables: HashMap<SmolStr, Value>,
110    function_arguments: Vec<Value>,
111    pub(crate) component_instance: InstanceRef<'a, 'id>,
112    /// When Some, a return statement was executed and one must stop evaluating
113    return_value: Option<Value>,
114}
115
116impl<'a, 'id> EvalLocalContext<'a, 'id> {
117    pub fn from_component_instance(component: InstanceRef<'a, 'id>) -> Self {
118        Self {
119            local_variables: Default::default(),
120            function_arguments: Default::default(),
121            component_instance: component,
122            return_value: None,
123        }
124    }
125
126    /// Create a context for a function and passing the arguments
127    pub fn from_function_arguments(
128        component: InstanceRef<'a, 'id>,
129        function_arguments: Vec<Value>,
130    ) -> Self {
131        Self {
132            component_instance: component,
133            function_arguments,
134            local_variables: Default::default(),
135            return_value: None,
136        }
137    }
138}
139
140/// Evaluate an expression and return a Value as the result of this expression
141pub fn eval_expression(expression: &Expression, local_context: &mut EvalLocalContext) -> Value {
142    if let Some(r) = &local_context.return_value {
143        return r.clone();
144    }
145    match expression {
146        Expression::Invalid => panic!("invalid expression while evaluating"),
147        Expression::Uncompiled(_) => panic!("uncompiled expression while evaluating"),
148        Expression::StringLiteral(s) => Value::String(s.as_str().into()),
149        Expression::NumberLiteral(n, unit) => Value::Number(unit.normalize(*n)),
150        Expression::BoolLiteral(b) => Value::Bool(*b),
151        Expression::ElementReference(_) => todo!("Element references are only supported in the context of built-in function calls at the moment"),
152        Expression::PropertyReference(nr) => {
153            load_property_helper(&ComponentInstance::InstanceRef(local_context.component_instance), &nr.element(), nr.name()).unwrap()
154        }
155        Expression::RepeaterIndexReference { element } => load_property_helper(&ComponentInstance::InstanceRef(local_context.component_instance),
156            &element.upgrade().unwrap().borrow().base_type.as_component().root_element,
157            crate::dynamic_item_tree::SPECIAL_PROPERTY_INDEX,
158        )
159        .unwrap(),
160        Expression::RepeaterModelReference { element } => {
161            let value = load_property_helper(&ComponentInstance::InstanceRef(local_context.component_instance),
162                    &element.upgrade().unwrap().borrow().base_type.as_component().root_element,
163                    crate::dynamic_item_tree::SPECIAL_PROPERTY_MODEL_DATA,
164                )
165                .unwrap();
166            if matches!(value, Value::Void) {
167                // Uninitialized model data (because the model returned None) should still be initialized to the default value of the type
168                default_value_for_type(&expression.ty())
169            } else {
170                value
171            }
172
173        },
174        Expression::FunctionParameterReference { index, .. } => {
175            local_context.function_arguments[*index].clone()
176        }
177        Expression::StructFieldAccess { base, name } => {
178            if let Value::Struct(o) = eval_expression(base, local_context) {
179                o.get_field(name).cloned().unwrap_or(Value::Void)
180            } else {
181                Value::Void
182            }
183        }
184        Expression::ArrayIndex { array, index } => {
185            let array = eval_expression(array, local_context);
186            let index = eval_expression(index, local_context);
187            match (array, index) {
188                (Value::Model(model), Value::Number(index)) => {
189                    model.row_data_tracked(index as isize as usize).unwrap_or_else(|| default_value_for_type(&expression.ty()))
190                }
191                _ => {
192                    Value::Void
193                }
194            }
195        }
196        Expression::Cast { from, to } => {
197            let v = eval_expression(from, local_context);
198            match (v, to) {
199                (Value::Number(n), Type::Int32) => Value::Number(n.trunc()),
200                (Value::Number(n), Type::String) => {
201                    Value::String(i_slint_core::string::shared_string_from_number(n))
202                }
203                (Value::Number(n), Type::Color) => Color::from_argb_encoded(n as u32).into(),
204                (Value::Brush(brush), Type::Color) => brush.color().into(),
205                (v, _) => v,
206            }
207        }
208        Expression::CodeBlock(sub) => {
209            let mut v = Value::Void;
210            for e in sub {
211                v = eval_expression(e, local_context);
212                if let Some(r) = &local_context.return_value {
213                    return r.clone();
214                }
215            }
216            v
217        }
218        Expression::FunctionCall { function, arguments, source_location } => match &function {
219            Callable::Function(nr) => {
220                let is_item_member = nr.element().borrow().native_class().is_some_and(|n| n.properties.contains_key(nr.name()));
221                if is_item_member {
222                    call_item_member_function(nr, local_context)
223                } else {
224                    let args = arguments.iter().map(|e| eval_expression(e, local_context)).collect::<Vec<_>>();
225                    call_function(&ComponentInstance::InstanceRef(local_context.component_instance), &nr.element(), nr.name(), args).unwrap()
226                }
227            }
228            Callable::Callback(nr) => {
229                let args = arguments.iter().map(|e| eval_expression(e, local_context)).collect::<Vec<_>>();
230                invoke_callback(&ComponentInstance::InstanceRef(local_context.component_instance), &nr.element(), nr.name(), &args).unwrap()
231            }
232            Callable::Builtin(f) => call_builtin_function(f.clone(), arguments, local_context, source_location),
233        }
234        Expression::SelfAssignment { lhs, rhs, op, .. } => {
235            let rhs = eval_expression(rhs, local_context);
236            eval_assignment(lhs, *op, rhs, local_context);
237            Value::Void
238        }
239        Expression::BinaryExpression { lhs, rhs, op } => {
240            let lhs = eval_expression(lhs, local_context);
241            let rhs = eval_expression(rhs, local_context);
242
243            match (op, lhs, rhs) {
244                ('+', Value::String(mut a), Value::String(b)) => { a.push_str(b.as_str()); Value::String(a) },
245                ('+', Value::Number(a), Value::Number(b)) => Value::Number(a + b),
246                ('+', a @ Value::Struct(_), b @ Value::Struct(_)) => {
247                    let a : Option<corelib::layout::LayoutInfo> = a.try_into().ok();
248                    let b : Option<corelib::layout::LayoutInfo> = b.try_into().ok();
249                    if let (Some(a), Some(b)) = (a, b) {
250                        a.merge(&b).into()
251                    } else {
252                        panic!("unsupported {a:?} {op} {b:?}");
253                    }
254                }
255                ('-', Value::Number(a), Value::Number(b)) => Value::Number(a - b),
256                ('/', Value::Number(a), Value::Number(b)) => Value::Number(a / b),
257                ('*', Value::Number(a), Value::Number(b)) => Value::Number(a * b),
258                ('<', Value::Number(a), Value::Number(b)) => Value::Bool(a < b),
259                ('>', Value::Number(a), Value::Number(b)) => Value::Bool(a > b),
260                ('≤', Value::Number(a), Value::Number(b)) => Value::Bool(a <= b),
261                ('≥', Value::Number(a), Value::Number(b)) => Value::Bool(a >= b),
262                ('<', Value::String(a), Value::String(b)) => Value::Bool(a < b),
263                ('>', Value::String(a), Value::String(b)) => Value::Bool(a > b),
264                ('≤', Value::String(a), Value::String(b)) => Value::Bool(a <= b),
265                ('≥', Value::String(a), Value::String(b)) => Value::Bool(a >= b),
266                ('=', a, b) => Value::Bool(a == b),
267                ('!', a, b) => Value::Bool(a != b),
268                ('&', Value::Bool(a), Value::Bool(b)) => Value::Bool(a && b),
269                ('|', Value::Bool(a), Value::Bool(b)) => Value::Bool(a || b),
270                (op, lhs, rhs) => panic!("unsupported {lhs:?} {op} {rhs:?}"),
271            }
272        }
273        Expression::UnaryOp { sub, op } => {
274            let sub = eval_expression(sub, local_context);
275            match (sub, op) {
276                (Value::Number(a), '+') => Value::Number(a),
277                (Value::Number(a), '-') => Value::Number(-a),
278                (Value::Bool(a), '!') => Value::Bool(!a),
279                (sub, op) => panic!("unsupported {op} {sub:?}"),
280            }
281        }
282        Expression::ImageReference{ resource_ref, nine_slice, .. } => {
283            let mut image = match resource_ref {
284                i_slint_compiler::expression_tree::ImageReference::None => {
285                    Ok(Default::default())
286                }
287                i_slint_compiler::expression_tree::ImageReference::AbsolutePath(path) => {
288                    let path = std::path::Path::new(path);
289                    if path.starts_with("builtin:/") {
290                        i_slint_compiler::fileaccess::load_file(path).and_then(|virtual_file| virtual_file.builtin_contents).map(|virtual_file| {
291                            let extension = path.extension().unwrap().to_str().unwrap();
292                            corelib::graphics::load_image_from_embedded_data(
293                                corelib::slice::Slice::from_slice(virtual_file),
294                                corelib::slice::Slice::from_slice(extension.as_bytes())
295                            )
296                        }).ok_or_else(Default::default)
297                    } else {
298                        corelib::graphics::Image::load_from_path(path)
299                    }
300                }
301                i_slint_compiler::expression_tree::ImageReference::EmbeddedData { .. } => {
302                    todo!()
303                }
304                i_slint_compiler::expression_tree::ImageReference::EmbeddedTexture { .. } => {
305                    todo!()
306                }
307            }.unwrap_or_else(|_| {
308                eprintln!("Could not load image {resource_ref:?}" );
309                Default::default()
310            });
311            if let Some(n) = nine_slice {
312                image.set_nine_slice_edges(n[0], n[1], n[2], n[3]);
313            }
314            Value::Image(image)
315        }
316        Expression::Condition { condition, true_expr, false_expr } => {
317            match eval_expression(condition, local_context).try_into()
318                as Result<bool, _>
319            {
320                Ok(true) => eval_expression(true_expr, local_context),
321                Ok(false) => eval_expression(false_expr, local_context),
322                _ => local_context.return_value.clone().expect("conditional expression did not evaluate to boolean"),
323            }
324        }
325        Expression::Array { values, .. } => Value::Model(
326            ModelRc::new(corelib::model::SharedVectorModel::from(
327                values.iter().map(|e| eval_expression(e, local_context)).collect::<SharedVector<_>>()
328            )
329        )),
330        Expression::Struct { values, .. } => Value::Struct(
331            values
332                .iter()
333                .map(|(k, v)| (k.to_string(), eval_expression(v, local_context)))
334                .collect(),
335        ),
336        Expression::PathData(data)  => {
337            Value::PathData(convert_path(data, local_context))
338        }
339        Expression::StoreLocalVariable { name, value } => {
340            let value = eval_expression(value, local_context);
341            local_context.local_variables.insert(name.clone(), value);
342            Value::Void
343        }
344        Expression::ReadLocalVariable { name, .. } => {
345            local_context.local_variables.get(name).unwrap().clone()
346        }
347        Expression::EasingCurve(curve) => Value::EasingCurve(match curve {
348            EasingCurve::Linear => corelib::animations::EasingCurve::Linear,
349            EasingCurve::EaseInElastic => corelib::animations::EasingCurve::EaseInElastic,
350            EasingCurve::EaseOutElastic => corelib::animations::EasingCurve::EaseOutElastic,
351            EasingCurve::EaseInOutElastic => corelib::animations::EasingCurve::EaseInOutElastic,
352            EasingCurve::EaseInBounce => corelib::animations::EasingCurve::EaseInBounce,
353            EasingCurve::EaseOutBounce => corelib::animations::EasingCurve::EaseOutBounce,
354            EasingCurve::EaseInOutBounce => corelib::animations::EasingCurve::EaseInOutBounce,
355            EasingCurve::CubicBezier(a, b, c, d) => {
356                corelib::animations::EasingCurve::CubicBezier([*a, *b, *c, *d])
357            }
358        }),
359        Expression::LinearGradient{angle, stops} => {
360            let angle = eval_expression(angle, local_context);
361            Value::Brush(Brush::LinearGradient(LinearGradientBrush::new(angle.try_into().unwrap(), stops.iter().map(|(color, stop)| {
362                let color = eval_expression(color, local_context).try_into().unwrap();
363                let position = eval_expression(stop, local_context).try_into().unwrap();
364                GradientStop{ color, position }
365            }))))
366        }
367        Expression::RadialGradient{stops} => {
368            Value::Brush(Brush::RadialGradient(RadialGradientBrush::new_circle(stops.iter().map(|(color, stop)| {
369                let color = eval_expression(color, local_context).try_into().unwrap();
370                let position = eval_expression(stop, local_context).try_into().unwrap();
371                GradientStop{ color, position }
372            }))))
373        }
374        Expression::ConicGradient{stops} => {
375            Value::Brush(Brush::ConicGradient(ConicGradientBrush::new(stops.iter().map(|(color, stop)| {
376                let color = eval_expression(color, local_context).try_into().unwrap();
377                let position = eval_expression(stop, local_context).try_into().unwrap();
378                GradientStop{ color, position }
379            }))))
380        }
381        Expression::EnumerationValue(value) => {
382            Value::EnumerationValue(value.enumeration.name.to_string(), value.to_string())
383        }
384        Expression::ReturnStatement(x) => {
385            let val = x.as_ref().map_or(Value::Void, |x| eval_expression(x, local_context));
386            if local_context.return_value.is_none() {
387                local_context.return_value = Some(val);
388            }
389            local_context.return_value.clone().unwrap()
390        }
391        Expression::LayoutCacheAccess { layout_cache_prop, index, repeater_index } => {
392            let cache = load_property_helper(&ComponentInstance::InstanceRef(local_context.component_instance), &layout_cache_prop.element(), layout_cache_prop.name()).unwrap();
393            if let Value::LayoutCache(cache) = cache {
394                if let Some(ri) = repeater_index {
395                    let offset : usize = eval_expression(ri, local_context).try_into().unwrap();
396                    Value::Number(cache.get((cache[*index] as usize) + offset * 2).copied().unwrap_or(0.).into())
397                } else {
398                    Value::Number(cache[*index].into())
399                }
400            } else {
401                panic!("invalid layout cache")
402            }
403        }
404        Expression::ComputeLayoutInfo(lay, o) => crate::eval_layout::compute_layout_info(lay, *o, local_context),
405        Expression::SolveLayout(lay, o) => crate::eval_layout::solve_layout(lay, *o, local_context),
406        Expression::MinMax { ty: _, op, lhs, rhs } => {
407            let Value::Number(lhs) = eval_expression(lhs, local_context) else {
408                return local_context.return_value.clone().expect("minmax lhs expression did not evaluate to number");
409            };
410            let Value::Number(rhs) =  eval_expression(rhs, local_context) else {
411                return local_context.return_value.clone().expect("minmax rhs expression did not evaluate to number");
412            };
413            match op {
414                MinMaxOp::Min => Value::Number(lhs.min(rhs)),
415                MinMaxOp::Max => Value::Number(lhs.max(rhs)),
416            }
417        }
418        Expression::EmptyComponentFactory => Value::ComponentFactory(Default::default()),
419        Expression::DebugHook { expression, .. } => eval_expression(expression, local_context),
420    }
421}
422
423fn call_builtin_function(
424    f: BuiltinFunction,
425    arguments: &[Expression],
426    local_context: &mut EvalLocalContext,
427    source_location: &Option<i_slint_compiler::diagnostics::SourceLocation>,
428) -> Value {
429    match f {
430        BuiltinFunction::GetWindowScaleFactor => Value::Number(
431            local_context.component_instance.access_window(|window| window.scale_factor()) as _,
432        ),
433        BuiltinFunction::GetWindowDefaultFontSize => Value::Number({
434            let component = local_context.component_instance;
435            let item_comp = component.self_weak().get().unwrap().upgrade().unwrap();
436            WindowItem::resolved_default_font_size(vtable::VRc::into_dyn(item_comp)).get() as _
437        }),
438        BuiltinFunction::AnimationTick => {
439            Value::Number(i_slint_core::animations::animation_tick() as f64)
440        }
441        BuiltinFunction::Debug => {
442            let to_print: SharedString =
443                eval_expression(&arguments[0], local_context).try_into().unwrap();
444            local_context.component_instance.description.debug_handler.borrow()(
445                source_location.as_ref(),
446                &to_print,
447            );
448            Value::Void
449        }
450        BuiltinFunction::Mod => {
451            let mut to_num = |e| -> f64 { eval_expression(e, local_context).try_into().unwrap() };
452            Value::Number(to_num(&arguments[0]).rem_euclid(to_num(&arguments[1])))
453        }
454        BuiltinFunction::Round => {
455            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
456            Value::Number(x.round())
457        }
458        BuiltinFunction::Ceil => {
459            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
460            Value::Number(x.ceil())
461        }
462        BuiltinFunction::Floor => {
463            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
464            Value::Number(x.floor())
465        }
466        BuiltinFunction::Sqrt => {
467            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
468            Value::Number(x.sqrt())
469        }
470        BuiltinFunction::Abs => {
471            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
472            Value::Number(x.abs())
473        }
474        BuiltinFunction::Sin => {
475            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
476            Value::Number(x.to_radians().sin())
477        }
478        BuiltinFunction::Cos => {
479            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
480            Value::Number(x.to_radians().cos())
481        }
482        BuiltinFunction::Tan => {
483            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
484            Value::Number(x.to_radians().tan())
485        }
486        BuiltinFunction::ASin => {
487            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
488            Value::Number(x.asin().to_degrees())
489        }
490        BuiltinFunction::ACos => {
491            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
492            Value::Number(x.acos().to_degrees())
493        }
494        BuiltinFunction::ATan => {
495            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
496            Value::Number(x.atan().to_degrees())
497        }
498        BuiltinFunction::ATan2 => {
499            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
500            let y: f64 = eval_expression(&arguments[1], local_context).try_into().unwrap();
501            Value::Number(x.atan2(y).to_degrees())
502        }
503        BuiltinFunction::Log => {
504            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
505            let y: f64 = eval_expression(&arguments[1], local_context).try_into().unwrap();
506            Value::Number(x.log(y))
507        }
508        BuiltinFunction::Ln => {
509            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
510            Value::Number(x.ln())
511        }
512        BuiltinFunction::Pow => {
513            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
514            let y: f64 = eval_expression(&arguments[1], local_context).try_into().unwrap();
515            Value::Number(x.powf(y))
516        }
517        BuiltinFunction::Exp => {
518            let x: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
519            Value::Number(x.exp())
520        }
521        BuiltinFunction::ToFixed => {
522            let n: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
523            let digits: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
524            let digits: usize = digits.max(0) as usize;
525            Value::String(i_slint_core::string::shared_string_from_number_fixed(n, digits))
526        }
527        BuiltinFunction::ToPrecision => {
528            let n: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap();
529            let precision: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
530            let precision: usize = precision.max(0) as usize;
531            Value::String(i_slint_core::string::shared_string_from_number_precision(n, precision))
532        }
533        BuiltinFunction::SetFocusItem => {
534            if arguments.len() != 1 {
535                panic!("internal error: incorrect argument count to SetFocusItem")
536            }
537            let component = local_context.component_instance;
538            if let Expression::ElementReference(focus_item) = &arguments[0] {
539                generativity::make_guard!(guard);
540
541                let focus_item = focus_item.upgrade().unwrap();
542                let enclosing_component =
543                    enclosing_component_for_element(&focus_item, component, guard);
544                let description = enclosing_component.description;
545
546                let item_info = &description.items[focus_item.borrow().id.as_str()];
547
548                let focus_item_comp =
549                    enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
550
551                component.access_window(|window| {
552                    window.set_focus_item(
553                        &corelib::items::ItemRc::new(
554                            vtable::VRc::into_dyn(focus_item_comp),
555                            item_info.item_index(),
556                        ),
557                        true,
558                        FocusReason::Programmatic,
559                    )
560                });
561                Value::Void
562            } else {
563                panic!("internal error: argument to SetFocusItem must be an element")
564            }
565        }
566        BuiltinFunction::ClearFocusItem => {
567            if arguments.len() != 1 {
568                panic!("internal error: incorrect argument count to SetFocusItem")
569            }
570            let component = local_context.component_instance;
571            if let Expression::ElementReference(focus_item) = &arguments[0] {
572                generativity::make_guard!(guard);
573
574                let focus_item = focus_item.upgrade().unwrap();
575                let enclosing_component =
576                    enclosing_component_for_element(&focus_item, component, guard);
577                let description = enclosing_component.description;
578
579                let item_info = &description.items[focus_item.borrow().id.as_str()];
580
581                let focus_item_comp =
582                    enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
583
584                component.access_window(|window| {
585                    window.set_focus_item(
586                        &corelib::items::ItemRc::new(
587                            vtable::VRc::into_dyn(focus_item_comp),
588                            item_info.item_index(),
589                        ),
590                        false,
591                        FocusReason::Programmatic,
592                    )
593                });
594                Value::Void
595            } else {
596                panic!("internal error: argument to ClearFocusItem must be an element")
597            }
598        }
599        BuiltinFunction::ShowPopupWindow => {
600            if arguments.len() != 1 {
601                panic!("internal error: incorrect argument count to ShowPopupWindow")
602            }
603            let component = local_context.component_instance;
604            if let Expression::ElementReference(popup_window) = &arguments[0] {
605                let popup_window = popup_window.upgrade().unwrap();
606                let pop_comp = popup_window.borrow().enclosing_component.upgrade().unwrap();
607                let parent_component = pop_comp
608                    .parent_element
609                    .upgrade()
610                    .unwrap()
611                    .borrow()
612                    .enclosing_component
613                    .upgrade()
614                    .unwrap();
615                let popup_list = parent_component.popup_windows.borrow();
616                let popup =
617                    popup_list.iter().find(|p| Rc::ptr_eq(&p.component, &pop_comp)).unwrap();
618
619                generativity::make_guard!(guard);
620                let enclosing_component =
621                    enclosing_component_for_element(&popup.parent_element, component, guard);
622                let parent_item_info = &enclosing_component.description.items
623                    [popup.parent_element.borrow().id.as_str()];
624                let parent_item_comp =
625                    enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
626                let parent_item = corelib::items::ItemRc::new(
627                    vtable::VRc::into_dyn(parent_item_comp),
628                    parent_item_info.item_index(),
629                );
630
631                let close_policy = Value::EnumerationValue(
632                    popup.close_policy.enumeration.name.to_string(),
633                    popup.close_policy.to_string(),
634                )
635                .try_into()
636                .expect("Invalid internal enumeration representation for close policy");
637
638                crate::dynamic_item_tree::show_popup(
639                    popup_window,
640                    component,
641                    popup,
642                    |instance_ref| {
643                        let comp = ComponentInstance::InstanceRef(instance_ref);
644                        let x = load_property_helper(&comp, &popup.x.element(), popup.x.name())
645                            .unwrap();
646                        let y = load_property_helper(&comp, &popup.y.element(), popup.y.name())
647                            .unwrap();
648                        corelib::api::LogicalPosition::new(
649                            x.try_into().unwrap(),
650                            y.try_into().unwrap(),
651                        )
652                    },
653                    close_policy,
654                    enclosing_component.self_weak().get().unwrap().clone(),
655                    component.window_adapter(),
656                    &parent_item,
657                );
658                Value::Void
659            } else {
660                panic!("internal error: argument to ShowPopupWindow must be an element")
661            }
662        }
663        BuiltinFunction::ClosePopupWindow => {
664            let component = local_context.component_instance;
665            if let Expression::ElementReference(popup_window) = &arguments[0] {
666                let popup_window = popup_window.upgrade().unwrap();
667                let pop_comp = popup_window.borrow().enclosing_component.upgrade().unwrap();
668                let parent_component = pop_comp
669                    .parent_element
670                    .upgrade()
671                    .unwrap()
672                    .borrow()
673                    .enclosing_component
674                    .upgrade()
675                    .unwrap();
676                let popup_list = parent_component.popup_windows.borrow();
677                let popup =
678                    popup_list.iter().find(|p| Rc::ptr_eq(&p.component, &pop_comp)).unwrap();
679
680                generativity::make_guard!(guard);
681                let enclosing_component =
682                    enclosing_component_for_element(&popup.parent_element, component, guard);
683                crate::dynamic_item_tree::close_popup(
684                    popup_window,
685                    enclosing_component,
686                    enclosing_component.window_adapter(),
687                );
688
689                Value::Void
690            } else {
691                panic!("internal error: argument to ClosePopupWindow must be an element")
692            }
693        }
694        BuiltinFunction::ShowPopupMenu | BuiltinFunction::ShowPopupMenuInternal => {
695            let [Expression::ElementReference(element), entries, position] = arguments else {
696                panic!("internal error: incorrect argument count to ShowPopupMenu")
697            };
698            let position = eval_expression(position, local_context)
699                .try_into()
700                .expect("internal error: popup menu position argument should be a point");
701
702            let component = local_context.component_instance;
703            let elem = element.upgrade().unwrap();
704            generativity::make_guard!(guard);
705            let enclosing_component = enclosing_component_for_element(&elem, component, guard);
706            let description = enclosing_component.description;
707            let item_info = &description.items[elem.borrow().id.as_str()];
708            let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
709            let item_tree = vtable::VRc::into_dyn(item_comp);
710            let item_rc = corelib::items::ItemRc::new(item_tree.clone(), item_info.item_index());
711
712            generativity::make_guard!(guard);
713            let compiled = enclosing_component.description.popup_menu_description.unerase(guard);
714            let inst = crate::dynamic_item_tree::instantiate(
715                compiled.clone(),
716                Some(enclosing_component.self_weak().get().unwrap().clone()),
717                None,
718                Some(&crate::dynamic_item_tree::WindowOptions::UseExistingWindow(
719                    component.window_adapter(),
720                )),
721                Default::default(),
722            );
723
724            generativity::make_guard!(guard);
725            let inst_ref = inst.unerase(guard);
726            if let Expression::ElementReference(e) = entries {
727                let menu_item_tree =
728                    e.upgrade().unwrap().borrow().enclosing_component.upgrade().unwrap();
729                let menu_item_tree = crate::dynamic_item_tree::make_menu_item_tree(
730                    &menu_item_tree,
731                    &enclosing_component,
732                    None,
733                );
734
735                if component.access_window(|window| {
736                    window.show_native_popup_menu(
737                        vtable::VRc::into_dyn(menu_item_tree.clone()),
738                        position,
739                        &item_rc,
740                    )
741                }) {
742                    return Value::Void;
743                }
744
745                let (entries, sub_menu, activated) = menu_item_tree_properties(menu_item_tree);
746
747                compiled.set_binding(inst_ref.borrow(), "entries", entries).unwrap();
748                compiled.set_callback_handler(inst_ref.borrow(), "sub-menu", sub_menu).unwrap();
749                compiled.set_callback_handler(inst_ref.borrow(), "activated", activated).unwrap();
750            } else {
751                let entries = eval_expression(entries, local_context);
752                compiled.set_property(inst_ref.borrow(), "entries", entries).unwrap();
753                let item_weak = item_rc.downgrade();
754                compiled
755                    .set_callback_handler(
756                        inst_ref.borrow(),
757                        "sub-menu",
758                        Box::new(move |args: &[Value]| -> Value {
759                            item_weak
760                                .upgrade()
761                                .unwrap()
762                                .downcast::<corelib::items::ContextMenu>()
763                                .unwrap()
764                                .sub_menu
765                                .call(&(args[0].clone().try_into().unwrap(),))
766                                .into()
767                        }),
768                    )
769                    .unwrap();
770                let item_weak = item_rc.downgrade();
771                compiled
772                    .set_callback_handler(
773                        inst_ref.borrow(),
774                        "activated",
775                        Box::new(move |args: &[Value]| -> Value {
776                            item_weak
777                                .upgrade()
778                                .unwrap()
779                                .downcast::<corelib::items::ContextMenu>()
780                                .unwrap()
781                                .activated
782                                .call(&(args[0].clone().try_into().unwrap(),));
783                            Value::Void
784                        }),
785                    )
786                    .unwrap();
787            }
788            let item_weak = item_rc.downgrade();
789            compiled
790                .set_callback_handler(
791                    inst_ref.borrow(),
792                    "close",
793                    Box::new(move |_args: &[Value]| -> Value {
794                        let Some(item_rc) = item_weak.upgrade() else { return Value::Void };
795                        if let Some(id) = item_rc
796                            .downcast::<corelib::items::ContextMenu>()
797                            .unwrap()
798                            .popup_id
799                            .take()
800                        {
801                            WindowInner::from_pub(item_rc.window_adapter().unwrap().window())
802                                .close_popup(id);
803                        }
804                        Value::Void
805                    }),
806                )
807                .unwrap();
808            component.access_window(|window| {
809                let context_menu_elem = item_rc.downcast::<corelib::items::ContextMenu>().unwrap();
810                if let Some(old_id) = context_menu_elem.popup_id.take() {
811                    window.close_popup(old_id)
812                }
813                let id = window.show_popup(
814                    &vtable::VRc::into_dyn(inst.clone()),
815                    position,
816                    corelib::items::PopupClosePolicy::CloseOnClickOutside,
817                    &item_rc,
818                    true,
819                );
820                context_menu_elem.popup_id.set(Some(id));
821            });
822            inst.run_setup_code();
823            Value::Void
824        }
825        BuiltinFunction::SetSelectionOffsets => {
826            if arguments.len() != 3 {
827                panic!("internal error: incorrect argument count to select range function call")
828            }
829            let component = local_context.component_instance;
830            if let Expression::ElementReference(element) = &arguments[0] {
831                generativity::make_guard!(guard);
832
833                let elem = element.upgrade().unwrap();
834                let enclosing_component = enclosing_component_for_element(&elem, component, guard);
835                let description = enclosing_component.description;
836                let item_info = &description.items[elem.borrow().id.as_str()];
837                let item_ref =
838                    unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
839
840                let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
841                let item_rc = corelib::items::ItemRc::new(
842                    vtable::VRc::into_dyn(item_comp),
843                    item_info.item_index(),
844                );
845
846                let window_adapter = component.window_adapter();
847
848                // TODO: Make this generic through RTTI
849                if let Some(textinput) =
850                    ItemRef::downcast_pin::<corelib::items::TextInput>(item_ref)
851                {
852                    let start: i32 =
853                        eval_expression(&arguments[1], local_context).try_into().expect(
854                            "internal error: second argument to set-selection-offsets must be an integer",
855                        );
856                    let end: i32 = eval_expression(&arguments[2], local_context).try_into().expect(
857                        "internal error: third argument to set-selection-offsets must be an integer",
858                    );
859
860                    textinput.set_selection_offsets(&window_adapter, &item_rc, start, end);
861                } else {
862                    panic!(
863                        "internal error: member function called on element that doesn't have it: {}",
864                        elem.borrow().original_name()
865                    )
866                }
867
868                Value::Void
869            } else {
870                panic!("internal error: first argument to set-selection-offsets must be an element")
871            }
872        }
873        BuiltinFunction::ItemFontMetrics => {
874            if arguments.len() != 1 {
875                panic!(
876                    "internal error: incorrect argument count to item font metrics function call"
877                )
878            }
879            let component = local_context.component_instance;
880            if let Expression::ElementReference(element) = &arguments[0] {
881                generativity::make_guard!(guard);
882
883                let elem = element.upgrade().unwrap();
884                let enclosing_component = enclosing_component_for_element(&elem, component, guard);
885                let description = enclosing_component.description;
886                let item_info = &description.items[elem.borrow().id.as_str()];
887                let item_ref =
888                    unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
889                let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
890                let item_rc = corelib::items::ItemRc::new(
891                    vtable::VRc::into_dyn(item_comp),
892                    item_info.item_index(),
893                );
894                let window_adapter = component.window_adapter();
895                let metrics = i_slint_core::items::slint_text_item_fontmetrics(
896                    &window_adapter,
897                    item_ref,
898                    &item_rc,
899                );
900                metrics.into()
901            } else {
902                panic!("internal error: argument to item-font-metrics must be an element")
903            }
904        }
905        BuiltinFunction::StringIsFloat => {
906            if arguments.len() != 1 {
907                panic!("internal error: incorrect argument count to StringIsFloat")
908            }
909            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
910                Value::Bool(<f64 as core::str::FromStr>::from_str(s.as_str()).is_ok())
911            } else {
912                panic!("Argument not a string");
913            }
914        }
915        BuiltinFunction::StringToFloat => {
916            if arguments.len() != 1 {
917                panic!("internal error: incorrect argument count to StringToFloat")
918            }
919            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
920                Value::Number(core::str::FromStr::from_str(s.as_str()).unwrap_or(0.))
921            } else {
922                panic!("Argument not a string");
923            }
924        }
925        BuiltinFunction::StringIsEmpty => {
926            if arguments.len() != 1 {
927                panic!("internal error: incorrect argument count to StringIsEmpty")
928            }
929            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
930                Value::Bool(s.is_empty())
931            } else {
932                panic!("Argument not a string");
933            }
934        }
935        BuiltinFunction::StringCharacterCount => {
936            if arguments.len() != 1 {
937                panic!("internal error: incorrect argument count to StringCharacterCount")
938            }
939            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
940                Value::Number(
941                    unicode_segmentation::UnicodeSegmentation::graphemes(s.as_str(), true).count()
942                        as f64,
943                )
944            } else {
945                panic!("Argument not a string");
946            }
947        }
948        BuiltinFunction::StringToLowercase => {
949            if arguments.len() != 1 {
950                panic!("internal error: incorrect argument count to StringToLowercase")
951            }
952            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
953                Value::String(s.to_lowercase().into())
954            } else {
955                panic!("Argument not a string");
956            }
957        }
958        BuiltinFunction::StringToUppercase => {
959            if arguments.len() != 1 {
960                panic!("internal error: incorrect argument count to StringToUppercase")
961            }
962            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
963                Value::String(s.to_uppercase().into())
964            } else {
965                panic!("Argument not a string");
966            }
967        }
968        BuiltinFunction::ColorRgbaStruct => {
969            if arguments.len() != 1 {
970                panic!("internal error: incorrect argument count to ColorRGBAComponents")
971            }
972            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
973                let color = brush.color();
974                let values = IntoIterator::into_iter([
975                    ("red".to_string(), Value::Number(color.red().into())),
976                    ("green".to_string(), Value::Number(color.green().into())),
977                    ("blue".to_string(), Value::Number(color.blue().into())),
978                    ("alpha".to_string(), Value::Number(color.alpha().into())),
979                ])
980                .collect();
981                Value::Struct(values)
982            } else {
983                panic!("First argument not a color");
984            }
985        }
986        BuiltinFunction::ColorHsvaStruct => {
987            if arguments.len() != 1 {
988                panic!("internal error: incorrect argument count to ColorHSVAComponents")
989            }
990            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
991                let color = brush.color().to_hsva();
992                let values = IntoIterator::into_iter([
993                    ("hue".to_string(), Value::Number(color.hue.into())),
994                    ("saturation".to_string(), Value::Number(color.saturation.into())),
995                    ("value".to_string(), Value::Number(color.value.into())),
996                    ("alpha".to_string(), Value::Number(color.alpha.into())),
997                ])
998                .collect();
999                Value::Struct(values)
1000            } else {
1001                panic!("First argument not a color");
1002            }
1003        }
1004        BuiltinFunction::ColorBrighter => {
1005            if arguments.len() != 2 {
1006                panic!("internal error: incorrect argument count to ColorBrighter")
1007            }
1008            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
1009                if let Value::Number(factor) = eval_expression(&arguments[1], local_context) {
1010                    brush.brighter(factor as _).into()
1011                } else {
1012                    panic!("Second argument not a number");
1013                }
1014            } else {
1015                panic!("First argument not a color");
1016            }
1017        }
1018        BuiltinFunction::ColorDarker => {
1019            if arguments.len() != 2 {
1020                panic!("internal error: incorrect argument count to ColorDarker")
1021            }
1022            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
1023                if let Value::Number(factor) = eval_expression(&arguments[1], local_context) {
1024                    brush.darker(factor as _).into()
1025                } else {
1026                    panic!("Second argument not a number");
1027                }
1028            } else {
1029                panic!("First argument not a color");
1030            }
1031        }
1032        BuiltinFunction::ColorTransparentize => {
1033            if arguments.len() != 2 {
1034                panic!("internal error: incorrect argument count to ColorFaded")
1035            }
1036            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
1037                if let Value::Number(factor) = eval_expression(&arguments[1], local_context) {
1038                    brush.transparentize(factor as _).into()
1039                } else {
1040                    panic!("Second argument not a number");
1041                }
1042            } else {
1043                panic!("First argument not a color");
1044            }
1045        }
1046        BuiltinFunction::ColorMix => {
1047            if arguments.len() != 3 {
1048                panic!("internal error: incorrect argument count to ColorMix")
1049            }
1050
1051            let arg0 = eval_expression(&arguments[0], local_context);
1052            let arg1 = eval_expression(&arguments[1], local_context);
1053            let arg2 = eval_expression(&arguments[2], local_context);
1054
1055            if !matches!(arg0, Value::Brush(Brush::SolidColor(_))) {
1056                panic!("First argument not a color");
1057            }
1058            if !matches!(arg1, Value::Brush(Brush::SolidColor(_))) {
1059                panic!("Second argument not a color");
1060            }
1061            if !matches!(arg2, Value::Number(_)) {
1062                panic!("Third argument not a number");
1063            }
1064
1065            let (
1066                Value::Brush(Brush::SolidColor(color_a)),
1067                Value::Brush(Brush::SolidColor(color_b)),
1068                Value::Number(factor),
1069            ) = (arg0, arg1, arg2)
1070            else {
1071                unreachable!()
1072            };
1073
1074            color_a.mix(&color_b, factor as _).into()
1075        }
1076        BuiltinFunction::ColorWithAlpha => {
1077            if arguments.len() != 2 {
1078                panic!("internal error: incorrect argument count to ColorWithAlpha")
1079            }
1080            if let Value::Brush(brush) = eval_expression(&arguments[0], local_context) {
1081                if let Value::Number(factor) = eval_expression(&arguments[1], local_context) {
1082                    brush.with_alpha(factor as _).into()
1083                } else {
1084                    panic!("Second argument not a number");
1085                }
1086            } else {
1087                panic!("First argument not a color");
1088            }
1089        }
1090        BuiltinFunction::ImageSize => {
1091            if arguments.len() != 1 {
1092                panic!("internal error: incorrect argument count to ImageSize")
1093            }
1094            if let Value::Image(img) = eval_expression(&arguments[0], local_context) {
1095                let size = img.size();
1096                let values = IntoIterator::into_iter([
1097                    ("width".to_string(), Value::Number(size.width as f64)),
1098                    ("height".to_string(), Value::Number(size.height as f64)),
1099                ])
1100                .collect();
1101                Value::Struct(values)
1102            } else {
1103                panic!("First argument not an image");
1104            }
1105        }
1106        BuiltinFunction::ArrayLength => {
1107            if arguments.len() != 1 {
1108                panic!("internal error: incorrect argument count to ArrayLength")
1109            }
1110            match eval_expression(&arguments[0], local_context) {
1111                Value::Model(model) => {
1112                    model.model_tracker().track_row_count_changes();
1113                    Value::Number(model.row_count() as f64)
1114                }
1115                _ => {
1116                    panic!("First argument not an array");
1117                }
1118            }
1119        }
1120        BuiltinFunction::Rgb => {
1121            let r: i32 = eval_expression(&arguments[0], local_context).try_into().unwrap();
1122            let g: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
1123            let b: i32 = eval_expression(&arguments[2], local_context).try_into().unwrap();
1124            let a: f32 = eval_expression(&arguments[3], local_context).try_into().unwrap();
1125            let r: u8 = r.clamp(0, 255) as u8;
1126            let g: u8 = g.clamp(0, 255) as u8;
1127            let b: u8 = b.clamp(0, 255) as u8;
1128            let a: u8 = (255. * a).clamp(0., 255.) as u8;
1129            Value::Brush(Brush::SolidColor(Color::from_argb_u8(a, r, g, b)))
1130        }
1131        BuiltinFunction::Hsv => {
1132            let h: f32 = eval_expression(&arguments[0], local_context).try_into().unwrap();
1133            let s: f32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
1134            let v: f32 = eval_expression(&arguments[2], local_context).try_into().unwrap();
1135            let a: f32 = eval_expression(&arguments[3], local_context).try_into().unwrap();
1136            let a = (1. * a).clamp(0., 1.);
1137            Value::Brush(Brush::SolidColor(Color::from_hsva(h, s, v, a)))
1138        }
1139        BuiltinFunction::ColorScheme => local_context
1140            .component_instance
1141            .window_adapter()
1142            .internal(corelib::InternalToken)
1143            .map_or(ColorScheme::Unknown, |x| x.color_scheme())
1144            .into(),
1145        BuiltinFunction::SupportsNativeMenuBar => local_context
1146            .component_instance
1147            .window_adapter()
1148            .internal(corelib::InternalToken)
1149            .is_some_and(|x| x.supports_native_menu_bar())
1150            .into(),
1151        BuiltinFunction::SetupMenuBar => {
1152            let component = local_context.component_instance;
1153            let [Expression::PropertyReference(entries_nr), Expression::PropertyReference(sub_menu_nr), Expression::PropertyReference(activated_nr), Expression::ElementReference(item_tree_root), Expression::BoolLiteral(no_native), rest @ ..] =
1154                arguments
1155            else {
1156                panic!("internal error: incorrect argument count to SetupMenuBar")
1157            };
1158
1159            let menu_item_tree =
1160                item_tree_root.upgrade().unwrap().borrow().enclosing_component.upgrade().unwrap();
1161            let menu_item_tree = crate::dynamic_item_tree::make_menu_item_tree(
1162                &menu_item_tree,
1163                &component,
1164                rest.first(),
1165            );
1166
1167            if let Some(w) = component.window_adapter().internal(i_slint_core::InternalToken) {
1168                if !no_native && w.supports_native_menu_bar() {
1169                    let menubar = vtable::VRc::into_dyn(menu_item_tree);
1170                    w.setup_menubar(menubar);
1171                    return Value::Void;
1172                }
1173            }
1174
1175            let (entries, sub_menu, activated) = menu_item_tree_properties(menu_item_tree);
1176
1177            assert_eq!(
1178                entries_nr.element().borrow().id,
1179                component.description.original.root_element.borrow().id,
1180                "entries need to be in the main element"
1181            );
1182            local_context
1183                .component_instance
1184                .description
1185                .set_binding(component.borrow(), entries_nr.name(), entries)
1186                .unwrap();
1187            let i = &ComponentInstance::InstanceRef(local_context.component_instance);
1188            set_callback_handler(i, &sub_menu_nr.element(), sub_menu_nr.name(), sub_menu).unwrap();
1189            set_callback_handler(i, &activated_nr.element(), activated_nr.name(), activated)
1190                .unwrap();
1191
1192            return Value::Void;
1193        }
1194        BuiltinFunction::MonthDayCount => {
1195            let m: u32 = eval_expression(&arguments[0], local_context).try_into().unwrap();
1196            let y: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
1197            Value::Number(i_slint_core::date_time::month_day_count(m, y).unwrap_or(0) as f64)
1198        }
1199        BuiltinFunction::MonthOffset => {
1200            let m: u32 = eval_expression(&arguments[0], local_context).try_into().unwrap();
1201            let y: i32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
1202
1203            Value::Number(i_slint_core::date_time::month_offset(m, y) as f64)
1204        }
1205        BuiltinFunction::FormatDate => {
1206            let f: SharedString = eval_expression(&arguments[0], local_context).try_into().unwrap();
1207            let d: u32 = eval_expression(&arguments[1], local_context).try_into().unwrap();
1208            let m: u32 = eval_expression(&arguments[2], local_context).try_into().unwrap();
1209            let y: i32 = eval_expression(&arguments[3], local_context).try_into().unwrap();
1210
1211            Value::String(i_slint_core::date_time::format_date(&f, d, m, y))
1212        }
1213        BuiltinFunction::DateNow => Value::Model(ModelRc::new(VecModel::from(
1214            i_slint_core::date_time::date_now()
1215                .into_iter()
1216                .map(|x| Value::Number(x as f64))
1217                .collect::<Vec<_>>(),
1218        ))),
1219        BuiltinFunction::ValidDate => {
1220            let d: SharedString = eval_expression(&arguments[0], local_context).try_into().unwrap();
1221            let f: SharedString = eval_expression(&arguments[1], local_context).try_into().unwrap();
1222            Value::Bool(i_slint_core::date_time::parse_date(d.as_str(), f.as_str()).is_some())
1223        }
1224        BuiltinFunction::ParseDate => {
1225            let d: SharedString = eval_expression(&arguments[0], local_context).try_into().unwrap();
1226            let f: SharedString = eval_expression(&arguments[1], local_context).try_into().unwrap();
1227
1228            Value::Model(ModelRc::new(
1229                i_slint_core::date_time::parse_date(d.as_str(), f.as_str())
1230                    .map(|x| {
1231                        VecModel::from(
1232                            x.into_iter().map(|x| Value::Number(x as f64)).collect::<Vec<_>>(),
1233                        )
1234                    })
1235                    .unwrap_or_default(),
1236            ))
1237        }
1238        BuiltinFunction::TextInputFocused => Value::Bool(
1239            local_context.component_instance.access_window(|window| window.text_input_focused())
1240                as _,
1241        ),
1242        BuiltinFunction::SetTextInputFocused => {
1243            local_context.component_instance.access_window(|window| {
1244                window.set_text_input_focused(
1245                    eval_expression(&arguments[0], local_context).try_into().unwrap(),
1246                )
1247            });
1248            Value::Void
1249        }
1250        BuiltinFunction::ImplicitLayoutInfo(orient) => {
1251            let component = local_context.component_instance;
1252            if let [Expression::ElementReference(item)] = arguments {
1253                generativity::make_guard!(guard);
1254
1255                let item = item.upgrade().unwrap();
1256                let enclosing_component = enclosing_component_for_element(&item, component, guard);
1257                let description = enclosing_component.description;
1258                let item_info = &description.items[item.borrow().id.as_str()];
1259                let item_ref =
1260                    unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
1261                let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
1262                let window_adapter = component.window_adapter();
1263                item_ref
1264                    .as_ref()
1265                    .layout_info(
1266                        crate::eval_layout::to_runtime(orient),
1267                        &window_adapter,
1268                        &ItemRc::new(vtable::VRc::into_dyn(item_comp), item_info.item_index()),
1269                    )
1270                    .into()
1271            } else {
1272                panic!("internal error: incorrect arguments to ImplicitLayoutInfo {arguments:?}");
1273            }
1274        }
1275        BuiltinFunction::ItemAbsolutePosition => {
1276            if arguments.len() != 1 {
1277                panic!("internal error: incorrect argument count to ItemAbsolutePosition")
1278            }
1279
1280            let component = local_context.component_instance;
1281
1282            if let Expression::ElementReference(item) = &arguments[0] {
1283                generativity::make_guard!(guard);
1284
1285                let item = item.upgrade().unwrap();
1286                let enclosing_component = enclosing_component_for_element(&item, component, guard);
1287                let description = enclosing_component.description;
1288
1289                let item_info = &description.items[item.borrow().id.as_str()];
1290
1291                let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
1292
1293                let item_rc = corelib::items::ItemRc::new(
1294                    vtable::VRc::into_dyn(item_comp),
1295                    item_info.item_index(),
1296                );
1297
1298                item_rc.map_to_window(Default::default()).to_untyped().into()
1299            } else {
1300                panic!("internal error: argument to SetFocusItem must be an element")
1301            }
1302        }
1303        BuiltinFunction::RegisterCustomFontByPath => {
1304            if arguments.len() != 1 {
1305                panic!("internal error: incorrect argument count to RegisterCustomFontByPath")
1306            }
1307            let component = local_context.component_instance;
1308            if let Value::String(s) = eval_expression(&arguments[0], local_context) {
1309                if let Some(err) = component
1310                    .window_adapter()
1311                    .renderer()
1312                    .register_font_from_path(&std::path::PathBuf::from(s.as_str()))
1313                    .err()
1314                {
1315                    corelib::debug_log!("Error loading custom font {}: {}", s.as_str(), err);
1316                }
1317                Value::Void
1318            } else {
1319                panic!("Argument not a string");
1320            }
1321        }
1322        BuiltinFunction::RegisterCustomFontByMemory | BuiltinFunction::RegisterBitmapFont => {
1323            unimplemented!()
1324        }
1325        BuiltinFunction::Translate => {
1326            let original: SharedString =
1327                eval_expression(&arguments[0], local_context).try_into().unwrap();
1328            let context: SharedString =
1329                eval_expression(&arguments[1], local_context).try_into().unwrap();
1330            let domain: SharedString =
1331                eval_expression(&arguments[2], local_context).try_into().unwrap();
1332            let args = eval_expression(&arguments[3], local_context);
1333            let Value::Model(args) = args else { panic!("Args to translate not a model {args:?}") };
1334            struct StringModelWrapper(ModelRc<Value>);
1335            impl corelib::translations::FormatArgs for StringModelWrapper {
1336                type Output<'a> = SharedString;
1337                fn from_index(&self, index: usize) -> Option<SharedString> {
1338                    self.0.row_data(index).map(|x| x.try_into().unwrap())
1339                }
1340            }
1341            Value::String(corelib::translations::translate(
1342                &original,
1343                &context,
1344                &domain,
1345                &StringModelWrapper(args),
1346                eval_expression(&arguments[4], local_context).try_into().unwrap(),
1347                &SharedString::try_from(eval_expression(&arguments[5], local_context)).unwrap(),
1348            ))
1349        }
1350        BuiltinFunction::Use24HourFormat => Value::Bool(corelib::date_time::use_24_hour_format()),
1351        BuiltinFunction::UpdateTimers => {
1352            crate::dynamic_item_tree::update_timers(local_context.component_instance);
1353            Value::Void
1354        }
1355        BuiltinFunction::DetectOperatingSystem => i_slint_core::detect_operating_system().into(),
1356        // start and stop are unreachable because they are lowered to simple assignment of running
1357        BuiltinFunction::StartTimer => unreachable!(),
1358        BuiltinFunction::StopTimer => unreachable!(),
1359        BuiltinFunction::RestartTimer => {
1360            if let [Expression::ElementReference(timer_element)] = arguments {
1361                crate::dynamic_item_tree::restart_timer(
1362                    timer_element.clone(),
1363                    local_context.component_instance,
1364                );
1365
1366                Value::Void
1367            } else {
1368                panic!("internal error: argument to RestartTimer must be an element")
1369            }
1370        }
1371    }
1372}
1373
1374fn call_item_member_function(nr: &NamedReference, local_context: &mut EvalLocalContext) -> Value {
1375    let component = local_context.component_instance;
1376    let elem = nr.element();
1377    let name = nr.name().as_str();
1378    generativity::make_guard!(guard);
1379    let enclosing_component = enclosing_component_for_element(&elem, component, guard);
1380    let description = enclosing_component.description;
1381    let item_info = &description.items[elem.borrow().id.as_str()];
1382    let item_ref = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
1383
1384    let item_comp = enclosing_component.self_weak().get().unwrap().upgrade().unwrap();
1385    let item_rc =
1386        corelib::items::ItemRc::new(vtable::VRc::into_dyn(item_comp), item_info.item_index());
1387
1388    let window_adapter = component.window_adapter();
1389
1390    // TODO: Make this generic through RTTI
1391    if let Some(textinput) = ItemRef::downcast_pin::<corelib::items::TextInput>(item_ref) {
1392        match name {
1393            "select-all" => textinput.select_all(&window_adapter, &item_rc),
1394            "clear-selection" => textinput.clear_selection(&window_adapter, &item_rc),
1395            "cut" => textinput.cut(&window_adapter, &item_rc),
1396            "copy" => textinput.copy(&window_adapter, &item_rc),
1397            "paste" => textinput.paste(&window_adapter, &item_rc),
1398            _ => panic!("internal: Unknown member function {name} called on TextInput"),
1399        }
1400    } else if let Some(s) = ItemRef::downcast_pin::<corelib::items::SwipeGestureHandler>(item_ref) {
1401        match name {
1402            "cancel" => s.cancel(&window_adapter, &item_rc),
1403            _ => panic!("internal: Unknown member function {name} called on SwipeGestureHandler"),
1404        }
1405    } else if let Some(s) = ItemRef::downcast_pin::<corelib::items::ContextMenu>(item_ref) {
1406        match name {
1407            "close" => s.close(&window_adapter, &item_rc),
1408            "is-open" => return Value::Bool(s.is_open(&window_adapter, &item_rc)),
1409            _ => {
1410                panic!("internal: Unknown member function {name} called on ContextMenu")
1411            }
1412        }
1413    } else {
1414        panic!(
1415            "internal error: member function {name} called on element that doesn't have it: {}",
1416            elem.borrow().original_name()
1417        )
1418    }
1419
1420    Value::Void
1421}
1422
1423fn eval_assignment(lhs: &Expression, op: char, rhs: Value, local_context: &mut EvalLocalContext) {
1424    let eval = |lhs| match (lhs, &rhs, op) {
1425        (Value::String(ref mut a), Value::String(b), '+') => {
1426            a.push_str(b.as_str());
1427            Value::String(a.clone())
1428        }
1429        (Value::Number(a), Value::Number(b), '+') => Value::Number(a + b),
1430        (Value::Number(a), Value::Number(b), '-') => Value::Number(a - b),
1431        (Value::Number(a), Value::Number(b), '/') => Value::Number(a / b),
1432        (Value::Number(a), Value::Number(b), '*') => Value::Number(a * b),
1433        (lhs, rhs, op) => panic!("unsupported {lhs:?} {op} {rhs:?}"),
1434    };
1435    match lhs {
1436        Expression::PropertyReference(nr) => {
1437            let element = nr.element();
1438            generativity::make_guard!(guard);
1439            let enclosing_component = enclosing_component_instance_for_element(
1440                &element,
1441                &ComponentInstance::InstanceRef(local_context.component_instance),
1442                guard,
1443            );
1444
1445            match enclosing_component {
1446                ComponentInstance::InstanceRef(enclosing_component) => {
1447                    if op == '=' {
1448                        store_property(enclosing_component, &element, nr.name(), rhs).unwrap();
1449                        return;
1450                    }
1451
1452                    let component = element.borrow().enclosing_component.upgrade().unwrap();
1453                    if element.borrow().id == component.root_element.borrow().id {
1454                        if let Some(x) =
1455                            enclosing_component.description.custom_properties.get(nr.name())
1456                        {
1457                            unsafe {
1458                                let p = Pin::new_unchecked(
1459                                    &*enclosing_component.as_ptr().add(x.offset),
1460                                );
1461                                x.prop.set(p, eval(x.prop.get(p).unwrap()), None).unwrap();
1462                            }
1463                            return;
1464                        }
1465                    };
1466                    let item_info =
1467                        &enclosing_component.description.items[element.borrow().id.as_str()];
1468                    let item =
1469                        unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
1470                    let p = &item_info.rtti.properties[nr.name().as_str()];
1471                    p.set(item, eval(p.get(item)), None).unwrap();
1472                }
1473                ComponentInstance::GlobalComponent(global) => {
1474                    let val = if op == '=' {
1475                        rhs
1476                    } else {
1477                        eval(global.as_ref().get_property(nr.name()).unwrap())
1478                    };
1479                    global.as_ref().set_property(nr.name(), val).unwrap();
1480                }
1481            }
1482        }
1483        Expression::StructFieldAccess { base, name } => {
1484            if let Value::Struct(mut o) = eval_expression(base, local_context) {
1485                let mut r = o.get_field(name).unwrap().clone();
1486                r = if op == '=' { rhs } else { eval(std::mem::take(&mut r)) };
1487                o.set_field(name.to_string(), r);
1488                eval_assignment(base, '=', Value::Struct(o), local_context)
1489            }
1490        }
1491        Expression::RepeaterModelReference { element } => {
1492            let element = element.upgrade().unwrap();
1493            let component_instance = local_context.component_instance;
1494            generativity::make_guard!(g1);
1495            let enclosing_component =
1496                enclosing_component_for_element(&element, component_instance, g1);
1497            // we need a 'static Repeater component in order to call model_set_row_data, so get it.
1498            // Safety: This is the only 'static Id in scope.
1499            let static_guard =
1500                unsafe { generativity::Guard::new(generativity::Id::<'static>::new()) };
1501            let repeater = crate::dynamic_item_tree::get_repeater_by_name(
1502                enclosing_component,
1503                element.borrow().id.as_str(),
1504                static_guard,
1505            );
1506            repeater.0.model_set_row_data(
1507                eval_expression(
1508                    &Expression::RepeaterIndexReference { element: Rc::downgrade(&element) },
1509                    local_context,
1510                )
1511                .try_into()
1512                .unwrap(),
1513                if op == '=' {
1514                    rhs
1515                } else {
1516                    eval(eval_expression(
1517                        &Expression::RepeaterModelReference { element: Rc::downgrade(&element) },
1518                        local_context,
1519                    ))
1520                },
1521            )
1522        }
1523        Expression::ArrayIndex { array, index } => {
1524            let array = eval_expression(array, local_context);
1525            let index = eval_expression(index, local_context);
1526            match (array, index) {
1527                (Value::Model(model), Value::Number(index)) => {
1528                    if index >= 0. && (index as usize) < model.row_count() {
1529                        let index = index as usize;
1530                        if op == '=' {
1531                            model.set_row_data(index, rhs);
1532                        } else {
1533                            model.set_row_data(
1534                                index,
1535                                eval(
1536                                    model
1537                                        .row_data(index)
1538                                        .unwrap_or_else(|| default_value_for_type(&lhs.ty())),
1539                                ),
1540                            );
1541                        }
1542                    }
1543                }
1544                _ => {
1545                    eprintln!("Attempting to write into an array that cannot be written");
1546                }
1547            }
1548        }
1549        _ => panic!("typechecking should make sure this was a PropertyReference"),
1550    }
1551}
1552
1553pub fn load_property(component: InstanceRef, element: &ElementRc, name: &str) -> Result<Value, ()> {
1554    load_property_helper(&ComponentInstance::InstanceRef(component), element, name)
1555}
1556
1557fn load_property_helper(
1558    component_instance: &ComponentInstance,
1559    element: &ElementRc,
1560    name: &str,
1561) -> Result<Value, ()> {
1562    generativity::make_guard!(guard);
1563    match enclosing_component_instance_for_element(element, component_instance, guard) {
1564        ComponentInstance::InstanceRef(enclosing_component) => {
1565            let element = element.borrow();
1566            if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id
1567            {
1568                if let Some(x) = enclosing_component.description.custom_properties.get(name) {
1569                    return unsafe {
1570                        x.prop.get(Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset)))
1571                    };
1572                } else if enclosing_component.description.original.is_global() {
1573                    return Err(());
1574                }
1575            };
1576            let item_info = enclosing_component
1577                .description
1578                .items
1579                .get(element.id.as_str())
1580                .unwrap_or_else(|| panic!("Unknown element for {}.{}", element.id, name));
1581            core::mem::drop(element);
1582            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
1583            Ok(item_info.rtti.properties.get(name).ok_or(())?.get(item))
1584        }
1585        ComponentInstance::GlobalComponent(glob) => glob.as_ref().get_property(name),
1586    }
1587}
1588
1589pub fn store_property(
1590    component_instance: InstanceRef,
1591    element: &ElementRc,
1592    name: &str,
1593    value: Value,
1594) -> Result<(), SetPropertyError> {
1595    generativity::make_guard!(guard);
1596    match enclosing_component_instance_for_element(
1597        element,
1598        &ComponentInstance::InstanceRef(component_instance),
1599        guard,
1600    ) {
1601        ComponentInstance::InstanceRef(enclosing_component) => {
1602            let maybe_animation = match element.borrow().bindings.get(name) {
1603                Some(b) => crate::dynamic_item_tree::animation_for_property(
1604                    enclosing_component,
1605                    &b.borrow().animation,
1606                ),
1607                None => {
1608                    crate::dynamic_item_tree::animation_for_property(enclosing_component, &None)
1609                }
1610            };
1611
1612            let component = element.borrow().enclosing_component.upgrade().unwrap();
1613            if element.borrow().id == component.root_element.borrow().id {
1614                if let Some(x) = enclosing_component.description.custom_properties.get(name) {
1615                    if let Some(orig_decl) = enclosing_component
1616                        .description
1617                        .original
1618                        .root_element
1619                        .borrow()
1620                        .property_declarations
1621                        .get(name)
1622                    {
1623                        // Do an extra type checking because PropertyInfo::set won't do it for custom structures or array
1624                        if !check_value_type(&value, &orig_decl.property_type) {
1625                            return Err(SetPropertyError::WrongType);
1626                        }
1627                    }
1628                    unsafe {
1629                        let p = Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset));
1630                        return x
1631                            .prop
1632                            .set(p, value, maybe_animation.as_animation())
1633                            .map_err(|()| SetPropertyError::WrongType);
1634                    }
1635                } else if enclosing_component.description.original.is_global() {
1636                    return Err(SetPropertyError::NoSuchProperty);
1637                }
1638            };
1639            let item_info = &enclosing_component.description.items[element.borrow().id.as_str()];
1640            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
1641            let p = &item_info.rtti.properties.get(name).ok_or(SetPropertyError::NoSuchProperty)?;
1642            p.set(item, value, maybe_animation.as_animation())
1643                .map_err(|()| SetPropertyError::WrongType)?;
1644        }
1645        ComponentInstance::GlobalComponent(glob) => {
1646            glob.as_ref().set_property(name, value)?;
1647        }
1648    }
1649    Ok(())
1650}
1651
1652/// Return true if the Value can be used for a property of the given type
1653fn check_value_type(value: &Value, ty: &Type) -> bool {
1654    match ty {
1655        Type::Void => true,
1656        Type::Invalid
1657        | Type::InferredProperty
1658        | Type::InferredCallback
1659        | Type::Callback { .. }
1660        | Type::Function { .. }
1661        | Type::ElementReference => panic!("not valid property type"),
1662        Type::Float32 => matches!(value, Value::Number(_)),
1663        Type::Int32 => matches!(value, Value::Number(_)),
1664        Type::String => matches!(value, Value::String(_)),
1665        Type::Color => matches!(value, Value::Brush(_)),
1666        Type::UnitProduct(_)
1667        | Type::Duration
1668        | Type::PhysicalLength
1669        | Type::LogicalLength
1670        | Type::Rem
1671        | Type::Angle
1672        | Type::Percent => matches!(value, Value::Number(_)),
1673        Type::Image => matches!(value, Value::Image(_)),
1674        Type::Bool => matches!(value, Value::Bool(_)),
1675        Type::Model => {
1676            matches!(value, Value::Model(_) | Value::Bool(_) | Value::Number(_))
1677        }
1678        Type::PathData => matches!(value, Value::PathData(_)),
1679        Type::Easing => matches!(value, Value::EasingCurve(_)),
1680        Type::Brush => matches!(value, Value::Brush(_)),
1681        Type::Array(inner) => {
1682            matches!(value, Value::Model(m) if m.iter().all(|v| check_value_type(&v, inner)))
1683        }
1684        Type::Struct(s) => {
1685            matches!(value, Value::Struct(str) if str.iter().all(|(k, v)| s.fields.get(k).is_some_and(|ty| check_value_type(v, ty))))
1686        }
1687        Type::Enumeration(en) => {
1688            matches!(value, Value::EnumerationValue(name, _) if name == en.name.as_str())
1689        }
1690        Type::LayoutCache => matches!(value, Value::LayoutCache(_)),
1691        Type::ComponentFactory => matches!(value, Value::ComponentFactory(_)),
1692    }
1693}
1694
1695pub(crate) fn invoke_callback(
1696    component_instance: &ComponentInstance,
1697    element: &ElementRc,
1698    callback_name: &SmolStr,
1699    args: &[Value],
1700) -> Option<Value> {
1701    generativity::make_guard!(guard);
1702    match enclosing_component_instance_for_element(element, component_instance, guard) {
1703        ComponentInstance::InstanceRef(enclosing_component) => {
1704            let description = enclosing_component.description;
1705            let element = element.borrow();
1706            if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id
1707            {
1708                if let Some(callback_offset) = description.custom_callbacks.get(callback_name) {
1709                    let callback = callback_offset.apply(&*enclosing_component.instance);
1710                    let res = callback.call(args);
1711                    return Some(if res != Value::Void {
1712                        res
1713                    } else if let Some(Type::Callback(callback)) = description
1714                        .original
1715                        .root_element
1716                        .borrow()
1717                        .property_declarations
1718                        .get(callback_name)
1719                        .map(|d| &d.property_type)
1720                    {
1721                        // If the callback was not set, the return value will be Value::Void, but we need
1722                        // to make sure that the value is actually of the right type as returned by the
1723                        // callback, otherwise we will get panics later
1724                        default_value_for_type(&callback.return_type)
1725                    } else {
1726                        res
1727                    });
1728                } else if enclosing_component.description.original.is_global() {
1729                    return None;
1730                }
1731            };
1732            let item_info = &description.items[element.id.as_str()];
1733            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
1734            item_info
1735                .rtti
1736                .callbacks
1737                .get(callback_name.as_str())
1738                .map(|callback| callback.call(item, args))
1739        }
1740        ComponentInstance::GlobalComponent(global) => {
1741            Some(global.as_ref().invoke_callback(callback_name, args).unwrap())
1742        }
1743    }
1744}
1745
1746pub(crate) fn set_callback_handler(
1747    component_instance: &ComponentInstance,
1748    element: &ElementRc,
1749    callback_name: &str,
1750    handler: CallbackHandler,
1751) -> Result<(), ()> {
1752    generativity::make_guard!(guard);
1753    match enclosing_component_instance_for_element(element, component_instance, guard) {
1754        ComponentInstance::InstanceRef(enclosing_component) => {
1755            let description = enclosing_component.description;
1756            let element = element.borrow();
1757            if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id
1758            {
1759                if let Some(callback_offset) = description.custom_callbacks.get(callback_name) {
1760                    let callback = callback_offset.apply(&*enclosing_component.instance);
1761                    callback.set_handler(handler);
1762                    return Ok(());
1763                } else if enclosing_component.description.original.is_global() {
1764                    return Err(());
1765                }
1766            };
1767            let item_info = &description.items[element.id.as_str()];
1768            let item = unsafe { item_info.item_from_item_tree(enclosing_component.as_ptr()) };
1769            if let Some(callback) = item_info.rtti.callbacks.get(callback_name) {
1770                callback.set_handler(item, handler);
1771                Ok(())
1772            } else {
1773                Err(())
1774            }
1775        }
1776        ComponentInstance::GlobalComponent(global) => {
1777            global.as_ref().set_callback_handler(callback_name, handler)
1778        }
1779    }
1780}
1781
1782/// Invoke the function.
1783///
1784/// Return None if the function don't exist
1785pub(crate) fn call_function(
1786    component_instance: &ComponentInstance,
1787    element: &ElementRc,
1788    function_name: &str,
1789    args: Vec<Value>,
1790) -> Option<Value> {
1791    generativity::make_guard!(guard);
1792    match enclosing_component_instance_for_element(element, component_instance, guard) {
1793        ComponentInstance::InstanceRef(c) => {
1794            let mut ctx = EvalLocalContext::from_function_arguments(c, args);
1795            eval_expression(
1796                &element.borrow().bindings.get(function_name)?.borrow().expression,
1797                &mut ctx,
1798            )
1799            .into()
1800        }
1801        ComponentInstance::GlobalComponent(g) => g.as_ref().eval_function(function_name, args).ok(),
1802    }
1803}
1804
1805/// Return the component instance which hold the given element.
1806/// Does not take in account the global component.
1807pub fn enclosing_component_for_element<'a, 'old_id, 'new_id>(
1808    element: &'a ElementRc,
1809    component: InstanceRef<'a, 'old_id>,
1810    _guard: generativity::Guard<'new_id>,
1811) -> InstanceRef<'a, 'new_id> {
1812    let enclosing = &element.borrow().enclosing_component.upgrade().unwrap();
1813    if Rc::ptr_eq(enclosing, &component.description.original) {
1814        // Safety: new_id is an unique id
1815        unsafe {
1816            std::mem::transmute::<InstanceRef<'a, 'old_id>, InstanceRef<'a, 'new_id>>(component)
1817        }
1818    } else {
1819        assert!(!enclosing.is_global());
1820        // Safety: this is the only place we use this 'static lifetime in this function and nothing is returned with it
1821        // For some reason we can't make a new guard here because the compiler thinks we are returning that
1822        // (it assumes that the 'id must outlive 'a , which is not true)
1823        let static_guard = unsafe { generativity::Guard::new(generativity::Id::<'static>::new()) };
1824
1825        let parent_instance = component.parent_instance(static_guard).unwrap();
1826        enclosing_component_for_element(element, parent_instance, _guard)
1827    }
1828}
1829
1830/// Return the component instance which hold the given element.
1831/// The difference with enclosing_component_for_element is that it takes the GlobalComponent into account.
1832pub(crate) fn enclosing_component_instance_for_element<'a, 'new_id>(
1833    element: &'a ElementRc,
1834    component_instance: &ComponentInstance<'a, '_>,
1835    guard: generativity::Guard<'new_id>,
1836) -> ComponentInstance<'a, 'new_id> {
1837    let enclosing = &element.borrow().enclosing_component.upgrade().unwrap();
1838    match component_instance {
1839        ComponentInstance::InstanceRef(component) => {
1840            if enclosing.is_global() && !Rc::ptr_eq(enclosing, &component.description.original) {
1841                let root = component.toplevel_instance(guard);
1842                ComponentInstance::GlobalComponent(
1843                    root.description
1844                        .extra_data_offset
1845                        .apply(root.instance.get_ref())
1846                        .globals
1847                        .get()
1848                        .unwrap()
1849                        .get(enclosing.root_element.borrow().id.as_str())
1850                        .unwrap(),
1851                )
1852            } else {
1853                ComponentInstance::InstanceRef(enclosing_component_for_element(
1854                    element, *component, guard,
1855                ))
1856            }
1857        }
1858        ComponentInstance::GlobalComponent(global) => {
1859            //assert!(Rc::ptr_eq(enclosing, &global.component));
1860            ComponentInstance::GlobalComponent(global.clone())
1861        }
1862    }
1863}
1864
1865pub fn new_struct_with_bindings<ElementType: 'static + Default + corelib::rtti::BuiltinItem>(
1866    bindings: &i_slint_compiler::object_tree::BindingsMap,
1867    local_context: &mut EvalLocalContext,
1868) -> ElementType {
1869    let mut element = ElementType::default();
1870    for (prop, info) in ElementType::fields::<Value>().into_iter() {
1871        if let Some(binding) = &bindings.get(prop) {
1872            let value = eval_expression(&binding.borrow(), local_context);
1873            info.set_field(&mut element, value).unwrap();
1874        }
1875    }
1876    element
1877}
1878
1879fn convert_from_lyon_path<'a>(
1880    events_it: impl IntoIterator<Item = &'a i_slint_compiler::expression_tree::Expression>,
1881    points_it: impl IntoIterator<Item = &'a i_slint_compiler::expression_tree::Expression>,
1882    local_context: &mut EvalLocalContext,
1883) -> PathData {
1884    let events = events_it
1885        .into_iter()
1886        .map(|event_expr| eval_expression(event_expr, local_context).try_into().unwrap())
1887        .collect::<SharedVector<_>>();
1888
1889    let points = points_it
1890        .into_iter()
1891        .map(|point_expr| {
1892            let point_value = eval_expression(point_expr, local_context);
1893            let point_struct: Struct = point_value.try_into().unwrap();
1894            let mut point = i_slint_core::graphics::Point::default();
1895            let x: f64 = point_struct.get_field("x").unwrap().clone().try_into().unwrap();
1896            let y: f64 = point_struct.get_field("y").unwrap().clone().try_into().unwrap();
1897            point.x = x as _;
1898            point.y = y as _;
1899            point
1900        })
1901        .collect::<SharedVector<_>>();
1902
1903    PathData::Events(events, points)
1904}
1905
1906pub fn convert_path(path: &ExprPath, local_context: &mut EvalLocalContext) -> PathData {
1907    match path {
1908        ExprPath::Elements(elements) => PathData::Elements(
1909            elements
1910                .iter()
1911                .map(|element| convert_path_element(element, local_context))
1912                .collect::<SharedVector<PathElement>>(),
1913        ),
1914        ExprPath::Events(events, points) => {
1915            convert_from_lyon_path(events.iter(), points.iter(), local_context)
1916        }
1917        ExprPath::Commands(commands) => {
1918            if let Value::String(commands) = eval_expression(commands, local_context) {
1919                PathData::Commands(commands)
1920            } else {
1921                panic!("binding to path commands does not evaluate to string");
1922            }
1923        }
1924    }
1925}
1926
1927fn convert_path_element(
1928    expr_element: &ExprPathElement,
1929    local_context: &mut EvalLocalContext,
1930) -> PathElement {
1931    match expr_element.element_type.native_class.class_name.as_str() {
1932        "MoveTo" => {
1933            PathElement::MoveTo(new_struct_with_bindings(&expr_element.bindings, local_context))
1934        }
1935        "LineTo" => {
1936            PathElement::LineTo(new_struct_with_bindings(&expr_element.bindings, local_context))
1937        }
1938        "ArcTo" => {
1939            PathElement::ArcTo(new_struct_with_bindings(&expr_element.bindings, local_context))
1940        }
1941        "CubicTo" => {
1942            PathElement::CubicTo(new_struct_with_bindings(&expr_element.bindings, local_context))
1943        }
1944        "QuadraticTo" => PathElement::QuadraticTo(new_struct_with_bindings(
1945            &expr_element.bindings,
1946            local_context,
1947        )),
1948        "Close" => PathElement::Close,
1949        _ => panic!(
1950            "Cannot create unsupported path element {}",
1951            expr_element.element_type.native_class.class_name
1952        ),
1953    }
1954}
1955
1956/// Create a value suitable as the default value of a given type
1957pub fn default_value_for_type(ty: &Type) -> Value {
1958    match ty {
1959        Type::Float32 | Type::Int32 => Value::Number(0.),
1960        Type::String => Value::String(Default::default()),
1961        Type::Color | Type::Brush => Value::Brush(Default::default()),
1962        Type::Duration | Type::Angle | Type::PhysicalLength | Type::LogicalLength | Type::Rem => {
1963            Value::Number(0.)
1964        }
1965        Type::Image => Value::Image(Default::default()),
1966        Type::Bool => Value::Bool(false),
1967        Type::Callback { .. } => Value::Void,
1968        Type::Struct(s) => Value::Struct(
1969            s.fields
1970                .iter()
1971                .map(|(n, t)| (n.to_string(), default_value_for_type(t)))
1972                .collect::<Struct>(),
1973        ),
1974        Type::Array(_) | Type::Model => Value::Model(Default::default()),
1975        Type::Percent => Value::Number(0.),
1976        Type::Enumeration(e) => Value::EnumerationValue(
1977            e.name.to_string(),
1978            e.values.get(e.default_value).unwrap().to_string(),
1979        ),
1980        Type::Easing => Value::EasingCurve(Default::default()),
1981        Type::Void | Type::Invalid => Value::Void,
1982        Type::UnitProduct(_) => Value::Number(0.),
1983        Type::PathData => Value::PathData(Default::default()),
1984        Type::LayoutCache => Value::LayoutCache(Default::default()),
1985        Type::ComponentFactory => Value::ComponentFactory(Default::default()),
1986        Type::InferredProperty
1987        | Type::InferredCallback
1988        | Type::ElementReference
1989        | Type::Function { .. } => {
1990            panic!("There can't be such property")
1991        }
1992    }
1993}
1994
1995fn menu_item_tree_properties(
1996    context_menu_item_tree: vtable::VRc<i_slint_core::menus::MenuVTable, MenuFromItemTree>,
1997) -> (Box<dyn Fn() -> Value>, CallbackHandler, CallbackHandler) {
1998    let context_menu_item_tree_ = context_menu_item_tree.clone();
1999    let entries = Box::new(move || {
2000        let mut entries = SharedVector::default();
2001        context_menu_item_tree_.sub_menu(None, &mut entries);
2002        Value::Model(ModelRc::new(VecModel::from(
2003            entries.into_iter().map(Value::from).collect::<Vec<_>>(),
2004        )))
2005    });
2006    let context_menu_item_tree_ = context_menu_item_tree.clone();
2007    let sub_menu = Box::new(move |args: &[Value]| -> Value {
2008        let mut entries = SharedVector::default();
2009        context_menu_item_tree_.sub_menu(Some(&args[0].clone().try_into().unwrap()), &mut entries);
2010        Value::Model(ModelRc::new(VecModel::from(
2011            entries.into_iter().map(Value::from).collect::<Vec<_>>(),
2012        )))
2013    });
2014    let activated = Box::new(move |args: &[Value]| -> Value {
2015        context_menu_item_tree.activate(&args[0].clone().try_into().unwrap());
2016        Value::Void
2017    });
2018    (entries, sub_menu, activated)
2019}