Keep scenario authoring visible and restore exact caller context

This commit is contained in:
2026-09-10 12:03:17 -07:00
parent 81668f94ed
commit 3978bbe23c
7 changed files with 1720 additions and 511 deletions
+50 -2
View File
@@ -1103,6 +1103,7 @@ impl App {
Message::ScenarioCanvas(
crate::behavior::scenario::CanvasEvent::Scrolled(..)
| crate::behavior::scenario::CanvasEvent::Restored(..)
| crate::behavior::scenario::CanvasEvent::Viewport(..)
) | Message::TopologyCanvas(
crate::behavior::topology::CanvasEvent::Scrolled(..)
| crate::behavior::topology::CanvasEvent::Viewport(..)
@@ -1294,6 +1295,11 @@ impl App {
.topology
.enter(context.document, context.owner);
}
if let Some(context) = self.scenario_context() {
self.behavior
.scenario
.enter(context.document, context.scenario);
}
if self.connection.as_ref().is_some_and(|session| {
Some(session.context) != self.route_context()
|| self.page != Page::Diagram
@@ -1364,6 +1370,17 @@ impl App {
Message::ScenarioCanvas(event) => {
use crate::behavior::scenario::{self, CanvasEvent};
let context = event.context();
if let CanvasEvent::Viewport(_, size) = event {
if self.scenario_context().is_some_and(|current| {
current.document == context.document
&& current.scenario == context.scenario
&& current.revision == context.revision
}) && self.behavior.scenario.viewport(size)
{
self.canvas_epoch = self.canvas_epoch.wrapping_add(1);
}
return Task::none();
}
if let CanvasEvent::Restored(_, token, area, offset) = event {
if self.scenario_context().is_some_and(|current| {
current.document == context.document && current.scenario == context.scenario
@@ -1377,7 +1394,7 @@ impl App {
return Task::none();
}
if let CanvasEvent::Scrolled(_, area, offset) = event {
// Inner and outer scroll notifications may come from the
// Canvas and outline notifications may come from the
// same frame. Accept both across the first epoch bump,
// while still rejecting another owner/document/revision.
if self.scenario_context().is_some_and(|current| {
@@ -1394,6 +1411,19 @@ impl App {
return Task::none();
}
match event {
CanvasEvent::Focus(_) => {
self.behavior.scenario.toggle_focus();
self.canvas_epoch = self.canvas_epoch.wrapping_add(1);
}
CanvasEvent::Shelf(_, shelf) => {
self.behavior.scenario.toggle_shelf(shelf);
self.canvas_epoch = self.canvas_epoch.wrapping_add(1);
}
CanvasEvent::Zoom(_, scale) => {
if self.behavior.scenario.zoom(scale) {
self.canvas_epoch = self.canvas_epoch.wrapping_add(1);
}
}
CanvasEvent::OpenUse(_, occurrence) => {
if self.behavior.has_pending() || self.draft_dirty() || self.source_dirty()
{
@@ -1405,6 +1435,9 @@ impl App {
self.behavior.scenario = state;
match target {
Ok(target) => {
// A command can preselect this target while the
// caller remains visible, bypassing select below.
self.behavior.active_owner = Some(target);
self.select(target);
self.canvas_epoch = self.canvas_epoch.wrapping_add(1);
}
@@ -1423,12 +1456,23 @@ impl App {
let caller = state.back(self.project(), context);
self.behavior.scenario = state;
if let Some(caller) = caller {
// A command may already have selected this UUID while
// leaving the referenced definition open. select's
// same-UUID fast path must not keep that old owner.
self.behavior.active_owner = Some(caller.owner);
self.select(caller.occurrence);
self.canvas_epoch = self.canvas_epoch.wrapping_add(1);
if let Some(context) = self.scenario_context() {
self.behavior.scenario.restore_caller(context, caller);
}
} else {
// An edit can select a retargeted caller outside the
// definition that remains visible after rejected Back.
if crate::behavior::selected_behavior(self.project(), self.selected)
!= Some(context.scenario)
{
self.select(context.scenario);
}
self.status =
"The calling scenario reference is no longer available.".into();
}
@@ -1443,7 +1487,11 @@ impl App {
}
}
CanvasEvent::Choose(_, tool) => {
if self.behavior.has_pending() || !self.apply() {
if self.behavior.has_pending() || self.draft_dirty() || self.source_dirty()
{
self.status =
"Apply or cancel pending edits before choosing a scenario tool."
.into();
return Task::none();
}
self.behavior.scenario.choose_tool(context.scenario, tool);