Allow Details properties for the exact displayed Saved scenario view
This commit is contained in:
@@ -1308,7 +1308,7 @@ impl App {
|
|||||||
&& (self.scenario_context() != Some(captured)
|
&& (self.scenario_context() != Some(captured)
|
||||||
|| self.selected != *id
|
|| self.selected != *id
|
||||||
|| !self.project().contains(*id)
|
|| !self.project().contains(*id)
|
||||||
|| behavior::selected_behavior(self.project(), *id) != Some(captured.scenario)
|
|| !behavior::scenario::properties_target(self.project(), captured, *id)
|
||||||
|| self.behavior.has_pending()
|
|| self.behavior.has_pending()
|
||||||
|| self.draft_dirty()
|
|| self.draft_dirty()
|
||||||
|| self.source_dirty()
|
|| self.source_dirty()
|
||||||
|
|||||||
@@ -18,6 +18,14 @@ mod workspace;
|
|||||||
pub(crate) use workspace::NAME_INPUT;
|
pub(crate) use workspace::NAME_INPUT;
|
||||||
pub use workspace::{Shelf, view};
|
pub use workspace::{Shelf, view};
|
||||||
|
|
||||||
|
// A picker may select the Saved diagram record itself. Another view of the
|
||||||
|
// same Scenario is not the property target of this displayed representation.
|
||||||
|
pub(crate) fn properties_target(p: &Project, context: Context, id: Id) -> bool {
|
||||||
|
super::selected_behavior(p, id) == Some(context.scenario)
|
||||||
|
|| matches!(context.representation, Representation::Saved { diagram } if diagram == id)
|
||||||
|
&& presentation::checked_owner(p, context.representation) == Some(context.scenario)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "scenario_operation_tests.rs"]
|
#[path = "scenario_operation_tests.rs"]
|
||||||
mod operation_tests;
|
mod operation_tests;
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ pub fn view<'a>(app: &'a App, owner: Id, out: Column<'a, Message>) -> Element<'a
|
|||||||
let mut details = column![
|
let mut details = column![
|
||||||
text(format!("Selected: {}", p.named(app.selected))).size(12),
|
text(format!("Selected: {}", p.named(app.selected))).size(12),
|
||||||
container(button(text("Properties").size(12)).on_press_maybe(
|
container(button(text("Properties").size(12)).on_press_maybe(
|
||||||
(clean && super::super::selected_behavior(p, app.selected) == Some(owner)).then_some(
|
(clean && properties_target(p, context, app.selected)).then_some(
|
||||||
Message::ScenarioCanvas(CanvasEvent::Properties(context, app.selected)),
|
Message::ScenarioCanvas(CanvasEvent::Properties(context, app.selected)),
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -227,6 +227,111 @@ fn details_properties_refuses_pending_property_source_and_behavior_drafts_withou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn focused_details_opens_current_saved_view_properties_after_following_diagram_picker() {
|
||||||
|
let (mut app, a, _) = setup();
|
||||||
|
let b = id(&app, "incident_wide");
|
||||||
|
// Selecting the current view record makes the real picker follow that
|
||||||
|
// record selection to B. Do not seed selected=B or its property draft.
|
||||||
|
let _ = app.update(Message::Select(a));
|
||||||
|
assert_eq!(app.selected, a);
|
||||||
|
let _ = app.update(Message::Diagram(crate::app::Choice {
|
||||||
|
id: b,
|
||||||
|
label: "B".into(),
|
||||||
|
}));
|
||||||
|
assert_eq!(app.selected, b);
|
||||||
|
assert_eq!(app.draft.as_ref().unwrap().original, b);
|
||||||
|
assert_eq!(
|
||||||
|
app.scenario_context().unwrap().representation,
|
||||||
|
Representation::Saved { diagram: b }
|
||||||
|
);
|
||||||
|
let _ = app.update(Message::InspectorTab(
|
||||||
|
crate::navigation::InspectorTab::Connections,
|
||||||
|
));
|
||||||
|
let mut mounted = Mounted::new(&mut app).await;
|
||||||
|
open_focused_details(&mut app);
|
||||||
|
mounted.settle(&mut app).await;
|
||||||
|
let context = app.scenario_context().unwrap();
|
||||||
|
let camera = stored_camera(&app);
|
||||||
|
let snapshot = app.document.snapshot();
|
||||||
|
let bundle = app.document.bundle().clone();
|
||||||
|
let before = mounted.geometry(&app);
|
||||||
|
assert!(!before.scrolls.contains_key(&widget::Id::new("inspector")));
|
||||||
|
let (details, offset) = before.scrolls[&widget::Id::new("scenario-details")];
|
||||||
|
let point = before.bounds("scenario-properties").center() - offset;
|
||||||
|
assert!(details.contains(point));
|
||||||
|
let events = mounted.click(&mut app, point).await;
|
||||||
|
assert!(events.iter().any(|event| matches!(event,
|
||||||
|
Message::ScenarioCanvas(CanvasEvent::Properties(c, selected))
|
||||||
|
if *c == context && *selected == b)));
|
||||||
|
mounted.settle(&mut app).await;
|
||||||
|
let shown = mounted.geometry(&app);
|
||||||
|
assert!(
|
||||||
|
!shown
|
||||||
|
.scrolls
|
||||||
|
.contains_key(&widget::Id::new("scenario-details"))
|
||||||
|
);
|
||||||
|
let (inspector, offset) = shown.scrolls[&widget::Id::new("inspector")];
|
||||||
|
assert!(
|
||||||
|
shown
|
||||||
|
.text_inputs
|
||||||
|
.iter()
|
||||||
|
.any(|bounds| inspector.contains(bounds.center() - offset)),
|
||||||
|
"current Saved diagram has a visible editable inspector"
|
||||||
|
);
|
||||||
|
assert!(!app.behavior.scenario.focused());
|
||||||
|
assert_eq!(
|
||||||
|
app.inspector_tab,
|
||||||
|
crate::navigation::InspectorTab::Properties
|
||||||
|
);
|
||||||
|
assert_eq!(app.selected, b);
|
||||||
|
assert_eq!(app.draft.as_ref().unwrap().original, b);
|
||||||
|
assert_eq!(app.active_diagram, Some(b));
|
||||||
|
assert_eq!(app.page, crate::app::Page::Behavior);
|
||||||
|
assert_eq!(
|
||||||
|
app.scenario_context().unwrap().representation,
|
||||||
|
context.representation
|
||||||
|
);
|
||||||
|
assert_eq!(app.scenario_context().unwrap().visit, context.visit);
|
||||||
|
assert_eq!(stored_camera(&app), camera);
|
||||||
|
assert!(Arc::ptr_eq(&snapshot, &app.document.snapshot()));
|
||||||
|
assert_eq!(app.document.bundle(), &bundle);
|
||||||
|
assert!(!app.document.can_undo() && !app.document.can_redo());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn details_properties_refuses_another_saved_view_even_with_the_same_scenario_owner() {
|
||||||
|
let (mut app, a, _) = setup();
|
||||||
|
let b = id(&app, "incident_wide");
|
||||||
|
let _ = app.update(Message::Diagram(crate::app::Choice {
|
||||||
|
id: b,
|
||||||
|
label: "B".into(),
|
||||||
|
}));
|
||||||
|
let _ = app.update(Message::Select(a));
|
||||||
|
assert_eq!(app.selected, a);
|
||||||
|
open_focused_details(&mut app);
|
||||||
|
let context = app.scenario_context().unwrap();
|
||||||
|
assert_eq!(context.representation, Representation::Saved { diagram: b });
|
||||||
|
assert_eq!(
|
||||||
|
presentation::checked_owner(app.project(), Representation::Saved { diagram: a }),
|
||||||
|
Some(context.scenario)
|
||||||
|
);
|
||||||
|
assert!(!properties_target(app.project(), context, a));
|
||||||
|
let camera = app.behavior.scenario.camera_boundary();
|
||||||
|
let epochs = (app.canvas_epoch, app.camera_epoch);
|
||||||
|
let snapshot = app.document.snapshot();
|
||||||
|
let bundle = app.document.bundle().clone();
|
||||||
|
let _ = app.update(Message::ScenarioCanvas(CanvasEvent::Properties(context, a)));
|
||||||
|
assert!(app.behavior.scenario.camera_boundary() == camera);
|
||||||
|
assert_eq!((app.canvas_epoch, app.camera_epoch), epochs);
|
||||||
|
assert_eq!(app.scenario_context(), Some(context));
|
||||||
|
assert_eq!(app.selected, a);
|
||||||
|
assert_eq!(app.draft.as_ref().unwrap().original, a);
|
||||||
|
assert!(Arc::ptr_eq(&snapshot, &app.document.snapshot()));
|
||||||
|
assert_eq!(app.document.bundle(), &bundle);
|
||||||
|
assert!(!app.document.can_undo() && !app.document.can_redo());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn details_properties_rejects_retired_view_selection_and_epoch_without_changing_panels() {
|
fn details_properties_rejects_retired_view_selection_and_epoch_without_changing_panels() {
|
||||||
for kind in 0..3 {
|
for kind in 0..3 {
|
||||||
@@ -294,6 +399,34 @@ fn opening_scenario_properties_cancels_held_spacing_and_rejects_its_late_finish(
|
|||||||
let _ = app.update(Message::ScenarioCanvas(CanvasEvent::Spacing(begin)));
|
let _ = app.update(Message::ScenarioCanvas(CanvasEvent::Spacing(begin)));
|
||||||
assert_eq!(app.behavior.scenario.spacing_token(), Some(begin.token()));
|
assert_eq!(app.behavior.scenario.spacing_token(), Some(begin.token()));
|
||||||
let snapshot = app.document.snapshot();
|
let snapshot = app.document.snapshot();
|
||||||
|
let end = press_screen + Vector::new(0., 12.);
|
||||||
|
let _ = app.update(Message::ScenarioCanvas(CanvasEvent::Spacing(
|
||||||
|
Spacing::Move {
|
||||||
|
stamp: begin.stamp(),
|
||||||
|
token: begin.token(),
|
||||||
|
screen: end,
|
||||||
|
},
|
||||||
|
)));
|
||||||
|
let paint = app
|
||||||
|
.behavior
|
||||||
|
.scenario
|
||||||
|
.spacing_paint(begin.stamp().context, begin.stamp().camera_epoch)
|
||||||
|
.unwrap();
|
||||||
|
assert!(paint.refusal.is_none());
|
||||||
|
let line = paint
|
||||||
|
.scene
|
||||||
|
.lines
|
||||||
|
.iter()
|
||||||
|
.find(|line| line.id == message)
|
||||||
|
.unwrap();
|
||||||
|
assert!(
|
||||||
|
line.points[0].y > 160.,
|
||||||
|
"a real proposed scene moved the first message"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
Arc::ptr_eq(&snapshot, &app.document.snapshot()),
|
||||||
|
"preview is not authored"
|
||||||
|
);
|
||||||
let camera = stored_camera(&app);
|
let camera = stored_camera(&app);
|
||||||
send(&mut app, |c| CanvasEvent::Properties(c, message));
|
send(&mut app, |c| CanvasEvent::Properties(c, message));
|
||||||
assert!(app.behavior.scenario.spacing_token().is_none());
|
assert!(app.behavior.scenario.spacing_token().is_none());
|
||||||
@@ -302,7 +435,7 @@ fn opening_scenario_properties_cancels_held_spacing_and_rejects_its_late_finish(
|
|||||||
Spacing::Finish {
|
Spacing::Finish {
|
||||||
stamp: begin.stamp(),
|
stamp: begin.stamp(),
|
||||||
token: begin.token(),
|
token: begin.token(),
|
||||||
screen: press_screen + Vector::new(0., 40.),
|
screen: end,
|
||||||
},
|
},
|
||||||
)));
|
)));
|
||||||
assert!(Arc::ptr_eq(&snapshot, &app.document.snapshot()));
|
assert!(Arc::ptr_eq(&snapshot, &app.document.snapshot()));
|
||||||
|
|||||||
Reference in New Issue
Block a user