i_slint_compiler/passes/lower_absolute_coordinates.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
4//! This pass creates bindings to the `absolute-position` property that can be used to compute
5//! the window-absolute coordinates of elements.
6
7use std::rc::Rc;
8
9use crate::expression_tree::{BuiltinFunction, Expression};
10use crate::object_tree::Component;
11
12pub fn lower_absolute_coordinates(component: &Rc<Component>) {
13 let mut to_materialize = std::collections::HashSet::new();
14
15 crate::object_tree::visit_all_named_references(component, &mut |nr| {
16 if nr.name() == "absolute-position" {
17 to_materialize.insert(nr.clone());
18 }
19 });
20
21 for nr in to_materialize {
22 let elem = nr.element();
23
24 // `ItemAbsolutePosition` already returns the element's own absolute window position: it
25 // maps the element's geometry origin through the ancestor transforms at runtime. We do
26 // not add the element's `x`/`y` here — doing so would double-count the offset once a
27 // wrapper element (Opacity/Layer/Transform) is injected around the element (the wrapper
28 // takes over the element's geometry, so `map_to_window` already includes it), and it
29 // would also be wrong under a parent scale/rotation. Computing everything at runtime
30 // keeps it correct regardless of injected wrappers and cross-component inlining.
31 //
32 // The `materialize_fake_properties` pass creates the actual property later.
33 let binding = Expression::FunctionCall {
34 function: BuiltinFunction::ItemAbsolutePosition.into(),
35 arguments: vec![Expression::ElementReference(Rc::downgrade(&elem))],
36 source_location: None,
37 };
38
39 elem.borrow_mut().set_binding(nr.name().clone(), binding.into());
40 }
41}