diff --git a/src/autorouter/invoker.rs b/src/autorouter/invoker.rs index 123daab..374d765 100644 --- a/src/autorouter/invoker.rs +++ b/src/autorouter/invoker.rs @@ -45,6 +45,12 @@ pub trait GetObstacles { fn obstacles(&self) -> &[PrimitiveIndex]; } +#[derive(Debug, Clone)] +pub enum InvokerStatus { + Running, + Finished(String), +} + #[derive(Error, Debug, Clone)] pub enum InvokerError { #[error(transparent)] @@ -53,12 +59,6 @@ pub enum InvokerError { Autorouter(#[from] AutorouterError), } -#[derive(Debug, Clone)] -pub enum InvokerStatus { - Running, - Finished(String), -} - impl TryInto<()> for InvokerStatus { type Error = (); fn try_into(self) -> Result<(), ()> { diff --git a/src/bin/topola-egui/activity.rs b/src/bin/topola-egui/activity.rs index 51f58b8..073056a 100644 --- a/src/bin/topola-egui/activity.rs +++ b/src/bin/topola-egui/activity.rs @@ -15,7 +15,12 @@ use topola::{ stepper::{Abort, Step}, }; +use crate::interaction::{ + InteractionContext, InteractionError, InteractionStatus, InteractionStepper, +}; + pub struct ActivityContext<'a> { + pub interaction: InteractionContext, pub invoker: &'a mut Invoker, } @@ -25,6 +30,15 @@ pub enum ActivityStatus { Finished(String), } +impl From for ActivityStatus { + fn from(status: InteractionStatus) -> Self { + match status { + InteractionStatus::Running => ActivityStatus::Running, + InteractionStatus::Finished(msg) => ActivityStatus::Finished(msg), + } + } +} + impl From for ActivityStatus { fn from(status: InvokerStatus) -> Self { match status { @@ -46,18 +60,23 @@ impl TryInto<()> for ActivityStatus { #[derive(Error, Debug, Clone)] pub enum ActivityError { + #[error(transparent)] + Interaction(#[from] InteractionError), #[error(transparent)] Invoker(#[from] InvokerError), } pub enum ActivityStepper { - // There will be another variant for interactive activities here soon. (TODO) + Interaction(InteractionStepper), Execution(ExecutionStepper), } impl Step, ActivityStatus, ActivityError, ()> for ActivityStepper { fn step(&mut self, context: &mut ActivityContext) -> Result { match self { + ActivityStepper::Interaction(interaction) => { + Ok(interaction.step(&mut context.interaction)?.into()) + } ActivityStepper::Execution(execution) => Ok(execution.step(context.invoker)?.into()), } } @@ -66,6 +85,9 @@ impl Step, ActivityStatus, ActivityError, ()> for ActivitySt impl Abort> for ActivityStepper { fn abort(&mut self, context: &mut ActivityContext) { match self { + ActivityStepper::Interaction(interaction) => { + Ok(interaction.abort(&mut context.interaction)) + } ActivityStepper::Execution(execution) => execution.finish(context.invoker), // TODO. }; } @@ -75,6 +97,7 @@ impl GetMaybeNavmesh for ActivityStepper { /// Implemented manually instead of with `enum_dispatch` because it doesn't work across crates. fn maybe_navmesh(&self) -> Option<&Navmesh> { match self { + ActivityStepper::Interaction(interaction) => interaction.maybe_navmesh(), ActivityStepper::Execution(execution) => execution.maybe_navmesh(), } } @@ -84,6 +107,7 @@ impl GetMaybeTrace for ActivityStepper { /// Implemented manually instead of with `enum_dispatch` because it doesn't work across crates. fn maybe_trace(&self) -> Option<&TraceStepper> { match self { + ActivityStepper::Interaction(interaction) => interaction.maybe_trace(), ActivityStepper::Execution(execution) => execution.maybe_trace(), } } @@ -93,6 +117,7 @@ impl GetGhosts for ActivityStepper { /// Implemented manually instead of with `enum_dispatch` because it doesn't work across crates. fn ghosts(&self) -> &[PrimitiveShape] { match self { + ActivityStepper::Interaction(interaction) => interaction.ghosts(), ActivityStepper::Execution(execution) => execution.ghosts(), } } @@ -102,6 +127,7 @@ impl GetObstacles for ActivityStepper { /// Implemented manually instead of with `enum_dispatch` because it doesn't work across crates. fn obstacles(&self) -> &[PrimitiveIndex] { match self { + ActivityStepper::Interaction(interaction) => interaction.obstacles(), ActivityStepper::Execution(execution) => execution.obstacles(), } } diff --git a/src/bin/topola-egui/app.rs b/src/bin/topola-egui/app.rs index 359ff3a..aae1fde 100644 --- a/src/bin/topola-egui/app.rs +++ b/src/bin/topola-egui/app.rs @@ -22,6 +22,7 @@ use crate::{ activity::{ActivityContext, ActivityStatus, ActivityStepperWithStatus}, config::Config, error_dialog::ErrorDialog, + interaction::InteractionContext, layers::Layers, menu_bar::MenuBar, overlay::Overlay, @@ -170,7 +171,10 @@ impl App { } if let Some(ref mut activity) = self.maybe_activity { - return match activity.step(&mut ActivityContext { invoker }) { + return match activity.step(&mut ActivityContext { + interaction: InteractionContext {}, + invoker, + }) { Ok(ActivityStatus::Running) => true, Ok(ActivityStatus::Finished(..)) => false, Err(err) => { diff --git a/src/bin/topola-egui/interaction.rs b/src/bin/topola-egui/interaction.rs new file mode 100644 index 0000000..3dfa5e8 --- /dev/null +++ b/src/bin/topola-egui/interaction.rs @@ -0,0 +1,84 @@ +use thiserror::Error; +use topola::{ + autorouter::invoker::{GetGhosts, GetMaybeNavmesh, GetMaybeTrace, GetObstacles}, + drawing::graph::PrimitiveIndex, + geometry::primitive::PrimitiveShape, + router::{navmesh::Navmesh, trace::TraceStepper}, + stepper::{Abort, Step}, +}; + +use crate::activity::ActivityStepperWithStatus; + +pub struct InteractionContext { + // Empty for now. + // For example, this will contain mouse pointer position. + // (we will need an additional struct to hold a reference to a `Board<...>`) +} + +#[derive(Debug, Clone)] +pub enum InteractionStatus { + Running, + Finished(String), +} + +impl TryInto<()> for InteractionStatus { + type Error = (); + fn try_into(self) -> Result<(), ()> { + match self { + InteractionStatus::Running => Err(()), + InteractionStatus::Finished(..) => Ok(()), + } + } +} + +#[derive(Error, Debug, Clone)] +pub enum InteractionError { + #[error("nothing to interact with")] + NothingToInteract, +} + +pub enum InteractionStepper { + // No interactions yet. This is only an empty skeleton for now. + // Examples of interactions: + // - interactively routing a track + // - interactively moving a footprint. +} + +impl Step for InteractionStepper { + fn step( + &mut self, + invoker: &mut InteractionContext, + ) -> Result { + Ok(InteractionStatus::Finished(String::from(""))) + } +} + +impl Abort for InteractionStepper { + fn abort(&mut self, context: &mut InteractionContext) { + todo!(); + } +} + +impl GetMaybeNavmesh for InteractionStepper { + fn maybe_navmesh(&self) -> Option<&Navmesh> { + todo!() + } +} + +impl GetMaybeTrace for InteractionStepper { + fn maybe_trace(&self) -> Option<&TraceStepper> { + todo!() + } +} + +impl GetGhosts for InteractionStepper { + fn ghosts(&self) -> &[PrimitiveShape] { + todo!() + } +} + +impl GetObstacles for InteractionStepper { + fn obstacles(&self) -> &[PrimitiveIndex] { + todo!() + } +} diff --git a/src/bin/topola-egui/main.rs b/src/bin/topola-egui/main.rs index 274e84e..6eb4408 100644 --- a/src/bin/topola-egui/main.rs +++ b/src/bin/topola-egui/main.rs @@ -5,6 +5,7 @@ mod activity; mod app; mod config; mod error_dialog; +mod interaction; mod layers; mod menu_bar; mod overlay; diff --git a/src/bin/topola-egui/menu_bar.rs b/src/bin/topola-egui/menu_bar.rs index f545197..dab8ad5 100644 --- a/src/bin/topola-egui/menu_bar.rs +++ b/src/bin/topola-egui/menu_bar.rs @@ -22,6 +22,7 @@ use crate::{ action::{Action, Switch, Trigger}, activity::{ActivityContext, ActivityStatus, ActivityStepperWithStatus}, app::{execute, handle_file}, + interaction::InteractionContext, overlay::Overlay, translator::Translator, viewport::Viewport, @@ -331,7 +332,10 @@ impl MenuBar { } 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(&mut ActivityContext { invoker }); + activity.abort(&mut ActivityContext { + interaction: InteractionContext {}, + invoker, + }); } } } else if remove_bands.consume_key_triggered(ctx, ui) { diff --git a/src/board/board.rs b/src/board/board.rs index dfab4ea..6799b76 100644 --- a/src/board/board.rs +++ b/src/board/board.rs @@ -77,7 +77,7 @@ impl Board { } /// Adds a fixed segment between two dots with an optional pin name. - /// + /// /// Adds the segment to the layout and maps the pin name to the created segment if provided. pub fn add_poly_fixed_dot_infringably( &mut self, @@ -95,7 +95,7 @@ impl Board { } /// Adds a fixed segment associated with a polygon in the layout. - /// + /// /// Adds the segment to the layout and updates the internal mapping if necessary. pub fn add_fixed_seg_infringably( &mut self, @@ -135,7 +135,7 @@ impl Board { seg } - + /// Adds a new polygon to the layout with an optional pin name. /// /// Inserts the polygon into the layout and, if a pin name is provided, maps it to the created polygon's node. @@ -153,7 +153,7 @@ impl Board { poly } - + /// Retrieves or creates the apex (top point) of a polygon in the layout. /// /// If the polygon already has an apex, returns it. Otherwise, creates and returns a new fixed dot as the apex. diff --git a/src/board/mesadata.rs b/src/board/mesadata.rs index 64c9fc1..e368c92 100644 --- a/src/board/mesadata.rs +++ b/src/board/mesadata.rs @@ -24,8 +24,3 @@ pub trait AccessMesadata: AccessRules { /// Retrieves the index of a net by its name. fn netname_net(&self, netname: &str) -> Option; } - - - - -