mirror of
https://github.com/slint-ui/slint.git
synced 2025-07-23 21:18:23 +00:00
live preview: Do not drop on elements that can not have children
Slpit up `lookup_type_for_child_elemnt` (in the compiler) into the part that looks at the element itself only (called `accepts_child_element`) and the part that looks at the child. When deciding whether we can drop something into another element in the live preview, we know the child type is going to be OK, even when the `TypeRegister` does not contain it yet (as it is not imported yet).
This commit is contained in:
parent
9eb52fb14a
commit
d0fc025bc8
4 changed files with 68 additions and 16 deletions
|
@ -481,23 +481,43 @@ impl ElementType {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn lookup_type_for_child_element(
|
||||
pub fn can_have_child(&self, name: &str, tr: &TypeRegister) -> bool {
|
||||
match self {
|
||||
Self::Component(component) if component.child_insertion_point.borrow().is_none() => {
|
||||
let base_type = component.root_element.borrow().base_type.clone();
|
||||
if base_type == tr.empty_type() {
|
||||
false
|
||||
} else {
|
||||
base_type.can_have_child(name, tr)
|
||||
}
|
||||
}
|
||||
Self::Builtin(builtin) => {
|
||||
if builtin.additional_accepted_child_types.contains_key(name) {
|
||||
true
|
||||
} else {
|
||||
!builtin.disallow_global_types_as_child_elements
|
||||
}
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn accepts_child_element(
|
||||
&self,
|
||||
name: &str,
|
||||
tr: &TypeRegister,
|
||||
) -> Result<ElementType, String> {
|
||||
) -> Result<Option<ElementType>, String> {
|
||||
match self {
|
||||
Self::Component(component) if component.child_insertion_point.borrow().is_none() => {
|
||||
let base_type = component.root_element.borrow().base_type.clone();
|
||||
if base_type == tr.empty_type() {
|
||||
return Err(format!("'{}' cannot have children. Only components with @children can have children", component.id));
|
||||
} else {
|
||||
return base_type.lookup_type_for_child_element(name, tr);
|
||||
}
|
||||
return base_type.accepts_child_element(name, tr);
|
||||
}
|
||||
Self::Builtin(builtin) => {
|
||||
if let Some(child_type) = builtin.additional_accepted_child_types.get(name) {
|
||||
return Ok(child_type.clone());
|
||||
return Ok(Some(child_type.clone()));
|
||||
}
|
||||
if builtin.disallow_global_types_as_child_elements {
|
||||
let mut valid_children: Vec<_> =
|
||||
|
@ -514,6 +534,18 @@ impl ElementType {
|
|||
}
|
||||
_ => {}
|
||||
};
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn lookup_type_for_child_element(
|
||||
&self,
|
||||
name: &str,
|
||||
tr: &TypeRegister,
|
||||
) -> Result<ElementType, String> {
|
||||
if let Some(ct) = self.accepts_child_element(name, tr)? {
|
||||
return Ok(ct);
|
||||
}
|
||||
|
||||
tr.lookup_element(name).and_then(|t| {
|
||||
if !tr.expose_internal_types && matches!(&t, Self::Builtin(e) if e.is_internal) {
|
||||
Err(format!("Unknown type {}. (The type exist as an internal type, but cannot be accessed in this scope)", name))
|
||||
|
|
|
@ -16,12 +16,19 @@ pub type UrlVersion = Option<i32>;
|
|||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::wasm_prelude::*;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct ElementRcNode {
|
||||
pub element: ElementRc,
|
||||
pub debug_index: usize,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ElementRcNode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let (path, offset) = self.path_and_offset();
|
||||
write!(f, "ElementNode {{ {path:?}:{offset} }}")
|
||||
}
|
||||
}
|
||||
|
||||
impl ElementRcNode {
|
||||
pub fn find_in(element: ElementRc, path: &std::path::Path, offset: u32) -> Option<Self> {
|
||||
let debug_index = element.borrow().debug.iter().position(|(n, _)| {
|
||||
|
|
|
@ -107,8 +107,8 @@ fn search_for_parent_element(root: &ElementRc, child: &ElementRc) -> Option<Elem
|
|||
}
|
||||
|
||||
// triggered from the UI, running in UI thread
|
||||
fn can_drop_component(_component_name: slint::SharedString, x: f32, y: f32) -> bool {
|
||||
drop_location::can_drop_at(x, y)
|
||||
fn can_drop_component(component_name: slint::SharedString, x: f32, y: f32) -> bool {
|
||||
drop_location::can_drop_at(x, y, component_name.into())
|
||||
}
|
||||
|
||||
// triggered from the UI, running in UI thread
|
||||
|
|
|
@ -57,9 +57,11 @@ fn find_drop_location(
|
|||
component_instance: &ComponentInstance,
|
||||
x: f32,
|
||||
y: f32,
|
||||
component_type: &str,
|
||||
) -> Option<DropInformation> {
|
||||
let target_element_node = {
|
||||
let mut result = None;
|
||||
let tl = component_instance.definition().type_loader();
|
||||
for sc in &element_selection::collect_all_element_nodes_covering(x, y, &component_instance)
|
||||
{
|
||||
let Some(en) = sc.as_element_node() else {
|
||||
|
@ -70,14 +72,23 @@ fn find_drop_location(
|
|||
continue;
|
||||
}
|
||||
|
||||
if !element_selection::is_same_file_as_root_node(&component_instance, &en) {
|
||||
let (path, _) = en.path_and_offset();
|
||||
let Some(doc) = tl.get_document(&path) else {
|
||||
continue;
|
||||
};
|
||||
if let Some(element_type) = en.with_element_node(|node| {
|
||||
util::lookup_current_element_type((node.clone()).into(), &doc.local_registry)
|
||||
}) {
|
||||
if !en.is_layout()
|
||||
&& element_type
|
||||
.accepts_child_element(component_type, &doc.local_registry)
|
||||
.is_err()
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if en.with_element_node(|n| {
|
||||
n.child_node(i_slint_compiler::parser::SyntaxKind::ChildrenPlaceholder).is_some()
|
||||
}) && !element_selection::is_root_element_node(&component_instance, &en)
|
||||
{
|
||||
if !element_selection::is_same_file_as_root_node(&component_instance, &en) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -105,8 +116,10 @@ fn find_drop_location(
|
|||
}
|
||||
|
||||
/// Find the Element to insert into. None means we can not insert at this point.
|
||||
pub fn can_drop_at(x: f32, y: f32) -> bool {
|
||||
super::component_instance().and_then(|ci| find_drop_location(&ci, x, y)).is_some()
|
||||
pub fn can_drop_at(x: f32, y: f32, component_type: String) -> bool {
|
||||
super::component_instance()
|
||||
.and_then(|ci| find_drop_location(&ci, x, y, &component_type))
|
||||
.is_some()
|
||||
}
|
||||
|
||||
/// Extra data on an added Element, relevant to the Preview side only.
|
||||
|
@ -130,7 +143,7 @@ pub fn drop_at(
|
|||
) -> Option<(lsp_types::WorkspaceEdit, DropData)> {
|
||||
let component_instance = preview::component_instance()?;
|
||||
let tl = component_instance.definition().type_loader();
|
||||
let drop_info = find_drop_location(&component_instance, x, y)?;
|
||||
let drop_info = find_drop_location(&component_instance, x, y, &component_type)?;
|
||||
|
||||
let properties = {
|
||||
let click_position =
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue