egui: keep activity status after activity finished

This commit is contained in:
Alain Emilia Anna Zscheile 2024-10-05 13:41:06 +02:00
parent 76537e7dfa
commit 8a372c4a7a
5 changed files with 156 additions and 155 deletions

View File

@ -106,21 +106,29 @@ impl GetObstacles for ActivityStepper {
} }
} }
#[derive(Default)]
pub struct ActivityStepperWithStatus { pub struct ActivityStepperWithStatus {
activity: ActivityStepper, pub maybe_activity: Option<ActivityStepper>,
maybe_status: Option<Poll<String>>, pub maybe_status: Option<Poll<String>>,
} }
impl ActivityStepperWithStatus { impl ActivityStepperWithStatus {
pub fn new_execution(execution: ExecutionStepper) -> ActivityStepperWithStatus { pub fn new_execution(execution: ExecutionStepper) -> ActivityStepperWithStatus {
Self { Self {
activity: ActivityStepper::Execution(execution), maybe_activity: Some(ActivityStepper::Execution(execution)),
maybe_status: None, maybe_status: None,
} }
} }
pub fn maybe_status(&self) -> Option<Poll<String>> { pub fn is_busy(&self) -> bool {
self.maybe_status.clone() if self.maybe_activity.is_none() {
return false;
}
// this might be left over from a previous execution
//if let Some(Poll::Ready(_)) = &self.maybe_status {
// return false;
//}
true
} }
} }
@ -133,7 +141,14 @@ impl PollStep<ActivityContext<'_>, String> for ActivityStepperWithStatus {
&mut self, &mut self,
context: &mut ActivityContext<'_>, context: &mut ActivityContext<'_>,
) -> Poll<Result<String, ActivityError>> { ) -> Poll<Result<String, ActivityError>> {
let res = self.activity.poll_step(context); let res = match &mut self.maybe_activity {
None => return Poll::Pending,
Some(act) => act.poll_step(context),
};
// fused stepping
if let Poll::Ready(_) = &res {
self.maybe_activity = None;
}
self.maybe_status = match &res { self.maybe_status = match &res {
Poll::Pending => Some(Poll::Pending), Poll::Pending => Some(Poll::Pending),
Poll::Ready(Ok(msg)) => Some(Poll::Ready(msg.clone())), Poll::Ready(Ok(msg)) => Some(Poll::Ready(msg.clone())),
@ -145,31 +160,39 @@ impl PollStep<ActivityContext<'_>, String> for ActivityStepperWithStatus {
impl Abort<ActivityContext<'_>> for ActivityStepperWithStatus { impl Abort<ActivityContext<'_>> for ActivityStepperWithStatus {
fn abort(&mut self, context: &mut ActivityContext<'_>) { fn abort(&mut self, context: &mut ActivityContext<'_>) {
if let Some(mut act) = self.maybe_activity.take() {
self.maybe_status = Some(Poll::Ready("aborted".to_string())); self.maybe_status = Some(Poll::Ready("aborted".to_string()));
self.activity.abort(context); act.abort(context);
}
} }
} }
impl GetMaybeNavmesh for ActivityStepperWithStatus { impl GetMaybeNavmesh for ActivityStepperWithStatus {
fn maybe_navmesh(&self) -> Option<&Navmesh> { fn maybe_navmesh(&self) -> Option<&Navmesh> {
self.activity.maybe_navmesh() self.maybe_activity.as_ref()?.maybe_navmesh()
} }
} }
impl GetMaybeTrace for ActivityStepperWithStatus { impl GetMaybeTrace for ActivityStepperWithStatus {
fn maybe_trace(&self) -> Option<&TraceStepper> { fn maybe_trace(&self) -> Option<&TraceStepper> {
self.activity.maybe_trace() self.maybe_activity.as_ref()?.maybe_trace()
} }
} }
impl GetGhosts for ActivityStepperWithStatus { impl GetGhosts for ActivityStepperWithStatus {
fn ghosts(&self) -> &[PrimitiveShape] { fn ghosts(&self) -> &[PrimitiveShape] {
self.activity.ghosts() match &self.maybe_activity {
None => &[],
Some(act) => act.ghosts(),
}
} }
} }
impl GetObstacles for ActivityStepperWithStatus { impl GetObstacles for ActivityStepperWithStatus {
fn obstacles(&self) -> &[PrimitiveIndex] { fn obstacles(&self) -> &[PrimitiveIndex] {
self.activity.obstacles() match &self.maybe_activity {
None => &[],
Some(act) => act.obstacles(),
}
} }
} }

View File

@ -40,7 +40,7 @@ pub struct App {
arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>, arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>,
maybe_activity: Option<ActivityStepperWithStatus>, activity: ActivityStepperWithStatus,
content_channel: ( content_channel: (
Sender<Result<SpecctraDesign, SpecctraLoadingError>>, Sender<Result<SpecctraDesign, SpecctraLoadingError>>,
@ -71,7 +71,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_activity: None, activity: ActivityStepperWithStatus::default(),
content_channel: channel(), content_channel: channel(),
history_channel: channel(), history_channel: channel(),
viewport: Viewport::new(), viewport: Viewport::new(),
@ -171,8 +171,11 @@ impl App {
} }
} }
if let Some(ref mut activity) = self.maybe_activity { if self.activity.maybe_activity.is_none() {
return match activity.poll_step(&mut ActivityContext { return false;
}
return match self.activity.poll_step(&mut ActivityContext {
interaction: InteractionContext {}, interaction: InteractionContext {},
invoker, invoker,
}) { }) {
@ -182,12 +185,11 @@ impl App {
self.error_dialog self.error_dialog
.push_error("tr-module-invoker", format!("{}", err)); .push_error("tr-module-invoker", format!("{}", err));
} }
self.maybe_activity = None; self.activity.maybe_activity = None;
false false
} }
}; };
} }
}
false false
} }
@ -233,7 +235,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_activity, &mut self.activity,
&mut self.viewport, &mut self.viewport,
&mut self.maybe_overlay, &mut self.maybe_overlay,
&self.maybe_design, &self.maybe_design,
@ -242,7 +244,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.status_bar self.status_bar
.update(ctx, &self.translator, &self.viewport, &self.maybe_activity); .update(ctx, &self.translator, &self.viewport, &self.activity);
if self.menu_bar.show_layer_manager { if self.menu_bar.show_layer_manager {
if let Some(ref mut layers) = self.maybe_layers { if let Some(ref mut layers) = self.maybe_layers {
@ -258,7 +260,7 @@ impl eframe::App for App {
ctx, ctx,
&self.menu_bar, &self.menu_bar,
&mut self.arc_mutex_maybe_invoker.lock().unwrap(), &mut self.arc_mutex_maybe_invoker.lock().unwrap(),
&mut self.maybe_activity, &mut self.activity,
&mut self.maybe_overlay, &mut self.maybe_overlay,
&self.maybe_layers, &self.maybe_layers,
); );

View File

@ -21,7 +21,7 @@ use topola::{
use crate::{ use crate::{
action::{Action, Switch, Trigger}, action::{Action, Switch, Trigger},
activity::{ActivityContext, ActivityStepperWithStatus}, activity::{ActivityContext, ActivityStepper, ActivityStepperWithStatus},
app::{execute, handle_file}, app::{execute, handle_file},
interaction::InteractionContext, interaction::InteractionContext,
overlay::Overlay, overlay::Overlay,
@ -67,7 +67,7 @@ impl MenuBar {
content_sender: Sender<Result<SpecctraDesign, SpecctraLoadingError>>, content_sender: Sender<Result<SpecctraDesign, SpecctraLoadingError>>,
history_sender: Sender<std::io::Result<Result<History, serde_json::Error>>>, history_sender: Sender<std::io::Result<Result<History, serde_json::Error>>>,
arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>, arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>,
maybe_activity: &mut Option<ActivityStepperWithStatus>, activity: &mut ActivityStepperWithStatus,
viewport: &mut Viewport, viewport: &mut Viewport,
maybe_overlay: &mut Option<Overlay>, maybe_overlay: &mut Option<Overlay>,
maybe_design: &Option<SpecctraDesign>, maybe_design: &Option<SpecctraDesign>,
@ -331,41 +331,34 @@ impl MenuBar {
invoker.redo(); invoker.redo();
} }
} else if abort.consume_key_triggered(ctx, ui) { } 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() { if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_mut() {
activity.abort(&mut ActivityContext { activity.abort(&mut ActivityContext {
interaction: InteractionContext {}, interaction: InteractionContext {},
invoker, invoker,
}); });
} }
}
} else if remove_bands.consume_key_triggered(ctx, ui) { } else if remove_bands.consume_key_triggered(ctx, ui) {
if maybe_activity.as_mut().map_or(true, |activity| { if !activity.is_busy() {
matches!(activity.maybe_status(), Some(Poll::Ready(..)))
}) {
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(),
maybe_overlay, maybe_overlay,
) { ) {
let selection = overlay.take_selection(); let selection = overlay.take_selection();
*maybe_activity = Some(ActivityStepperWithStatus::new_execution( activity.maybe_activity =
invoker.execute_stepper(Command::RemoveBands( Some(ActivityStepper::Execution(invoker.execute_stepper(
selection.band_selection, Command::RemoveBands(selection.band_selection),
))?, )?));
));
} }
} }
} 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 autoroute.consume_key_triggered(ctx, ui) { } else if autoroute.consume_key_triggered(ctx, ui) {
if maybe_activity.as_mut().map_or(true, |activity| { if !activity.is_busy() {
matches!(activity.maybe_status(), Some(Poll::Ready(..)))
}) {
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(),
maybe_overlay, maybe_overlay,
) { ) {
let selection = overlay.take_selection(); let selection = overlay.take_selection();
*maybe_activity = Some(ActivityStepperWithStatus::new_execution( activity.maybe_activity = Some(ActivityStepper::Execution(
invoker.execute_stepper(Command::Autoroute( invoker.execute_stepper(Command::Autoroute(
selection.pin_selection, selection.pin_selection,
self.autorouter_options, self.autorouter_options,
@ -374,15 +367,13 @@ impl MenuBar {
} }
} }
} else if compare_detours.consume_key_triggered(ctx, ui) { } else if compare_detours.consume_key_triggered(ctx, ui) {
if maybe_activity.as_mut().map_or(true, |activity| { if !activity.is_busy() {
matches!(activity.maybe_status(), Some(Poll::Ready(..)))
}) {
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(),
maybe_overlay, maybe_overlay,
) { ) {
let selection = overlay.take_selection(); let selection = overlay.take_selection();
*maybe_activity = Some(ActivityStepperWithStatus::new_execution( activity.maybe_activity = Some(ActivityStepper::Execution(
invoker.execute_stepper(Command::CompareDetours( invoker.execute_stepper(Command::CompareDetours(
selection.pin_selection, selection.pin_selection,
self.autorouter_options, self.autorouter_options,
@ -391,19 +382,16 @@ impl MenuBar {
} }
} }
} else if measure_length.consume_key_triggered(ctx, ui) { } else if measure_length.consume_key_triggered(ctx, ui) {
if maybe_activity.as_mut().map_or(true, |activity| { if !activity.is_busy() {
matches!(activity.maybe_status(), Some(Poll::Ready(..)))
}) {
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(),
maybe_overlay, maybe_overlay,
) { ) {
let selection = overlay.take_selection(); let selection = overlay.take_selection();
*maybe_activity = Some(ActivityStepperWithStatus::new_execution( activity.maybe_activity =
invoker.execute_stepper(Command::MeasureLength( Some(ActivityStepper::Execution(invoker.execute_stepper(
selection.band_selection, Command::MeasureLength(selection.band_selection),
))?, )?));
));
} }
} }
} }

View File

@ -13,7 +13,7 @@ impl StatusBar {
ctx: &egui::Context, ctx: &egui::Context,
tr: &Translator, tr: &Translator,
viewport: &Viewport, viewport: &Viewport,
maybe_activity: &Option<ActivityStepperWithStatus>, activity: &ActivityStepperWithStatus,
) { ) {
egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| { egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| {
let latest_pos = viewport.transform.inverse() let latest_pos = viewport.transform.inverse()
@ -21,10 +21,8 @@ impl StatusBar {
let mut message = String::new(); let mut message = String::new();
if let Some(activity) = maybe_activity { if let Some(Poll::Ready(msg)) = &activity.maybe_status {
if let Some(Poll::Ready(msg)) = activity.maybe_status() { message = msg.clone();
message = msg;
}
} }
ui.label(format!( ui.label(format!(

View File

@ -42,7 +42,7 @@ impl Viewport {
ctx: &egui::Context, ctx: &egui::Context,
top: &MenuBar, top: &MenuBar,
maybe_invoker: &mut Option<Invoker<SpecctraMesadata>>, maybe_invoker: &mut Option<Invoker<SpecctraMesadata>>,
maybe_activity: &mut Option<ActivityStepperWithStatus>, activity: &mut ActivityStepperWithStatus,
maybe_overlay: &mut Option<Overlay>, maybe_overlay: &mut Option<Overlay>,
maybe_layers: &Option<Layers>, maybe_layers: &Option<Layers>,
) -> egui::Rect { ) -> egui::Rect {
@ -50,7 +50,7 @@ impl Viewport {
ctx, ctx,
top, top,
maybe_invoker, maybe_invoker,
maybe_activity, activity,
maybe_overlay, maybe_overlay,
maybe_layers, maybe_layers,
); );
@ -67,7 +67,7 @@ impl Viewport {
ctx: &egui::Context, ctx: &egui::Context,
top: &MenuBar, top: &MenuBar,
maybe_invoker: &mut Option<Invoker<SpecctraMesadata>>, maybe_invoker: &mut Option<Invoker<SpecctraMesadata>>,
maybe_activity: &mut Option<ActivityStepperWithStatus>, activity: &mut ActivityStepperWithStatus,
maybe_overlay: &mut Option<Overlay>, maybe_overlay: &mut Option<Overlay>,
maybe_layers: &Option<Layers>, maybe_layers: &Option<Layers>,
) -> egui::Rect { ) -> egui::Rect {
@ -125,16 +125,10 @@ impl Viewport {
.contains_node(board, GenericNode::Primitive(primitive)) .contains_node(board, GenericNode::Primitive(primitive))
{ {
layers.highlight_colors[i] layers.highlight_colors[i]
} else { } else if activity.obstacles().contains(&primitive) {
if let Some(activity) = maybe_activity {
if activity.obstacles().contains(&primitive) {
layers.highlight_colors[i] layers.highlight_colors[i]
} else { } else {
layers.colors[i] layers.colors[i]
}
} else {
layers.colors[i]
}
}; };
painter.paint_primitive(&shape, color); painter.paint_primitive(&shape, color);
@ -180,7 +174,6 @@ impl Viewport {
} }
if top.show_navmesh { if top.show_navmesh {
if let Some(activity) = maybe_activity {
if let Some(navmesh) = activity.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)
@ -236,7 +229,6 @@ impl Viewport {
} }
} }
} }
}
if top.show_bboxes { if top.show_bboxes {
let root_bbox3d = board.layout().drawing().rtree().root().envelope(); let root_bbox3d = board.layout().drawing().rtree().root().envelope();
@ -245,8 +237,7 @@ impl Viewport {
painter.paint_bbox(root_bbox); painter.paint_bbox(root_bbox);
} }
if let Some(activity) = maybe_activity { for ghost in activity.ghosts() {
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));
} }
@ -271,7 +262,6 @@ impl Viewport {
} }
} }
} }
}
viewport_rect viewport_rect
}) })