slint/sixtyfps_compiler/passes/clip.rs
Simon Hausmann 48e6d2f48b Fix handling of non-zero border width in clip-enabled Rectangles
The border should be visible (as in the included test case), which this
patch fixes for Qt by subtracting the border width just like when drawing.
2021-04-14 13:34:51 +02:00

90 lines
3.5 KiB
Rust

/* LICENSE BEGIN
This file is part of the SixtyFPS Project -- https://sixtyfps.io
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
SPDX-License-Identifier: GPL-3.0-only
This file is also available under commercial licensing terms.
Please contact info@sixtyfps.io for more information.
LICENSE END */
//! Pass that lowers synthetic `clip` properties to Clip element
use std::cell::RefCell;
use std::rc::Rc;
use crate::diagnostics::BuildDiagnostics;
use crate::expression_tree::{BindingExpression, Expression, NamedReference};
use crate::langtype::{NativeClass, Type};
use crate::object_tree::{Component, Element, ElementRc};
use crate::typeregister::TypeRegister;
pub fn handle_clip(
component: &Rc<Component>,
type_register: &TypeRegister,
diag: &mut BuildDiagnostics,
) {
let native_clip = type_register.lookup("Clip").as_builtin().native_class.clone();
crate::object_tree::recurse_elem_including_sub_components(
&component,
&(),
&mut |elem_rc: &ElementRc, _| {
let mut elem = elem_rc.borrow_mut();
if let Some(clip_prop) = elem.bindings.remove("clip") {
if !elem.builtin_type().map_or(false, |bt| bt.name == "Rectangle") {
diag.push_error(
"The 'clip' property can only be applied to a Rectangle for now".into(),
&clip_prop.span,
);
return;
};
// Was added by the meterialier_fake_properties pass
elem.property_declarations.remove("clip");
match &clip_prop.expression {
Expression::BoolLiteral(false) => {}
Expression::BoolLiteral(true) => {
drop(elem);
create_clip_element(elem_rc, &native_clip);
}
_ => diag.push_error(
"The 'clip' property can only be a boolean literal (true or false) for now"
.into(),
&clip_prop.span,
),
}
}
},
)
}
fn create_clip_element(parent_elem: &ElementRc, native_clip: &Rc<NativeClass>) {
let mut parent = parent_elem.borrow_mut();
let clip = Rc::new(RefCell::new(Element {
id: format!("{}_clip", parent.id),
base_type: Type::Native(native_clip.clone()),
children: std::mem::take(&mut parent.children),
enclosing_component: parent.enclosing_component.clone(),
..Element::default()
}));
parent.children.push(clip.clone());
drop(parent); // NamedReference::new will borrow() the parent, so we can't hold a mutable ref
clip.borrow_mut().bindings = ["width", "height"]
.iter()
.map(|prop| -> (String, BindingExpression) {
(
(*prop).to_owned(),
Expression::PropertyReference(NamedReference::new(parent_elem, prop)).into(),
)
})
.collect();
for optional_binding in ["border_radius", "border_width"].iter() {
if parent_elem.borrow().bindings.contains_key(*optional_binding) {
clip.borrow_mut().bindings.insert(
optional_binding.to_string(),
Expression::PropertyReference(NamedReference::new(parent_elem, optional_binding))
.into(),
);
}
}
}