egui: step through every band routing step, once per frame

At last! We finally have that implemented without concurrency.
This commit is contained in:
Mikolaj Wielgus 2024-06-29 22:40:06 +02:00
parent 6cadcd3b41
commit ee6eeac6d8
2 changed files with 72 additions and 71 deletions

View File

@ -50,10 +50,13 @@ use crate::{
#[serde(default)] #[serde(default)]
pub struct App { pub struct App {
#[serde(skip)] #[serde(skip)]
overlay: Option<Overlay>, maybe_overlay: Option<Overlay>,
#[serde(skip)] #[serde(skip)]
invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>, arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>,
#[serde(skip)]
maybe_execute: Option<Execute>,
#[serde(skip)] #[serde(skip)]
text_channel: (Sender<String>, Receiver<String>), text_channel: (Sender<String>, Receiver<String>),
@ -68,19 +71,20 @@ pub struct App {
bottom: Bottom, bottom: Bottom,
#[serde(skip)] #[serde(skip)]
layers: Option<Layers>, maybe_layers: Option<Layers>,
} }
impl Default for App { impl Default for App {
fn default() -> Self { fn default() -> Self {
Self { Self {
overlay: None, maybe_overlay: None,
invoker: Arc::new(Mutex::new(None)), arc_mutex_maybe_invoker: Arc::new(Mutex::new(None)),
maybe_execute: None,
text_channel: channel(), text_channel: channel(),
viewport: Viewport::new(), viewport: Viewport::new(),
top: Top::new(), top: Top::new(),
bottom: Bottom::new(), bottom: Bottom::new(),
layers: None, maybe_layers: None,
} }
} }
} }
@ -95,6 +99,44 @@ impl App {
Default::default() Default::default()
} }
fn update_state(&mut self) {
if cfg!(target_arch = "wasm32") {
if let Ok(file_contents) = self.text_channel.1.try_recv() {
let design = SpecctraDesign::load_from_string(file_contents).unwrap();
let board = design.make_board();
self.maybe_overlay = Some(Overlay::new(&board).unwrap());
self.maybe_layers = Some(Layers::new(&board));
self.arc_mutex_maybe_invoker = Arc::new(Mutex::new(Some(Invoker::new(
Autorouter::new(board).unwrap(),
))));
}
} else {
if let Ok(path) = self.text_channel.1.try_recv() {
let design = SpecctraDesign::load_from_file(&path).unwrap();
let board = design.make_board();
self.maybe_overlay = Some(Overlay::new(&board).unwrap());
self.maybe_layers = Some(Layers::new(&board));
self.arc_mutex_maybe_invoker = Arc::new(Mutex::new(Some(Invoker::new(
Autorouter::new(board).unwrap(),
))));
}
}
if let Some(invoker) = self.arc_mutex_maybe_invoker.lock().unwrap().as_mut() {
if let Some(ref mut execute) = self.maybe_execute {
let status = match execute.step(invoker) {
Ok(status) => status,
Err(err) => return,
};
if let InvokerStatus::Finished = status {
self.maybe_execute = None;
return;
}
}
}
}
} }
impl eframe::App for App { impl eframe::App for App {
@ -105,37 +147,18 @@ impl eframe::App for App {
/// Called each time the UI has to be repainted. /// Called each time the UI has to be repainted.
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
if cfg!(target_arch = "wasm32") { self.update_state();
if let Ok(file_contents) = self.text_channel.1.try_recv() {
let design = SpecctraDesign::load_from_string(file_contents).unwrap();
let board = design.make_board();
self.overlay = Some(Overlay::new(&board).unwrap());
self.layers = Some(Layers::new(&board));
self.invoker = Arc::new(Mutex::new(Some(Invoker::new(
Autorouter::new(board).unwrap(),
))));
}
} else {
if let Ok(path) = self.text_channel.1.try_recv() {
let design = SpecctraDesign::load_from_file(&path).unwrap();
let board = design.make_board();
self.overlay = Some(Overlay::new(&board).unwrap());
self.layers = Some(Layers::new(&board));
self.invoker = Arc::new(Mutex::new(Some(Invoker::new(
Autorouter::new(board).unwrap(),
))));
}
}
self.top.update( self.top.update(
ctx, ctx,
self.text_channel.0.clone(), self.text_channel.0.clone(),
self.invoker.clone(), self.arc_mutex_maybe_invoker.clone(),
&mut self.overlay, &mut self.maybe_execute,
&mut self.maybe_overlay,
); );
if let Some(ref mut layers) = self.layers { if let Some(ref mut layers) = self.maybe_layers {
if let Some(invoker) = self.invoker.lock().unwrap().as_ref() { if let Some(invoker) = self.arc_mutex_maybe_invoker.lock().unwrap().as_ref() {
layers.update(ctx, invoker.autorouter().board()); layers.update(ctx, invoker.autorouter().board());
} }
} }
@ -143,9 +166,9 @@ impl eframe::App for App {
let viewport_rect = self.viewport.update( let viewport_rect = self.viewport.update(
ctx, ctx,
&self.top, &self.top,
&mut self.invoker.lock().unwrap(), &mut self.arc_mutex_maybe_invoker.lock().unwrap(),
&mut self.overlay, &mut self.maybe_overlay,
&self.layers, &self.maybe_layers,
); );
self.bottom.update(ctx, &self.viewport, viewport_rect); self.bottom.update(ctx, &self.viewport, viewport_rect);

View File

@ -32,7 +32,8 @@ impl Top {
&mut self, &mut self,
ctx: &egui::Context, ctx: &egui::Context,
sender: Sender<String>, sender: Sender<String>,
maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>, arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>,
maybe_execute: &mut Option<Execute>,
maybe_overlay: &Option<Overlay>, maybe_overlay: &Option<Overlay>,
) { ) {
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
@ -55,7 +56,7 @@ impl Top {
ui.separator(); ui.separator();
if ui.button("Load history").clicked() { if ui.button("Load history").clicked() {
let invoker_arc_mutex = maybe_invoker.clone(); let invoker_arc_mutex = arc_mutex_maybe_invoker.clone();
let ctx = ui.ctx().clone(); let ctx = ui.ctx().clone();
let task = rfd::AsyncFileDialog::new().pick_file(); let task = rfd::AsyncFileDialog::new().pick_file();
@ -79,7 +80,7 @@ impl Top {
} }
if ui.button("Save history").clicked() { if ui.button("Save history").clicked() {
let invoker_arc_mutex = maybe_invoker.clone(); let invoker_arc_mutex = arc_mutex_maybe_invoker.clone();
let ctx = ui.ctx().clone(); let ctx = ui.ctx().clone();
let task = rfd::AsyncFileDialog::new().save_file(); let task = rfd::AsyncFileDialog::new().save_file();
@ -115,39 +116,15 @@ impl Top {
ui.separator(); ui.separator();
if ui.button("Autoroute").clicked() { if ui.button("Autoroute").clicked() {
if let (Some(invoker), Some(ref overlay)) = if maybe_execute.is_none() {
(maybe_invoker.lock().unwrap().as_mut(), maybe_overlay) if let (Some(invoker), Some(ref overlay)) = (
{ arc_mutex_maybe_invoker.lock().unwrap().as_mut(),
maybe_overlay,
) {
let selection = overlay.selection().clone(); let selection = overlay.selection().clone();
let mut execute = invoker.execute_walk(Command::Autoroute(selection)); maybe_execute
.insert(invoker.execute_walk(Command::Autoroute(selection)));
if let Execute::Autoroute(ref mut autoroute) = execute {
let from = autoroute.navmesh().as_ref().unwrap().source();
let to = autoroute.navmesh().as_ref().unwrap().target();
/*{
let mut shared_data = shared_data_arc_mutex.lock().unwrap();
shared_data.from = Some(from);
shared_data.to = Some(to);
shared_data.navmesh = autoroute.navmesh().cloned();
}*/
} }
let _ = loop {
let status = match execute.step(invoker) {
Ok(status) => status,
Err(err) => return,
};
if let InvokerStatus::Finished = status {
break;
}
/*if let Execute::Autoroute(ref mut autoroute) = execute {
shared_data_arc_mutex.lock().unwrap().navmesh =
autoroute.navmesh().cloned();
}*/
};
} }
} }
@ -158,7 +135,7 @@ impl Top {
if ui.button("Undo").clicked() if ui.button("Undo").clicked()
|| ctx.input_mut(|i| i.consume_key(egui::Modifiers::CTRL, egui::Key::Z)) || ctx.input_mut(|i| i.consume_key(egui::Modifiers::CTRL, egui::Key::Z))
{ {
if let Some(invoker) = maybe_invoker.lock().unwrap().as_mut() { if let Some(invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_mut() {
invoker.undo(); invoker.undo();
} }
} }
@ -166,7 +143,8 @@ impl Top {
if ui.button("Redo").clicked() if ui.button("Redo").clicked()
|| ctx.input_mut(|i| i.consume_key(egui::Modifiers::CTRL, egui::Key::Y)) || ctx.input_mut(|i| i.consume_key(egui::Modifiers::CTRL, egui::Key::Y))
{ {
if let Some(ref mut invoker) = maybe_invoker.lock().unwrap().as_mut() { if let Some(ref mut invoker) = arc_mutex_maybe_invoker.lock().unwrap().as_mut()
{
invoker.redo(); invoker.redo();
} }
} }