171 lines
5.5 KiB
Rust
171 lines
5.5 KiB
Rust
use super::*;
|
|
|
|
fn canvas(project: &Project, diagram: Id, zoom: f32) -> DiagramCanvas<'_> {
|
|
DiagramCanvas {
|
|
project,
|
|
view_index: None,
|
|
diagram,
|
|
selected: Id::nil(),
|
|
navigation_focus: None,
|
|
zoom,
|
|
pan: Vector::new(17., 23.),
|
|
context: Context {
|
|
document: project.id,
|
|
diagram,
|
|
revision: 0,
|
|
epoch: 0,
|
|
},
|
|
selected_bend: None,
|
|
editable: true,
|
|
placing: false,
|
|
connection: None,
|
|
}
|
|
}
|
|
|
|
fn local(canvas: &DiagramCanvas<'_>, position: Position) -> Point {
|
|
Point::new(
|
|
canvas.pan.x + position.x * canvas.zoom,
|
|
canvas.pan.y + position.y * canvas.zoom,
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn nearest_port_center_wins_on_all_borders_and_zoom_levels() {
|
|
let project = Project::empty();
|
|
let diagram = Id::new_v4();
|
|
for side in [
|
|
PortAnchorSide::Left,
|
|
PortAnchorSide::Right,
|
|
PortAnchorSide::Top,
|
|
PortAnchorSide::Bottom,
|
|
] {
|
|
let horizontal = matches!(side, PortAnchorSide::Top | PortAnchorSide::Bottom);
|
|
let mut view = ProjectedView {
|
|
ports: (0..2)
|
|
.map(|i| projection::ProjectedPort {
|
|
element: Id::from_u128(i + 10),
|
|
owner: diagram,
|
|
position: Position {
|
|
x: 100. + if horizontal { i as f32 * 28. } else { 0. },
|
|
y: 100. + if horizontal { 0. } else { i as f32 * 28. },
|
|
},
|
|
side,
|
|
})
|
|
.collect(),
|
|
..Default::default()
|
|
};
|
|
for zoom in [0.0001, 0.35, 1., 3.] {
|
|
let canvas = canvas(&project, diagram, zoom);
|
|
for _ in 0..2 {
|
|
for port in &view.ports {
|
|
assert_eq!(
|
|
canvas.endpoint_at(&view, local(&canvas, port.position)),
|
|
Some(port.element),
|
|
"Exact port center must win at zoom {zoom} on {side:?}"
|
|
);
|
|
}
|
|
view.ports.reverse();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn coincident_ports_keep_selection_then_use_stable_identity() {
|
|
let project = Project::empty();
|
|
let diagram = Id::new_v4();
|
|
let a = Id::from_u128(10);
|
|
let b = Id::from_u128(20);
|
|
let mut view = ProjectedView {
|
|
ports: [b, a]
|
|
.into_iter()
|
|
.map(|element| projection::ProjectedPort {
|
|
element,
|
|
owner: diagram,
|
|
position: Position { x: 100., y: 100. },
|
|
side: PortAnchorSide::Right,
|
|
})
|
|
.collect(),
|
|
..Default::default()
|
|
};
|
|
let mut canvas = canvas(&project, diagram, 0.35);
|
|
let at = local(&canvas, view.ports[0].position);
|
|
for _ in 0..2 {
|
|
canvas.selected = Id::nil();
|
|
assert_eq!(canvas.endpoint_at(&view, at), Some(a));
|
|
canvas.selected = b;
|
|
assert_eq!(canvas.endpoint_at(&view, at), Some(b));
|
|
view.ports.reverse();
|
|
}
|
|
assert!(canvas.hit_port(&view, Point::new(-100., -100.)).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn nested_owner_palette_selection_drag_and_context_menu_pick_the_same_port() {
|
|
let mut project = Project::empty();
|
|
let group = project
|
|
.add_element(Kind::Function, Layer::Sa, "Response", None)
|
|
.unwrap();
|
|
let owner = project
|
|
.add_element(Kind::Function, Layer::Sa, "Send report", Some(group))
|
|
.unwrap();
|
|
let ports = [Id::from_u128(10), Id::from_u128(20)];
|
|
for (i, id) in ports.into_iter().enumerate() {
|
|
let port = make_port(
|
|
&project,
|
|
id,
|
|
owner,
|
|
&format!("Output {i}"),
|
|
PortContract::FunctionOutput {
|
|
outgoing_items: vec![],
|
|
},
|
|
)
|
|
.unwrap();
|
|
project.elements.insert(id, port);
|
|
}
|
|
let diagram = project.ensure_diagram(Layer::Sa);
|
|
project.diagrams.get_mut(&diagram).unwrap().projection = ProjectionKind::FunctionalDataflow;
|
|
project.place(diagram, group, Position { x: 60., y: 60. });
|
|
let node = project.place(diagram, owner, Position { x: 100., y: 140. });
|
|
project
|
|
.diagrams
|
|
.get_mut(&diagram)
|
|
.unwrap()
|
|
.nodes
|
|
.get_mut(&node)
|
|
.unwrap()
|
|
.port_anchors = ports
|
|
.into_iter()
|
|
.enumerate()
|
|
.map(|(i, port)| PortAnchor {
|
|
port,
|
|
side: PortAnchorSide::Right,
|
|
offset: 0.4 + i as f32 * 0.1,
|
|
})
|
|
.collect();
|
|
validate_candidate(&project).unwrap();
|
|
let canvas = canvas(&project, diagram, 0.35);
|
|
let view = project_view(&project, diagram);
|
|
let bounds = Rectangle::new(Point::new(200., 80.), Size::new(800., 600.));
|
|
for port in &view.ports {
|
|
let at = local(&canvas, port.position);
|
|
assert_eq!(canvas.endpoint_at(&view, at), Some(port.element));
|
|
let mut state = State::default();
|
|
let cursor = mouse::Cursor::Available(Point::new(bounds.x + at.x, bounds.y + at.y));
|
|
let press = canvas::Program::update(
|
|
&canvas,
|
|
&mut state,
|
|
&canvas::Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)),
|
|
bounds,
|
|
cursor,
|
|
)
|
|
.unwrap()
|
|
.into_inner()
|
|
.0;
|
|
assert!(matches!(press, Some(Message::Select(id)) if id == port.element));
|
|
assert_eq!(state.port_drag.as_ref().unwrap().anchor.port, port.element);
|
|
let menu = canvas.context_request(&state, at, bounds);
|
|
assert_eq!(menu.object, port.element);
|
|
}
|
|
}
|