89 lines
3.7 KiB
Rust
89 lines
3.7 KiB
Rust
//! Admit spacing packets before ordinary navigation can retire a newer reveal.
|
|
use super::*;
|
|
use behavior::scenario::spacing::{Event, controller::Finish};
|
|
|
|
#[cfg(test)]
|
|
mod tests;
|
|
|
|
impl App {
|
|
pub(super) fn spacing_enabled(&self) -> bool {
|
|
self.pending_diagram_reveal.is_none()
|
|
&& !self.behavior.has_pending()
|
|
&& !self.draft_dirty()
|
|
&& !self.source_dirty()
|
|
&& !self.source_rename.open()
|
|
&& behavior::canvas_workspace::keyboard_enabled(self)
|
|
}
|
|
|
|
pub(super) fn scenario_spacing(&mut self, event: Event) -> Task<Message> {
|
|
let stamp = event.stamp();
|
|
if self.scenario_context() != Some(stamp.context) || self.camera_epoch != stamp.camera_epoch
|
|
{
|
|
return Task::none();
|
|
}
|
|
let state = &self.behavior.scenario;
|
|
let matches =
|
|
state.spacing_token() == Some(event.token()) && state.spacing_stamp() == Some(stamp);
|
|
if match event {
|
|
Event::Begin { token, .. } => token.is_nil() || state.spacing_token().is_some(),
|
|
_ => !matches,
|
|
} {
|
|
return Task::none();
|
|
}
|
|
if matches!(event, Event::Cancel { .. }) || !self.spacing_enabled() {
|
|
if self.behavior.scenario.cancel_spacing() {
|
|
self.canvas_epoch = self.canvas_epoch.wrapping_add(1);
|
|
}
|
|
return Task::none();
|
|
}
|
|
match event {
|
|
Event::Begin { .. } => {
|
|
let mut state = std::mem::take(&mut self.behavior.scenario);
|
|
let result = state.begin_spacing(self.project(), event);
|
|
self.behavior.scenario = state;
|
|
if result.is_err() {
|
|
self.status = "The drag could not start in this view. Try again.".into();
|
|
}
|
|
}
|
|
Event::Move { screen, .. } => self.behavior.scenario.move_spacing(screen),
|
|
Event::Finish { screen, .. } => {
|
|
let finished = self.behavior.scenario.finish_spacing(screen);
|
|
// Retire queued packets even for zero motion or a refused finish.
|
|
self.canvas_epoch = self.canvas_epoch.wrapping_add(1);
|
|
match finished {
|
|
Ok(Finish::Click(target)) => self.select(target),
|
|
Ok(Finish::Noop) => {}
|
|
Ok(Finish::Commit {
|
|
command,
|
|
selected,
|
|
scale,
|
|
pan,
|
|
}) => {
|
|
// Document prepares and writes the source candidate before
|
|
// committing its snapshot. Failure leaves camera/selection
|
|
// and source/history at their accepted values.
|
|
match self.document.execute(*command) {
|
|
Ok(_) => {
|
|
self.selected = selected;
|
|
self.selected_node = None;
|
|
self.diagram_navigation_focus = None;
|
|
self.behavior.scenario.accept_spacing_camera(scale, pan);
|
|
self.sync();
|
|
self.status = "Scenario spacing updated.".into();
|
|
}
|
|
Err(error) => self.status = format!("Spacing was not applied: {error}"),
|
|
}
|
|
}
|
|
Err(_) => {
|
|
self.status =
|
|
"That position cannot be applied. The saved arrangement is unchanged."
|
|
.into()
|
|
}
|
|
}
|
|
}
|
|
Event::Cancel { .. } => unreachable!(),
|
|
}
|
|
Task::none()
|
|
}
|
|
}
|