Support atomic Allocation group assignment and Arrange gestures
This commit is contained in:
@@ -8,6 +8,9 @@ use iced::{
|
||||
#[path = "allocation_drag_full_tree_tests.rs"]
|
||||
mod full_tree;
|
||||
|
||||
#[path = "allocation_drag_tests/group.rs"]
|
||||
mod group;
|
||||
|
||||
#[path = "allocation_drag_tests/navigation_union.rs"]
|
||||
mod navigation_union;
|
||||
|
||||
@@ -48,6 +51,7 @@ fn fixture(layer: Layer) -> Fixture {
|
||||
app.zoom = 1.;
|
||||
app.pan = Vector::ZERO;
|
||||
app.fit_to_view = false;
|
||||
app.reconcile_multiselect();
|
||||
Fixture {
|
||||
app,
|
||||
a,
|
||||
@@ -59,7 +63,7 @@ fn fixture(layer: Layer) -> Fixture {
|
||||
}
|
||||
fn canvas(app: &App) -> DiagramCanvas<'_> {
|
||||
DiagramCanvas {
|
||||
selection: None,
|
||||
selection: app.diagram_selection.as_ref(),
|
||||
allocation: Some(app.allocation_capability()),
|
||||
project: app.project(),
|
||||
view_index: Some(app.document.view_index()),
|
||||
@@ -122,6 +126,18 @@ fn press(f: &Fixture) -> Arc<Press> {
|
||||
})
|
||||
.expect("actual clean work-body press")
|
||||
}
|
||||
fn admit_press(f: &mut Fixture) -> Arc<Press> {
|
||||
let p = press(f);
|
||||
let _ = f.app.update(Message::WorkDrag(Event::Press(p.clone())));
|
||||
assert!(f.app.allocation_drag.active.is_some(), "{}", f.app.status);
|
||||
p
|
||||
}
|
||||
fn singleton(candidate: &Candidate) -> &Arc<plan::SemanticPlan> {
|
||||
let Candidate::Singleton(plan) = candidate else {
|
||||
panic!("legacy singleton candidate")
|
||||
};
|
||||
plan
|
||||
}
|
||||
fn drag(f: &mut Fixture, to: Point) {
|
||||
let events = batch(&f.app, start(f), to);
|
||||
assert!(matches!(
|
||||
@@ -359,7 +375,7 @@ fn arrange_is_one_gesture_and_snapped_noop_preserves_redo_and_source() {
|
||||
assert!(f.app.allocation_drag.arrange_next);
|
||||
let p = press(&f);
|
||||
let _ = f.app.update(Message::WorkDrag(Event::Press(p.clone())));
|
||||
assert!(p.arrange);
|
||||
assert_eq!(p.mode, Mode::Arrange);
|
||||
assert!(!f.app.allocation_drag.arrange_next);
|
||||
let _ = f.app.update(Message::WorkDrag(Event::Release(
|
||||
p.stamp,
|
||||
@@ -370,7 +386,7 @@ fn arrange_is_one_gesture_and_snapped_noop_preserves_redo_and_source() {
|
||||
assert_eq!(f.app.document.revision(), revision);
|
||||
assert!(f.app.document.can_redo());
|
||||
assert!(f.app.project().relations.is_empty());
|
||||
assert!(!press(&f).arrange);
|
||||
assert_eq!(press(&f).mode, Mode::Assign);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -397,14 +413,15 @@ fn candidate_semantics_are_cached_per_destination_with_stable_ids_and_own_index(
|
||||
let _ = f
|
||||
.app
|
||||
.update(Message::WorkDrag(Event::Preview(p.stamp, p.token, Some(a))));
|
||||
let first = f
|
||||
.app
|
||||
.allocation_drag
|
||||
.preview
|
||||
.as_ref()
|
||||
.expect(&f.app.status)
|
||||
.semantic
|
||||
.clone();
|
||||
let first = singleton(
|
||||
&f.app
|
||||
.allocation_drag
|
||||
.preview
|
||||
.as_ref()
|
||||
.expect(&f.app.status)
|
||||
.candidate,
|
||||
)
|
||||
.clone();
|
||||
let stable = first
|
||||
.project()
|
||||
.relations
|
||||
@@ -419,20 +436,20 @@ fn candidate_semantics_are_cached_per_destination_with_stable_ids_and_own_index(
|
||||
)));
|
||||
assert!(Arc::ptr_eq(
|
||||
&first,
|
||||
&f.app.allocation_drag.preview.as_ref().unwrap().semantic
|
||||
singleton(&f.app.allocation_drag.preview.as_ref().unwrap().candidate)
|
||||
));
|
||||
let _ = f
|
||||
.app
|
||||
.update(Message::WorkDrag(Event::Preview(p.stamp, p.token, Some(b))));
|
||||
let preview = f.app.allocation_drag.preview.as_ref().expect(&f.app.status);
|
||||
assert!(!Arc::ptr_eq(&first, &preview.semantic));
|
||||
assert_eq!(preview.semantic.project().relations[&stable].source(), f.b);
|
||||
assert!(!Arc::ptr_eq(&first, singleton(&preview.candidate)));
|
||||
assert_eq!(preview.project().relations[&stable].source(), f.b);
|
||||
assert_eq!(
|
||||
preview.placement.view,
|
||||
projection::project_diagram_with_index(
|
||||
preview.semantic.project(),
|
||||
preview.project(),
|
||||
&preview.placement.diagram,
|
||||
preview.semantic.index()
|
||||
preview.index()
|
||||
)
|
||||
);
|
||||
assert_ne!(
|
||||
@@ -448,7 +465,7 @@ fn candidate_semantics_are_cached_per_destination_with_stable_ids_and_own_index(
|
||||
.update(Message::WorkDrag(Event::Preview(p.stamp, p.token, Some(a))));
|
||||
assert!(Arc::ptr_eq(
|
||||
&first,
|
||||
&f.app.allocation_drag.preview.as_ref().unwrap().semantic
|
||||
singleton(&f.app.allocation_drag.preview.as_ref().unwrap().candidate)
|
||||
));
|
||||
assert_eq!(
|
||||
f.app.allocation_drag.active.as_ref().unwrap().cache.len(),
|
||||
@@ -458,9 +475,19 @@ fn candidate_semantics_are_cached_per_destination_with_stable_ids_and_own_index(
|
||||
|
||||
#[test]
|
||||
fn frozen_targets_use_half_open_semantic_priority_and_refuse_incomparable_overlap() {
|
||||
let f = fixture(Layer::Oa);
|
||||
let p = press(&f);
|
||||
let mut frozen = p.frozen.clone();
|
||||
let mut f = fixture(Layer::Oa);
|
||||
let p = admit_press(&mut f);
|
||||
let mut frozen = f
|
||||
.app
|
||||
.allocation_drag
|
||||
.active
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.frozen
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.clone();
|
||||
let ai = frozen
|
||||
.targets
|
||||
.iter()
|
||||
@@ -540,6 +567,7 @@ fn release_uses_ordered_native_position_before_later_motion_in_same_batch() {
|
||||
fn replace(f: &mut Fixture, project: Project) {
|
||||
f.app.document = crate::document::Document::from_project(project, Default::default()).unwrap();
|
||||
f.app.sync();
|
||||
f.app.reconcile_multiselect();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -588,7 +616,7 @@ fn same_snapped_position_on_opposite_shared_border_rebuilds_semantics_even_if_la
|
||||
.1
|
||||
.as_ref()
|
||||
.unwrap();
|
||||
assert!(!Arc::ptr_eq(a, b));
|
||||
assert!(!Arc::ptr_eq(singleton(a), singleton(b)));
|
||||
let stable = a
|
||||
.project()
|
||||
.relations
|
||||
@@ -655,13 +683,24 @@ fn mounted_role_only_outgoing_refusal_retains_placement_and_same_performer_creat
|
||||
"{}",
|
||||
f.app.status
|
||||
);
|
||||
let target = press(&f)
|
||||
let admitted = admit_press(&mut f);
|
||||
let target = f
|
||||
.app
|
||||
.allocation_drag
|
||||
.active
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.frozen
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.targets
|
||||
.iter()
|
||||
.find(|t| t.element == f.a)
|
||||
.unwrap()
|
||||
.region;
|
||||
let _ = f
|
||||
.app
|
||||
.update(Message::WorkDrag(Event::Cancel(admitted.token)));
|
||||
drag(&mut f, screen(xy(target.x + 45., target.y + 100.)));
|
||||
assert_eq!(f.app.document.revision(), 1, "{}", f.app.status);
|
||||
assert_eq!(f.app.project().relations, relations);
|
||||
@@ -774,8 +813,18 @@ fn frozen_collapsed_target_uses_only_visible_header_and_port_edge_controls_occlu
|
||||
.unwrap()
|
||||
.collapsed = true;
|
||||
replace(&mut f, project);
|
||||
let p = press(&f);
|
||||
let mut frozen = p.frozen.clone();
|
||||
let p = admit_press(&mut f);
|
||||
let mut frozen = f
|
||||
.app
|
||||
.allocation_drag
|
||||
.active
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.frozen
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.clone();
|
||||
let t = frozen.targets.iter().find(|t| t.element == f.a).unwrap();
|
||||
let bottom = xy(t.region.x + 30., t.region.y + t.region.height);
|
||||
assert!(t.region.height <= 62.);
|
||||
@@ -945,7 +994,7 @@ fn toolbar_destination_names_transformed_target_whose_header_is_clipped() {
|
||||
send(&mut f.app, events);
|
||||
let feedback = f.app.allocation_drag.feedback.as_ref().unwrap();
|
||||
assert!(!feedback.refused, "{}", feedback.text);
|
||||
let target = &feedback.press.frozen.targets[feedback.targets[0]];
|
||||
let target = &feedback.frozen.as_ref().unwrap().targets[feedback.targets[0]];
|
||||
assert!(screen(xy(target.region.x, target.region.y)).y < bounds().y);
|
||||
assert_eq!(feedback.destination_identity(), "A");
|
||||
assert!(f.app.allocation_drag.preview.is_some());
|
||||
@@ -1004,7 +1053,7 @@ fn oa_sa_clipped_selected_header_refuses_preview_release_and_retries_without_par
|
||||
assert!(feedback.refused, "{}", feedback.text);
|
||||
assert!(feedback.text.contains("Make room or adjust the view"));
|
||||
assert_eq!(
|
||||
feedback.press.frozen.targets[feedback.targets[0]].element,
|
||||
feedback.frozen.as_ref().unwrap().targets[feedback.targets[0]].element,
|
||||
f.a
|
||||
);
|
||||
assert_eq!(f.app.project(), &accepted);
|
||||
@@ -1029,14 +1078,14 @@ fn oa_sa_clipped_selected_header_refuses_preview_release_and_retries_without_par
|
||||
send(&mut f.app, events);
|
||||
let active = f.app.allocation_drag.active.as_ref().unwrap();
|
||||
let p = active.press.clone();
|
||||
let semantic = active.cache[0].1.as_ref().unwrap().clone();
|
||||
let semantic = singleton(active.cache[0].1.as_ref().unwrap()).clone();
|
||||
let _ = f.app.update(Message::WorkDrag(Event::Preview(
|
||||
p.stamp,
|
||||
p.token,
|
||||
Some(clear),
|
||||
)));
|
||||
let preview = f.app.allocation_drag.preview.as_ref().expect(&f.app.status);
|
||||
assert!(Arc::ptr_eq(&semantic, &preview.semantic));
|
||||
assert!(Arc::ptr_eq(&semantic, singleton(&preview.candidate)));
|
||||
assert_eq!(
|
||||
preview.placement.diagram.nodes[&f.node].position,
|
||||
xy(120., 160.)
|
||||
@@ -1132,7 +1181,7 @@ fn oa_sa_toolbar_identity_accepts_exact_receiver_and_collapsed_header_drag() {
|
||||
assert!(!feedback.refused, "{}", feedback.text);
|
||||
assert_eq!(feedback.destination_identity(), name);
|
||||
assert_eq!(
|
||||
feedback.press.frozen.targets[feedback.targets[0]].placement,
|
||||
feedback.frozen.as_ref().unwrap().targets[feedback.targets[0]].placement,
|
||||
target_id
|
||||
);
|
||||
let preview = f.app.allocation_drag.preview.as_ref().expect(&f.app.status);
|
||||
@@ -1144,12 +1193,12 @@ fn oa_sa_toolbar_identity_accepts_exact_receiver_and_collapsed_header_drag() {
|
||||
assert_eq!(
|
||||
preview.placement.view,
|
||||
projection::project_diagram_with_index(
|
||||
preview.semantic.project(),
|
||||
preview.project(),
|
||||
&preview.placement.diagram,
|
||||
preview.semantic.index()
|
||||
preview.index()
|
||||
)
|
||||
);
|
||||
let mut expected = preview.semantic.project().clone();
|
||||
let mut expected = preview.project().clone();
|
||||
expected
|
||||
.diagrams
|
||||
.insert(f.diagram, preview.placement.diagram.clone());
|
||||
@@ -1184,6 +1233,8 @@ fn destination_identity_does_not_describe_blocked_or_outside_viewport_as_unalloc
|
||||
let p = press(&f);
|
||||
let mut feedback = Feedback {
|
||||
press: p,
|
||||
frozen: None,
|
||||
ordinary_performers: false,
|
||||
targets: vec![],
|
||||
inspection_targets: vec![],
|
||||
text: "A card blocks this drop".into(),
|
||||
|
||||
Reference in New Issue
Block a user