mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-17 18:57:10 +00:00
live preview: Prefer LogicalPoint over providing x and y
This commit is contained in:
parent
69b8e8d57c
commit
9b2a7fc694
3 changed files with 276 additions and 367 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.2 OR LicenseRef-Slint-commercial
|
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.2 OR LicenseRef-Slint-commercial
|
||||||
|
|
||||||
use i_slint_compiler::parser::{SyntaxKind, SyntaxNode};
|
use i_slint_compiler::parser::{SyntaxKind, SyntaxNode};
|
||||||
use i_slint_core::lengths::{LogicalPoint, LogicalRect};
|
use i_slint_core::lengths::{LogicalPoint, LogicalRect, LogicalSize};
|
||||||
use slint_interpreter::ComponentInstance;
|
use slint_interpreter::ComponentInstance;
|
||||||
|
|
||||||
use crate::common;
|
use crate::common;
|
||||||
|
|
@ -75,16 +75,15 @@ impl DropMarkDirection {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn border_size(dimension: f32) -> f32 {
|
fn border_size(dimension: f32) -> f32 {
|
||||||
match dimension {
|
let bs = (dimension / 4.0).floor();
|
||||||
d if d >= 16.0 => 4.0,
|
if bs > 8.0 {
|
||||||
d if d >= 14.0 => 3.0,
|
8.0
|
||||||
d if d >= 12.0 => 2.0,
|
} else {
|
||||||
d if d >= 6.0 => 1.0,
|
bs
|
||||||
_ => 0.0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does this hit the center of an element that accepty drops?
|
// Does this hit the center area of an element that accept drops?
|
||||||
fn element_accepts(
|
fn element_accepts(
|
||||||
element_geometry: &LogicalRect,
|
element_geometry: &LogicalRect,
|
||||||
position: LogicalPoint,
|
position: LogicalPoint,
|
||||||
|
|
@ -171,7 +170,6 @@ impl DropMarkDirection {
|
||||||
|
|
||||||
let ne_half = y <= ascend * x;
|
let ne_half = y <= ascend * x;
|
||||||
let nw_half = y <= (x * -ascend) + element_geometry.size.height;
|
let nw_half = y <= (x * -ascend) + element_geometry.size.height;
|
||||||
eprintln!("GRID: {position:?} in {element_geometry:?}: x: {x}, y: {y}, ascend: {ascend} => NE-half: {} => {ne_half}, NW-half: {} => {nw_half}", -ascend * x, (x * ascend) - element_geometry.size.height);
|
|
||||||
|
|
||||||
match (ne_half, nw_half) {
|
match (ne_half, nw_half) {
|
||||||
(false, false) => DropMarkDirection::S,
|
(false, false) => DropMarkDirection::S,
|
||||||
|
|
@ -260,14 +258,13 @@ fn insert_position_at_end(
|
||||||
|
|
||||||
fn drop_target_element_node(
|
fn drop_target_element_node(
|
||||||
component_instance: &ComponentInstance,
|
component_instance: &ComponentInstance,
|
||||||
x: f32,
|
position: LogicalPoint,
|
||||||
y: f32,
|
|
||||||
component_type: &str,
|
component_type: &str,
|
||||||
) -> (Option<common::ElementRcNode>, Option<common::ElementRcNode>) {
|
) -> (Option<common::ElementRcNode>, Option<common::ElementRcNode>) {
|
||||||
let mut self_node = None;
|
let mut self_node = None;
|
||||||
let mut surrounding_node = None;
|
let mut surrounding_node = None;
|
||||||
let tl = component_instance.definition().type_loader();
|
let tl = component_instance.definition().type_loader();
|
||||||
for sc in &element_selection::collect_all_element_nodes_covering(x, y, component_instance) {
|
for sc in &element_selection::collect_all_element_nodes_covering(position, component_instance) {
|
||||||
let Some(en) = sc.as_element_node() else {
|
let Some(en) = sc.as_element_node() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
@ -318,34 +315,15 @@ fn extract_element(node: SyntaxNode) -> Option<i_slint_compiler::parser::syntax_
|
||||||
fn examine_target_element_node(
|
fn examine_target_element_node(
|
||||||
context: &str,
|
context: &str,
|
||||||
component_instance: &ComponentInstance,
|
component_instance: &ComponentInstance,
|
||||||
x: f32,
|
position: LogicalPoint,
|
||||||
y: f32,
|
|
||||||
target_element_node: &common::ElementRcNode,
|
target_element_node: &common::ElementRcNode,
|
||||||
) {
|
) {
|
||||||
let geometry = target_element_node.geometry_at(component_instance, x, y);
|
let geometry = target_element_node.geometry_at(component_instance, position);
|
||||||
eprintln!(
|
|
||||||
"{context} :: {target_element_node:?}<{:?}> [{:?}] @ {x}, {y}",
|
|
||||||
target_element_node.with_element_node(|n| n.kind()),
|
|
||||||
target_element_node.layout_kind()
|
|
||||||
);
|
|
||||||
// let mut result = Vec::new();
|
// let mut result = Vec::new();
|
||||||
if let Some(geometry) = geometry {
|
if let Some(geometry) = geometry {
|
||||||
eprintln!(
|
|
||||||
" Element : children count: {}, Geometry: {geometry:?}",
|
|
||||||
target_element_node.element.borrow().children.len()
|
|
||||||
);
|
|
||||||
for (i, c) in target_element_node.element.borrow().children.iter().enumerate() {
|
for (i, c) in target_element_node.element.borrow().children.iter().enumerate() {
|
||||||
let c = common::ElementRcNode::new(c.clone(), 0).unwrap();
|
let c = common::ElementRcNode::new(c.clone(), 0).unwrap();
|
||||||
eprintln!(
|
|
||||||
" {i}: {c:?}<{:?}>, Geometry: {:?}",
|
|
||||||
c.with_element_node(|n| n.kind()),
|
|
||||||
c.geometry_in(component_instance, &geometry)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
eprintln!(
|
|
||||||
" Node : children count: {}",
|
|
||||||
target_element_node.with_element_node(|node| node.children().count())
|
|
||||||
);
|
|
||||||
target_element_node.with_element_node(|node| {
|
target_element_node.with_element_node(|node| {
|
||||||
for (i, c) in node.children().enumerate() {
|
for (i, c) in node.children().enumerate() {
|
||||||
let element_data = if let Some(c_element) = extract_element(c.clone()) {
|
let element_data = if let Some(c_element) = extract_element(c.clone()) {
|
||||||
|
|
@ -357,46 +335,90 @@ fn examine_target_element_node(
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
eprintln!(" {i}: {:?}<{:?}>{element_data}", c.text_range(), c.kind());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn drop_into_layout(
|
||||||
|
component_instance: &ComponentInstance,
|
||||||
|
element_node: common::ElementRcNode,
|
||||||
|
insert_position: Option<(DropMarkDirection, common::ElementRcNode)>,
|
||||||
|
position: LogicalPoint,
|
||||||
|
) -> Option<DropInformation> {
|
||||||
|
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,
|
||||||
|
surround_node: Option<common::ElementRcNode>,
|
||||||
|
position: LogicalPoint,
|
||||||
|
) -> Option<DropInformation> {
|
||||||
|
let geometry = element_node.geometry_at(component_instance, position)?;
|
||||||
|
let drop_mark_direction = DropMarkDirection::for_element(
|
||||||
|
&geometry,
|
||||||
|
position,
|
||||||
|
surround_node.as_ref().map(|n| n.layout_kind()).unwrap_or(ui::LayoutKind::None),
|
||||||
|
);
|
||||||
|
|
||||||
|
if drop_mark_direction == DropMarkDirection::None {
|
||||||
|
let insert_info = insert_position_at_end(&element_node)?;
|
||||||
|
|
||||||
|
Some(DropInformation { target_element_node: element_node, insert_info, drop_mark: None })
|
||||||
|
} else {
|
||||||
|
drop_into_layout(
|
||||||
|
component_instance,
|
||||||
|
surround_node.unwrap(),
|
||||||
|
Some((drop_mark_direction, element_node)),
|
||||||
|
position,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn find_drop_location(
|
fn find_drop_location(
|
||||||
component_instance: &ComponentInstance,
|
component_instance: &ComponentInstance,
|
||||||
x: f32,
|
position: LogicalPoint,
|
||||||
y: f32,
|
|
||||||
component_type: &str,
|
component_type: &str,
|
||||||
) -> Option<DropInformation> {
|
) -> Option<DropInformation> {
|
||||||
let (drop_element_node, drop_surrounding_element_node) =
|
let (drop_element_node, drop_surrounding_element_node) =
|
||||||
drop_target_element_node(component_instance, x, y, component_type);
|
drop_target_element_node(component_instance, position, component_type);
|
||||||
|
|
||||||
let drop_element_node = drop_element_node?;
|
let drop_element_node = drop_element_node?;
|
||||||
|
|
||||||
examine_target_element_node("Drop target", component_instance, x, y, &drop_element_node);
|
examine_target_element_node("Drop target", component_instance, position, &drop_element_node);
|
||||||
if let Some(sn) = &drop_surrounding_element_node {
|
if let Some(sn) = &drop_surrounding_element_node {
|
||||||
examine_target_element_node("Surrounding", component_instance, x, y, sn);
|
examine_target_element_node("Surrounding", component_instance, position, sn);
|
||||||
}
|
}
|
||||||
|
|
||||||
let insert_info = insert_position_at_end(&drop_element_node)?;
|
if drop_element_node.layout_kind() != ui::LayoutKind::None {
|
||||||
|
drop_into_layout(component_instance, drop_element_node, None, position)
|
||||||
Some(DropInformation {
|
} else {
|
||||||
target_element_node: drop_element_node,
|
drop_into_element(
|
||||||
insert_info,
|
component_instance,
|
||||||
drop_mark: Some(DropMark {
|
drop_element_node,
|
||||||
start: LogicalPoint::new(x - 10.0, y - 10.0),
|
drop_surrounding_element_node,
|
||||||
end: LogicalPoint::new(x + 10.0, y + 10.0),
|
position,
|
||||||
}),
|
)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find the Element to insert into. None means we can not insert at this point.
|
/// Find the Element to insert into. None means we can not insert at this point.
|
||||||
pub fn can_drop_at(x: f32, y: f32, component: &common::ComponentInformation) -> bool {
|
pub fn can_drop_at(x: f32, y: f32, component: &common::ComponentInformation) -> bool {
|
||||||
let component_type = component.name.to_string();
|
let component_type = component.name.to_string();
|
||||||
if let Some(dm) =
|
let position = LogicalPoint::new(x, y);
|
||||||
&super::component_instance().and_then(|ci| find_drop_location(&ci, x, y, &component_type))
|
if let Some(dm) = &super::component_instance()
|
||||||
|
.and_then(|ci| find_drop_location(&ci, position, &component_type))
|
||||||
{
|
{
|
||||||
super::set_drop_mark(&dm.drop_mark);
|
super::set_drop_mark(&dm.drop_mark);
|
||||||
true
|
true
|
||||||
|
|
@ -424,10 +446,11 @@ pub fn drop_at(
|
||||||
y: f32,
|
y: f32,
|
||||||
component: &common::ComponentInformation,
|
component: &common::ComponentInformation,
|
||||||
) -> Option<(lsp_types::WorkspaceEdit, DropData)> {
|
) -> Option<(lsp_types::WorkspaceEdit, DropData)> {
|
||||||
|
let position = LogicalPoint::new(x, y);
|
||||||
let component_type = &component.name;
|
let component_type = &component.name;
|
||||||
let component_instance = preview::component_instance()?;
|
let component_instance = preview::component_instance()?;
|
||||||
let tl = component_instance.definition().type_loader();
|
let tl = component_instance.definition().type_loader();
|
||||||
let drop_info = find_drop_location(&component_instance, x, y, component_type)?;
|
let drop_info = find_drop_location(&component_instance, position, component_type)?;
|
||||||
|
|
||||||
let properties = {
|
let properties = {
|
||||||
let mut props = component.default_properties.clone();
|
let mut props = component.default_properties.clone();
|
||||||
|
|
@ -435,7 +458,8 @@ pub fn drop_at(
|
||||||
if drop_info.target_element_node.layout_kind() == ui::LayoutKind::None
|
if drop_info.target_element_node.layout_kind() == ui::LayoutKind::None
|
||||||
&& !component.fills_parent
|
&& !component.fills_parent
|
||||||
{
|
{
|
||||||
if let Some(area) = drop_info.target_element_node.geometry_at(&component_instance, x, y)
|
if let Some(area) =
|
||||||
|
drop_info.target_element_node.geometry_at(&component_instance, position)
|
||||||
{
|
{
|
||||||
props.push(common::PropertyChange::new("x", format!("{}px", x - area.origin.x)));
|
props.push(common::PropertyChange::new("x", format!("{}px", x - area.origin.x)));
|
||||||
props.push(common::PropertyChange::new("y", format!("{}px", y - area.origin.y)));
|
props.push(common::PropertyChange::new("y", format!("{}px", y - area.origin.y)));
|
||||||
|
|
@ -508,13 +532,15 @@ mod tests {
|
||||||
for i in 0_u16..100 {
|
for i in 0_u16..100 {
|
||||||
let dimension = f32::from(i) / 10.0;
|
let dimension = f32::from(i) / 10.0;
|
||||||
let bs = DropMarkDirection::border_size(dimension);
|
let bs = DropMarkDirection::border_size(dimension);
|
||||||
assert!(bs >= (expected - 0.05));
|
assert!(
|
||||||
assert!(bs <= (expected + 1.05));
|
bs >= (expected - 0.05) && bs < (expected + 0.05)
|
||||||
assert!((bs * 2.0) <= dimension); // this makes sure the first bs is 0.0
|
|| (bs >= (expected + 0.95) && bs < (expected + 1.05))
|
||||||
expected = bs;
|
);
|
||||||
|
assert!((bs * 3.0) <= dimension); // this makes sure the first bs is 0.0
|
||||||
|
expected = bs.round();
|
||||||
}
|
}
|
||||||
// The maximum border size is 4px:
|
// The maximum border size is 4px:
|
||||||
assert!(expected <= 4.05);
|
assert!(expected <= 8.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -666,342 +692,218 @@ mod tests {
|
||||||
);
|
);
|
||||||
let bs_h = DropMarkDirection::border_size(rect.size.width);
|
let bs_h = DropMarkDirection::border_size(rect.size.width);
|
||||||
let bs_v = DropMarkDirection::border_size(rect.size.height);
|
let bs_v = DropMarkDirection::border_size(rect.size.height);
|
||||||
eprintln!("width: {width}, height: {height} => border-h: {bs_h}, border-v: {bs_v}");
|
|
||||||
|
|
||||||
// Center: Drop into self, no drop mark ever:
|
// Center: Drop into self, no drop mark ever:
|
||||||
let pos =
|
let pos = LogicalPoint::new(50.0 + (width / 2.0), 50.0 + (height / 2.0));
|
||||||
LogicalPoint::new(50.0 + (width / 2.0), 50.0 + (height / 2.0));
|
|
||||||
eprintln!(" Testing: {pos:?}");
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::None),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::None
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Horizontal),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Horizontal
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Vertical),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Vertical
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Grid),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Grid
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
|
|
||||||
// N-side (in border):
|
// N-side (in border):
|
||||||
let pos = LogicalPoint::new(50.0 + (width / 2.0), 49.0 + bs_v);
|
let pos = LogicalPoint::new(50.0 + (width / 2.0), 49.0 + bs_v);
|
||||||
eprintln!(" Testing: {pos:?}");
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::None),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::None
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Horizontal),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Horizontal
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Vertical),
|
||||||
&rect,
|
if bs_h > 0.9 && bs_v > 0.9 {
|
||||||
pos,
|
DropMarkDirection::N
|
||||||
ui::LayoutKind::Vertical
|
} else {
|
||||||
),
|
DropMarkDirection::None
|
||||||
if bs_h > 0.9 && bs_v > 0.9 { DropMarkDirection::N } else { DropMarkDirection::None }
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Grid),
|
||||||
&rect,
|
if bs_h > 0.9 && bs_v > 0.9 {
|
||||||
pos,
|
DropMarkDirection::N
|
||||||
ui::LayoutKind::Grid
|
} else {
|
||||||
),
|
DropMarkDirection::None
|
||||||
if bs_h > 0.9 && bs_v > 0.9 { DropMarkDirection::N } else { DropMarkDirection::None }
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// N-side (outside border):
|
// N-side (outside border):
|
||||||
let pos = LogicalPoint::new(50.0 + (width / 2.0), 50.0 + bs_v);
|
let pos = LogicalPoint::new(50.0 + (width / 2.0), 50.0 + bs_v);
|
||||||
eprintln!(" Testing: {pos:?}");
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::None),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::None
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Horizontal),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Horizontal
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Vertical),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Vertical
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Grid),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Grid
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
|
|
||||||
// E-side (inside border):
|
// E-side (inside border):
|
||||||
let pos = LogicalPoint::new(50.0 + width - bs_h, 50.0 + (height / 2.0));
|
let pos = LogicalPoint::new(50.0 + width - bs_h, 50.0 + (height / 2.0));
|
||||||
eprintln!(" Testing: {pos:?}");
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::None),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::None
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Horizontal),
|
||||||
&rect,
|
if bs_h > 0.9 && bs_v > 0.9 {
|
||||||
pos,
|
DropMarkDirection::E
|
||||||
ui::LayoutKind::Horizontal
|
} else {
|
||||||
),
|
DropMarkDirection::None
|
||||||
if bs_h > 0.9 && bs_v > 0.9 { DropMarkDirection::E } else { DropMarkDirection::None }
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Vertical),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Vertical
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Grid),
|
||||||
&rect,
|
if bs_h > 0.9 && bs_v > 0.9 {
|
||||||
pos,
|
DropMarkDirection::E
|
||||||
ui::LayoutKind::Grid
|
} else {
|
||||||
),
|
DropMarkDirection::None
|
||||||
if bs_h > 0.9 && bs_v > 0.9 { DropMarkDirection::E } else { DropMarkDirection::None }
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// E-side (outside border):
|
// E-side (outside border):
|
||||||
let pos = LogicalPoint::new(49.0 + width - bs_h, 50.0 + (height / 2.0));
|
let pos = LogicalPoint::new(49.0 + width - bs_h, 50.0 + (height / 2.0));
|
||||||
eprintln!(" Testing: {pos:?}");
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::None),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::None
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Horizontal),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Horizontal
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Vertical),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Vertical
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Grid),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Grid
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
|
|
||||||
// S-side (in border):
|
// S-side (in border):
|
||||||
let pos = LogicalPoint::new(50.0 + (width / 2.0), 50.0 + height - bs_v);
|
let pos = LogicalPoint::new(50.0 + (width / 2.0), 50.0 + height - bs_v);
|
||||||
eprintln!(" Testing: {pos:?}");
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::None),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::None
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Horizontal),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Horizontal
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Vertical),
|
||||||
&rect,
|
if bs_h > 0.9 && bs_v > 0.9 {
|
||||||
pos,
|
DropMarkDirection::S
|
||||||
ui::LayoutKind::Vertical
|
} else {
|
||||||
),
|
DropMarkDirection::None
|
||||||
if bs_h > 0.9 && bs_v > 0.9 { DropMarkDirection::S } else { DropMarkDirection::None }
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Grid),
|
||||||
&rect,
|
if bs_h > 0.9 && bs_v > 0.9 {
|
||||||
pos,
|
DropMarkDirection::S
|
||||||
ui::LayoutKind::Grid
|
} else {
|
||||||
),
|
DropMarkDirection::None
|
||||||
if bs_h > 0.9 && bs_v > 0.9 { DropMarkDirection::S } else { DropMarkDirection::None }
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// S-side (outside border):
|
// S-side (outside border):
|
||||||
let pos = LogicalPoint::new(50.0 + (width / 2.0), 49.0 + height - bs_v);
|
let pos = LogicalPoint::new(50.0 + (width / 2.0), 49.0 + height - bs_v);
|
||||||
eprintln!(" Testing: {pos:?}");
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::None),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::None
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Horizontal),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Horizontal
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Vertical),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Vertical
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Grid),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Grid
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
|
|
||||||
// W-side (inside border):
|
// W-side (inside border):
|
||||||
let pos = LogicalPoint::new(49.0 + bs_h, 50.0 + (height / 2.0));
|
let pos = LogicalPoint::new(49.0 + bs_h, 50.0 + (height / 2.0));
|
||||||
eprintln!(" Testing: {pos:?}");
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::None),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::None
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Horizontal),
|
||||||
&rect,
|
if bs_h > 0.9 && bs_v > 0.9 {
|
||||||
pos,
|
DropMarkDirection::W
|
||||||
ui::LayoutKind::Horizontal
|
} else {
|
||||||
),
|
DropMarkDirection::None
|
||||||
if bs_h > 0.9 && bs_v > 0.9 { DropMarkDirection::W } else { DropMarkDirection::None }
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Vertical),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Vertical
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Grid),
|
||||||
&rect,
|
if bs_h > 0.9 && bs_v > 0.9 {
|
||||||
pos,
|
DropMarkDirection::W
|
||||||
ui::LayoutKind::Grid
|
} else {
|
||||||
),
|
DropMarkDirection::None
|
||||||
if bs_h > 0.9 && bs_v > 0.9 { DropMarkDirection::W } else { DropMarkDirection::None }
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// W-side (outside border):
|
// W-side (outside border):
|
||||||
let pos = LogicalPoint::new(50.0 + bs_h, 50.0 + (height / 2.0));
|
let pos = LogicalPoint::new(50.0 + bs_h, 50.0 + (height / 2.0));
|
||||||
eprintln!(" Testing: {pos:?}");
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::None),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::None
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Horizontal),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Horizontal
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Vertical),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Vertical
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DropMarkDirection::for_element(
|
DropMarkDirection::for_element(&rect, pos, ui::LayoutKind::Grid),
|
||||||
&rect,
|
|
||||||
pos,
|
|
||||||
ui::LayoutKind::Grid
|
|
||||||
),
|
|
||||||
DropMarkDirection::None
|
DropMarkDirection::None
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use std::{path::PathBuf, rc::Rc};
|
||||||
|
|
||||||
use i_slint_compiler::diagnostics::SourceFile;
|
use i_slint_compiler::diagnostics::SourceFile;
|
||||||
use i_slint_compiler::object_tree::{Component, ElementRc};
|
use i_slint_compiler::object_tree::{Component, ElementRc};
|
||||||
use i_slint_core::lengths::{LogicalLength, LogicalPoint};
|
use i_slint_core::lengths::LogicalPoint;
|
||||||
use rowan::TextRange;
|
use rowan::TextRange;
|
||||||
use slint_interpreter::ComponentInstance;
|
use slint_interpreter::ComponentInstance;
|
||||||
|
|
||||||
|
|
@ -73,17 +73,11 @@ fn lsp_element_node_position(element: &ElementRcNode) -> Option<(String, lsp_typ
|
||||||
}
|
}
|
||||||
|
|
||||||
fn element_covers_point(
|
fn element_covers_point(
|
||||||
x: f32,
|
position: LogicalPoint,
|
||||||
y: f32,
|
|
||||||
component_instance: &ComponentInstance,
|
component_instance: &ComponentInstance,
|
||||||
selected_element: &ElementRc,
|
selected_element: &ElementRc,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let click_position = LogicalPoint::from_lengths(LogicalLength::new(x), LogicalLength::new(y));
|
component_instance.element_positions(selected_element).iter().any(|p| p.contains(position))
|
||||||
|
|
||||||
component_instance
|
|
||||||
.element_positions(selected_element)
|
|
||||||
.iter()
|
|
||||||
.any(|p| p.contains(click_position))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unselect_element() {
|
pub fn unselect_element() {
|
||||||
|
|
@ -197,8 +191,7 @@ impl std::fmt::Debug for SelectionCandidate {
|
||||||
// Traverse the element tree in reverse render order and collect information on
|
// Traverse the element tree in reverse render order and collect information on
|
||||||
// all elements that "render" at the given x and y coordinates
|
// all elements that "render" at the given x and y coordinates
|
||||||
fn collect_all_element_nodes_covering_impl(
|
fn collect_all_element_nodes_covering_impl(
|
||||||
x: f32,
|
position: LogicalPoint,
|
||||||
y: f32,
|
|
||||||
component_instance: &ComponentInstance,
|
component_instance: &ComponentInstance,
|
||||||
current_element: &ElementRc,
|
current_element: &ElementRc,
|
||||||
component_stack: &Vec<Rc<Component>>,
|
component_stack: &Vec<Rc<Component>>,
|
||||||
|
|
@ -223,8 +216,7 @@ fn collect_all_element_nodes_covering_impl(
|
||||||
|
|
||||||
for c in ce.borrow().children.iter().rev() {
|
for c in ce.borrow().children.iter().rev() {
|
||||||
collect_all_element_nodes_covering_impl(
|
collect_all_element_nodes_covering_impl(
|
||||||
x,
|
position,
|
||||||
y,
|
|
||||||
component_instance,
|
component_instance,
|
||||||
c,
|
c,
|
||||||
children_component_stack,
|
children_component_stack,
|
||||||
|
|
@ -232,7 +224,7 @@ fn collect_all_element_nodes_covering_impl(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if element_covers_point(x, y, component_instance, &ce) {
|
if element_covers_point(position, component_instance, &ce) {
|
||||||
for (i, _) in ce.borrow().debug.iter().enumerate().rev() {
|
for (i, _) in ce.borrow().debug.iter().enumerate().rev() {
|
||||||
// All nodes have the same geometry
|
// All nodes have the same geometry
|
||||||
let text_range = element_node_source_range(&ce, i);
|
let text_range = element_node_source_range(&ce, i);
|
||||||
|
|
@ -247,15 +239,13 @@ fn collect_all_element_nodes_covering_impl(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_all_element_nodes_covering(
|
pub fn collect_all_element_nodes_covering(
|
||||||
x: f32,
|
position: LogicalPoint,
|
||||||
y: f32,
|
|
||||||
component_instance: &ComponentInstance,
|
component_instance: &ComponentInstance,
|
||||||
) -> Vec<SelectionCandidate> {
|
) -> Vec<SelectionCandidate> {
|
||||||
let root_element = root_element(component_instance);
|
let root_element = root_element(component_instance);
|
||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
collect_all_element_nodes_covering_impl(
|
collect_all_element_nodes_covering_impl(
|
||||||
x,
|
position,
|
||||||
y,
|
|
||||||
component_instance,
|
component_instance,
|
||||||
&root_element,
|
&root_element,
|
||||||
&vec![],
|
&vec![],
|
||||||
|
|
@ -300,11 +290,10 @@ pub fn is_same_file_as_root_node(
|
||||||
|
|
||||||
fn select_element_at_impl(
|
fn select_element_at_impl(
|
||||||
component_instance: &ComponentInstance,
|
component_instance: &ComponentInstance,
|
||||||
x: f32,
|
position: LogicalPoint,
|
||||||
y: f32,
|
|
||||||
enter_component: bool,
|
enter_component: bool,
|
||||||
) -> Option<ElementRcNode> {
|
) -> Option<ElementRcNode> {
|
||||||
for sc in &collect_all_element_nodes_covering(x, y, component_instance) {
|
for sc in &collect_all_element_nodes_covering(position, component_instance) {
|
||||||
if let Some(en) = filter_nodes_for_selection(component_instance, sc, enter_component) {
|
if let Some(en) = filter_nodes_for_selection(component_instance, sc, enter_component) {
|
||||||
return Some(en);
|
return Some(en);
|
||||||
}
|
}
|
||||||
|
|
@ -317,20 +306,22 @@ pub fn select_element_at(x: f32, y: f32, enter_component: bool) {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let position = LogicalPoint::new(x, y);
|
||||||
|
|
||||||
if let Some(se) = super::selected_element() {
|
if let Some(se) = super::selected_element() {
|
||||||
if let Some(element) = se.as_element() {
|
if let Some(element) = se.as_element() {
|
||||||
if element_covers_point(x, y, &component_instance, &element) {
|
if element_covers_point(position, &component_instance, &element) {
|
||||||
// We clicked on the already selected element: Do nothing!
|
// We clicked on the already selected element: Do nothing!
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(en) = select_element_at_impl(&component_instance, x, y, enter_component) else {
|
let Some(en) = select_element_at_impl(&component_instance, position, enter_component) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
select_element_node(&component_instance, &en, Some(LogicalPoint::new(x, y)));
|
select_element_node(&component_instance, &en, Some(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_element_node_in_layout(element: &ElementRcNode) -> bool {
|
pub fn is_element_node_in_layout(element: &ElementRcNode) -> bool {
|
||||||
|
|
@ -381,12 +372,11 @@ fn filter_nodes_for_selection(
|
||||||
pub fn select_element_behind_impl(
|
pub fn select_element_behind_impl(
|
||||||
component_instance: &ComponentInstance,
|
component_instance: &ComponentInstance,
|
||||||
selected_element_node: &ElementRcNode,
|
selected_element_node: &ElementRcNode,
|
||||||
x: f32,
|
position: LogicalPoint,
|
||||||
y: f32,
|
|
||||||
enter_component: bool,
|
enter_component: bool,
|
||||||
reverse: bool,
|
reverse: bool,
|
||||||
) -> Option<ElementRcNode> {
|
) -> Option<ElementRcNode> {
|
||||||
let elements = collect_all_element_nodes_covering(x, y, component_instance);
|
let elements = collect_all_element_nodes_covering(position, component_instance);
|
||||||
let current_selection_position =
|
let current_selection_position =
|
||||||
elements.iter().position(|sc| sc.is_selected_element_node(selected_element_node))?;
|
elements.iter().position(|sc| sc.is_selected_element_node(selected_element_node))?;
|
||||||
|
|
||||||
|
|
@ -422,6 +412,7 @@ pub fn select_element_behind(x: f32, y: f32, enter_component: bool, reverse: boo
|
||||||
let Some(component_instance) = super::component_instance() else {
|
let Some(component_instance) = super::component_instance() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
let position = LogicalPoint::new(x, y);
|
||||||
let Some(selected_element_node) =
|
let Some(selected_element_node) =
|
||||||
super::selected_element().and_then(|sel| sel.as_element_node())
|
super::selected_element().and_then(|sel| sel.as_element_node())
|
||||||
else {
|
else {
|
||||||
|
|
@ -431,15 +422,14 @@ pub fn select_element_behind(x: f32, y: f32, enter_component: bool, reverse: boo
|
||||||
let Some(en) = select_element_behind_impl(
|
let Some(en) = select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&selected_element_node,
|
&selected_element_node,
|
||||||
x,
|
position,
|
||||||
y,
|
|
||||||
enter_component,
|
enter_component,
|
||||||
reverse,
|
reverse,
|
||||||
) else {
|
) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
select_element_node(&component_instance, &en, Some(LogicalPoint::new(x, y)));
|
select_element_node(&component_instance, &en, Some(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from UI thread!
|
// Called from UI thread!
|
||||||
|
|
@ -459,6 +449,7 @@ pub fn reselect_element() {
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use i_slint_core::lengths::LogicalPoint;
|
||||||
use slint_interpreter::ComponentInstance;
|
use slint_interpreter::ComponentInstance;
|
||||||
|
|
||||||
fn demo_app() -> ComponentInstance {
|
fn demo_app() -> ComponentInstance {
|
||||||
|
|
@ -494,8 +485,10 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
fn test_find_covering_elements() {
|
fn test_find_covering_elements() {
|
||||||
let component_instance = demo_app();
|
let component_instance = demo_app();
|
||||||
|
|
||||||
let mut covers_center =
|
let mut covers_center = super::collect_all_element_nodes_covering(
|
||||||
super::collect_all_element_nodes_covering(100.0, 100.0, &component_instance);
|
LogicalPoint::new(100.0, 100.0),
|
||||||
|
&component_instance,
|
||||||
|
);
|
||||||
|
|
||||||
// Remove the "button" implenmentation details. They must be at the start:
|
// Remove the "button" implenmentation details. They must be at the start:
|
||||||
let button_path = PathBuf::from("builtin:/fluent-base/button.slint");
|
let button_path = PathBuf::from("builtin:/fluent-base/button.slint");
|
||||||
|
|
@ -518,8 +511,10 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
assert_eq!(offset, *expected_offset);
|
assert_eq!(offset, *expected_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
let covers_below =
|
let covers_below = super::collect_all_element_nodes_covering(
|
||||||
super::collect_all_element_nodes_covering(100.0, 180.0, &component_instance);
|
LogicalPoint::new(100.0, 180.0),
|
||||||
|
&component_instance,
|
||||||
|
);
|
||||||
|
|
||||||
// All but the button itself as well as the SomeComponent (impl and use)
|
// All but the button itself as well as the SomeComponent (impl and use)
|
||||||
assert_eq!(covers_below.len(), covers_center.len() - 3);
|
assert_eq!(covers_below.len(), covers_center.len() - 3);
|
||||||
|
|
@ -537,26 +532,31 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let component_instance = demo_app();
|
let component_instance = demo_app();
|
||||||
|
|
||||||
let button_path = PathBuf::from("builtin:/fluent-base/button.slint");
|
let button_path = PathBuf::from("builtin:/fluent-base/button.slint");
|
||||||
let mut covers_center =
|
let mut covers_center = super::collect_all_element_nodes_covering(
|
||||||
super::collect_all_element_nodes_covering(100.0, 100.0, &component_instance)
|
LogicalPoint::new(100.0, 100.0),
|
||||||
.iter()
|
&component_instance,
|
||||||
.flat_map(|sc| sc.as_element_node())
|
)
|
||||||
.map(|en| en.path_and_offset())
|
.iter()
|
||||||
.collect::<Vec<_>>();
|
.flat_map(|sc| sc.as_element_node())
|
||||||
|
.map(|en| en.path_and_offset())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let first_non_button = covers_center.iter().position(|(p, _)| p != &button_path).unwrap();
|
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
|
covers_center.drain(1..(first_non_button - 1)); // strip all but first/last of button
|
||||||
|
|
||||||
// Select without crossing file boundries
|
// Select without crossing file boundries
|
||||||
let select =
|
let select = super::select_element_at_impl(
|
||||||
super::select_element_at_impl(&component_instance, 100.0, 100.0, false).unwrap();
|
&component_instance,
|
||||||
|
LogicalPoint::new(100.0, 100.0),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(&select.path_and_offset(), covers_center.get(2).unwrap());
|
assert_eq!(&select.path_and_offset(), covers_center.get(2).unwrap());
|
||||||
|
|
||||||
// Move deeper into the image:
|
// Move deeper into the image:
|
||||||
let next = super::select_element_behind_impl(
|
let next = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&select,
|
&select,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
@ -565,8 +565,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let next = super::select_element_behind_impl(
|
let next = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&next,
|
&next,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
@ -575,8 +574,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let next = super::select_element_behind_impl(
|
let next = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&next,
|
&next,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
@ -585,8 +583,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let next = super::select_element_behind_impl(
|
let next = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&next,
|
&next,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
@ -595,8 +592,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
assert!(super::select_element_behind_impl(
|
assert!(super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&next,
|
&next,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
@ -606,8 +602,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let prev = super::select_element_behind_impl(
|
let prev = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&next,
|
&next,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
|
@ -616,8 +611,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let prev = super::select_element_behind_impl(
|
let prev = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&prev,
|
&prev,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
|
@ -626,8 +620,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let prev = super::select_element_behind_impl(
|
let prev = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&prev,
|
&prev,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
|
@ -636,8 +629,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let prev = super::select_element_behind_impl(
|
let prev = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&prev,
|
&prev,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
|
@ -646,8 +638,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
assert!(super::select_element_behind_impl(
|
assert!(super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&prev,
|
&prev,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
@ -657,8 +648,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
super::select_element_behind_impl(
|
super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&select,
|
&select,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
true
|
true
|
||||||
),
|
),
|
||||||
|
|
@ -666,8 +656,12 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
);
|
);
|
||||||
|
|
||||||
// Select with crossing file boundries
|
// Select with crossing file boundries
|
||||||
let select =
|
let select = super::select_element_at_impl(
|
||||||
super::select_element_at_impl(&component_instance, 100.0, 100.0, true).unwrap();
|
&component_instance,
|
||||||
|
LogicalPoint::new(100.0, 100.0),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(&select.path_and_offset(), covers_center.get(0).unwrap());
|
assert_eq!(&select.path_and_offset(), covers_center.get(0).unwrap());
|
||||||
|
|
||||||
// move to the last in the button definition:
|
// move to the last in the button definition:
|
||||||
|
|
@ -676,8 +670,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
button = super::select_element_behind_impl(
|
button = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&button,
|
&button,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
@ -691,8 +684,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let next = super::select_element_behind_impl(
|
let next = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&button,
|
&button,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
@ -701,8 +693,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let next = super::select_element_behind_impl(
|
let next = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&next,
|
&next,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
@ -711,8 +702,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let next = super::select_element_behind_impl(
|
let next = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&next,
|
&next,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
@ -721,8 +711,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let next = super::select_element_behind_impl(
|
let next = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&next,
|
&next,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
@ -731,8 +720,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
let next = super::select_element_behind_impl(
|
let next = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&next,
|
&next,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
|
@ -741,33 +729,57 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
assert!(super::select_element_behind_impl(
|
assert!(super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&next,
|
&next,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
false,
|
false,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
.is_none());
|
.is_none());
|
||||||
|
|
||||||
// Move towards the viewer:
|
// Move towards the viewer:
|
||||||
let prev =
|
let prev = super::select_element_behind_impl(
|
||||||
super::select_element_behind_impl(&component_instance, &next, 100.0, 100.0, true, true)
|
&component_instance,
|
||||||
.unwrap();
|
&next,
|
||||||
|
LogicalPoint::new(100.0, 100.0),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(&prev.path_and_offset(), covers_center.get(5).unwrap());
|
assert_eq!(&prev.path_and_offset(), covers_center.get(5).unwrap());
|
||||||
let prev =
|
let prev = super::select_element_behind_impl(
|
||||||
super::select_element_behind_impl(&component_instance, &prev, 100.0, 100.0, true, true)
|
&component_instance,
|
||||||
.unwrap();
|
&prev,
|
||||||
|
LogicalPoint::new(100.0, 100.0),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(&prev.path_and_offset(), covers_center.get(4).unwrap());
|
assert_eq!(&prev.path_and_offset(), covers_center.get(4).unwrap());
|
||||||
let prev =
|
let prev = super::select_element_behind_impl(
|
||||||
super::select_element_behind_impl(&component_instance, &prev, 100.0, 100.0, true, true)
|
&component_instance,
|
||||||
.unwrap();
|
&prev,
|
||||||
|
LogicalPoint::new(100.0, 100.0),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(&prev.path_and_offset(), covers_center.get(3).unwrap());
|
assert_eq!(&prev.path_and_offset(), covers_center.get(3).unwrap());
|
||||||
let prev =
|
let prev = super::select_element_behind_impl(
|
||||||
super::select_element_behind_impl(&component_instance, &prev, 100.0, 100.0, true, true)
|
&component_instance,
|
||||||
.unwrap();
|
&prev,
|
||||||
|
LogicalPoint::new(100.0, 100.0),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(&prev.path_and_offset(), covers_center.get(2).unwrap());
|
assert_eq!(&prev.path_and_offset(), covers_center.get(2).unwrap());
|
||||||
let prev =
|
let prev = super::select_element_behind_impl(
|
||||||
super::select_element_behind_impl(&component_instance, &prev, 100.0, 100.0, true, true)
|
&component_instance,
|
||||||
.unwrap();
|
&prev,
|
||||||
|
LogicalPoint::new(100.0, 100.0),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(&prev.path_and_offset(), covers_center.get(1).unwrap());
|
assert_eq!(&prev.path_and_offset(), covers_center.get(1).unwrap());
|
||||||
|
|
||||||
button = prev;
|
button = prev;
|
||||||
|
|
@ -775,8 +787,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
button = super::select_element_behind_impl(
|
button = super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&button,
|
&button,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
|
@ -789,8 +800,7 @@ export component Entry inherits Main { /* @lsp:ignore-node */ } // 401
|
||||||
assert!(super::select_element_behind_impl(
|
assert!(super::select_element_behind_impl(
|
||||||
&component_instance,
|
&component_instance,
|
||||||
&button,
|
&button,
|
||||||
100.0,
|
LogicalPoint::new(100.0, 100.0),
|
||||||
100.0,
|
|
||||||
true,
|
true,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,7 @@ pub trait ElementRcNodeExt {
|
||||||
fn geometry_at(
|
fn geometry_at(
|
||||||
&self,
|
&self,
|
||||||
component_instance: &ComponentInstance,
|
component_instance: &ComponentInstance,
|
||||||
x: f32,
|
position: LogicalPoint,
|
||||||
y: f32,
|
|
||||||
) -> Option<i_slint_core::lengths::LogicalRect>;
|
) -> Option<i_slint_core::lengths::LogicalRect>;
|
||||||
|
|
||||||
/// Find the first geometry of ElementRcNode in `rect`
|
/// Find the first geometry of ElementRcNode in `rect`
|
||||||
|
|
@ -60,11 +59,9 @@ impl ElementRcNodeExt for common::ElementRcNode {
|
||||||
fn geometry_at(
|
fn geometry_at(
|
||||||
&self,
|
&self,
|
||||||
component_instance: &ComponentInstance,
|
component_instance: &ComponentInstance,
|
||||||
x: f32,
|
position: LogicalPoint,
|
||||||
y: f32,
|
|
||||||
) -> Option<i_slint_core::lengths::LogicalRect> {
|
) -> Option<i_slint_core::lengths::LogicalRect> {
|
||||||
let click_position = LogicalPoint::new(x, y);
|
self.geometries(component_instance).iter().find(|g| g.contains(position)).cloned()
|
||||||
self.geometries(component_instance).iter().find(|g| g.contains(click_position)).cloned()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn geometry_in(
|
fn geometry_in(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue