From 8a372c4a7a109ff17b8a775bca358151747ae23a Mon Sep 17 00:00:00 2001 From: Alain Emilia Anna Zscheile Date: Sat, 5 Oct 2024 13:41:06 +0200 Subject: [PATCH] egui: keep activity status after activity finished --- src/bin/topola-egui/activity.rs | 47 ++++++--- src/bin/topola-egui/app.rs | 42 ++++---- src/bin/topola-egui/menu_bar.rs | 54 ++++------ src/bin/topola-egui/status_bar.rs | 8 +- src/bin/topola-egui/viewport.rs | 160 ++++++++++++++---------------- 5 files changed, 156 insertions(+), 155 deletions(-) diff --git a/src/bin/topola-egui/activity.rs b/src/bin/topola-egui/activity.rs index 60df549..eee1151 100644 --- a/src/bin/topola-egui/activity.rs +++ b/src/bin/topola-egui/activity.rs @@ -106,21 +106,29 @@ impl GetObstacles for ActivityStepper { } } +#[derive(Default)] pub struct ActivityStepperWithStatus { - activity: ActivityStepper, - maybe_status: Option>, + pub maybe_activity: Option, + pub maybe_status: Option>, } impl ActivityStepperWithStatus { pub fn new_execution(execution: ExecutionStepper) -> ActivityStepperWithStatus { Self { - activity: ActivityStepper::Execution(execution), + maybe_activity: Some(ActivityStepper::Execution(execution)), maybe_status: None, } } - pub fn maybe_status(&self) -> Option> { - self.maybe_status.clone() + pub fn is_busy(&self) -> bool { + 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, String> for ActivityStepperWithStatus { &mut self, context: &mut ActivityContext<'_>, ) -> Poll> { - 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 { Poll::Pending => Some(Poll::Pending), Poll::Ready(Ok(msg)) => Some(Poll::Ready(msg.clone())), @@ -145,31 +160,39 @@ impl PollStep, String> for ActivityStepperWithStatus { impl Abort> for ActivityStepperWithStatus { fn abort(&mut self, context: &mut ActivityContext<'_>) { - self.maybe_status = Some(Poll::Ready("aborted".to_string())); - self.activity.abort(context); + if let Some(mut act) = self.maybe_activity.take() { + self.maybe_status = Some(Poll::Ready("aborted".to_string())); + act.abort(context); + } } } impl GetMaybeNavmesh for ActivityStepperWithStatus { fn maybe_navmesh(&self) -> Option<&Navmesh> { - self.activity.maybe_navmesh() + self.maybe_activity.as_ref()?.maybe_navmesh() } } impl GetMaybeTrace for ActivityStepperWithStatus { fn maybe_trace(&self) -> Option<&TraceStepper> { - self.activity.maybe_trace() + self.maybe_activity.as_ref()?.maybe_trace() } } impl GetGhosts for ActivityStepperWithStatus { fn ghosts(&self) -> &[PrimitiveShape] { - self.activity.ghosts() + match &self.maybe_activity { + None => &[], + Some(act) => act.ghosts(), + } } } impl GetObstacles for ActivityStepperWithStatus { fn obstacles(&self) -> &[PrimitiveIndex] { - self.activity.obstacles() + match &self.maybe_activity { + None => &[], + Some(act) => act.obstacles(), + } } } diff --git a/src/bin/topola-egui/app.rs b/src/bin/topola-egui/app.rs index b1eaa65..8e1e012 100644 --- a/src/bin/topola-egui/app.rs +++ b/src/bin/topola-egui/app.rs @@ -40,7 +40,7 @@ pub struct App { arc_mutex_maybe_invoker: Arc>>>, - maybe_activity: Option, + activity: ActivityStepperWithStatus, content_channel: ( Sender>, @@ -71,7 +71,7 @@ impl Default for App { translator: Translator::new(langid!("en-US")), maybe_overlay: None, arc_mutex_maybe_invoker: Arc::new(Mutex::new(None)), - maybe_activity: None, + activity: ActivityStepperWithStatus::default(), content_channel: channel(), history_channel: channel(), viewport: Viewport::new(), @@ -171,22 +171,24 @@ impl App { } } - if let Some(ref mut activity) = self.maybe_activity { - return match activity.poll_step(&mut ActivityContext { - interaction: InteractionContext {}, - invoker, - }) { - Poll::Pending => true, - Poll::Ready(res) => { - if let Err(err) = res { - self.error_dialog - .push_error("tr-module-invoker", format!("{}", err)); - } - self.maybe_activity = None; - false - } - }; + if self.activity.maybe_activity.is_none() { + return false; } + + return match self.activity.poll_step(&mut ActivityContext { + interaction: InteractionContext {}, + invoker, + }) { + Poll::Pending => true, + Poll::Ready(res) => { + if let Err(err) = res { + self.error_dialog + .push_error("tr-module-invoker", format!("{}", err)); + } + self.activity.maybe_activity = None; + false + } + }; } false @@ -233,7 +235,7 @@ impl eframe::App for App { self.content_channel.0.clone(), self.history_channel.0.clone(), self.arc_mutex_maybe_invoker.clone(), - &mut self.maybe_activity, + &mut self.activity, &mut self.viewport, &mut self.maybe_overlay, &self.maybe_design, @@ -242,7 +244,7 @@ impl eframe::App for App { self.advance_state_by_dt(ctx.input(|i| i.stable_dt)); 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 let Some(ref mut layers) = self.maybe_layers { @@ -258,7 +260,7 @@ impl eframe::App for App { ctx, &self.menu_bar, &mut self.arc_mutex_maybe_invoker.lock().unwrap(), - &mut self.maybe_activity, + &mut self.activity, &mut self.maybe_overlay, &self.maybe_layers, ); diff --git a/src/bin/topola-egui/menu_bar.rs b/src/bin/topola-egui/menu_bar.rs index 5010d31..0e597ca 100644 --- a/src/bin/topola-egui/menu_bar.rs +++ b/src/bin/topola-egui/menu_bar.rs @@ -21,7 +21,7 @@ use topola::{ use crate::{ action::{Action, Switch, Trigger}, - activity::{ActivityContext, ActivityStepperWithStatus}, + activity::{ActivityContext, ActivityStepper, ActivityStepperWithStatus}, app::{execute, handle_file}, interaction::InteractionContext, overlay::Overlay, @@ -67,7 +67,7 @@ impl MenuBar { content_sender: Sender>, history_sender: Sender>>, arc_mutex_maybe_invoker: Arc>>>, - maybe_activity: &mut Option, + activity: &mut ActivityStepperWithStatus, viewport: &mut Viewport, maybe_overlay: &mut Option, maybe_design: &Option, @@ -331,41 +331,34 @@ impl MenuBar { 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(&mut ActivityContext { - interaction: InteractionContext {}, - invoker, - }); - } + if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_mut() { + activity.abort(&mut ActivityContext { + interaction: InteractionContext {}, + invoker, + }); } } else if remove_bands.consume_key_triggered(ctx, ui) { - if maybe_activity.as_mut().map_or(true, |activity| { - matches!(activity.maybe_status(), Some(Poll::Ready(..))) - }) { + if !activity.is_busy() { if let (Some(invoker), Some(ref mut overlay)) = ( arc_mutex_maybe_invoker.lock().unwrap().as_mut(), maybe_overlay, ) { let selection = overlay.take_selection(); - *maybe_activity = Some(ActivityStepperWithStatus::new_execution( - invoker.execute_stepper(Command::RemoveBands( - selection.band_selection, - ))?, - )); + activity.maybe_activity = + Some(ActivityStepper::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(Poll::Ready(..))) - }) { + if !activity.is_busy() { if let (Some(invoker), Some(ref mut overlay)) = ( arc_mutex_maybe_invoker.lock().unwrap().as_mut(), maybe_overlay, ) { let selection = overlay.take_selection(); - *maybe_activity = Some(ActivityStepperWithStatus::new_execution( + activity.maybe_activity = Some(ActivityStepper::Execution( invoker.execute_stepper(Command::Autoroute( selection.pin_selection, self.autorouter_options, @@ -374,15 +367,13 @@ impl MenuBar { } } } else if compare_detours.consume_key_triggered(ctx, ui) { - if maybe_activity.as_mut().map_or(true, |activity| { - matches!(activity.maybe_status(), Some(Poll::Ready(..))) - }) { + if !activity.is_busy() { if let (Some(invoker), Some(ref mut overlay)) = ( arc_mutex_maybe_invoker.lock().unwrap().as_mut(), maybe_overlay, ) { let selection = overlay.take_selection(); - *maybe_activity = Some(ActivityStepperWithStatus::new_execution( + activity.maybe_activity = Some(ActivityStepper::Execution( invoker.execute_stepper(Command::CompareDetours( selection.pin_selection, self.autorouter_options, @@ -391,19 +382,16 @@ impl MenuBar { } } } else if measure_length.consume_key_triggered(ctx, ui) { - if maybe_activity.as_mut().map_or(true, |activity| { - matches!(activity.maybe_status(), Some(Poll::Ready(..))) - }) { + if !activity.is_busy() { if let (Some(invoker), Some(ref mut overlay)) = ( arc_mutex_maybe_invoker.lock().unwrap().as_mut(), maybe_overlay, ) { let selection = overlay.take_selection(); - *maybe_activity = Some(ActivityStepperWithStatus::new_execution( - invoker.execute_stepper(Command::MeasureLength( - selection.band_selection, - ))?, - )); + activity.maybe_activity = + Some(ActivityStepper::Execution(invoker.execute_stepper( + Command::MeasureLength(selection.band_selection), + )?)); } } } diff --git a/src/bin/topola-egui/status_bar.rs b/src/bin/topola-egui/status_bar.rs index f6000bc..ae2e776 100644 --- a/src/bin/topola-egui/status_bar.rs +++ b/src/bin/topola-egui/status_bar.rs @@ -13,7 +13,7 @@ impl StatusBar { ctx: &egui::Context, tr: &Translator, viewport: &Viewport, - maybe_activity: &Option, + activity: &ActivityStepperWithStatus, ) { egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| { let latest_pos = viewport.transform.inverse() @@ -21,10 +21,8 @@ impl StatusBar { let mut message = String::new(); - if let Some(activity) = maybe_activity { - if let Some(Poll::Ready(msg)) = activity.maybe_status() { - message = msg; - } + if let Some(Poll::Ready(msg)) = &activity.maybe_status { + message = msg.clone(); } ui.label(format!( diff --git a/src/bin/topola-egui/viewport.rs b/src/bin/topola-egui/viewport.rs index 18de39f..d4d3ba4 100644 --- a/src/bin/topola-egui/viewport.rs +++ b/src/bin/topola-egui/viewport.rs @@ -42,7 +42,7 @@ impl Viewport { ctx: &egui::Context, top: &MenuBar, maybe_invoker: &mut Option>, - maybe_activity: &mut Option, + activity: &mut ActivityStepperWithStatus, maybe_overlay: &mut Option, maybe_layers: &Option, ) -> egui::Rect { @@ -50,7 +50,7 @@ impl Viewport { ctx, top, maybe_invoker, - maybe_activity, + activity, maybe_overlay, maybe_layers, ); @@ -67,7 +67,7 @@ impl Viewport { ctx: &egui::Context, top: &MenuBar, maybe_invoker: &mut Option>, - maybe_activity: &mut Option, + activity: &mut ActivityStepperWithStatus, maybe_overlay: &mut Option, maybe_layers: &Option, ) -> egui::Rect { @@ -125,16 +125,10 @@ impl Viewport { .contains_node(board, GenericNode::Primitive(primitive)) { layers.highlight_colors[i] + } else if activity.obstacles().contains(&primitive) { + layers.highlight_colors[i] } else { - if let Some(activity) = maybe_activity { - if activity.obstacles().contains(&primitive) { - layers.highlight_colors[i] - } else { - layers.colors[i] - } - } else { - layers.colors[i] - } + layers.colors[i] }; painter.paint_primitive(&shape, color); @@ -180,60 +174,58 @@ impl Viewport { } if top.show_navmesh { - if let Some(activity) = maybe_activity { - if let Some(navmesh) = activity.maybe_navmesh() { - for edge in navmesh.edge_references() { - let mut from = PrimitiveIndex::from(navmesh.node_weight(edge.source()).unwrap().node) - .primitive(board.layout().drawing()) - .shape() - .center(); - let mut to = PrimitiveIndex::from(navmesh.node_weight(edge.target()).unwrap().node) - .primitive(board.layout().drawing()) - .shape() - .center(); + if let Some(navmesh) = activity.maybe_navmesh() { + for edge in navmesh.edge_references() { + let mut from = PrimitiveIndex::from(navmesh.node_weight(edge.source()).unwrap().node) + .primitive(board.layout().drawing()) + .shape() + .center(); + let mut to = PrimitiveIndex::from(navmesh.node_weight(edge.target()).unwrap().node) + .primitive(board.layout().drawing()) + .shape() + .center(); - if let Some(from_cw) = navmesh.node_weight(edge.source()).unwrap().maybe_cw { - if from_cw { - from -= [0.0, 150.0].into(); - } else { - from += [0.0, 150.0].into(); - } + if let Some(from_cw) = navmesh.node_weight(edge.source()).unwrap().maybe_cw { + if from_cw { + from -= [0.0, 150.0].into(); + } else { + from += [0.0, 150.0].into(); } - - if let Some(to_cw) = navmesh.node_weight(edge.target()).unwrap().maybe_cw { - if to_cw { - to -= [0.0, 150.0].into(); - } else { - to += [0.0, 150.0].into(); - } - } - - let stroke = 'blk: { - if let (Some(source_pos), Some(target_pos)) = ( - activity.maybe_trace().map(|trace| - trace.path - .iter() - .position(|node| *node == edge.source())).flatten(), - activity.maybe_trace().map(|trace| - trace.path - .iter() - .position(|node| *node == edge.target())).flatten(), - ) { - if target_pos == source_pos + 1 - || source_pos == target_pos + 1 - { - break 'blk egui::Stroke::new( - 5.0, - egui::Color32::from_rgb(250, 250, 0), - ); - } - } - - egui::Stroke::new(1.0, egui::Color32::from_rgb(125, 125, 125)) - }; - - painter.paint_edge(from, to, stroke); } + + if let Some(to_cw) = navmesh.node_weight(edge.target()).unwrap().maybe_cw { + if to_cw { + to -= [0.0, 150.0].into(); + } else { + to += [0.0, 150.0].into(); + } + } + + let stroke = 'blk: { + if let (Some(source_pos), Some(target_pos)) = ( + activity.maybe_trace().map(|trace| + trace.path + .iter() + .position(|node| *node == edge.source())).flatten(), + activity.maybe_trace().map(|trace| + trace.path + .iter() + .position(|node| *node == edge.target())).flatten(), + ) { + if target_pos == source_pos + 1 + || source_pos == target_pos + 1 + { + break 'blk egui::Stroke::new( + 5.0, + egui::Color32::from_rgb(250, 250, 0), + ); + } + } + + egui::Stroke::new(1.0, egui::Color32::from_rgb(125, 125, 125)) + }; + + painter.paint_edge(from, to, stroke); } } } @@ -245,29 +237,27 @@ impl Viewport { painter.paint_bbox(root_bbox); } - if let Some(activity) = maybe_activity { - for ghost in activity.ghosts().iter() { - painter.paint_primitive(&ghost, egui::Color32::from_rgb(75, 75, 150)); - } + for ghost in activity.ghosts() { + painter.paint_primitive(&ghost, egui::Color32::from_rgb(75, 75, 150)); + } - if let Some(navmesh) = activity.maybe_navmesh() { - if top.show_origin_destination { - let (origin, destination) = (navmesh.origin(), navmesh.destination()); - painter.paint_dot( - Circle { - pos: board.layout().drawing().primitive(origin).shape().center(), - r: 150.0, - }, - egui::Color32::from_rgb(255, 255, 100), - ); - painter.paint_dot( - Circle { - pos: board.layout().drawing().primitive(destination).shape().center(), - r: 150.0, - }, - egui::Color32::from_rgb(255, 255, 100), - ); - } + if let Some(navmesh) = activity.maybe_navmesh() { + if top.show_origin_destination { + let (origin, destination) = (navmesh.origin(), navmesh.destination()); + painter.paint_dot( + Circle { + pos: board.layout().drawing().primitive(origin).shape().center(), + r: 150.0, + }, + egui::Color32::from_rgb(255, 255, 100), + ); + painter.paint_dot( + Circle { + pos: board.layout().drawing().primitive(destination).shape().center(), + r: 150.0, + }, + egui::Color32::from_rgb(255, 255, 100), + ); } } }