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
4//! This pass creates bindings to "absolute-y" and "absolute-y" properties
5//! that can be used to compute the window-absolute coordinates of elements.
6
7use smol_str::SmolStr;
8use std::cell::RefCell;
9use std::rc::Rc;
10
11use crate::expression_tree::{BuiltinFunction, Expression};
12use crate::langtype::Type;
13use crate::namedreference::NamedReference;
14use crate::object_tree::{
15 recurse_elem_including_sub_components_no_borrow, visit_all_named_references_in_element,
16 Component,
17};
18
19pub fn lower_absolute_coordinates(component: &Rc<Component>) {
20 let mut to_materialize = std::collections::HashSet::new();
21
22 recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem, _| {
23 visit_all_named_references_in_element(elem, |nr| {
24 if nr.name() == "absolute-position" {
25 to_materialize.insert(nr.clone());
26 }
27 });
28 });
29
30 let Type::Struct(point_type) = BuiltinFunction::ItemAbsolutePosition.ty().return_type.clone()
31 else {
32 unreachable!()
33 };
34
35 for nr in to_materialize {
36 let elem = nr.element();
37
38 // Create a binding for the `absolute-position` property. The
39 // materialize properties pass is going to create the actual property later.
40
41 let parent_position_var = Box::new(Expression::ReadLocalVariable {
42 name: "parent_position".into(),
43 ty: point_type.clone().into(),
44 });
45
46 let binding = Expression::CodeBlock(vec![
47 Expression::StoreLocalVariable {
48 name: "parent_position".into(),
49 value: Expression::FunctionCall {
50 function: BuiltinFunction::ItemAbsolutePosition.into(),
51 arguments: vec![Expression::ElementReference(Rc::downgrade(&elem))],
52 source_location: None,
53 }
54 .into(),
55 },
56 Expression::Struct {
57 ty: point_type.clone(),
58 values: IntoIterator::into_iter(["x", "y"])
59 .map(|coord| {
60 (
61 coord.into(),
62 Expression::BinaryExpression {
63 lhs: Expression::StructFieldAccess {
64 base: parent_position_var.clone(),
65 name: coord.into(),
66 }
67 .into(),
68 rhs: Expression::PropertyReference(NamedReference::new(
69 &elem,
70 SmolStr::new_static(coord),
71 ))
72 .into(),
73 op: '+',
74 },
75 )
76 })
77 .collect(),
78 },
79 ]);
80
81 elem.borrow_mut().bindings.insert(nr.name().clone(), RefCell::new(binding.into()));
82 }
83}
84