slint/internal/compiler/passes/visible.rs
Olivier Goffart 975abf3c42 Don't steal the x and y properties for dummy parents
Parents surch as Opacity, Clip, and co, used to steal the x and y
property of their children, making the property not what they ought to
be.

Now that we refactored recently the code so that geometry need not to be
always linked to a property of the same name, we can dissociate the x
and y property of these generated elements and their content so that the
actual "x" property of the former elementstay some value, despite its
relative item property is now 0.

Had to change a bit of code that was still assuming a literal "height"
or "width" or "y" or "x" property that no longer worked when the
geometry is dissociated from its property

Fix #1072
2023-10-21 07:30:46 +02:00

104 lines
4.1 KiB
Rust

// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
//! Pass that lowers synthetic `visible` properties to Clip element
use std::cell::RefCell;
use std::rc::Rc;
use crate::diagnostics::BuildDiagnostics;
use crate::expression_tree::{Expression, NamedReference};
use crate::langtype::{ElementType, NativeClass, Type};
use crate::object_tree::{self, Component, Element, ElementRc};
use crate::typeregister::TypeRegister;
pub fn handle_visible(
component: &Rc<Component>,
type_register: &TypeRegister,
diag: &mut BuildDiagnostics,
) {
if let Some(b) = component.root_element.borrow().bindings.get("visible") {
diag.push_warning(
"The visible property cannot be used on the root element, it will not be applied"
.into(),
&*b.borrow(),
);
}
let native_clip =
type_register.lookup_element("Clip").unwrap().as_builtin().native_class.clone();
crate::object_tree::recurse_elem_including_sub_components(
component,
&(),
&mut |elem: &ElementRc, _| {
let is_lowered_from_visible_property =
elem.borrow().native_class().map_or(false, |n| {
Rc::ptr_eq(&n, &native_clip) && elem.borrow().id.ends_with("-visibility")
});
if is_lowered_from_visible_property {
// This is the element we just created. Skip it.
return;
}
let old_children = {
let mut elem = elem.borrow_mut();
let new_children = Vec::with_capacity(elem.children.len());
std::mem::replace(&mut elem.children, new_children)
};
let has_visible_binding = |e: &ElementRc| {
e.borrow().base_type.lookup_property("visible").property_type != Type::Invalid
&& (e.borrow().bindings.contains_key("visible")
|| e.borrow()
.property_analysis
.borrow()
.get("visible")
.map_or(false, |a| a.is_set))
};
for mut child in old_children {
if child.borrow().repeated.is_some() {
let root_elem = child.borrow().base_type.as_component().root_element.clone();
if has_visible_binding(&root_elem) {
let clip_elem = create_visibility_element(&root_elem, &native_clip);
object_tree::inject_element_as_repeated_element(&child, clip_elem.clone());
// The width and the height must be null
let d = NamedReference::new(&clip_elem, "dummy");
clip_elem.borrow_mut().geometry_props.as_mut().unwrap().width = d.clone();
clip_elem.borrow_mut().geometry_props.as_mut().unwrap().height = d;
}
} else if has_visible_binding(&child) {
let new_child = create_visibility_element(&child, &native_clip);
new_child.borrow_mut().children.push(child);
child = new_child;
}
elem.borrow_mut().children.push(child);
}
},
);
}
fn create_visibility_element(child: &ElementRc, native_clip: &Rc<NativeClass>) -> ElementRc {
let element = Element {
id: format!("{}-visibility", child.borrow().id),
base_type: ElementType::Native(native_clip.clone()),
enclosing_component: child.borrow().enclosing_component.clone(),
bindings: std::iter::once((
"clip".to_owned(),
RefCell::new(
Expression::UnaryOp {
sub: Box::new(Expression::PropertyReference(NamedReference::new(
child, "visible",
))),
op: '!',
}
.into(),
),
))
.collect(),
..Default::default()
};
Element::make_rc(element)
}