Skip to main content

slint_interpreter/
eval.rs

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