mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-22 16:22:17 +00:00
live preview: Drop elements into layouts (MVP!)
This is the minimum layout support: It drops elements into a layout right before the layout's closing brace.
This commit is contained in:
parent
e61c97fbdf
commit
171c9e215a
3 changed files with 60 additions and 22 deletions
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
|
||||
|
||||
use i_slint_compiler::object_tree::ElementRc;
|
||||
use i_slint_core::lengths::{LogicalLength, LogicalPoint};
|
||||
use slint_interpreter::ComponentInstance;
|
||||
|
||||
|
|
@ -10,9 +9,10 @@ use crate::preview::element_selection::collect_all_element_nodes_covering;
|
|||
#[cfg(target_arch = "wasm32")]
|
||||
use crate::wasm_prelude::*;
|
||||
|
||||
use super::element_selection::ElementRcNode;
|
||||
|
||||
pub struct DropInformation {
|
||||
pub target_element: ElementRc,
|
||||
pub node_index: usize,
|
||||
pub target_element_node: ElementRcNode,
|
||||
pub insertion_position: crate::common::VersionedPosition,
|
||||
}
|
||||
|
||||
|
|
@ -21,24 +21,27 @@ fn find_drop_location(
|
|||
x: f32,
|
||||
y: f32,
|
||||
) -> Option<DropInformation> {
|
||||
let elements = collect_all_element_nodes_covering(x, y, &component_instance);
|
||||
let (node_index, target_element) = elements.iter().find_map(|sc| {
|
||||
sc.element
|
||||
.borrow()
|
||||
.debug
|
||||
.iter()
|
||||
.position(|d| !super::is_element_node_ignored(&d.0))
|
||||
.map(|i| (i, sc.element.clone()))
|
||||
})?;
|
||||
let target_element_node = {
|
||||
let mut result = None;
|
||||
for sc in &collect_all_element_nodes_covering(x, y, &component_instance) {
|
||||
let Some(en) = sc.as_element_node() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if en.on_element_node(|n| super::is_element_node_ignored(n)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = Some(en);
|
||||
break;
|
||||
}
|
||||
result
|
||||
}?;
|
||||
|
||||
let insertion_position = {
|
||||
let elem = target_element.borrow();
|
||||
let elem = target_element_node.element.borrow();
|
||||
|
||||
let (node, layout) = elem.debug.get(node_index)?;
|
||||
|
||||
if layout.is_some() {
|
||||
return None;
|
||||
}
|
||||
let (node, _) = elem.debug.get(target_element_node.debug_index)?;
|
||||
|
||||
let last_token = crate::util::last_non_ws_token(node)?;
|
||||
|
||||
|
|
@ -53,7 +56,7 @@ fn find_drop_location(
|
|||
)
|
||||
};
|
||||
|
||||
Some(DropInformation { target_element, node_index, insertion_position })
|
||||
Some(DropInformation { target_element_node, insertion_position })
|
||||
}
|
||||
|
||||
/// Find the Element to insert into. None means we can not insert at this point.
|
||||
|
|
@ -79,8 +82,10 @@ pub fn drop_at(
|
|||
let click_position =
|
||||
LogicalPoint::from_lengths(LogicalLength::new(x), LogicalLength::new(y));
|
||||
|
||||
if let Some(area) = component_instance
|
||||
.element_position(&drop_info.target_element)
|
||||
if drop_info.target_element_node.is_layout() {
|
||||
vec![]
|
||||
} else if let Some(area) = component_instance
|
||||
.element_position(&drop_info.target_element_node.element)
|
||||
.iter()
|
||||
.find(|p| p.contains(click_position))
|
||||
{
|
||||
|
|
@ -95,7 +100,11 @@ pub fn drop_at(
|
|||
|
||||
let indentation = format!(
|
||||
"{} ",
|
||||
crate::util::find_element_indent(&drop_info.target_element).unwrap_or_default()
|
||||
crate::util::find_element_node_indent(
|
||||
&drop_info.target_element_node.element,
|
||||
drop_info.target_element_node.debug_index
|
||||
)
|
||||
.unwrap_or_default()
|
||||
);
|
||||
|
||||
let component_text = if properties.is_empty() {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,18 @@ impl ElementRcNode {
|
|||
Some(Self { element, debug_index })
|
||||
}
|
||||
|
||||
pub fn on_element_debug<R>(
|
||||
&self,
|
||||
func: impl Fn(
|
||||
&i_slint_compiler::parser::syntax_nodes::Element,
|
||||
&Option<i_slint_compiler::layout::Layout>,
|
||||
) -> R,
|
||||
) -> R {
|
||||
let elem = self.element.borrow();
|
||||
let (n, l) = &elem.debug.get(self.debug_index).unwrap();
|
||||
func(n, l)
|
||||
}
|
||||
|
||||
pub fn on_element_node<R>(
|
||||
&self,
|
||||
func: impl Fn(&i_slint_compiler::parser::syntax_nodes::Element) -> R,
|
||||
|
|
@ -40,6 +52,10 @@ impl ElementRcNode {
|
|||
(n.source_file.path().to_owned(), u32::from(n.text_range().start()))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_layout(&self) -> bool {
|
||||
self.on_element_debug(|_, l| l.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
|
|||
|
|
@ -70,6 +70,19 @@ pub fn find_element_indent(element: &ElementRc) -> Option<String> {
|
|||
None
|
||||
}
|
||||
|
||||
/// Find the indentation of the element itself as well as the indentation of properties inside the element.
|
||||
/// Returns the element indent followed by the block indent
|
||||
pub fn find_element_node_indent(element: &ElementRc, debug_index: usize) -> Option<String> {
|
||||
let mut token = element.borrow().debug.get(debug_index)?.0.first_token()?.prev_token();
|
||||
while let Some(t) = token {
|
||||
if t.kind() == SyntaxKind::Whitespace && t.text().contains('\n') {
|
||||
return t.text().split('\n').last().map(|s| s.to_owned());
|
||||
}
|
||||
token = t.prev_token();
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Given a node within an element, return the Type for the Element under that node.
|
||||
/// (If node is an element, return the Type for that element, otherwise the type of the element under it)
|
||||
/// Will return `Foo` in the following example where `|` is the cursor.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue