Skip to content

Commit

Permalink
live-preview: Recognize GridLayouts as layouts and find layouts in co…
Browse files Browse the repository at this point in the history
…mponents

... when deciding whether or not we are dropping into a layout or not.
Components that take @children (like a GroupBox) were misrecognized before.

This is a bit tricky as the optimized Elements do not allow to find out whether
something had a child insertion point. So I need to convert over to the
unoptimized Element found in my `document_cache`.

Unfortunately there the lowering pass for the layouts has not been done yet,
so my "normal" approach to figuring out whether something is a layout or not
does not work anymore:-/

I ended up duplicating the logic of the layout lowering step: Match specific
type names for Builtin types. That's not nice and should be cleaned up at
some point.
  • Loading branch information
hunger committed Jul 19, 2024
1 parent 97ac713 commit 7bbe2a9
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 5 deletions.
20 changes: 20 additions & 0 deletions tools/lsp/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,26 @@ impl ElementRcNode {
Some(Self { element, debug_index })
}

pub fn in_document_cache(&self, document_cache: &DocumentCache) -> Option<Self> {
self.with_element_node(|en| {
let element_start = en.text_range().start();
let path = en.source_file.path();

let doc = document_cache.get_document_by_path(path)?;
let component = doc.inner_components.iter().find(|c| {
let Some(c_node) = &c.node else {
return false;
};
c_node.text_range().contains(element_start)
})?;
ElementRcNode::find_in_or_below(
component.root_element.clone(),
path,
u32::from(element_start),
)
})
}

/// Some nodes get merged into the same ElementRc with no real connections between them...
pub fn next_element_rc_node(&self) -> Option<Self> {
Self::new(self.element.clone(), self.debug_index + 1)
Expand Down
48 changes: 43 additions & 5 deletions tools/lsp/preview/drop_location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::cell::RefCell;
use std::num::NonZeroUsize;

use i_slint_compiler::diagnostics::{BuildDiagnostics, SourceFile};
use i_slint_compiler::object_tree;
use i_slint_compiler::parser::{syntax_nodes, SyntaxKind, SyntaxNode};
use i_slint_core::lengths::{LogicalPoint, LogicalRect, LogicalSize};
use slint_interpreter::ComponentInstance;
Expand Down Expand Up @@ -802,9 +803,9 @@ pub fn can_move_to(
// Cache compilation results:
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
struct CacheEntry {
source_element: by_address::ByAddress<i_slint_compiler::object_tree::ElementRc>,
source_element: by_address::ByAddress<object_tree::ElementRc>,
source_node_index: usize,
target_element: by_address::ByAddress<i_slint_compiler::object_tree::ElementRc>,
target_element: by_address::ByAddress<object_tree::ElementRc>,
target_node_index: usize,
child_index: usize,
}
Expand Down Expand Up @@ -909,6 +910,20 @@ fn drop_ignored_elements_from_node(
})
}

fn element_base_type_is_layout(element: &object_tree::ElementRc) -> bool {
let base_type = if let i_slint_compiler::langtype::ElementType::Builtin(base_type) =
&element.borrow().base_type
{
base_type.clone()
} else {
return false;
};
matches!(
base_type.name.as_str(),
"Row" | "GridLayout" | "HorizontalLayout" | "VerticalLayout" | "Dialog"
)
}

/// Find a location in a file that would be a good place to insert the new component at
///
/// Return a WorkspaceEdit to send to the editor and extra info for the live preview in
Expand All @@ -926,11 +941,34 @@ pub fn drop_at(
let properties = {
let mut props = component.default_properties.clone();

if drop_info.target_element_node.layout_kind() == ui::LayoutKind::None
&& !component.fills_parent
{
let is_layout = {
let is_layout = drop_info.target_element_node.layout_kind() != ui::LayoutKind::None;

// We go for an target node without any of the optimization passes!
if let Some(unopt_target_element_node) =
drop_info.target_element_node.in_document_cache(&document_cache)
{
match &unopt_target_element_node.as_element().borrow().base_type {
i_slint_compiler::langtype::ElementType::Component(component) => {
if let Some((child_insertion_parent, _, _)) =
&*component.child_insertion_point.borrow()
{
element_base_type_is_layout(&child_insertion_parent)
} else {
false
}
}
_ => is_layout,
}
} else {
false
}
};

if !is_layout && !component.fills_parent {
if let Some(area) =
drop_info.target_element_node.geometry_at(&component_instance, position)
// Use the "real" target_element_node here!
{
props.push(common::PropertyChange::new(
"x",
Expand Down

0 comments on commit 7bbe2a9

Please sign in to comment.