egui: s/ExecuteWithStatus/ActivityWithStatus, move it to own file

This commit is contained in:
Mikolaj Wielgus 2024-09-30 01:36:22 +02:00
parent a700bd8c20
commit c8a40860af
7 changed files with 149 additions and 112 deletions

View File

@ -1,10 +1,28 @@
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{board::mesadata::AccessMesadata, drawing::graph::PrimitiveIndex, geometry::primitive::PrimitiveShape, layout::via::ViaWeight, router::{navmesh::Navmesh, trace::Trace}, step::Step}; use crate::{
board::mesadata::AccessMesadata,
use super::{autoroute::{Autoroute, AutorouteStatus}, compare_detours::{CompareDetours, CompareDetoursStatus}, invoker::{GetGhosts, GetMaybeNavmesh, GetMaybeTrace, GetObstacles, Invoker, InvokerError, InvokerStatus}, measure_length::MeasureLength, place_via::PlaceVia, remove_bands::RemoveBands, selection::{BandSelection, PinSelection}, AutorouterOptions}; drawing::graph::PrimitiveIndex,
geometry::primitive::PrimitiveShape,
layout::via::ViaWeight,
router::{navmesh::Navmesh, trace::Trace},
step::Step,
};
use super::{
autoroute::{Autoroute, AutorouteStatus},
compare_detours::{CompareDetours, CompareDetoursStatus},
invoker::{
GetGhosts, GetMaybeNavmesh, GetMaybeTrace, GetObstacles, Invoker, InvokerError,
InvokerStatus,
},
measure_length::MeasureLength,
place_via::PlaceVia,
remove_bands::RemoveBands,
selection::{BandSelection, PinSelection},
AutorouterOptions,
};
type Type = PinSelection; type Type = PinSelection;
@ -91,54 +109,3 @@ impl<M: AccessMesadata> Step<Invoker<M>, InvokerStatus, InvokerError, ()> for Ex
} }
} }
} }
pub struct ExecuteWithStatus {
execute: Execute,
maybe_status: Option<InvokerStatus>,
}
impl ExecuteWithStatus {
pub fn new(execute: Execute) -> ExecuteWithStatus {
Self {
execute,
maybe_status: None,
}
}
pub fn step<M: AccessMesadata>(
&mut self,
invoker: &mut Invoker<M>,
) -> Result<InvokerStatus, InvokerError> {
let status = self.execute.step(invoker)?;
self.maybe_status = Some(status.clone());
Ok(status)
}
pub fn maybe_status(&self) -> Option<InvokerStatus> {
self.maybe_status.clone()
}
}
impl GetMaybeNavmesh for ExecuteWithStatus {
fn maybe_navmesh(&self) -> Option<&Navmesh> {
self.execute.maybe_navmesh()
}
}
impl GetMaybeTrace for ExecuteWithStatus {
fn maybe_trace(&self) -> Option<&Trace> {
self.execute.maybe_trace()
}
}
impl GetGhosts for ExecuteWithStatus {
fn ghosts(&self) -> &[PrimitiveShape] {
self.execute.ghosts()
}
}
impl GetObstacles for ExecuteWithStatus {
fn obstacles(&self) -> &[PrimitiveIndex] {
self.execute.obstacles()
}
}

View File

@ -0,0 +1,65 @@
use topola::{
autorouter::{
execute::Execute,
invoker::{
GetGhosts, GetMaybeNavmesh, GetMaybeTrace, GetObstacles, Invoker, InvokerError,
InvokerStatus,
},
},
board::mesadata::AccessMesadata,
drawing::graph::PrimitiveIndex,
geometry::primitive::PrimitiveShape,
router::{navmesh::Navmesh, trace::Trace},
step::Step,
};
pub struct ActivityWithStatus {
execute: Execute,
maybe_status: Option<InvokerStatus>,
}
impl ActivityWithStatus {
pub fn new_execute(execute: Execute) -> ActivityWithStatus {
Self {
execute,
maybe_status: None,
}
}
pub fn step<M: AccessMesadata>(
&mut self,
invoker: &mut Invoker<M>,
) -> Result<InvokerStatus, InvokerError> {
let status = self.execute.step(invoker)?;
self.maybe_status = Some(status.clone());
Ok(status)
}
pub fn maybe_status(&self) -> Option<InvokerStatus> {
self.maybe_status.clone()
}
}
impl GetMaybeNavmesh for ActivityWithStatus {
fn maybe_navmesh(&self) -> Option<&Navmesh> {
self.execute.maybe_navmesh()
}
}
impl GetMaybeTrace for ActivityWithStatus {
fn maybe_trace(&self) -> Option<&Trace> {
self.execute.maybe_trace()
}
}
impl GetGhosts for ActivityWithStatus {
fn ghosts(&self) -> &[PrimitiveShape] {
self.execute.ghosts()
}
}
impl GetObstacles for ActivityWithStatus {
fn obstacles(&self) -> &[PrimitiveIndex] {
self.execute.obstacles()
}
}

View File

@ -14,7 +14,6 @@ use unic_langid::{langid, LanguageIdentifier};
use topola::{ use topola::{
autorouter::{ autorouter::{
execute::ExecuteWithStatus,
invoker::{Invoker, InvokerStatus}, invoker::{Invoker, InvokerStatus},
Autorouter, Autorouter,
}, },
@ -43,8 +42,8 @@ use topola::{
}; };
use crate::{ use crate::{
bottom::Bottom, file_receiver::FileReceiver, layers::Layers, overlay::Overlay, activity::ActivityWithStatus, bottom::Bottom, file_receiver::FileReceiver, layers::Layers,
painter::Painter, top::Top, translator::Translator, viewport::Viewport, overlay::Overlay, painter::Painter, top::Top, translator::Translator, viewport::Viewport,
}; };
/// Deserialize/Serialize is needed to persist app state between restarts. /// Deserialize/Serialize is needed to persist app state between restarts.
@ -60,7 +59,7 @@ pub struct App {
arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>, arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>,
#[serde(skip)] #[serde(skip)]
maybe_execute: Option<ExecuteWithStatus>, maybe_activity: Option<ActivityWithStatus>,
#[serde(skip)] #[serde(skip)]
content_channel: (Sender<String>, Receiver<String>), content_channel: (Sender<String>, Receiver<String>),
@ -93,7 +92,7 @@ impl Default for App {
translator: Translator::new(langid!("en-US")), translator: Translator::new(langid!("en-US")),
maybe_overlay: None, maybe_overlay: None,
arc_mutex_maybe_invoker: Arc::new(Mutex::new(None)), arc_mutex_maybe_invoker: Arc::new(Mutex::new(None)),
maybe_execute: None, maybe_activity: None,
content_channel: channel(), content_channel: channel(),
history_channel: channel(), history_channel: channel(),
viewport: Viewport::new(), viewport: Viewport::new(),
@ -158,8 +157,8 @@ impl App {
invoker.replay(serde_json::from_reader(bufread).unwrap()) invoker.replay(serde_json::from_reader(bufread).unwrap())
} }
if let Some(ref mut execute) = self.maybe_execute { if let Some(ref mut activity) = self.maybe_activity {
match execute.step(invoker) { match activity.step(invoker) {
Ok(InvokerStatus::Running) => return true, Ok(InvokerStatus::Running) => return true,
Ok(InvokerStatus::Finished(..)) => return false, Ok(InvokerStatus::Finished(..)) => return false,
Err(err) => return false, Err(err) => return false,
@ -185,7 +184,7 @@ impl eframe::App for App {
self.content_channel.0.clone(), self.content_channel.0.clone(),
self.history_channel.0.clone(), self.history_channel.0.clone(),
self.arc_mutex_maybe_invoker.clone(), self.arc_mutex_maybe_invoker.clone(),
&mut self.maybe_execute, &mut self.maybe_activity,
&mut self.viewport, &mut self.viewport,
&mut self.maybe_overlay, &mut self.maybe_overlay,
&self.maybe_design, &self.maybe_design,
@ -194,7 +193,7 @@ impl eframe::App for App {
self.advance_state_by_dt(ctx.input(|i| i.stable_dt)); self.advance_state_by_dt(ctx.input(|i| i.stable_dt));
self.bottom self.bottom
.update(ctx, &self.translator, &self.viewport, &self.maybe_execute); .update(ctx, &self.translator, &self.viewport, &self.maybe_activity);
if self.top.show_layer_manager { if self.top.show_layer_manager {
if let Some(ref mut layers) = self.maybe_layers { if let Some(ref mut layers) = self.maybe_layers {
@ -208,7 +207,7 @@ impl eframe::App for App {
ctx, ctx,
&self.top, &self.top,
&mut self.arc_mutex_maybe_invoker.lock().unwrap(), &mut self.arc_mutex_maybe_invoker.lock().unwrap(),
&mut self.maybe_execute, &mut self.maybe_activity,
&mut self.maybe_overlay, &mut self.maybe_overlay,
&self.maybe_layers, &self.maybe_layers,
); );

View File

@ -1,6 +1,6 @@
use topola::autorouter::{execute::ExecuteWithStatus, invoker::InvokerStatus}; use topola::autorouter::invoker::InvokerStatus;
use crate::{translator::Translator, viewport::Viewport}; use crate::{activity::ActivityWithStatus, translator::Translator, viewport::Viewport};
pub struct Bottom {} pub struct Bottom {}
@ -14,7 +14,7 @@ impl Bottom {
ctx: &egui::Context, ctx: &egui::Context,
tr: &Translator, tr: &Translator,
viewport: &Viewport, viewport: &Viewport,
maybe_execute: &Option<ExecuteWithStatus>, maybe_activity: &Option<ActivityWithStatus>,
) { ) {
egui::TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| { egui::TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| {
let latest_pos = viewport.transform.inverse() let latest_pos = viewport.transform.inverse()
@ -22,8 +22,8 @@ impl Bottom {
let mut message = String::from(""); let mut message = String::from("");
if let Some(execute) = maybe_execute { if let Some(activity) = maybe_activity {
if let Some(InvokerStatus::Finished(msg)) = execute.maybe_status() { if let Some(InvokerStatus::Finished(msg)) = activity.maybe_status() {
message = msg; message = msg;
} }
} }

View File

@ -1,6 +1,7 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
mod action; mod action;
mod activity;
mod app; mod app;
mod bottom; mod bottom;
mod file_receiver; mod file_receiver;

View File

@ -6,7 +6,7 @@ use std::{
use topola::{ use topola::{
autorouter::{ autorouter::{
execute::{Command, ExecuteWithStatus}, execute::Command,
invoker::{Invoker, InvokerError, InvokerStatus}, invoker::{Invoker, InvokerError, InvokerStatus},
AutorouterOptions, AutorouterOptions,
}, },
@ -16,6 +16,7 @@ use topola::{
use crate::{ use crate::{
action::{Action, Switch, Trigger}, action::{Action, Switch, Trigger},
activity::ActivityWithStatus,
app::execute, app::execute,
file_sender::FileSender, file_sender::FileSender,
overlay::Overlay, overlay::Overlay,
@ -61,7 +62,7 @@ impl Top {
content_sender: Sender<String>, content_sender: Sender<String>,
history_sender: Sender<String>, history_sender: Sender<String>,
arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>, arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>,
maybe_execute: &mut Option<ExecuteWithStatus>, maybe_activity: &mut Option<ActivityWithStatus>,
viewport: &mut Viewport, viewport: &mut Viewport,
maybe_overlay: &mut Option<Overlay>, maybe_overlay: &mut Option<Overlay>,
maybe_design: &Option<SpecctraDesign>, maybe_design: &Option<SpecctraDesign>,
@ -233,9 +234,7 @@ impl Top {
}); });
} else if export_session.consume_key_triggered(ctx, ui) { } else if export_session.consume_key_triggered(ctx, ui) {
if let Some(design) = maybe_design { if let Some(design) = maybe_design {
if let Some(invoker) = if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_ref() {
arc_mutex_maybe_invoker.lock().unwrap().as_ref()
{
let ctx = ui.ctx().clone(); let ctx = ui.ctx().clone();
let board = invoker.autorouter().board(); let board = invoker.autorouter().board();
@ -274,8 +273,7 @@ impl Top {
} }
}); });
} else if export_history.consume_key_triggered(ctx, ui) { } else if export_history.consume_key_triggered(ctx, ui) {
if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_ref() if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_ref() {
{
let ctx = ctx.clone(); let ctx = ctx.clone();
let task = rfd::AsyncFileDialog::new().save_file(); let task = rfd::AsyncFileDialog::new().save_file();
@ -293,8 +291,8 @@ impl Top {
} else if quit.consume_key_triggered(ctx, ui) { } else if quit.consume_key_triggered(ctx, ui) {
ctx.send_viewport_cmd(egui::ViewportCommand::Close); ctx.send_viewport_cmd(egui::ViewportCommand::Close);
} else if autoroute.consume_key_triggered(ctx, ui) { } else if autoroute.consume_key_triggered(ctx, ui) {
if maybe_execute.as_mut().map_or(true, |execute| { if maybe_activity.as_mut().map_or(true, |activity| {
matches!(execute.maybe_status(), Some(InvokerStatus::Finished(..))) matches!(activity.maybe_status(), Some(InvokerStatus::Finished(..)))
}) { }) {
if let (Some(invoker), Some(ref mut overlay)) = ( if let (Some(invoker), Some(ref mut overlay)) = (
arc_mutex_maybe_invoker.lock().unwrap().as_mut(), arc_mutex_maybe_invoker.lock().unwrap().as_mut(),
@ -302,18 +300,18 @@ impl Top {
) { ) {
let selection = overlay.selection().clone(); let selection = overlay.selection().clone();
overlay.clear_selection(); overlay.clear_selection();
maybe_execute.insert(ExecuteWithStatus::new(invoker.execute_stepper( maybe_activity.insert(ActivityWithStatus::new_execute(
Command::Autoroute( invoker.execute_stepper(Command::Autoroute(
selection.pin_selection, selection.pin_selection,
self.autorouter_options, self.autorouter_options,
), ))?,
)?)); ));
} }
} }
} else if place_via.consume_key_enabled(ctx, ui, &mut self.is_placing_via) { } else if place_via.consume_key_enabled(ctx, ui, &mut self.is_placing_via) {
} else if remove_bands.consume_key_triggered(ctx, ui) { } else if remove_bands.consume_key_triggered(ctx, ui) {
if maybe_execute.as_mut().map_or(true, |execute| { if maybe_activity.as_mut().map_or(true, |activity| {
matches!(execute.maybe_status(), Some(InvokerStatus::Finished(..))) matches!(activity.maybe_status(), Some(InvokerStatus::Finished(..)))
}) { }) {
if let (Some(invoker), Some(ref mut overlay)) = ( if let (Some(invoker), Some(ref mut overlay)) = (
arc_mutex_maybe_invoker.lock().unwrap().as_mut(), arc_mutex_maybe_invoker.lock().unwrap().as_mut(),
@ -321,14 +319,16 @@ impl Top {
) { ) {
let selection = overlay.selection().clone(); let selection = overlay.selection().clone();
overlay.clear_selection(); overlay.clear_selection();
maybe_execute.insert(ExecuteWithStatus::new(invoker.execute_stepper( maybe_activity.insert(ActivityWithStatus::new_execute(
Command::RemoveBands(selection.band_selection), invoker.execute_stepper(Command::RemoveBands(
)?)); selection.band_selection,
))?,
));
} }
} }
} else if measure_length.consume_key_triggered(ctx, ui) { } else if measure_length.consume_key_triggered(ctx, ui) {
if maybe_execute.as_mut().map_or(true, |execute| { if maybe_activity.as_mut().map_or(true, |activity| {
matches!(execute.maybe_status(), Some(InvokerStatus::Finished(..))) matches!(activity.maybe_status(), Some(InvokerStatus::Finished(..)))
}) { }) {
if let (Some(invoker), Some(ref mut overlay)) = ( if let (Some(invoker), Some(ref mut overlay)) = (
arc_mutex_maybe_invoker.lock().unwrap().as_mut(), arc_mutex_maybe_invoker.lock().unwrap().as_mut(),
@ -336,9 +336,11 @@ impl Top {
) { ) {
let selection = overlay.selection().clone(); let selection = overlay.selection().clone();
overlay.clear_selection(); overlay.clear_selection();
maybe_execute.insert(ExecuteWithStatus::new(invoker.execute_stepper( maybe_activity.insert(ActivityWithStatus::new_execute(
Command::MeasureLength(selection.band_selection), invoker.execute_stepper(Command::MeasureLength(
)?)); selection.band_selection,
))?,
));
} }
} }
} else if undo.consume_key_triggered(ctx, ui) { } else if undo.consume_key_triggered(ctx, ui) {
@ -350,8 +352,8 @@ impl Top {
invoker.redo(); invoker.redo();
} }
} else if compare_detours.consume_key_triggered(ctx, ui) { } else if compare_detours.consume_key_triggered(ctx, ui) {
if maybe_execute.as_mut().map_or(true, |execute| { if maybe_activity.as_mut().map_or(true, |activity| {
matches!(execute.maybe_status(), Some(InvokerStatus::Finished(..))) matches!(activity.maybe_status(), Some(InvokerStatus::Finished(..)))
}) { }) {
if let (Some(invoker), Some(ref mut overlay)) = ( if let (Some(invoker), Some(ref mut overlay)) = (
arc_mutex_maybe_invoker.lock().unwrap().as_mut(), arc_mutex_maybe_invoker.lock().unwrap().as_mut(),
@ -359,12 +361,12 @@ impl Top {
) { ) {
let selection = overlay.selection().clone(); let selection = overlay.selection().clone();
overlay.clear_selection(); overlay.clear_selection();
maybe_execute.insert(ExecuteWithStatus::new(invoker.execute_stepper( maybe_activity.insert(ActivityWithStatus::new_execute(
Command::CompareDetours( invoker.execute_stepper(Command::CompareDetours(
selection.pin_selection, selection.pin_selection,
self.autorouter_options, self.autorouter_options,
), ))?,
)?)); ));
} }
} }
} }

View File

@ -6,7 +6,7 @@ use petgraph::{
use rstar::{Envelope, AABB}; use rstar::{Envelope, AABB};
use topola::{ use topola::{
autorouter::{ autorouter::{
execute::{Command, ExecuteWithStatus}, execute::Command,
invoker::{GetGhosts, GetMaybeNavmesh, GetMaybeTrace, GetObstacles, Invoker}, invoker::{GetGhosts, GetMaybeNavmesh, GetMaybeTrace, GetObstacles, Invoker},
}, },
board::mesadata::AccessMesadata, board::mesadata::AccessMesadata,
@ -20,7 +20,10 @@ use topola::{
specctra::mesadata::SpecctraMesadata, specctra::mesadata::SpecctraMesadata,
}; };
use crate::{app::execute, layers::Layers, overlay::Overlay, painter::Painter, top::Top}; use crate::{
activity::ActivityWithStatus, app::execute, layers::Layers, overlay::Overlay, painter::Painter,
top::Top,
};
pub struct Viewport { pub struct Viewport {
pub transform: egui::emath::TSTransform, pub transform: egui::emath::TSTransform,
@ -40,7 +43,7 @@ impl Viewport {
ctx: &egui::Context, ctx: &egui::Context,
top: &Top, top: &Top,
maybe_invoker: &mut Option<Invoker<SpecctraMesadata>>, maybe_invoker: &mut Option<Invoker<SpecctraMesadata>>,
maybe_execute: &mut Option<ExecuteWithStatus>, maybe_activity: &mut Option<ActivityWithStatus>,
maybe_overlay: &mut Option<Overlay>, maybe_overlay: &mut Option<Overlay>,
maybe_layers: &Option<Layers>, maybe_layers: &Option<Layers>,
) -> egui::Rect { ) -> egui::Rect {
@ -48,7 +51,7 @@ impl Viewport {
ctx, ctx,
top, top,
maybe_invoker, maybe_invoker,
maybe_execute, maybe_activity,
maybe_overlay, maybe_overlay,
maybe_layers, maybe_layers,
); );
@ -65,7 +68,7 @@ impl Viewport {
ctx: &egui::Context, ctx: &egui::Context,
top: &Top, top: &Top,
maybe_invoker: &mut Option<Invoker<SpecctraMesadata>>, maybe_invoker: &mut Option<Invoker<SpecctraMesadata>>,
maybe_execute: &mut Option<ExecuteWithStatus>, maybe_activity: &mut Option<ActivityWithStatus>,
maybe_overlay: &mut Option<Overlay>, maybe_overlay: &mut Option<Overlay>,
maybe_layers: &Option<Layers>, maybe_layers: &Option<Layers>,
) -> egui::Rect { ) -> egui::Rect {
@ -124,8 +127,8 @@ impl Viewport {
{ {
layers.highlight_colors[i] layers.highlight_colors[i]
} else { } else {
if let Some(execute) = maybe_execute { if let Some(activity) = maybe_activity {
if execute.obstacles().contains(&primitive) { if activity.obstacles().contains(&primitive) {
layers.highlight_colors[i] layers.highlight_colors[i]
} else { } else {
layers.colors[i] layers.colors[i]
@ -178,8 +181,8 @@ impl Viewport {
} }
if top.show_navmesh { if top.show_navmesh {
if let Some(execute) = maybe_execute { if let Some(activity) = maybe_activity {
if let Some(navmesh) = execute.maybe_navmesh() { if let Some(navmesh) = activity.maybe_navmesh() {
for edge in navmesh.edge_references() { for edge in navmesh.edge_references() {
let mut from = PrimitiveIndex::from(navmesh.node_weight(edge.source()).unwrap().node) let mut from = PrimitiveIndex::from(navmesh.node_weight(edge.source()).unwrap().node)
.primitive(board.layout().drawing()) .primitive(board.layout().drawing())
@ -208,11 +211,11 @@ impl Viewport {
let stroke = 'blk: { let stroke = 'blk: {
if let (Some(source_pos), Some(target_pos)) = ( if let (Some(source_pos), Some(target_pos)) = (
execute.maybe_trace().map(|trace| activity.maybe_trace().map(|trace|
trace.path trace.path
.iter() .iter()
.position(|node| *node == edge.source())).flatten(), .position(|node| *node == edge.source())).flatten(),
execute.maybe_trace().map(|trace| activity.maybe_trace().map(|trace|
trace.path trace.path
.iter() .iter()
.position(|node| *node == edge.target())).flatten(), .position(|node| *node == edge.target())).flatten(),
@ -243,12 +246,12 @@ impl Viewport {
painter.paint_bbox(root_bbox); painter.paint_bbox(root_bbox);
} }
if let Some(execute) = maybe_execute { if let Some(activity) = maybe_activity {
for ghost in execute.ghosts().iter() { for ghost in activity.ghosts().iter() {
painter.paint_primitive(&ghost, egui::Color32::from_rgb(75, 75, 150)); painter.paint_primitive(&ghost, egui::Color32::from_rgb(75, 75, 150));
} }
if let Some(navmesh) = execute.maybe_navmesh() { if let Some(navmesh) = activity.maybe_navmesh() {
if top.show_origin_destination { if top.show_origin_destination {
if let (origin, destination) = (navmesh.origin(), navmesh.destination()) { if let (origin, destination) = (navmesh.origin(), navmesh.destination()) {
painter.paint_dot( painter.paint_dot(