106 lines
4.0 KiB
Rust
106 lines
4.0 KiB
Rust
//! The actual State workspace picker, App root and subscriptions.
|
|
use super::*;
|
|
use crate::behavior::canvas_workspace::tests::{Mounted, key};
|
|
use iced::{keyboard::key::Named, mouse};
|
|
|
|
async fn press_escape(mounted: &mut Mounted, app: &mut App) -> Vec<Message> {
|
|
let input = key(Named::Escape);
|
|
let (mut messages, statuses) = mounted.input_with_status(
|
|
app,
|
|
std::slice::from_ref(&input),
|
|
mouse::Cursor::Unavailable,
|
|
);
|
|
crate::app::escape::tests::subscriptions(app, input, statuses[0], &mut messages);
|
|
for message in messages.iter().cloned() {
|
|
let task = app.update(message);
|
|
mounted.perform(app, task).await;
|
|
}
|
|
mounted.settle(app).await;
|
|
messages
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn mounted_state_missing_picker_escape_preserves_exact_document_then_reopens_and_places() {
|
|
let mut f = fixture();
|
|
let diagram = create_view(&mut f).diagram;
|
|
let mut project = f.app.project().clone();
|
|
project
|
|
.diagrams
|
|
.get_mut(&diagram)
|
|
.unwrap()
|
|
.nodes
|
|
.retain(|_, node| node.element != f.b);
|
|
let mut app = App::with_project(project);
|
|
app.window_size = iced::Size::new(1800., 1100.);
|
|
send(&mut app, Message::Select(f.a));
|
|
send(&mut app, Message::Page(Page::Behavior));
|
|
let choice = Choice {
|
|
id: diagram,
|
|
label: app.project().diagrams[&diagram].name.clone(),
|
|
};
|
|
send(&mut app, Message::BehaviorDiagram(choice));
|
|
let mut mounted = Mounted::new(&mut app).await;
|
|
assert_eq!(state_edit::unplaced(app.project(), diagram), vec![f.b]);
|
|
let focus_id = iced::advanced::widget::Id::from("diagram-keyboard-owner");
|
|
let (_, canvas, _) = mounted
|
|
.geometry(&app)
|
|
.focused
|
|
.into_iter()
|
|
.find(|(id, _, _)| id.as_ref() == Some(&focus_id))
|
|
.unwrap();
|
|
// The existing picker is immediately above the measured canvas, separated
|
|
// by 8px. Its 12px text and 8px padding give a 31.6px row.
|
|
let picker = iced::Point::new(canvas.center_x(), canvas.y - 24.);
|
|
let option = iced::Point::new(picker.x, canvas.y + 8.);
|
|
let before = app.document.snapshot();
|
|
let original = app.project().clone();
|
|
let source = app.document.bundle().clone();
|
|
let selection = (
|
|
app.selected,
|
|
app.selected_node,
|
|
app.behavior.diagram.placement,
|
|
);
|
|
let camera = (
|
|
app.behavior.diagram.zoom,
|
|
app.behavior.diagram.pan,
|
|
app.behavior.diagram.fit,
|
|
);
|
|
let revision = app.document.revision();
|
|
let history = (app.document.can_undo(), app.document.can_redo());
|
|
mounted.click(&mut app, picker).await;
|
|
assert!(
|
|
press_escape(&mut mounted, &mut app).await.is_empty(),
|
|
"open picker owns Escape, not the State canvas or App"
|
|
);
|
|
assert!(std::sync::Arc::ptr_eq(&before, &app.document.snapshot()));
|
|
assert_eq!(app.document.bundle(), &source);
|
|
assert_eq!(
|
|
(
|
|
app.selected,
|
|
app.selected_node,
|
|
app.behavior.diagram.placement
|
|
),
|
|
selection
|
|
);
|
|
assert_eq!(
|
|
(
|
|
app.behavior.diagram.zoom,
|
|
app.behavior.diagram.pan,
|
|
app.behavior.diagram.fit
|
|
),
|
|
camera
|
|
);
|
|
assert_eq!(app.document.revision(), revision);
|
|
assert_eq!((app.document.can_undo(), app.document.can_redo()), history);
|
|
// If Escape left the menu open this click would close it, and the following
|
|
// option click would fail to place. This checks actual overlay dismissal.
|
|
mounted.click(&mut app, picker).await;
|
|
let messages = mounted.click(&mut app, option).await;
|
|
assert!(messages.iter().any(|message| matches!(message, Message::StateDiagram(Event::Place { element, .. }) if *element == f.b)));
|
|
assert!(state_edit::unplaced(app.project(), diagram).is_empty());
|
|
assert_eq!(app.project().elements, original.elements);
|
|
assert_eq!(app.project().relations, original.relations);
|
|
let _ = app.update(Message::Undo);
|
|
assert_eq!(app.document.bundle(), &source);
|
|
}
|