mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-29 05:14:48 +00:00

Have a warning when a component is exported from the main file and doesn't inherit Window. Unless it's the last component, for compatibility with Slint 1.6 Also don't warn in the interpreter
151 lines
5.4 KiB
Rust
151 lines
5.4 KiB
Rust
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
|
|
|
//! Make sure that the top level element of the component is always a Window
|
|
|
|
use crate::diagnostics::BuildDiagnostics;
|
|
use crate::expression_tree::{BindingExpression, BuiltinFunction, Expression};
|
|
use crate::langtype::Type;
|
|
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,
|
|
style_metrics: &Rc<Component>,
|
|
diag: &mut BuildDiagnostics,
|
|
) {
|
|
if component.inherits_popup_window.get() {
|
|
diag.push_error(
|
|
"PopupWindow cannot be the top level".into(),
|
|
&*component.root_element.borrow(),
|
|
);
|
|
}
|
|
|
|
if inherits_window(component) {
|
|
return; // already a window, nothing to do
|
|
}
|
|
|
|
let window_type = type_register.lookup_builtin_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(),
|
|
change_callbacks: Default::default(),
|
|
is_component_placeholder: false,
|
|
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,
|
|
has_popup_child: false,
|
|
layout_info_prop: Default::default(),
|
|
default_fill_parent: Default::default(),
|
|
accessibility_props: Default::default(),
|
|
geometry_props: Default::default(),
|
|
is_flickable_viewport: false,
|
|
item_index: Default::default(),
|
|
item_index_of_first_children: Default::default(),
|
|
debug: std::mem::take(&mut win_elem_mut.debug),
|
|
|
|
inline_depth: 0,
|
|
is_legacy_syntax: false,
|
|
};
|
|
let new_root = new_root.make_rc();
|
|
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))),
|
|
);
|
|
};
|
|
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());
|
|
}
|
|
});
|
|
|
|
// Fix up any ElementReferences for builtin member function calls, to not refer to the WindowItem,
|
|
// as we swapped out the base_type.
|
|
let fixup_element_reference = |expr: &mut Expression| match expr {
|
|
Expression::FunctionCall { function, arguments, .. }
|
|
if matches!(
|
|
function.as_ref(),
|
|
Expression::BuiltinFunctionReference(BuiltinFunction::ItemMemberFunction(..), ..)
|
|
) =>
|
|
{
|
|
for arg in arguments.iter_mut() {
|
|
if matches!(arg, Expression::ElementReference(elr)
|
|
if elr.upgrade().map_or(false, |elemrc| Rc::ptr_eq(&elemrc, &win_elem)) )
|
|
{
|
|
*arg = Expression::ElementReference(Rc::downgrade(&new_root))
|
|
}
|
|
}
|
|
}
|
|
_ => {}
|
|
};
|
|
|
|
crate::object_tree::visit_all_expressions(component, |expr, _| {
|
|
expr.visit_recursive_mut(&mut |expr| fixup_element_reference(expr));
|
|
fixup_element_reference(expr)
|
|
});
|
|
|
|
component.root_element.borrow_mut().set_binding_if_not_set("background".into(), || {
|
|
Expression::Cast {
|
|
from: Expression::PropertyReference(NamedReference::new(
|
|
&style_metrics.root_element,
|
|
"window-background",
|
|
))
|
|
.into(),
|
|
to: Type::Brush,
|
|
}
|
|
});
|
|
}
|
|
|
|
pub fn inherits_window(component: &Rc<Component>) -> bool {
|
|
component.root_element.borrow().builtin_type().map_or(true, |b| {
|
|
matches!(b.name.as_str(), "Window" | "Dialog" | "WindowItem" | "PopupWindow")
|
|
})
|
|
}
|