Skip to main content

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}