slint/sixtyfps_compiler/passes/clip.rs
Olivier Goffart 1773f9143b Add a border-radius property to the Clip
So that `clip: true` used on a Rectangle with border radius can be clipped
with that radius

Only the Qt backend is implemented for now
2021-04-12 19:47:18 +02:00

87 lines
3.3 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();
if parent_elem.borrow().bindings.contains_key("border_radius") {
clip.borrow_mut().bindings.insert(
"border_radius".to_string(),
Expression::PropertyReference(NamedReference::new(parent_elem, "border_radius")).into(),
);
}
}