1use crate::Value;
13use crate::eval::{EvalContext, eval_expression};
14use crate::instance::{Instance, SubComponentInstance};
15use i_slint_compiler::llr::{
16 self, Animation, Expression, LocalMemberIndex, MemberReference, MutExpression, SubComponent,
17};
18use i_slint_core::Property;
19use i_slint_core::items::PropertyAnimation;
20use i_slint_core::rtti::AnimatedBindingKind;
21use std::pin::Pin;
22use std::rc::{Rc, Weak};
23use vtable::VRc;
24
25use i_slint_core::item_tree::ItemTreeVTable;
26
27pub fn install_bindings_only(instance: &VRc<ItemTreeVTable, Instance>) {
33 install_property_bindings(&instance.root_sub_component);
40 install_trackers_and_timers(&instance.root_sub_component);
41}
42
43pub fn run_init_code_for_instance(instance: &VRc<ItemTreeVTable, Instance>) {
44 run_init_code(&instance.root_sub_component);
45}
46
47fn install_property_bindings(sub: &Pin<Rc<SubComponentInstance>>) {
48 let cu = &sub.compilation_unit;
49 let sc: &SubComponent = &cu.sub_components[sub.sub_component_idx];
50 let weak_sub = Rc::downgrade(&Pin::into_inner(sub.clone()));
51
52 for nested in &sub.sub_components {
61 install_property_bindings(nested);
62 }
63
64 for e in &sc.pre_init_code {
67 let expr = mut_expression_clone(e);
68 let mut ctx = EvalContext::new(sub.clone());
69 eval_expression(&mut ctx, &expr);
70 }
71
72 for twb in &sc.two_way_bindings {
73 install_two_way_binding(twb, sub);
74 }
75
76 for (target, binding) in &sc.property_init {
77 install_property_init(target, binding, sub, &weak_sub);
78 }
79
80 install_repeater_model_bindings(sub, &weak_sub);
81}
82
83fn install_trackers_and_timers(sub: &Pin<Rc<SubComponentInstance>>) {
84 for nested in &sub.sub_components {
85 install_trackers_and_timers(nested);
86 }
87 let weak_sub = Rc::downgrade(&Pin::into_inner(sub.clone()));
88 install_change_callbacks(sub, &weak_sub);
89 install_timers(sub, &weak_sub);
90}
91
92fn install_timers(sub: &Pin<Rc<SubComponentInstance>>, weak_sub: &Weak<SubComponentInstance>) {
96 let cu = &sub.compilation_unit;
97 let sc: &SubComponent = &cu.sub_components[sub.sub_component_idx];
98 if sc.timers.is_empty() {
99 return;
100 }
101 let update = {
102 let weak_sub = weak_sub.clone();
103 move || {
104 let Some(owner_rc) = weak_sub.upgrade() else { return };
105 let owner = Pin::new(owner_rc);
106 let cu = owner.compilation_unit.clone();
107 let sc = &cu.sub_components[owner.sub_component_idx];
108 for (idx, t) in sc.timers.iter().enumerate() {
109 let running_expr = t.running.borrow().clone();
110 let interval_expr = t.interval.borrow().clone();
111 let triggered_expr = t.triggered.borrow().clone();
112 let mut ctx = EvalContext::new(owner.clone());
113 let running = matches!(eval_expression(&mut ctx, &running_expr), Value::Bool(true));
114 if !running {
115 if let Some(timer) = owner.timers.get(idx) {
116 timer.stop();
117 }
118 continue;
119 }
120 let mut ctx = EvalContext::new(owner.clone());
121 let interval_ms: i64 =
122 eval_expression(&mut ctx, &interval_expr).try_into().unwrap_or(0);
123 if interval_ms < 0 {
124 if let Some(timer) = owner.timers.get(idx) {
125 timer.stop();
126 }
127 continue;
128 }
129 let interval = std::time::Duration::from_millis(interval_ms as u64);
130 let Some(timer) = owner.timers.get(idx) else { continue };
131 if timer.running() && timer.interval() == interval {
132 continue;
133 }
134 let weak = Rc::downgrade(&Pin::into_inner(owner.clone()));
135 let expr = triggered_expr.clone();
136 timer.start(i_slint_core::timers::TimerMode::Repeated, interval, move || {
137 let Some(owner) = weak.upgrade() else { return };
138 let mut ctx = EvalContext::new(Pin::new(owner));
139 eval_expression(&mut ctx, &expr);
140 });
141 }
142 }
143 };
144
145 update();
149 for (timer_idx, t) in sc.timers.iter().enumerate() {
150 for (expr_idx, expr) in [&t.running, &t.interval].into_iter().enumerate() {
151 let get_expr = expr.borrow().clone();
152 let weak_get = weak_sub.clone();
153 let update = update.clone();
154 sub.change_trackers[2 * timer_idx + expr_idx].init(
155 (),
156 move |()| -> Value {
157 let Some(owner) = weak_get.upgrade() else { return Value::Void };
158 let mut ctx = EvalContext::new(Pin::new(owner));
159 eval_expression(&mut ctx, &get_expr)
160 },
161 move |(), _| {
162 update();
163 },
164 );
165 }
166 }
167}
168
169fn install_change_callbacks(
170 sub: &Pin<Rc<SubComponentInstance>>,
171 weak_sub: &Weak<SubComponentInstance>,
172) {
173 let cu = &sub.compilation_unit;
174 let sc: &SubComponent = &cu.sub_components[sub.sub_component_idx];
175 if sc.change_callbacks.is_empty() {
176 return;
177 }
178 let base = 2 * sc.timers.len();
179 for (idx, (target, expr)) in sc.change_callbacks.iter().enumerate() {
180 let target = target.clone();
181 let expr = mut_expression_clone(expr);
182 let weak_get = weak_sub.clone();
183 let weak_set = weak_sub.clone();
184 let expr_for_set = expr.clone();
185 sub.change_trackers[base + idx].init(
186 (),
187 move |()| -> Value {
188 let Some(owner) = weak_get.upgrade() else { return Value::Void };
189 let ctx = EvalContext::new(Pin::new(owner));
190 crate::eval::load_property(&ctx, &target)
191 },
192 move |(), _| {
193 let Some(owner) = weak_set.upgrade() else { return };
194 let mut ctx = EvalContext::new(Pin::new(owner));
195 eval_expression(&mut ctx, &expr_for_set);
196 },
197 );
198 }
199}
200
201fn install_repeater_model_bindings(
202 sub: &Pin<Rc<SubComponentInstance>>,
203 weak_sub: &Weak<SubComponentInstance>,
204) {
205 let cu = &sub.compilation_unit;
206 let sc: &SubComponent = &cu.sub_components[sub.sub_component_idx];
207 for (idx, repeated) in sc.repeated.iter_enumerated() {
208 let repeater = &sub.repeaters[idx];
209 let expr = mut_expression_clone(&repeated.model);
210 let weak_sub = weak_sub.clone();
211 if repeater.is_conditional() {
212 repeater.set_condition_binding(move || {
213 let Some(owner) = weak_sub.upgrade() else { return false };
214 let mut ctx = EvalContext::new(Pin::new(owner));
215 matches!(eval_expression(&mut ctx, &expr), Value::Bool(true))
217 });
218 } else {
219 repeater.set_model_binding(move || {
220 let Some(owner) = weak_sub.upgrade() else {
221 return i_slint_core::model::ModelRc::default();
222 };
223 let mut ctx = EvalContext::new(Pin::new(owner));
224 match eval_expression(&mut ctx, &expr) {
225 Value::Model(m) => m,
226 Value::Number(n) => i_slint_core::model::ModelRc::new(
229 crate::value_model::IntModel(n.max(0.) as usize),
230 ),
231 _ => i_slint_core::model::ModelRc::default(),
232 }
233 });
234 }
235 }
236}
237
238fn install_property_init(
239 target: &MemberReference,
240 binding: &llr::BindingExpression,
241 sub: &Pin<Rc<SubComponentInstance>>,
242 weak_sub: &Weak<SubComponentInstance>,
243) {
244 if let MemberReference::Global { global_index, member } = target {
245 install_global_property_init(*global_index, member, binding, weak_sub);
246 return;
247 }
248 let MemberReference::Relative { parent_level, local_reference } = target else {
249 unreachable!()
250 };
251 assert_eq!(*parent_level, 0, "property_init targets must be local to the sub-component");
252 let instance = walk_sub_path(sub.clone(), &local_reference.sub_component_path);
253
254 match &local_reference.reference {
255 LocalMemberIndex::Callback(idx) => {
256 let callback = Pin::as_ref(&instance.callbacks[*idx]);
257 let arg_types = instance.compilation_unit.sub_components[instance.sub_component_idx]
258 .callbacks[*idx]
259 .args
260 .clone();
261 let handler = make_callback_handler(
262 weak_sub.clone(),
263 mut_expression_clone(&binding.expression),
264 arg_types,
265 );
266 callback.set_handler(handler);
267 }
268 LocalMemberIndex::Property(idx) => {
269 let prop = Pin::as_ref(&instance.properties[*idx]);
270 let cu = &instance.compilation_unit;
271 let ty = &cu.sub_components[instance.sub_component_idx].properties[*idx].ty;
272 install_property_binding(prop, binding, weak_sub, ty);
273 }
274 LocalMemberIndex::Native { item_index, prop_name, kind } => {
275 let item = Pin::as_ref(&instance.items[*item_index]);
280 match kind {
281 i_slint_compiler::llr::NativeMemberKind::Callback => {
282 let expr = mut_expression_clone(&binding.expression);
283 let cb_weak = weak_sub.clone();
284 let cu = &instance.compilation_unit;
285 let sc = &cu.sub_components[instance.sub_component_idx];
286 let arg_types = match sc.items[*item_index].ty.lookup_property(prop_name) {
287 Some(i_slint_compiler::langtype::Type::Callback(f)) => f.args.clone(),
288 _ => Vec::new(),
289 };
290 let _ = item.set_callback_handler(
291 prop_name,
292 Box::new(make_callback_handler(cb_weak, expr, arg_types)),
293 );
294 }
295 i_slint_compiler::llr::NativeMemberKind::Property => {
296 let expr = mut_expression_clone(&binding.expression);
297 let weak_sub_eval = weak_sub.clone();
298 let closure: Box<dyn Fn() -> Value> = Box::new(move || {
299 let Some(owner) = weak_sub_eval.upgrade() else { return Value::Void };
300 let mut ctx = EvalContext::new(Pin::new(owner));
301 eval_expression(&mut ctx, &expr)
302 });
303 let animation_kind =
304 animation_for_binding(binding.animation.as_ref(), weak_sub.clone());
305 let _ = item.set_property_binding(prop_name, closure, animation_kind);
306 }
307 i_slint_compiler::llr::NativeMemberKind::Function => {
308 }
311 }
312 }
313 LocalMemberIndex::Function(_) => {
314 }
317 LocalMemberIndex::Timer(_) => unreachable!("a timer is not a binding target"),
318 }
319}
320
321fn install_global_property_init(
324 global_index: i_slint_compiler::llr::GlobalIdx,
325 member: &LocalMemberIndex,
326 binding: &llr::BindingExpression,
327 weak_sub: &Weak<SubComponentInstance>,
328) {
329 let Some(sub) = weak_sub.upgrade() else { return };
330 let globals = sub.root.get().and_then(|w| w.upgrade()).map(|inst| inst.globals.clone());
331 let Some(globals) = globals else { return };
332 let Some(global) = globals.get(global_index) else { return };
333
334 let g = &sub.compilation_unit.globals[global_index];
335 match member {
336 LocalMemberIndex::Property(idx) => {
337 let ty = &g.properties[*idx].ty;
338 if let Some(native) = &global.native {
339 if let Some(prop) =
340 native.as_ref().prepare_property_for_two_way_binding(&g.properties[*idx].name)
341 {
342 install_property_binding(prop.as_ref(), binding, weak_sub, ty);
343 }
344 } else {
345 let prop = Pin::as_ref(&global.properties[*idx]);
346 install_property_binding(prop, binding, weak_sub, ty);
347 }
348 }
349 LocalMemberIndex::Callback(idx) => {
350 let handler = make_callback_handler(
351 weak_sub.clone(),
352 mut_expression_clone(&binding.expression),
353 g.callbacks[*idx].args.clone(),
354 );
355 if let Some(native) = &global.native {
356 let _ = native
357 .as_ref()
358 .set_callback_handler(&g.callbacks[*idx].name, Box::new(handler));
359 } else {
360 Pin::as_ref(&global.callbacks[*idx]).set_handler(handler);
361 }
362 }
363 LocalMemberIndex::Function(_)
364 | LocalMemberIndex::Native { .. }
365 | LocalMemberIndex::Timer(_) => {}
366 }
367}
368
369pub(crate) fn animated_value_map(
373 ty: &i_slint_compiler::langtype::Type,
374) -> Option<fn(Value) -> Value> {
375 use i_slint_compiler::langtype::Type;
376 matches!(ty, Type::Int32 | Type::Duration).then_some(|v| match v {
377 Value::Number(n) => Value::Number(n.round()),
378 other => other,
379 })
380}
381
382fn install_property_binding(
383 prop: Pin<&Property<Value>>,
384 binding: &llr::BindingExpression,
385 weak_sub: &Weak<SubComponentInstance>,
386 ty: &i_slint_compiler::langtype::Type,
387) {
388 let expr = mut_expression_clone(&binding.expression);
389 let weak_sub_eval = weak_sub.clone();
390
391 use i_slint_compiler::llr::BindingKind;
392 if binding.kind == BindingKind::Constant {
393 if let Some(owner) = weak_sub_eval.upgrade() {
394 let mut ctx = EvalContext::new(Pin::new(owner));
395 prop.set(eval_expression(&mut ctx, &expr));
396 }
397 return;
398 }
399
400 if binding.kind == BindingKind::State {
401 let weak = weak_sub.clone();
404 i_slint_core::properties::set_state_binding(prop, move || {
405 let Some(owner) = weak.upgrade() else { return 0 };
406 let mut ctx = EvalContext::new(Pin::new(owner));
407 match eval_expression(&mut ctx, &expr) {
408 Value::Number(n) => n as i32,
409 _ => 0,
410 }
411 });
412 return;
413 }
414
415 let binding_fn: Box<dyn Fn() -> Value> = Box::new(move || {
416 let Some(owner) = weak_sub_eval.upgrade() else { return Value::Void };
417 let mut ctx = EvalContext::new(Pin::new(owner));
418 eval_expression(&mut ctx, &expr)
419 });
420
421 match (
422 animation_for_binding(binding.animation.as_ref(), weak_sub.clone()),
423 animated_value_map(ty),
424 ) {
425 (AnimatedBindingKind::NotAnimated, _) => prop.set_binding(binding_fn),
426 (AnimatedBindingKind::Animation(anim_fn), None) => {
427 prop.set_animated_binding(binding_fn, move || (anim_fn(), None));
428 }
429 (AnimatedBindingKind::Animation(anim_fn), Some(map)) => {
430 prop.set_animated_binding_with_map(binding_fn, move || (anim_fn(), None), map);
431 }
432 (AnimatedBindingKind::Transition(transition_fn), None) => {
433 prop.set_animated_binding(binding_fn, move || {
434 let (anim, change_time) = transition_fn();
435 (anim, Some(change_time))
436 });
437 }
438 (AnimatedBindingKind::Transition(transition_fn), Some(map)) => {
439 prop.set_animated_binding_with_map(
440 binding_fn,
441 move || {
442 let (anim, change_time) = transition_fn();
443 (anim, Some(change_time))
444 },
445 map,
446 );
447 }
448 }
449}
450
451fn animation_for_binding(
452 animation: Option<&Animation>,
453 weak_sub: Weak<SubComponentInstance>,
454) -> AnimatedBindingKind {
455 match animation {
456 None => AnimatedBindingKind::NotAnimated,
457 Some(Animation::Static(expr)) => {
458 let expr = expr.clone();
459 AnimatedBindingKind::Animation(Box::new(move || -> PropertyAnimation {
460 let Some(owner) = weak_sub.upgrade() else { return Default::default() };
461 let mut ctx = EvalContext::new(Pin::new(owner));
462 value_to_property_animation(eval_expression(&mut ctx, &expr))
463 }))
464 }
465 Some(Animation::Transition(expr)) => {
466 let expr = expr.clone();
467 AnimatedBindingKind::Transition(Box::new(
468 move || -> (PropertyAnimation, i_slint_core::animations::Instant) {
469 let Some(owner) = weak_sub.upgrade() else {
470 return (Default::default(), Default::default());
471 };
472 let mut ctx = EvalContext::new(Pin::new(owner));
473 let v = eval_expression(&mut ctx, &expr);
474 let Value::Struct(s) = v else {
476 return (Default::default(), Default::default());
477 };
478 let anim = s
479 .get_field("0")
480 .cloned()
481 .map(value_to_property_animation)
482 .unwrap_or_default();
483 let change_time = s
484 .get_field("1")
485 .cloned()
486 .and_then(|v| v.try_into().ok())
487 .unwrap_or_default();
488 (anim, change_time)
489 },
490 ))
491 }
492 }
493}
494
495pub(crate) fn value_to_property_animation(v: Value) -> PropertyAnimation {
499 let Value::Struct(s) = v else { return PropertyAnimation::default() };
500 let mut anim = PropertyAnimation::default();
501 if let Some(Value::Number(n)) = s.get_field("delay") {
502 anim.delay = *n as i32;
503 }
504 if let Some(Value::Number(n)) = s.get_field("duration") {
505 anim.duration = *n as i32;
506 }
507 if let Some(Value::Number(n)) = s.get_field("iteration-count") {
508 anim.iteration_count = *n as f32;
509 }
510 if let Some(Value::EasingCurve(curve)) = s.get_field("easing") {
511 anim.easing = *curve;
512 }
513 if let Some(direction) = s.get_field("direction")
514 && let Ok(parsed) = direction.clone().try_into()
515 {
516 anim.direction = parsed;
517 }
518 if let Some(Value::Bool(b)) = s.get_field("enabled") {
519 anim.enabled = *b;
520 }
521 anim
522}
523
524fn install_two_way_binding(
525 twb: &i_slint_compiler::llr::TwoWayBinding,
526 sub: &Pin<Rc<SubComponentInstance>>,
527) {
528 let a: MemberReference = twb.prop1.clone().into();
529 let field_path: &[smol_str::SmolStr] = &twb.field_access;
530 let Some(pa) = prepare_two_way(&a, sub) else { return };
531
532 if let Some(index_prop) = twb.is_model {
533 let MemberReference::Relative { parent_level, local_reference } = &twb.prop2 else {
538 return;
539 };
540 let LocalMemberIndex::Property(data_prop) = local_reference.reference else {
541 return;
542 };
543 let body = walk_parent(sub, *parent_level);
544 let body_weak = Rc::downgrade(&Pin::into_inner(body));
545 let path_get: Vec<smol_str::SmolStr> = field_path.to_vec();
546 let path_set = path_get.clone();
547 pa.as_ref().link_two_way_to_model_data(
548 body_weak,
549 move |body_weak: &std::rc::Weak<SubComponentInstance>| {
550 let body = Pin::new(body_weak.upgrade()?);
551 let data = Pin::as_ref(&body.properties[data_prop]).get();
552 if path_get.is_empty() {
553 Some(data)
554 } else {
555 extract_field(data, &path_get).filter(|v| !matches!(v, Value::Void))
556 }
557 },
558 move |body_weak: &std::rc::Weak<SubComponentInstance>, value: &Value| {
559 let Some(body) = body_weak.upgrade().map(Pin::new) else { return };
560 let Some((parent_weak, rep_idx)) = body.repeated_in.get() else { return };
561 let Some(parent) = parent_weak.upgrade().map(Pin::new) else { return };
562 let index: usize = match Pin::as_ref(&body.properties[index_prop]).get() {
563 Value::Number(n) => n as usize,
564 _ => return,
565 };
566 let data = if path_set.is_empty() {
569 let current = Pin::as_ref(&body.properties[data_prop]).get();
570 if ¤t == value {
571 return;
572 }
573 value.clone()
574 } else {
575 let mut data = Pin::as_ref(&body.properties[data_prop]).get();
576 if extract_field(data.clone(), &path_set).as_ref() == Some(value) {
577 return;
578 }
579 replace_field(&mut data, &path_set, value.clone());
580 data
581 };
582 parent.repeaters[*rep_idx].model_set_row_data(index, data);
583 },
584 );
585 return;
586 }
587
588 let Some(pb) = prepare_two_way(&twb.prop2, sub) else { return };
589
590 if field_path.is_empty() {
591 Property::link_two_way(pa.as_ref(), pb.as_ref());
592 return;
593 }
594
595 let path: Vec<smol_str::SmolStr> = field_path.to_vec();
599 let path_get = path.clone();
600 let path_set = path.clone();
601 let leaf_default = member_property_ty(&twb.prop2, sub)
605 .map(|ty| crate::eval::default_value_for_type(&field_leaf_ty(ty, field_path)))
606 .unwrap_or(Value::Void);
607 Property::link_two_way_with_map(
608 pb.as_ref(),
609 pa.as_ref(),
610 move |s| {
611 extract_field(s.clone(), &path_get)
612 .filter(|v| !matches!(v, Value::Void))
613 .unwrap_or_else(|| leaf_default.clone())
614 },
615 move |s, v| {
616 replace_field(s, &path_set, v.clone());
617 },
618 );
619}
620
621fn extract_field(value: Value, path: &[smol_str::SmolStr]) -> Option<Value> {
623 let mut current = value;
624 for p in path {
625 let Value::Struct(s) = current else { return None };
626 current = s.get_field(p.as_str()).cloned()?;
627 }
628 Some(current)
629}
630
631fn replace_field(s: &mut Value, path: &[smol_str::SmolStr], new_leaf: Value) {
633 if path.is_empty() {
634 *s = new_leaf;
635 return;
636 }
637 let Value::Struct(top) = s else { return };
638 let head = path[0].as_str();
639 let mut child = top.get_field(head).cloned().unwrap_or(Value::Void);
640 replace_field(&mut child, &path[1..], new_leaf);
641 top.set_field(head.to_string(), child);
642}
643
644fn member_property_ty(
646 mr: &MemberReference,
647 sub: &Pin<Rc<SubComponentInstance>>,
648) -> Option<i_slint_compiler::langtype::Type> {
649 match mr {
650 MemberReference::Relative { parent_level, local_reference } => {
651 let base = walk_parent(sub, *parent_level);
652 let instance = walk_sub_path(base, &local_reference.sub_component_path);
653 let cu = &instance.compilation_unit;
654 let sc = &cu.sub_components[instance.sub_component_idx];
655 match &local_reference.reference {
656 LocalMemberIndex::Property(idx) => Some(sc.properties[*idx].ty.clone()),
657 LocalMemberIndex::Native { item_index, prop_name, .. } => {
658 sc.items[*item_index].ty.lookup_property(prop_name).cloned()
659 }
660 _ => None,
661 }
662 }
663 MemberReference::Global { global_index, member } => {
664 let root = sub.root.get().and_then(|w| w.upgrade())?;
665 let cu = root.root_sub_component.compilation_unit.clone();
666 let global = &cu.globals[*global_index];
667 if let LocalMemberIndex::Property(idx) = member {
668 Some(global.properties[*idx].ty.clone())
669 } else {
670 None
671 }
672 }
673 }
674}
675
676fn field_leaf_ty(
678 mut ty: i_slint_compiler::langtype::Type,
679 path: &[smol_str::SmolStr],
680) -> i_slint_compiler::langtype::Type {
681 for f in path {
682 let i_slint_compiler::langtype::Type::Struct(s) = &ty else { break };
683 match s.fields.get(f.as_str()) {
684 Some(t) => ty = t.clone(),
685 None => break,
686 }
687 }
688 ty
689}
690
691fn prepare_two_way(
692 mr: &MemberReference,
693 sub: &Pin<Rc<SubComponentInstance>>,
694) -> Option<Pin<Rc<Property<Value>>>> {
695 match mr {
696 MemberReference::Relative { parent_level, local_reference } => {
697 let base = walk_parent(sub, *parent_level);
698 let instance = walk_sub_path(base, &local_reference.sub_component_path);
699 match &local_reference.reference {
700 LocalMemberIndex::Property(idx) => Some(instance.properties[*idx].clone()),
701 LocalMemberIndex::Native { item_index, prop_name, .. } => {
702 Pin::as_ref(&instance.items[*item_index])
703 .prepare_property_for_two_way_binding(prop_name)
704 }
705 _ => None,
706 }
707 }
708 MemberReference::Global { global_index, member } => {
709 let root = sub.root.get().and_then(|w| w.upgrade())?;
713 let global_inst = root.globals.get(*global_index)?;
714 if let LocalMemberIndex::Property(idx) = member {
715 if let Some(native) = &global_inst.native {
716 let g = &global_inst.compilation_unit.globals[global_inst.global_idx];
717 return native
718 .as_ref()
719 .prepare_property_for_two_way_binding(&g.properties[*idx].name);
720 }
721 Some(global_inst.properties[*idx].clone())
722 } else {
723 None
724 }
725 }
726 }
727}
728
729fn run_init_code(sub: &Pin<Rc<SubComponentInstance>>) {
730 for nested in &sub.sub_components {
734 run_init_code(nested);
735 }
736 let cu = sub.compilation_unit.clone();
737 let sc = &cu.sub_components[sub.sub_component_idx];
738 for e in &sc.init_code {
739 let expr = mut_expression_clone(e);
740 let mut ctx = EvalContext::new(sub.clone());
741 eval_expression(&mut ctx, &expr);
742 }
743}
744
745use crate::eval::{walk_parent, walk_sub_path};
746
747fn mut_expression_clone(e: &MutExpression) -> Expression {
748 e.borrow().clone()
749}
750
751fn make_callback_handler(
754 weak: Weak<SubComponentInstance>,
755 expr: Expression,
756 arg_types: Vec<i_slint_compiler::langtype::Type>,
757) -> impl Fn(&[Value]) -> Value + 'static {
758 move |args| {
759 let Some(owner) = weak.upgrade() else { return Value::Void };
760 let mut ctx = EvalContext::with_arguments(Pin::new(owner), args.to_vec());
761 ctx.function_arg_types = arg_types.clone();
762 eval_expression(&mut ctx, &expr)
763 }
764}