diff --git a/src/autorouter/autoroute.rs b/src/autorouter/autoroute.rs index 81a4f92..df585e2 100644 --- a/src/autorouter/autoroute.rs +++ b/src/autorouter/autoroute.rs @@ -15,7 +15,7 @@ use super::{ pub struct Autoroute { ratlines_iter: Box>>, route: Option, - cur_ratline: Option>, + curr_ratline: Option>, } impl Autoroute { @@ -25,16 +25,16 @@ impl Autoroute { ) -> Result { let mut ratlines_iter = Box::new(ratlines.into_iter()); - let Some(cur_ratline) = ratlines_iter.next() else { + let Some(curr_ratline) = ratlines_iter.next() else { return Err(AutorouterError::NothingToRoute); }; - let (source, target) = autorouter.ratline_endpoints(cur_ratline); + let (source, target) = autorouter.ratline_endpoints(curr_ratline); let mut router = Router::new(autorouter.board.layout_mut()); let this = Self { ratlines_iter, - cur_ratline: Some(cur_ratline), + curr_ratline: Some(curr_ratline), route: Some(router.route_walk(source, target, 100.0)?), }; @@ -50,11 +50,11 @@ impl Autoroute { return Ok(AutorouterStatus::Finished); }; - let Some(cur_ratline) = self.cur_ratline else { + let Some(curr_ratline) = self.curr_ratline else { return Ok(AutorouterStatus::Finished); }; - let (source, target) = autorouter.ratline_endpoints(cur_ratline); + let (source, target) = autorouter.ratline_endpoints(curr_ratline); let band = { let mut router = Router::new(autorouter.board.layout_mut()); @@ -67,21 +67,21 @@ impl Autoroute { autorouter .ratsnest - .assign_band_to_ratline(self.cur_ratline.unwrap(), band); + .assign_band_to_ratline(self.curr_ratline.unwrap(), band); autorouter .board .try_set_band_between_nodes(source, target, band); let Some(new_ratline) = self.ratlines_iter.next() else { - self.cur_ratline = None; + self.curr_ratline = None; return Ok(AutorouterStatus::Finished); }; let (source, target) = autorouter.ratline_endpoints(new_ratline); let mut router = Router::new(autorouter.board.layout_mut()); - self.cur_ratline = Some(new_ratline); + self.curr_ratline = Some(new_ratline); self.route = Some(router.route_walk(source, target, 100.0)?); Ok(AutorouterStatus::Running) diff --git a/src/autorouter/invoker.rs b/src/autorouter/invoker.rs index 8d42e69..79ba103 100644 --- a/src/autorouter/invoker.rs +++ b/src/autorouter/invoker.rs @@ -176,9 +176,9 @@ impl Invoker { (self.autorouter, self.history, self.ongoing_command) } - #[debug_requires(self.ongoing_command.is_none())] + //#[debug_requires(self.ongoing_command.is_none())] pub fn execute(&mut self, command: Command) -> Result<(), InvokerError> { - let mut execute = self.execute_walk(command); + let mut execute = self.execute_walk(command)?; loop { let status = match execute.step(self) { @@ -194,21 +194,21 @@ impl Invoker { } #[debug_requires(self.ongoing_command.is_none())] - pub fn execute_walk(&mut self, command: Command) -> Execute { + pub fn execute_walk(&mut self, command: Command) -> Result { let execute = self.dispatch_command(&command); self.ongoing_command = Some(command); execute } #[debug_requires(self.ongoing_command.is_none())] - fn dispatch_command(&mut self, command: &Command) -> Execute { + fn dispatch_command(&mut self, command: &Command) -> Result { match command { - Command::Autoroute(selection) => { - Execute::Autoroute(self.autorouter.autoroute_walk(selection).unwrap()) - } - Command::PlaceVia(weight) => { - Execute::PlaceVia(self.autorouter.place_via_walk(*weight).unwrap()) - } + Command::Autoroute(selection) => Ok::(Execute::Autoroute( + self.autorouter.autoroute_walk(selection)?, + )), + Command::PlaceVia(weight) => Ok::(Execute::PlaceVia( + self.autorouter.place_via_walk(*weight)?, + )), } } @@ -227,7 +227,7 @@ impl Invoker { //#[debug_requires(self.ongoing.is_none())] pub fn redo(&mut self) -> Result<(), InvokerError> { let command = self.history.last_undone()?.clone(); - let mut execute = self.execute_walk(command); + let mut execute = self.execute_walk(command)?; loop { let status = match execute.step(self) { diff --git a/src/bin/topola-egui/top.rs b/src/bin/topola-egui/top.rs index bc92517..65ec1b2 100644 --- a/src/bin/topola-egui/top.rs +++ b/src/bin/topola-egui/top.rs @@ -4,7 +4,9 @@ use std::{ }; use topola::{ - autorouter::invoker::{Command, Execute, ExecuteWithStatus, Invoker, InvokerStatus}, + autorouter::invoker::{ + Command, Execute, ExecuteWithStatus, Invoker, InvokerError, InvokerStatus, + }, specctra::mesadata::SpecctraMesadata, }; @@ -37,117 +39,124 @@ impl Top { arc_mutex_maybe_invoker: Arc>>>, maybe_execute: &mut Option, maybe_overlay: &mut Option, - ) { - egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { - egui::menu::bar(ui, |ui| { - ui.menu_button("File", |ui| { - if ui.button("Open").clicked() { - // `Context` is cheap to clone as it's wrapped in an `Arc`. - let ctx = ui.ctx().clone(); - // NOTE: On Linux, this requires Zenity to be installed on your system. - let task = rfd::AsyncFileDialog::new().pick_file(); + ) -> Result<(), InvokerError> { + Ok::<(), InvokerError>( + egui::TopBottomPanel::top("top_panel") + .show(ctx, |ui| { + egui::menu::bar(ui, |ui| { + ui.menu_button("File", |ui| { + if ui.button("Open").clicked() { + // `Context` is cheap to clone as it's wrapped in an `Arc`. + let ctx = ui.ctx().clone(); + // NOTE: On Linux, this requires Zenity to be installed on your system. + let task = rfd::AsyncFileDialog::new().pick_file(); - execute(async move { - if let Some(file_handle) = task.await { - let file_sender = FileSender::new(content_sender); - file_sender.send(file_handle).await; - ctx.request_repaint(); + execute(async move { + if let Some(file_handle) = task.await { + let file_sender = FileSender::new(content_sender); + file_sender.send(file_handle).await; + ctx.request_repaint(); + } + }); } - }); - } - ui.separator(); + ui.separator(); - if ui.button("Load history").clicked() { - let ctx = ui.ctx().clone(); - let task = rfd::AsyncFileDialog::new().pick_file(); + if ui.button("Load history").clicked() { + let ctx = ui.ctx().clone(); + let task = rfd::AsyncFileDialog::new().pick_file(); - execute(async move { - if let Some(file_handle) = task.await { - let file_sender = FileSender::new(history_sender); - file_sender.send(file_handle).await; - ctx.request_repaint(); - } - }); - } else if ui.button("Save history").clicked() { - if let Some(invoker) = - arc_mutex_maybe_invoker.clone().lock().unwrap().as_ref() - { - let ctx = ui.ctx().clone(); - let task = rfd::AsyncFileDialog::new().save_file(); + execute(async move { + if let Some(file_handle) = task.await { + let file_sender = FileSender::new(history_sender); + file_sender.send(file_handle).await; + ctx.request_repaint(); + } + }); + } else if ui.button("Save history").clicked() { + if let Some(invoker) = + arc_mutex_maybe_invoker.clone().lock().unwrap().as_ref() + { + let ctx = ui.ctx().clone(); + let task = rfd::AsyncFileDialog::new().save_file(); - // FIXME: I don't think we should be buffering everything in a `Vec`. - let mut writebuf = vec![]; - serde_json::to_writer_pretty(&mut writebuf, invoker.history()); + // FIXME: I don't think we should be buffering everything in a `Vec`. + let mut writebuf = vec![]; + serde_json::to_writer_pretty(&mut writebuf, invoker.history()); - execute(async move { - if let Some(file_handle) = task.await { - dbg!(file_handle.write(&writebuf).await); - ctx.request_repaint(); + execute(async move { + if let Some(file_handle) = task.await { + dbg!(file_handle.write(&writebuf).await); + ctx.request_repaint(); + } + }); } - }); + } + + ui.separator(); + + // "Quit" button wouldn't work on a Web page. + if !cfg!(target_arch = "wasm32") { + if ui.button("Quit").clicked() { + ctx.send_viewport_cmd(egui::ViewportCommand::Close); + } + } + }); + + ui.separator(); + + if ui.button("Autoroute").clicked() { + if maybe_execute.as_mut().map_or(true, |execute| { + matches!(execute.maybe_status(), Some(InvokerStatus::Finished)) + }) { + if let (Some(invoker), Some(ref mut overlay)) = ( + arc_mutex_maybe_invoker.lock().unwrap().as_mut(), + maybe_overlay, + ) { + let selection = overlay.selection().clone(); + overlay.clear_selection(); + maybe_execute.insert(ExecuteWithStatus::new( + invoker.execute_walk(Command::Autoroute(selection))?, + )); + } + } } - } - ui.separator(); + ui.toggle_value(&mut self.is_placing_via, "Place Via"); - // "Quit" button wouldn't work on a Web page. - if !cfg!(target_arch = "wasm32") { - if ui.button("Quit").clicked() { - ctx.send_viewport_cmd(egui::ViewportCommand::Close); + ui.separator(); + + if ui.button("Undo").clicked() + || ctx.input_mut(|i| i.consume_key(egui::Modifiers::CTRL, egui::Key::Z)) + { + if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_mut() + { + invoker.undo(); + } } - } - }); - ui.separator(); - - if ui.button("Autoroute").clicked() { - if maybe_execute.as_mut().map_or(true, |execute| { - matches!(execute.maybe_status(), Some(InvokerStatus::Finished)) - }) { - if let (Some(invoker), Some(ref mut overlay)) = ( - arc_mutex_maybe_invoker.lock().unwrap().as_mut(), - maybe_overlay, - ) { - let selection = overlay.selection().clone(); - overlay.clear_selection(); - maybe_execute.insert(ExecuteWithStatus::new( - invoker.execute_walk(Command::Autoroute(selection)), - )); + if ui.button("Redo").clicked() + || ctx.input_mut(|i| i.consume_key(egui::Modifiers::CTRL, egui::Key::Y)) + { + if let Some(ref mut invoker) = + arc_mutex_maybe_invoker.lock().unwrap().as_mut() + { + invoker.redo(); + } } - } - } - ui.toggle_value(&mut self.is_placing_via, "Place Via"); + ui.separator(); - ui.separator(); + ui.toggle_value(&mut self.show_ratsnest, "Show Ratsnest"); + ui.toggle_value(&mut self.show_navmesh, "Show Navmesh"); - if ui.button("Undo").clicked() - || ctx.input_mut(|i| i.consume_key(egui::Modifiers::CTRL, egui::Key::Z)) - { - if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_mut() { - invoker.undo(); - } - } + ui.separator(); - if ui.button("Redo").clicked() - || ctx.input_mut(|i| i.consume_key(egui::Modifiers::CTRL, egui::Key::Y)) - { - if let Some(ref mut invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_mut() - { - invoker.redo(); - } - } - - ui.separator(); - - ui.toggle_value(&mut self.show_ratsnest, "Show Ratsnest"); - ui.toggle_value(&mut self.show_navmesh, "Show Navmesh"); - - ui.separator(); - - egui::widgets::global_dark_light_mode_buttons(ui); - }); - }); + egui::widgets::global_dark_light_mode_buttons(ui); + Ok::<(), InvokerError>(()) + }); + }) + .inner, + ) } }