slint/sixtyfps_compiler/passes/ensure_window.rs
Olivier Goffart dd3fa1c221 Make the BindingMap hold RefCell of the BindingExpression
This will allow later to be able to operate on the binding despite the
element is borrowed.

Since the Binding itself is in a RefCell, the analysis don't need to
be anymore.
To do this change, a small change in the binding_analysis logic was required
which means that we will now detect binding loop if a binding was causing
two binding loop. (before, only one binding loop was detected)
2021-11-11 11:14:59 +01:00

95 lines
3.5 KiB
Rust

/* LICENSE BEGIN
This file is part of the SixtyFPS Project -- https://sixtyfps.io
Copyright (c) 2021 Olivier Goffart <olivier.goffart@sixtyfps.io>
Copyright (c) 2021 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 */
//! Make sure that the top level element of the component is always a Window
use crate::expression_tree::BindingExpression;
use crate::namedreference::NamedReference;
use crate::object_tree::{Component, Element};
use crate::typeregister::TypeRegister;
use std::cell::RefCell;
use std::collections::HashSet;
use std::rc::Rc;
pub fn ensure_window(component: &Rc<Component>, type_register: &TypeRegister) {
if component.root_element.borrow().builtin_type().map_or(true, |b| {
matches!(b.name.as_str(), "Window" | "Dialog" | "WindowItem" | "PopupWindow")
}) {
return; // already a window, nothing to do
}
let window_type = type_register.lookup_element("Window").unwrap();
let win_elem = component.root_element.clone();
// the old_root becomes the Window
let mut win_elem_mut = win_elem.borrow_mut();
let new_root = Element {
id: std::mem::replace(&mut win_elem_mut.id, "root_window".into()),
base_type: std::mem::replace(&mut win_elem_mut.base_type, window_type),
bindings: Default::default(),
property_analysis: Default::default(),
children: std::mem::take(&mut win_elem_mut.children),
enclosing_component: win_elem_mut.enclosing_component.clone(),
property_declarations: Default::default(),
named_references: Default::default(),
repeated: Default::default(),
states: Default::default(),
transitions: Default::default(),
child_of_layout: false,
layout_info_prop: Default::default(),
is_flickable_viewport: false,
item_index: Default::default(),
node: win_elem_mut.node.clone(),
};
let new_root = Rc::new(RefCell::new(new_root));
win_elem_mut.children.push(new_root.clone());
drop(win_elem_mut);
let make_two_way = |name: &str| {
new_root.borrow_mut().bindings.insert(
name.into(),
RefCell::new(BindingExpression::new_two_way(
NamedReference::new(&win_elem, name).into(),
)),
);
};
make_two_way("width");
make_two_way("height");
let mut must_update = HashSet::new();
let mut base_props: HashSet<String> =
new_root.borrow().base_type.property_list().into_iter().map(|x| x.0).collect();
base_props.extend(win_elem.borrow().bindings.keys().cloned());
for prop in base_props {
if prop == "width" || prop == "height" {
continue;
}
if win_elem.borrow().property_declarations.contains_key(&prop) {
continue;
}
must_update.insert(NamedReference::new(&win_elem, &prop));
if let Some(b) = win_elem.borrow_mut().bindings.remove(&prop) {
new_root.borrow_mut().bindings.insert(prop.clone(), b);
}
if let Some(a) = win_elem.borrow().property_analysis.borrow_mut().remove(&prop) {
new_root.borrow().property_analysis.borrow_mut().insert(prop.clone(), a);
}
}
crate::object_tree::visit_all_named_references(component, &mut |nr| {
if must_update.contains(nr) {
*nr = NamedReference::new(&new_root, nr.name());
}
});
}