egui: add button and key to abort execution

It actually finishes execution, as I haven't implemented actual aborting
yet.
This commit is contained in:
Mikolaj Wielgus 2024-10-02 02:28:43 +02:00
parent bfcae7f308
commit 9159312ea5
6 changed files with 131 additions and 99 deletions

View File

@ -22,6 +22,7 @@ action-measure-length = Measure Length
action-undo = Undo
action-redo = Redo
action-abort = Abort
presort-by-pairwise-detours = Presort by Pairwise Detours
squeeze-through-under-bands = Squeeze through under Bands

View File

@ -7,6 +7,7 @@ use topola::{
InvokerStatus,
},
},
board::mesadata::AccessMesadata,
drawing::graph::PrimitiveIndex,
geometry::primitive::PrimitiveShape,
router::{navmesh::Navmesh, trace::TraceStepper},
@ -105,52 +106,63 @@ impl GetObstacles for ActivityStepper {
}
}
pub struct ActivityWithStatus {
pub struct ActivityStepperWithStatus {
activity: ActivityStepper,
maybe_status: Option<ActivityStatus>,
}
impl ActivityWithStatus {
pub fn new_execution(execution: ExecutionStepper) -> ActivityWithStatus {
impl ActivityStepperWithStatus {
pub fn new_execution(execution: ExecutionStepper) -> ActivityStepperWithStatus {
Self {
activity: ActivityStepper::Execution(execution),
maybe_status: None,
}
}
pub fn step(
&mut self,
invoker: &mut Invoker<SpecctraMesadata>,
) -> Result<ActivityStatus, ActivityError> {
let status = self.activity.step(invoker)?;
self.maybe_status = Some(status.clone());
Ok(status.into())
}
pub fn maybe_status(&self) -> Option<ActivityStatus> {
self.maybe_status.clone()
}
}
impl GetMaybeNavmesh for ActivityWithStatus {
impl Step<Invoker<SpecctraMesadata>, ActivityStatus, ActivityError, ()>
for ActivityStepperWithStatus
{
fn step(
&mut self,
invoker: &mut Invoker<SpecctraMesadata>,
) -> Result<ActivityStatus, ActivityError> {
let status = self.activity.step(invoker)?;
self.maybe_status = Some(status.clone());
Ok(status.into())
}
}
impl Abort<Invoker<SpecctraMesadata>> for ActivityStepperWithStatus {
fn abort(&mut self, invoker: &mut Invoker<SpecctraMesadata>) {
self.maybe_status = Some(ActivityStatus::Finished(String::from("aborted")));
self.activity.abort(invoker);
}
}
impl GetMaybeNavmesh for ActivityStepperWithStatus {
fn maybe_navmesh(&self) -> Option<&Navmesh> {
self.activity.maybe_navmesh()
}
}
impl GetMaybeTrace for ActivityWithStatus {
impl GetMaybeTrace for ActivityStepperWithStatus {
fn maybe_trace(&self) -> Option<&TraceStepper> {
self.activity.maybe_trace()
}
}
impl GetGhosts for ActivityWithStatus {
impl GetGhosts for ActivityStepperWithStatus {
fn ghosts(&self) -> &[PrimitiveShape] {
self.activity.ghosts()
}
}
impl GetObstacles for ActivityWithStatus {
impl GetObstacles for ActivityStepperWithStatus {
fn obstacles(&self) -> &[PrimitiveIndex] {
self.activity.obstacles()
}

View File

@ -11,10 +11,11 @@ use unic_langid::{langid, LanguageIdentifier};
use topola::{
autorouter::{invoker::Invoker, Autorouter},
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
stepper::Step,
};
use crate::{
activity::{ActivityStatus, ActivityWithStatus},
activity::{ActivityStatus, ActivityStepperWithStatus},
error_dialog::ErrorDialog,
file_receiver::FileReceiver,
layers::Layers,
@ -38,7 +39,7 @@ pub struct App {
arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>,
#[serde(skip)]
maybe_activity: Option<ActivityWithStatus>,
maybe_activity: Option<ActivityStepperWithStatus>,
#[serde(skip)]
content_channel: (Sender<String>, Receiver<String>),
@ -50,10 +51,10 @@ pub struct App {
viewport: Viewport,
#[serde(skip)]
top: MenuBar,
menu_bar: MenuBar,
#[serde(skip)]
bottom: StatusBar,
status_bar: StatusBar,
#[serde(skip)]
error_dialog: ErrorDialog,
@ -78,8 +79,8 @@ impl Default for App {
content_channel: channel(),
history_channel: channel(),
viewport: Viewport::new(),
top: MenuBar::new(),
bottom: StatusBar::new(),
menu_bar: MenuBar::new(),
status_bar: StatusBar::new(),
error_dialog: ErrorDialog::new(),
maybe_layers: None,
maybe_design: None,
@ -109,8 +110,8 @@ impl App {
fn advance_state_by_dt(&mut self, dt: f32) {
self.update_counter += dt;
while self.update_counter >= self.top.frame_timestep {
self.update_counter -= self.top.frame_timestep;
while self.update_counter >= self.menu_bar.frame_timestep {
self.update_counter -= self.menu_bar.frame_timestep;
if !self.update_state() {
return;
@ -200,7 +201,7 @@ impl eframe::App for App {
/// Called each time the UI has to be repainted.
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
self.top.update(
self.menu_bar.update(
ctx,
&self.translator,
self.content_channel.0.clone(),
@ -214,10 +215,10 @@ impl eframe::App for App {
self.advance_state_by_dt(ctx.input(|i| i.stable_dt));
self.bottom
self.status_bar
.update(ctx, &self.translator, &self.viewport, &self.maybe_activity);
if self.top.show_layer_manager {
if self.menu_bar.show_layer_manager {
if let Some(ref mut layers) = self.maybe_layers {
if let Some(invoker) = self.arc_mutex_maybe_invoker.lock().unwrap().as_ref() {
layers.update(ctx, invoker.autorouter().board());
@ -229,7 +230,7 @@ impl eframe::App for App {
let _viewport_rect = self.viewport.update(
ctx,
&self.top,
&self.menu_bar,
&mut self.arc_mutex_maybe_invoker.lock().unwrap(),
&mut self.maybe_activity,
&mut self.maybe_overlay,

View File

@ -11,11 +11,12 @@ use topola::{
},
router::RouterOptions,
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
stepper::Abort,
};
use crate::{
action::{Action, Switch, Trigger},
activity::{ActivityStatus, ActivityWithStatus},
activity::{ActivityStatus, ActivityStepperWithStatus},
app::execute,
file_sender::FileSender,
overlay::Overlay,
@ -61,7 +62,7 @@ impl MenuBar {
content_sender: Sender<String>,
history_sender: Sender<String>,
arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>,
maybe_activity: &mut Option<ActivityWithStatus>,
maybe_activity: &mut Option<ActivityStepperWithStatus>,
viewport: &mut Viewport,
maybe_overlay: &mut Option<Overlay>,
maybe_design: &Option<SpecctraDesign>,
@ -91,20 +92,35 @@ impl MenuBar {
egui::Modifiers::CTRL,
egui::Key::Q,
));
let mut autoroute = Trigger::new(Action::new(
tr.text("action-autoroute"),
let mut undo = Trigger::new(Action::new(
tr.text("action-undo"),
egui::Modifiers::CTRL,
egui::Key::A,
egui::Key::Z,
));
let mut redo = Trigger::new(Action::new(
tr.text("action-redo"),
egui::Modifiers::CTRL,
egui::Key::Y,
));
let mut abort = Trigger::new(Action::new(
tr.text("action-abort"),
egui::Modifiers::NONE,
egui::Key::Escape,
));
let mut remove_bands = Trigger::new(Action::new(
tr.text("action-remove-bands"),
egui::Modifiers::NONE,
egui::Key::Delete,
));
let mut place_via = Switch::new(Action::new(
tr.text("action-place-via"),
egui::Modifiers::CTRL,
egui::Key::P,
));
let mut remove_bands = Trigger::new(Action::new(
tr.text("action-remove-bands"),
egui::Modifiers::NONE,
egui::Key::Delete,
let mut autoroute = Trigger::new(Action::new(
tr.text("action-autoroute"),
egui::Modifiers::CTRL,
egui::Key::A,
));
let mut compare_detours = Trigger::new(Action::new(
tr.text("action-compare-detours"),
@ -116,16 +132,6 @@ impl MenuBar {
egui::Modifiers::NONE,
egui::Key::Plus,
));
let mut undo = Trigger::new(Action::new(
tr.text("action-undo"),
egui::Modifiers::CTRL,
egui::Key::Z,
));
let mut redo = Trigger::new(Action::new(
tr.text("action-redo"),
egui::Modifiers::CTRL,
egui::Key::Y,
));
egui::TopBottomPanel::top("menu_bar")
.show(ctx, |ui| {
@ -153,6 +159,10 @@ impl MenuBar {
ui.separator();
abort.button(ctx, ui);
ui.separator();
remove_bands.button(ctx, ui);
});
@ -199,7 +209,10 @@ impl MenuBar {
tr.text("presort-by-pairwise-detours"),
);
ui.checkbox(
&mut self.autorouter_options.router_options.squeeze_through_under_bands,
&mut self
.autorouter_options
.router_options
.squeeze_through_under_bands,
tr.text("squeeze-through-under-bands"),
);
ui.checkbox(
@ -289,25 +302,20 @@ impl MenuBar {
}
} else if quit.consume_key_triggered(ctx, ui) {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
} else if autoroute.consume_key_triggered(ctx, ui) {
if maybe_activity.as_mut().map_or(true, |activity| {
matches!(activity.maybe_status(), Some(ActivityStatus::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_activity.insert(ActivityWithStatus::new_execution(
invoker.execute_stepper(Command::Autoroute(
selection.pin_selection,
self.autorouter_options,
))?,
));
} else if undo.consume_key_triggered(ctx, ui) {
if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_mut() {
invoker.undo();
}
} else if redo.consume_key_triggered(ctx, ui) {
if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_mut() {
invoker.redo();
}
} else if abort.consume_key_triggered(ctx, ui) {
if let Some(activity) = maybe_activity {
if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_mut() {
activity.abort(invoker);
}
}
} else if place_via.consume_key_enabled(ctx, ui, &mut self.is_placing_via) {
} else if remove_bands.consume_key_triggered(ctx, ui) {
if maybe_activity.as_mut().map_or(true, |activity| {
matches!(activity.maybe_status(), Some(ActivityStatus::Finished(..)))
@ -318,13 +326,50 @@ impl MenuBar {
) {
let selection = overlay.selection().clone();
overlay.clear_selection();
maybe_activity.insert(ActivityWithStatus::new_execution(
maybe_activity.insert(ActivityStepperWithStatus::new_execution(
invoker.execute_stepper(Command::RemoveBands(
selection.band_selection,
))?,
));
}
}
} else if place_via.consume_key_enabled(ctx, ui, &mut self.is_placing_via) {
} else if autoroute.consume_key_triggered(ctx, ui) {
if maybe_activity.as_mut().map_or(true, |activity| {
matches!(activity.maybe_status(), Some(ActivityStatus::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_activity.insert(ActivityStepperWithStatus::new_execution(
invoker.execute_stepper(Command::Autoroute(
selection.pin_selection,
self.autorouter_options,
))?,
));
}
}
} else if compare_detours.consume_key_triggered(ctx, ui) {
if maybe_activity.as_mut().map_or(true, |activity| {
matches!(activity.maybe_status(), Some(ActivityStatus::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_activity.insert(ActivityStepperWithStatus::new_execution(
invoker.execute_stepper(Command::CompareDetours(
selection.pin_selection,
self.autorouter_options,
))?,
));
}
}
} else if measure_length.consume_key_triggered(ctx, ui) {
if maybe_activity.as_mut().map_or(true, |activity| {
matches!(activity.maybe_status(), Some(ActivityStatus::Finished(..)))
@ -335,41 +380,14 @@ impl MenuBar {
) {
let selection = overlay.selection().clone();
overlay.clear_selection();
maybe_activity.insert(ActivityWithStatus::new_execution(
maybe_activity.insert(ActivityStepperWithStatus::new_execution(
invoker.execute_stepper(Command::MeasureLength(
selection.band_selection,
))?,
));
}
}
} else if undo.consume_key_triggered(ctx, ui) {
if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_mut() {
invoker.undo();
}
} else if redo.consume_key_triggered(ctx, ui) {
if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_mut() {
invoker.redo();
}
} else if compare_detours.consume_key_triggered(ctx, ui) {
if maybe_activity.as_mut().map_or(true, |activity| {
matches!(activity.maybe_status(), Some(ActivityStatus::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_activity.insert(ActivityWithStatus::new_execution(
invoker.execute_stepper(Command::CompareDetours(
selection.pin_selection,
self.autorouter_options,
))?,
));
}
}
}
Ok::<(), InvokerError>(())
})
.inner

View File

@ -1,5 +1,5 @@
use crate::{
activity::{ActivityStatus, ActivityWithStatus},
activity::{ActivityStatus, ActivityStepperWithStatus},
translator::Translator,
viewport::Viewport,
};
@ -16,7 +16,7 @@ impl StatusBar {
ctx: &egui::Context,
tr: &Translator,
viewport: &Viewport,
maybe_activity: &Option<ActivityWithStatus>,
maybe_activity: &Option<ActivityStepperWithStatus>,
) {
egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| {
let latest_pos = viewport.transform.inverse()

View File

@ -20,7 +20,7 @@ use topola::{
};
use crate::{
activity::ActivityWithStatus, layers::Layers, menu_bar::MenuBar, overlay::Overlay,
activity::ActivityStepperWithStatus, layers::Layers, menu_bar::MenuBar, overlay::Overlay,
painter::Painter,
};
@ -42,7 +42,7 @@ impl Viewport {
ctx: &egui::Context,
top: &MenuBar,
maybe_invoker: &mut Option<Invoker<SpecctraMesadata>>,
maybe_activity: &mut Option<ActivityWithStatus>,
maybe_activity: &mut Option<ActivityStepperWithStatus>,
maybe_overlay: &mut Option<Overlay>,
maybe_layers: &Option<Layers>,
) -> egui::Rect {
@ -67,7 +67,7 @@ impl Viewport {
ctx: &egui::Context,
top: &MenuBar,
maybe_invoker: &mut Option<Invoker<SpecctraMesadata>>,
maybe_activity: &mut Option<ActivityWithStatus>,
maybe_activity: &mut Option<ActivityStepperWithStatus>,
maybe_overlay: &mut Option<Overlay>,
maybe_layers: &Option<Layers>,
) -> egui::Rect {