diff --git a/tools/lsp/common.rs b/tools/lsp/common.rs index bc2f57e91..f4f50ef9f 100644 --- a/tools/lsp/common.rs +++ b/tools/lsp/common.rs @@ -49,16 +49,20 @@ impl ElementRcNode { Some(Self { element, debug_index }) } - - pub fn find_in_or_below(element: ElementRc, path: &std::path::Path, offset: u32) -> Option { - let debug_index = element.borrow().debug.iter().position(|(n, _)| { + + pub fn find_in_or_below( + element: ElementRc, + path: &std::path::Path, + offset: u32, + ) -> Option { + let debug_index = element.borrow().debug.iter().position(|(n, _)| { u32::from(n.text_range().start()) == offset && n.source_file.path() == path }); if let Some(debug_index) = debug_index { Some(Self { element, debug_index }) } else { for c in &element.borrow().children { - let result = Self::find_in_or_below(c.clone(), path, offset); + let result = Self::find_in_or_below(c.clone(), path, offset); if result.is_some() { return result; } diff --git a/tools/lsp/fmt/fmt.rs b/tools/lsp/fmt/fmt.rs index a64b5d9ea..a31f5343b 100644 --- a/tools/lsp/fmt/fmt.rs +++ b/tools/lsp/fmt/fmt.rs @@ -539,8 +539,7 @@ fn format_argument_declaration( writer: &mut impl TokenWriter, state: &mut FormatState, ) -> Result<(), std::io::Error> { - let mut sub = node.children_with_tokens(); - while let Some(n) = sub.next() { + for n in node.children_with_tokens() { state.skip_all_whitespace = true; match n.kind() { SyntaxKind::Colon => { diff --git a/tools/lsp/language/component_catalog.rs b/tools/lsp/language/component_catalog.rs index 425425eed..dacd9af72 100644 --- a/tools/lsp/language/component_catalog.rs +++ b/tools/lsp/language/component_catalog.rs @@ -26,6 +26,10 @@ fn builtin_component_info(name: &str, fills_parent: bool) -> ComponentInformatio let default_properties = match name { "Text" | "TextInput" => vec![PropertyChange::new("text", format!("\"{name}\""))], "Image" => vec![PropertyChange::new("source", "@image-url(\"EDIT_ME.png\")".to_string())], + "GridLayout" | "HorizontalLayout" | "VerticalLayout" => vec![ + PropertyChange::new("min-width", "16px".to_string()), + PropertyChange::new("min-height", "16px".to_string()), + ], _ => vec![], }; @@ -60,6 +64,10 @@ fn std_widgets_info(name: &str, is_global: bool) -> ComponentInformation { "ComboBox" => { vec![PropertyChange::new("model", "[\"first\", \"second\", \"third\"]".to_string())] } + "GridBox" | "HorizontalBox" | "VerticalBox" => vec![ + PropertyChange::new("min-width", "16px".to_string()), + PropertyChange::new("min-height", "16px".to_string()), + ], "Slider" | "SpinBox" => vec![ PropertyChange::new("minimum", "0".to_string()), PropertyChange::new("value", "42".to_string()), diff --git a/tools/lsp/preview/drop_location.rs b/tools/lsp/preview/drop_location.rs index c16b0b0e3..db9f788c3 100644 --- a/tools/lsp/preview/drop_location.rs +++ b/tools/lsp/preview/drop_location.rs @@ -1,10 +1,8 @@ // Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.2 OR LicenseRef-Slint-commercial -use std::path::PathBuf; - use i_slint_compiler::parser::{syntax_nodes, SyntaxKind, SyntaxNode}; -use i_slint_core::lengths::{LogicalPoint, LogicalRect, LogicalSize, PointLengths}; +use i_slint_core::lengths::{LogicalPoint, LogicalRect, LogicalSize}; use slint_interpreter::ComponentInstance; use crate::common; @@ -98,7 +96,7 @@ fn calculate_drop_acceptance( position: LogicalPoint, layout_kind: &crate::preview::ui::LayoutKind, ) -> DropAccept { - assert!(geometry.contains(position)); // Just checked that before callig this + assert!(geometry.contains(position)); // Just checked that before calling this let horizontal = border_size(geometry.size.width); let vertical = border_size(geometry.size.height); @@ -119,7 +117,7 @@ fn calculate_drop_acceptance( LogicalPoint::new(geometry.origin.x + horizontal, geometry.origin.y), LogicalSize::new(geometry.size.width - (2.0 * horizontal), geometry.size.height), ), - ui::LayoutKind::Grid => geometry.clone(), + ui::LayoutKind::Grid => *geometry, }; if certain_rect.contains(position) { @@ -129,141 +127,146 @@ fn calculate_drop_acceptance( } } -#[derive(Debug)] -struct ChildrenInformation { - geometry: LogicalRect, - path: PathBuf, - range: (u32, u32), -} - // calculate where to draw the `DropMark` fn calculate_drop_information_for_layout( geometry: &LogicalRect, position: LogicalPoint, layout_kind: &crate::preview::ui::LayoutKind, - children_information: &[ChildrenInformation], + children_geometries: &[LogicalRect], ) -> (Option, usize) { - eprintln!("calculate_drop_information_for_layout({geometry:?}, {position:?}, {layout_kind:?}, {children_information:?}): Starting up"); - let horizontal = border_size(geometry.size.width); - let vertical = border_size(geometry.size.height); - match layout_kind { ui::LayoutKind::None => unreachable!("We are in a layout"), ui::LayoutKind::Horizontal => { - if children_information.len() == 0 { - eprintln!("Horizontal, No child"); + if children_geometries.is_empty() { // No children: Draw a drop mark in the middle // TODO: Take padding into account: We have no way to get that though - return ( + let start = (geometry.origin.x + (geometry.size.width / 2.0)).floor(); + + ( Some(DropMark { - start: LogicalPoint::new( - (geometry.origin.x + (geometry.size.width / 2.0)).floor(), - geometry.origin.y, - ), + start: LogicalPoint::new(start, geometry.origin.y), end: LogicalPoint::new( - (geometry.origin.x + (geometry.size.width / 2.0)).ceil(), + start + 1.0, geometry.origin.y + geometry.size.height, ), }), usize::MAX, - ); + ) } else { let mut last_midpoint = geometry.origin.x; let mut last_endpoint = geometry.origin.x; - for (pos, c) in children_information.iter().enumerate() { - let new_midpoint = c.geometry.origin.x + c.geometry.size.width / 2.0; - let hit_rect = LogicalRect::new(LogicalPoint::new(last_midpoint, geometry.origin.y), LogicalSize::new(new_midpoint - last_midpoint, geometry.size.height)); + for (pos, c) in children_geometries.iter().enumerate() { + let new_midpoint = c.origin.x + c.size.width / 2.0; + let hit_rect = LogicalRect::new( + LogicalPoint::new(last_midpoint, geometry.origin.y), + LogicalSize::new(new_midpoint - last_midpoint, geometry.size.height), + ); if hit_rect.contains(position) { - eprintln!("Horizontal, before_child {pos} with geometry {:?}: {hit_rect:?} cointains {position:?}? => HIT", c.geometry); - let start = (c.geometry.origin.x - last_endpoint) / 2.0; - let start_pos = last_endpoint + if start.floor() < geometry.origin.x { - geometry.origin.x - } else { - start - }; + let start = (c.origin.x - last_endpoint) / 2.0; + let start_pos = last_endpoint + + if start.floor() < geometry.origin.x { + geometry.origin.x + } else { + start + }; let end_pos = start_pos + 1.0; - - return ( - Some(DropMark { - start: LogicalPoint::new(start_pos, geometry.origin.y), - end: LogicalPoint::new(end_pos, geometry.origin.y + geometry.size.height), - }), - pos, - ); - } - eprintln!("Horizontal, before_child {pos} with geometry {:?}: {hit_rect:?} cointains {position:?}? => MISS", c.geometry); - last_midpoint = new_midpoint; - last_endpoint = c.geometry.origin.x + c.geometry.size.width; - } - eprintln!("Horizontal, after last child..."); - return ( - Some(DropMark { - start: LogicalPoint::new(geometry.origin.x + geometry.size.width - 1.0, geometry.origin.y), - end: LogicalPoint::new(geometry.origin.x + geometry.size.width, geometry.origin.y + geometry.size.height), - }), - usize::MAX, - ); - } - } - ui::LayoutKind::Vertical => { - if children_information.len() == 0 { - eprintln!("Vertical, No child"); - // No children: Draw a drop mark in the middle - // TODO: Take padding into account: We have no way to get that though - return ( + return ( + Some(DropMark { + start: LogicalPoint::new(start_pos, geometry.origin.y), + end: LogicalPoint::new( + end_pos, + geometry.origin.y + geometry.size.height, + ), + }), + pos, + ); + } + last_midpoint = new_midpoint; + last_endpoint = c.origin.x + c.size.width; + } + ( Some(DropMark { start: LogicalPoint::new( - geometry.origin.x, - (geometry.origin.y + (geometry.size.height / 2.0)).floor(), + geometry.origin.x + geometry.size.width - 1.0, + geometry.origin.y, ), end: LogicalPoint::new( geometry.origin.x + geometry.size.width, - (geometry.origin.y + (geometry.size.height / 2.0)).ceil(), + geometry.origin.y + geometry.size.height, ), }), usize::MAX, - ); + ) + } + } + ui::LayoutKind::Vertical => { + if children_geometries.is_empty() { + // No children: Draw a drop mark in the middle + // TODO: Take padding into account: We have no way to get that though + let start = (geometry.origin.y + (geometry.size.height / 2.0)).floor(); + ( + Some(DropMark { + start: LogicalPoint::new(geometry.origin.x, start), + end: LogicalPoint::new( + geometry.origin.x + geometry.size.width, + start + 1.0, + ), + }), + usize::MAX, + ) } else { let mut last_midpoint = geometry.origin.y; let mut last_endpoint = geometry.origin.y; - for (pos, c) in children_information.iter().enumerate() { - let new_midpoint = c.geometry.origin.y + c.geometry.size.height / 2.0; - let hit_rect = LogicalRect::new(LogicalPoint::new(geometry.origin.y, last_midpoint), LogicalSize::new(geometry.size.width, new_midpoint - last_midpoint)); + for (pos, c) in children_geometries.iter().enumerate() { + let new_midpoint = c.origin.y + c.size.height / 2.0; + let hit_rect = LogicalRect::new( + LogicalPoint::new(geometry.origin.y, last_midpoint), + LogicalSize::new(geometry.size.width, new_midpoint - last_midpoint), + ); if hit_rect.contains(position) { - eprintln!("Vertical, before_child {pos} with geometry {:?}: {hit_rect:?} cointains {position:?}? => HIT", c.geometry); - let start = (c.geometry.origin.y - last_endpoint) / 2.0; - let start_pos = last_endpoint + if start.floor() < geometry.origin.y { - geometry.origin.y - } else { - start - }; + let start = (c.origin.y - last_endpoint) / 2.0; + let start_pos = last_endpoint + + if start.floor() < geometry.origin.y { + geometry.origin.y + } else { + start + }; let end_pos = start_pos + 1.0; - - return ( - Some(DropMark { - start: LogicalPoint::new(geometry.origin.x, start_pos), - end: LogicalPoint::new(geometry.origin.x + geometry.size.width, end_pos), - }), - pos, - ); - } - eprintln!("Vertical, before_child {pos} with geometry {:?}: {hit_rect:?} cointains {position:?}? => MISS", c.geometry); - last_midpoint = new_midpoint; - last_endpoint = c.geometry.origin.y + c.geometry.size.height; - } - eprintln!("Vertical, after last child..."); - return ( - Some(DropMark { - start: LogicalPoint::new(geometry.origin.x, geometry.origin.y + geometry.size.height - 1.0), - end: LogicalPoint::new(geometry.origin.x + geometry.size.width, geometry.origin.y + geometry.size.height), + return ( + Some(DropMark { + start: LogicalPoint::new(geometry.origin.x, start_pos), + end: LogicalPoint::new( + geometry.origin.x + geometry.size.width, + end_pos, + ), + }), + pos, + ); + } + last_midpoint = new_midpoint; + last_endpoint = c.origin.y + c.size.height; + } + ( + Some(DropMark { + start: LogicalPoint::new( + geometry.origin.x, + geometry.origin.y + geometry.size.height - 1.0, + ), + end: LogicalPoint::new( + geometry.origin.x + geometry.size.width, + geometry.origin.y + geometry.size.height, + ), }), usize::MAX, - ); + ) } } - ui::LayoutKind::Grid => todo!(), + ui::LayoutKind::Grid => { + // TODO: Do something here + (None, usize::MAX) + } } } @@ -274,7 +277,6 @@ fn accept_drop_at( ) -> DropAccept { let layout_kind = element_node.layout_kind(); let Some(geometry) = element_node.geometry_at(component_instance, position) else { - eprintln!(" accept_drop_at: NO, element not at position"); return DropAccept::No; }; calculate_drop_acceptance(&geometry, position, &layout_kind) @@ -310,7 +312,7 @@ fn insert_position_at_end( } else if before_closing.kind() == SyntaxKind::Whitespace && !before_closing.text().contains('\n') { - let indent = util::find_element_indent(&target_element_node).unwrap_or_default(); + let indent = util::find_element_indent(target_element_node).unwrap_or_default(); let ws_len = before_closing.text().len() as u32; ( format!("\n{indent} "), @@ -320,7 +322,7 @@ fn insert_position_at_end( ws_len, ) } else { - let indent = util::find_element_indent(&target_element_node).unwrap_or_default(); + let indent = util::find_element_indent(target_element_node).unwrap_or_default(); (format!("\n{indent} "), format!("{indent} "), indent, closing_brace_offset, 0) }; @@ -340,11 +342,72 @@ fn insert_position_at_end( }) } +fn insert_position_before_child( + target_element_node: &common::ElementRcNode, + child_index: usize, +) -> Option { + target_element_node.with_element_node(|node| { + for (index, child_node) in node + .children() + .filter(|n| { + [ + SyntaxKind::SubElement, + SyntaxKind::RepeatedElement, + SyntaxKind::ConditionalElement, + ] + .contains(&n.kind()) + }) + .enumerate() + { + if index < child_index { + continue; + } + + assert!(index == child_index); + + let first_token = child_node.first_token()?; + let first_token_offset = u32::from(first_token.text_range().start()); + let before_first_token = first_token.prev_token()?; + + let (pre_indent, indent) = if before_first_token.kind() == SyntaxKind::Whitespace + && before_first_token.text().contains('\n') + { + let element_indent = before_first_token.text().split('\n').last().unwrap(); // must exist in this branch + ("".to_string(), element_indent.to_string()) + } else if before_first_token.kind() == SyntaxKind::Whitespace + && !before_first_token.text().contains('\n') + { + let indent = util::find_element_indent(target_element_node).unwrap_or_default(); + ("".to_string(), format!("{indent} ")) + } else { + let indent = util::find_element_indent(target_element_node).unwrap_or_default(); + (format!("\n{indent} "), format!("{indent} ")) + }; + + let url = lsp_types::Url::from_file_path(child_node.source_file.path()).ok()?; + let (version, _) = preview::get_url_from_cache(&url)?; + + return Some(InsertInformation { + insertion_position: common::VersionedPosition::new( + crate::common::VersionedUrl::new(url, version), + first_token_offset, + ), + replacement_range: 0, + pre_indent, + indent: indent.clone(), + post_indent: indent, + }); + } + + // We should never get here... + None + }) +} + // find all elements covering the given `position`. fn drop_target_element_nodes( component_instance: &ComponentInstance, position: LogicalPoint, - component_type: &str, ) -> Vec { let mut result = Vec::with_capacity(3); @@ -378,70 +441,11 @@ fn extract_element(node: SyntaxNode) -> Option { } } -fn examine_target_element_node( - context: &str, - component_instance: &ComponentInstance, - position: LogicalPoint, - target_element_node: &common::ElementRcNode, -) { - let geometry = target_element_node.geometry_at(component_instance, position); - // let mut result = Vec::new(); - if let Some(geometry) = geometry { - for (i, c) in target_element_node.element.borrow().children.iter().enumerate() { - let c = common::ElementRcNode::new(c.clone(), 0).unwrap(); - } - target_element_node.with_element_node(|node| { - for (i, c) in node.children().enumerate() { - let element_data = if let Some(c_element) = extract_element(c.clone()) { - format!( - "\n {:?}:{:?}", - c_element.source_file.path(), - c_element.text_range().start() - ) - } else { - String::new() - }; - } - }); - } -} - -fn drop_into_layout( - component_instance: &ComponentInstance, - element_node: common::ElementRcNode, - position: LogicalPoint, - layout_kind: ui::LayoutKind, - children_geometries: &[LogicalRect], -) -> Option { - let geometry = element_node.geometry_at(component_instance, position)?; - let insert_info = insert_position_at_end(&element_node)?; - - Some(DropInformation { - target_element_node: element_node, - insert_info, - drop_mark: Some(DropMark { - start: geometry.origin + LogicalSize::new(0.0, geometry.size.height - 1.0), - end: geometry.origin + geometry.size, - }), - }) -} - -fn drop_into_element( - component_instance: &ComponentInstance, - element_node: common::ElementRcNode, - position: LogicalPoint, -) -> Option { - let geometry = element_node.geometry_at(component_instance, position)?; - let insert_info = insert_position_at_end(&element_node)?; - Some(DropInformation { target_element_node: element_node, insert_info, drop_mark: None }) -} - fn find_element_to_drop_into( component_instance: &ComponentInstance, position: LogicalPoint, - component_type: &str, ) -> Option { - let all_element_nodes = drop_target_element_nodes(component_instance, position, component_type); + let all_element_nodes = drop_target_element_nodes(component_instance, position); let mut tmp = None; for element_node in &all_element_nodes { @@ -465,39 +469,27 @@ fn find_drop_location( position: LogicalPoint, component_type: &str, ) -> Option { - eprintln!("find_drop_location at {position:?}: Considering ["); - let drop_target_node = find_element_to_drop_into(component_instance, position, component_type)?; - eprintln!("find_drop_location at {position:?}: ] => {drop_target_node:?}"); + let drop_target_node = find_element_to_drop_into(component_instance, position)?; let (path, _) = drop_target_node.path_and_offset(); let tl = component_instance.definition().type_loader(); - let Some(doc) = tl.get_document(&path) else { - eprintln!("find_drop_location at {position:?}: No document found for {drop_target_node:?} => NONE"); - return None; - }; + let doc = tl.get_document(&path)?; if let Some(element_type) = drop_target_node.with_element_node(|node| { util::lookup_current_element_type((node.clone()).into(), &doc.local_registry) }) { if drop_target_node.layout_kind() == ui::LayoutKind::None && element_type.accepts_child_element(component_type, &doc.local_registry).is_err() { - eprintln!("find_drop_location at {position:?}: {drop_target_node:?} does not accept {component_type} => NONE"); return None; } } let layout_kind = drop_target_node.layout_kind(); if layout_kind != ui::LayoutKind::None { - let parent_kind = drop_target_node.with_element_node(|node| node.kind()); let geometry = drop_target_node.geometry_at(component_instance, position)?; let children_information: Vec<_> = drop_target_node.with_element_node(|node| { let mut children_info = Vec::new(); for c in node.children() { - eprintln!("Child syntax_node of {parent_kind:?}: {:?}", c.kind()); - - let c_path = c.source_file.path().to_path_buf(); - let c_range = (u32::from(c.text_range().start()), u32::from(c.text_range().end())); - if let Some(element) = extract_element(c.clone()) { let e_path = element.source_file.path().to_path_buf(); let e_offset = u32::from(element.text_range().start()); @@ -509,12 +501,11 @@ fn find_drop_location( ) else { continue; }; - let Some(c_geometry) = child_node.geometry_in(component_instance, &geometry) else { continue; }; - children_info.push(ChildrenInformation { - geometry: c_geometry.clone(), - path: c_path, - range: c_range, - }); + let Some(c_geometry) = child_node.geometry_in(component_instance, &geometry) + else { + continue; + }; + children_info.push(c_geometry); } } @@ -532,13 +523,18 @@ fn find_drop_location( if child_index == usize::MAX { insert_position_at_end(&drop_target_node) } else { - insert_position_at_end(&drop_target_node) + insert_position_before_child(&drop_target_node, child_index) } }?; Some(DropInformation { target_element_node: drop_target_node, insert_info, drop_mark }) } else { - drop_into_element(component_instance, drop_target_node, position) + let insert_info = insert_position_at_end(&drop_target_node)?; + Some(DropInformation { + target_element_node: drop_target_node, + insert_info, + drop_mark: None, + }) } } diff --git a/tools/lsp/preview/element_selection.rs b/tools/lsp/preview/element_selection.rs index 8f78bdb2a..203711ae6 100644 --- a/tools/lsp/preview/element_selection.rs +++ b/tools/lsp/preview/element_selection.rs @@ -3,10 +3,8 @@ use std::{path::PathBuf, rc::Rc}; -use i_slint_compiler::diagnostics::SourceFile; use i_slint_compiler::object_tree::{Component, ElementRc}; use i_slint_core::lengths::LogicalPoint; -use rowan::TextRange; use slint_interpreter::ComponentInstance; use crate::common::ElementRcNode; @@ -142,16 +140,6 @@ fn select_element_node( } } -fn element_node_source_range( - element: &ElementRc, - debug_index: usize, -) -> Option<(SourceFile, TextRange)> { - let node = element.borrow().debug.get(debug_index)?.0.clone(); - let source_file = node.source_file.clone(); - let range = node.text_range(); - Some((source_file, range)) -} - // Return the real root element, skipping any WindowElement that got added pub fn root_element(component_instance: &ComponentInstance) -> ElementRc { let root_element = component_instance.definition().root_component().root_element.clone(); @@ -167,7 +155,6 @@ pub struct SelectionCandidate { pub component_stack: Vec>, pub element: ElementRc, pub debug_index: usize, - pub text_range: Option<(SourceFile, TextRange)>, } impl SelectionCandidate { @@ -227,12 +214,10 @@ fn collect_all_element_nodes_covering_impl( if element_covers_point(position, component_instance, &ce) { for (i, _) in ce.borrow().debug.iter().enumerate().rev() { // All nodes have the same geometry - let text_range = element_node_source_range(&ce, i); result.push(SelectionCandidate { element: ce.clone(), debug_index: i, component_stack: component_stack.clone(), - text_range, }); } } @@ -490,7 +475,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401 &component_instance, ); - // Remove the "button" implenmentation details. They must be at the start: + // Remove the "button" implementation details. They must be at the start: let button_path = PathBuf::from("builtin:/fluent-base/button.slint"); let first_non_button = covers_center .iter() @@ -543,7 +528,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401 let first_non_button = covers_center.iter().position(|(p, _)| p != &button_path).unwrap(); covers_center.drain(1..(first_non_button - 1)); // strip all but first/last of button - // Select without crossing file boundries + // Select without crossing file boundaries let select = super::select_element_at_impl( &component_instance, LogicalPoint::new(100.0, 100.0), @@ -655,7 +640,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401 None ); - // Select with crossing file boundries + // Select with crossing file boundaries let select = super::select_element_at_impl( &component_instance, LogicalPoint::new(100.0, 100.0), diff --git a/tools/lsp/preview/ext.rs b/tools/lsp/preview/ext.rs index acb365dca..9ae3f837a 100644 --- a/tools/lsp/preview/ext.rs +++ b/tools/lsp/preview/ext.rs @@ -6,7 +6,6 @@ use i_slint_core::lengths::{LogicalPoint, LogicalRect}; use crate::common; use crate::preview::ui; -use crate::util; use slint_interpreter::ComponentInstance; @@ -32,13 +31,6 @@ pub trait ElementRcNodeExt { component_instance: &ComponentInstance, rect: &LogicalRect, ) -> Option; - - /// Checks wether the given type is acceptable as a child - fn accepts_child_type( - &self, - component_instance: &ComponentInstance, - component_type: &str, - ) -> bool; } impl ElementRcNodeExt for common::ElementRcNode { @@ -61,7 +53,7 @@ impl ElementRcNodeExt for common::ElementRcNode { &self, component_instance: &ComponentInstance, ) -> Vec { - component_instance.element_positions(&self.as_element()) + component_instance.element_positions(self.as_element()) } fn geometry_at( @@ -77,30 +69,6 @@ impl ElementRcNodeExt for common::ElementRcNode { component_instance: &ComponentInstance, rect: &LogicalRect, ) -> Option { - self.geometries(component_instance) - .iter() - .find(|g| rect.contains_rect(g)) - .cloned() - } - - fn accepts_child_type( - &self, - component_instance: &ComponentInstance, - component_type: &str, - ) -> bool { - let tl = component_instance.definition().type_loader(); - let (path, _) = self.path_and_offset(); - let Some(doc) = tl.get_document(&path) else { - return false; - }; - let Some(element_type) = self.with_element_node(|node| { - util::lookup_current_element_type((node.clone()).into(), &doc.local_registry) - }) else { - return false; - }; - - self.layout_kind() != ui::LayoutKind::None - || element_type.accepts_child_element(component_type, &doc.local_registry).is_ok() + self.geometries(component_instance).iter().find(|g| rect.contains_rect(g)).cloned() } } -