mirror of https://codeberg.org/topola/topola.git
refactor(autorouter): store edits in history entries
This commit is contained in:
parent
e0de008f51
commit
db9d897315
|
|
@ -9,6 +9,7 @@ use crate::{
|
|||
board::mesadata::AccessMesadata,
|
||||
drawing::{band::BandTermsegIndex, graph::PrimitiveIndex},
|
||||
geometry::primitive::PrimitiveShape,
|
||||
layout::LayoutEdit,
|
||||
router::{navcord::NavcordStepper, navmesh::Navmesh, route::RouteStepper, Router},
|
||||
stepper::Step,
|
||||
};
|
||||
|
|
@ -71,7 +72,7 @@ impl AutorouteExecutionStepper {
|
|||
}
|
||||
}
|
||||
|
||||
impl<M: AccessMesadata> Step<Autorouter<M>, (), AutorouteContinueStatus>
|
||||
impl<M: AccessMesadata> Step<Autorouter<M>, Option<LayoutEdit>, AutorouteContinueStatus>
|
||||
for AutorouteExecutionStepper
|
||||
{
|
||||
type Error = AutorouterError;
|
||||
|
|
@ -79,14 +80,14 @@ impl<M: AccessMesadata> Step<Autorouter<M>, (), AutorouteContinueStatus>
|
|||
fn step(
|
||||
&mut self,
|
||||
autorouter: &mut Autorouter<M>,
|
||||
) -> Result<ControlFlow<(), AutorouteContinueStatus>, AutorouterError> {
|
||||
) -> Result<ControlFlow<Option<LayoutEdit>, AutorouteContinueStatus>, AutorouterError> {
|
||||
let Some(curr_ratline) = self.curr_ratline else {
|
||||
return Ok(ControlFlow::Break(()));
|
||||
return Ok(ControlFlow::Break(None));
|
||||
};
|
||||
|
||||
let Some(ref mut route) = self.route else {
|
||||
// Shouldn't happen.
|
||||
return Ok(ControlFlow::Break(()));
|
||||
return Ok(ControlFlow::Break(None));
|
||||
};
|
||||
|
||||
let (source, target) = autorouter.ratline_endpoints(curr_ratline);
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, (f64, f64)> for CompareDetoursExecut
|
|||
|
||||
Ok(ControlFlow::Continue(()))
|
||||
}
|
||||
ControlFlow::Break(()) => {
|
||||
ControlFlow::Break(..) => {
|
||||
if let Some(next_autoroute) = self.next_autoroute.take() {
|
||||
autorouter.undo_autoroute_ratlines(vec![self.ratline1, self.ratline2])?;
|
||||
self.autoroute = next_autoroute;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@ use std::ops::ControlFlow;
|
|||
use enum_dispatch::enum_dispatch;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{board::mesadata::AccessMesadata, layout::via::ViaWeight, stepper::Step};
|
||||
use crate::{
|
||||
board::mesadata::AccessMesadata,
|
||||
layout::{via::ViaWeight, LayoutEdit},
|
||||
stepper::Step,
|
||||
};
|
||||
|
||||
use super::{
|
||||
autoroute::AutorouteExecutionStepper,
|
||||
|
|
@ -40,34 +44,37 @@ impl ExecutionStepper {
|
|||
fn step_catch_err<M: AccessMesadata>(
|
||||
&mut self,
|
||||
autorouter: &mut Autorouter<M>,
|
||||
) -> Result<ControlFlow<String>, InvokerError> {
|
||||
) -> Result<ControlFlow<(Option<LayoutEdit>, String)>, InvokerError> {
|
||||
Ok(match self {
|
||||
ExecutionStepper::Autoroute(autoroute) => match autoroute.step(autorouter)? {
|
||||
ControlFlow::Continue(..) => ControlFlow::Continue(()),
|
||||
ControlFlow::Break(..) => ControlFlow::Break("finished autorouting".to_string()),
|
||||
ControlFlow::Break(edit) => {
|
||||
ControlFlow::Break((edit, "finished autorouting".to_string()))
|
||||
}
|
||||
},
|
||||
ExecutionStepper::PlaceVia(place_via) => {
|
||||
place_via.doit(autorouter)?;
|
||||
ControlFlow::Break("finished placing via".to_string())
|
||||
ControlFlow::Break((None, "finished placing via".to_string()))
|
||||
}
|
||||
ExecutionStepper::RemoveBands(remove_bands) => {
|
||||
remove_bands.doit(autorouter)?;
|
||||
ControlFlow::Break("finished removing bands".to_string())
|
||||
ControlFlow::Break((None, "finished removing bands".to_string()))
|
||||
}
|
||||
ExecutionStepper::CompareDetours(compare_detours) => {
|
||||
match compare_detours.step(autorouter)? {
|
||||
ControlFlow::Continue(()) => ControlFlow::Continue(()),
|
||||
ControlFlow::Break((total_length1, total_length2)) => {
|
||||
ControlFlow::Break(format!(
|
||||
ControlFlow::Break((total_length1, total_length2)) => ControlFlow::Break((
|
||||
None,
|
||||
format!(
|
||||
"total detour lengths are {} and {}",
|
||||
total_length1, total_length2
|
||||
))
|
||||
}
|
||||
),
|
||||
)),
|
||||
}
|
||||
}
|
||||
ExecutionStepper::MeasureLength(measure_length) => {
|
||||
let length = measure_length.doit(autorouter)?;
|
||||
ControlFlow::Break(format!("Total length of selected bands: {}", length))
|
||||
ControlFlow::Break((None, format!("Total length of selected bands: {}", length)))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -79,9 +86,9 @@ impl<M: AccessMesadata> Step<Invoker<M>, String> for ExecutionStepper {
|
|||
fn step(&mut self, invoker: &mut Invoker<M>) -> Result<ControlFlow<String>, InvokerError> {
|
||||
match self.step_catch_err(&mut invoker.autorouter) {
|
||||
Ok(ControlFlow::Continue(())) => Ok(ControlFlow::Continue(())),
|
||||
Ok(ControlFlow::Break(msg)) => {
|
||||
if let Some(command) = invoker.ongoing_command.take() {
|
||||
invoker.history.do_(command);
|
||||
Ok(ControlFlow::Break((maybe_edit, msg))) => {
|
||||
if let (Some(command), Some(edit)) = (invoker.ongoing_command.take(), maybe_edit) {
|
||||
invoker.history.do_(command, Some(edit));
|
||||
}
|
||||
|
||||
Ok(ControlFlow::Break(msg))
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use derive_getters::{Dissolve, Getters};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::autorouter::execution::Command;
|
||||
use crate::{autorouter::execution::Command, layout::LayoutEdit};
|
||||
|
||||
#[derive(Error, Debug, Clone)]
|
||||
pub enum HistoryError {
|
||||
|
|
@ -16,10 +16,18 @@ pub enum HistoryError {
|
|||
NoNextCommand,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Getters, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct HistoryEntry {
|
||||
command: Command,
|
||||
#[serde(skip)]
|
||||
edit: Option<LayoutEdit>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Getters, Dissolve, Serialize, Deserialize)]
|
||||
pub struct History {
|
||||
done: Vec<Command>,
|
||||
undone: Vec<Command>,
|
||||
done: Vec<HistoryEntry>,
|
||||
undone: Vec<HistoryEntry>,
|
||||
}
|
||||
|
||||
impl History {
|
||||
|
|
@ -27,8 +35,8 @@ impl History {
|
|||
Self::default()
|
||||
}
|
||||
|
||||
pub fn do_(&mut self, command: Command) {
|
||||
self.done.push(command);
|
||||
pub fn do_(&mut self, command: Command, edit: Option<LayoutEdit>) {
|
||||
self.done.push(HistoryEntry { command, edit });
|
||||
}
|
||||
|
||||
pub fn undo(&mut self) -> Result<(), HistoryError> {
|
||||
|
|
@ -49,15 +57,15 @@ impl History {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_undone(&mut self, iter: impl IntoIterator<Item = Command>) {
|
||||
pub fn set_undone(&mut self, iter: impl IntoIterator<Item = HistoryEntry>) {
|
||||
self.undone = Vec::from_iter(iter);
|
||||
}
|
||||
|
||||
pub fn last_done(&self) -> Result<&Command, HistoryError> {
|
||||
pub fn last_done(&self) -> Result<&HistoryEntry, HistoryError> {
|
||||
self.done.last().ok_or(HistoryError::NoPreviousCommand)
|
||||
}
|
||||
|
||||
pub fn last_undone(&self) -> Result<&Command, HistoryError> {
|
||||
pub fn last_undone(&self) -> Result<&HistoryEntry, HistoryError> {
|
||||
self.undone.last().ok_or(HistoryError::NoNextCommand)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ impl<M: AccessMesadata> Invoker<M> {
|
|||
#[debug_requires(self.ongoing_command.is_none())]
|
||||
/// Undo last command
|
||||
pub fn undo(&mut self) -> Result<(), InvokerError> {
|
||||
let command = self.history.last_done()?;
|
||||
let command = self.history.last_done()?.command();
|
||||
|
||||
match command {
|
||||
Command::Autoroute(ref selection, ..) => {
|
||||
|
|
@ -194,7 +194,7 @@ impl<M: AccessMesadata> Invoker<M> {
|
|||
//#[debug_requires(self.ongoing_command.is_none())]
|
||||
/// Redo last command
|
||||
pub fn redo(&mut self) -> Result<(), InvokerError> {
|
||||
let command = self.history.last_undone()?.clone();
|
||||
let command = self.history.last_undone()?.command().clone();
|
||||
let mut execute = self.execute_stepper(command)?;
|
||||
|
||||
loop {
|
||||
|
|
@ -214,8 +214,8 @@ impl<M: AccessMesadata> Invoker<M> {
|
|||
pub fn replay(&mut self, history: History) {
|
||||
let (done, undone) = history.dissolve();
|
||||
|
||||
for command in done {
|
||||
self.execute(command);
|
||||
for entry in done {
|
||||
self.execute(entry.command().clone());
|
||||
}
|
||||
|
||||
self.history.set_undone(undone.into_iter());
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub trait ApplyGeometryEdit<
|
|||
fn apply(&mut self, edit: GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GeometryEdit<
|
||||
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
||||
DW: AccessDotWeight<PW> + GetLayer,
|
||||
|
|
|
|||
Loading…
Reference in New Issue