From d8e128e81a782bcb2dc21e49c22699435b29c6ca Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Sat, 9 Mar 2024 17:03:05 +0000 Subject: [PATCH] egui: actually load and display the layout --- src/bin/topola-egui/app.rs | 64 +++++++++++++++++++---------- src/bin/topola-sdl2-demo/main.rs | 20 ++++++--- src/bin/topola-sdl2-demo/painter.rs | 4 +- src/dsn/design.rs | 4 ++ src/dsn/mod.rs | 2 +- 5 files changed, 64 insertions(+), 30 deletions(-) diff --git a/src/bin/topola-egui/app.rs b/src/bin/topola-egui/app.rs index 6b0a472..df072ff 100644 --- a/src/bin/topola-egui/app.rs +++ b/src/bin/topola-egui/app.rs @@ -5,8 +5,9 @@ use std::{ }; use topola::{ - dsn::design::DsnDesign, + dsn::{design::DsnDesign, rules::DsnRules}, geometry::shape::{BendShape, DotShape, SegShape, Shape}, + layout::{graph::MakePrimitive, primitive::MakeShape, Layout}, math::Circle, }; @@ -20,10 +21,10 @@ pub struct App { label: String, #[serde(skip)] // Don't serialize this field. - file_handle_channel: (Sender, Receiver), + text_channel: (Sender, Receiver), #[serde(skip)] - design: Option, + layout: Option>, #[serde(skip)] from_rect: egui::emath::Rect, @@ -34,9 +35,9 @@ impl Default for App { Self { // Example stuff: label: "Hello World!".to_owned(), - file_handle_channel: channel(), - design: None, - from_rect: egui::Rect::from_x_y_ranges(0.0..=1000.0, 0.0..=500.0), + text_channel: channel(), + layout: None, + from_rect: egui::Rect::from_x_y_ranges(0.0..=1000000.0, 0.0..=500000.0), } } } @@ -61,33 +62,35 @@ impl eframe::App for App { /// Called each time the UI has to be repainted. fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + if cfg!(target_arch = "wasm32") { + if let Ok(file_contents) = self.text_channel.1.try_recv() { + let design = DsnDesign::load_from_string(file_contents).unwrap(); + self.layout = Some(design.make_layout()); + } + } else { + if let Ok(path) = self.text_channel.1.try_recv() { + let design = DsnDesign::load_from_file(&path).unwrap(); + self.layout = Some(design.make_layout()); + } + } + egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { egui::menu::bar(ui, |ui| { ui.menu_button("File", |ui| { - if let Ok(file_handle) = self.file_handle_channel.1.try_recv() { - dbg!(file_handle); - // TODO: actually load the file from the handle. - } - if ui.button("Open").clicked() { // `Context` is cheap to clone as it's wrapped in an `Arc`. let ctx = ui.ctx().clone(); // NOTE: On Linux, this requires Zenity to be installed on your system. - let sender = self.file_handle_channel.0.clone(); + let sender = self.text_channel.0.clone(); let task = rfd::AsyncFileDialog::new().pick_file(); execute(async move { let maybe_file_handle = task.await; if let Some(file_handle) = maybe_file_handle { - let _ = sender.send(file_handle); + let _ = sender.send(channel_text(file_handle).await); ctx.request_repaint(); } - /*if let Some(file) = file { - let text = file.read().await; - let _ = sender.send(String::from_utf8_lossy(&text).to_string()); - ctx.request_repaint(); - }*/ }); } @@ -128,7 +131,9 @@ impl eframe::App for App { ctx.input(|i| latest_pos.to_vec2() * (new_scale - old_scale) / new_scale), ); - self.from_rect = self.from_rect.translate(ctx.input(|i| -i.raw_scroll_delta)); + self.from_rect = self + .from_rect + .translate(ctx.input(|i| -i.raw_scroll_delta / new_scale)); let transform = egui::emath::RectTransform::from_to(self.from_rect, viewport_rect); let mut painter = Painter::new(ui, transform); @@ -156,9 +161,12 @@ impl eframe::App for App { width: 12.0, }); - painter.paint_shape(&dot_shape, egui::Color32::from_rgb(255, 0, 0)); - painter.paint_shape(&seg_shape, egui::Color32::from_rgb(128, 128, 128)); - painter.paint_shape(&bend_shape, egui::Color32::from_rgb(255, 255, 0)); + if let Some(layout) = &self.layout { + for node in layout.nodes() { + let shape = node.primitive(layout).shape(); + painter.paint_shape(&shape, egui::Color32::from_rgb(255, 0, 0)); + } + } }) }); @@ -177,3 +185,15 @@ fn execute + Send + 'static>(f: F) { fn execute + 'static>(f: F) { wasm_bindgen_futures::spawn_local(f); } + +#[cfg(not(target_arch = "wasm32"))] +async fn channel_text(file_handle: rfd::FileHandle) -> String { + file_handle.path().to_str().unwrap().to_string() +} + +#[cfg(target_arch = "wasm32")] +async fn channel_text(file_handle: rfd::FileHandle) -> String { + std::str::from_utf8(&file_handle.read().await) + .unwrap() + .to_string() +} diff --git a/src/bin/topola-sdl2-demo/main.rs b/src/bin/topola-sdl2-demo/main.rs index d8b40e3..61907f5 100644 --- a/src/bin/topola-sdl2-demo/main.rs +++ b/src/bin/topola-sdl2-demo/main.rs @@ -251,14 +251,19 @@ fn main() -> Result<(), anyhow::Error> { ]), }));*/ - let design = DsnDesign::load_from_file("tests/data/prerouted_lm317_breakout/prerouted_lm317_breakout.dsn")?; + let design = DsnDesign::load_from_file( + "tests/data/prerouted_lm317_breakout/prerouted_lm317_breakout.dsn", + )?; //let design = DsnDesign::load_from_file("tests/data/test/test.dsn")?; //dbg!(&design); let layout = design.make_layout(); let board = Board::new(layout); let mut router = Router::new(board); - let mut view = View { pan: vec2f(-80000.0, -60000.0), zoom: 0.005 }; + let mut view = View { + pan: vec2f(-80000.0, -60000.0), + zoom: 0.005, + }; render_times( &mut event_pump, @@ -333,12 +338,17 @@ fn render_times( } => break 'running, Event::MouseWheel { y, .. } => { view.zoom *= f32::powf(1.4, y as f32); - }, - Event::MouseMotion { xrel, yrel, mousestate, .. } => { + } + Event::MouseMotion { + xrel, + yrel, + mousestate, + .. + } => { if mousestate.left() { view.pan += vec2f(xrel as f32, yrel as f32) / view.zoom; } - }, + } _ => {} } } diff --git a/src/bin/topola-sdl2-demo/painter.rs b/src/bin/topola-sdl2-demo/painter.rs index 410cd1a..274b4c3 100644 --- a/src/bin/topola-sdl2-demo/painter.rs +++ b/src/bin/topola-sdl2-demo/painter.rs @@ -60,7 +60,7 @@ impl<'a> Painter<'a> { // XXX: points represented as arrays can't be conveniently converted to vector types let topleft = vec2f(envelope.lower()[0] as f32, envelope.lower()[1] as f32); let bottomright = vec2f(envelope.upper()[0] as f32, envelope.upper()[1] as f32); - self.canvas.set_line_width(2.0/zoom); + self.canvas.set_line_width(2.0 / zoom); self.canvas .set_stroke_style(ColorU::new(100, 100, 100, 255)); self.canvas @@ -72,7 +72,7 @@ impl<'a> Painter<'a> { path.move_to(vec2f(from.x() as f32, from.y() as f32)); path.line_to(vec2f(to.x() as f32, to.y() as f32)); self.canvas.set_stroke_style(color); - self.canvas.set_line_width(2.0/zoom); + self.canvas.set_line_width(2.0 / zoom); self.canvas.stroke_path(path); } } diff --git a/src/dsn/design.rs b/src/dsn/design.rs index b2adc32..89ca81a 100644 --- a/src/dsn/design.rs +++ b/src/dsn/design.rs @@ -29,6 +29,10 @@ pub struct DsnDesign { impl DsnDesign { pub fn load_from_file(filename: &str) -> Result { let contents = std::fs::read_to_string(filename)?; + Self::load_from_string(contents) + } + + pub fn load_from_string(contents: String) -> Result { let pcb = de::from_str::(&contents) .map_err(|err| LoadingError::Syntax(err))? .pcb; diff --git a/src/dsn/mod.rs b/src/dsn/mod.rs index e31dc01..eb845a6 100644 --- a/src/dsn/mod.rs +++ b/src/dsn/mod.rs @@ -1,4 +1,4 @@ mod de; pub mod design; -mod rules; +pub mod rules; mod structure;