mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-30 13:51:13 +00:00

* Make sure that the compiler don't panic if the parent of a PopupWindow is optimized (by not optiizing such element) * Ensure that we can call popup.show() from within a deeper repeater * Ensure that the parent element of the popup is the right one in case of repeater (and not the node in the parent component) This partially revertad5991f8fa
and6c7a7aed0e
because we must do the lower_popup adter the repeater pass, because otherwise the parent element of the created component for the PopupWindow might be wrong and it is not easy to adjust (we would have to make Component::parent_element a RefCell or duplicate it again. Fixes #1132
134 lines
4.7 KiB
Rust
134 lines
4.7 KiB
Rust
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
|
|
|
//! Passe that transform the PopupWindow element into a component
|
|
|
|
use crate::diagnostics::BuildDiagnostics;
|
|
use crate::expression_tree::{Expression, NamedReference};
|
|
use crate::langtype::Type;
|
|
use crate::object_tree::*;
|
|
use crate::typeregister::TypeRegister;
|
|
use std::cell::RefCell;
|
|
use std::rc::Rc;
|
|
|
|
pub fn lower_popups(
|
|
component: &Rc<Component>,
|
|
type_register: &TypeRegister,
|
|
diag: &mut BuildDiagnostics,
|
|
) {
|
|
let window_type = type_register.lookup_element("Window").unwrap();
|
|
|
|
recurse_elem_including_sub_components_no_borrow(
|
|
component,
|
|
&None,
|
|
&mut |elem, parent_element: &Option<ElementRc>| {
|
|
let is_popup = elem.borrow().base_type.to_string() == "PopupWindow";
|
|
if is_popup {
|
|
lower_popup_window(elem, parent_element.as_ref(), &window_type, diag);
|
|
}
|
|
Some(elem.clone())
|
|
},
|
|
)
|
|
}
|
|
|
|
fn lower_popup_window(
|
|
popup_window_element: &ElementRc,
|
|
parent_element: Option<&ElementRc>,
|
|
window_type: &Type,
|
|
diag: &mut BuildDiagnostics,
|
|
) {
|
|
let parent_element = match parent_element {
|
|
None => {
|
|
diag.push_error(
|
|
"PopupWindow cannot be the top level".into(),
|
|
&*popup_window_element.borrow(),
|
|
);
|
|
return;
|
|
}
|
|
Some(parent_element) => parent_element,
|
|
};
|
|
|
|
let parent_component = popup_window_element.borrow().enclosing_component.upgrade().unwrap();
|
|
if Rc::ptr_eq(&parent_component.root_element, popup_window_element) {
|
|
diag.push_error(
|
|
"PopupWindow cannot be directly repeated or conditional".into(),
|
|
&*popup_window_element.borrow(),
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Remove the popup_window_element from its parent
|
|
let old_size = parent_element.borrow().children.len();
|
|
parent_element.borrow_mut().children.retain(|child| !Rc::ptr_eq(child, popup_window_element));
|
|
debug_assert_eq!(
|
|
parent_element.borrow().children.len() + 1,
|
|
old_size,
|
|
"Exactly one child must be removed (the popup itself)"
|
|
);
|
|
parent_element.borrow_mut().has_popup_child = true;
|
|
|
|
popup_window_element.borrow_mut().base_type = window_type.clone();
|
|
|
|
let popup_comp = Rc::new(Component {
|
|
root_element: popup_window_element.clone(),
|
|
parent_element: Rc::downgrade(parent_element),
|
|
..Component::default()
|
|
});
|
|
|
|
let weak = Rc::downgrade(&popup_comp);
|
|
recurse_elem(&popup_comp.root_element, &(), &mut |e, _| {
|
|
e.borrow_mut().enclosing_component = weak.clone()
|
|
});
|
|
|
|
// Generate a x and y property, relative to the window coordinate
|
|
// FIXME: this is a hack that doesn't always work, perhaps should we store an item ref or something
|
|
let coord_x = create_coordinate(&popup_comp, parent_element, "x");
|
|
let coord_y = create_coordinate(&popup_comp, parent_element, "y");
|
|
|
|
// Throw error when accessing the popup from outside
|
|
// FIXME:
|
|
// - the span is the span of the PopupWindow, that's wrong, we should have the span of the reference
|
|
// - There are other object reference than in the NamedReference
|
|
// - Maybe this should actually be allowed
|
|
visit_all_named_references(&parent_component, &mut |nr| {
|
|
if std::rc::Weak::ptr_eq(&nr.element().borrow().enclosing_component, &weak) {
|
|
diag.push_error(
|
|
"Cannot access the inside of a PopupWindow from enclosing component".into(),
|
|
&*popup_window_element.borrow(),
|
|
);
|
|
// just set it to whatever is a valid NamedReference, otherwise we'll panic later
|
|
*nr = coord_x.clone();
|
|
}
|
|
});
|
|
|
|
parent_component.popup_windows.borrow_mut().push(PopupWindow {
|
|
component: popup_comp,
|
|
x: coord_x,
|
|
y: coord_y,
|
|
parent_element: parent_element.clone(),
|
|
});
|
|
}
|
|
|
|
fn create_coordinate(
|
|
popup_comp: &Rc<Component>,
|
|
parent_element: &ElementRc,
|
|
coord: &str,
|
|
) -> NamedReference {
|
|
let expression = popup_comp
|
|
.root_element
|
|
.borrow()
|
|
.bindings
|
|
.get(coord)
|
|
.map(|e| e.borrow().expression.clone())
|
|
.unwrap_or(Expression::NumberLiteral(0., crate::expression_tree::Unit::Phx));
|
|
let property_name = format!("{}-popup-{}", popup_comp.root_element.borrow().id, coord);
|
|
parent_element
|
|
.borrow_mut()
|
|
.property_declarations
|
|
.insert(property_name.clone(), Type::LogicalLength.into());
|
|
parent_element
|
|
.borrow_mut()
|
|
.bindings
|
|
.insert(property_name.clone(), RefCell::new(expression.into()));
|
|
NamedReference::new(parent_element, &property_name)
|
|
}
|