egui: actually load and display the layout

This commit is contained in:
Mikolaj Wielgus 2024-03-09 17:03:05 +00:00
parent f8892f64a7
commit d8e128e81a
5 changed files with 64 additions and 30 deletions

View File

@ -5,8 +5,9 @@ use std::{
}; };
use topola::{ use topola::{
dsn::design::DsnDesign, dsn::{design::DsnDesign, rules::DsnRules},
geometry::shape::{BendShape, DotShape, SegShape, Shape}, geometry::shape::{BendShape, DotShape, SegShape, Shape},
layout::{graph::MakePrimitive, primitive::MakeShape, Layout},
math::Circle, math::Circle,
}; };
@ -20,10 +21,10 @@ pub struct App {
label: String, label: String,
#[serde(skip)] // Don't serialize this field. #[serde(skip)] // Don't serialize this field.
file_handle_channel: (Sender<rfd::FileHandle>, Receiver<rfd::FileHandle>), text_channel: (Sender<String>, Receiver<String>),
#[serde(skip)] #[serde(skip)]
design: Option<DsnDesign>, layout: Option<Layout<DsnRules>>,
#[serde(skip)] #[serde(skip)]
from_rect: egui::emath::Rect, from_rect: egui::emath::Rect,
@ -34,9 +35,9 @@ impl Default for App {
Self { Self {
// Example stuff: // Example stuff:
label: "Hello World!".to_owned(), label: "Hello World!".to_owned(),
file_handle_channel: channel(), text_channel: channel(),
design: None, layout: None,
from_rect: egui::Rect::from_x_y_ranges(0.0..=1000.0, 0.0..=500.0), 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. /// 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") {
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::TopBottomPanel::top("top_panel").show(ctx, |ui| {
egui::menu::bar(ui, |ui| { egui::menu::bar(ui, |ui| {
ui.menu_button("File", |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() { if ui.button("Open").clicked() {
// `Context` is cheap to clone as it's wrapped in an `Arc`. // `Context` is cheap to clone as it's wrapped in an `Arc`.
let ctx = ui.ctx().clone(); let ctx = ui.ctx().clone();
// NOTE: On Linux, this requires Zenity to be installed on your system. // 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(); let task = rfd::AsyncFileDialog::new().pick_file();
execute(async move { execute(async move {
let maybe_file_handle = task.await; let maybe_file_handle = task.await;
if let Some(file_handle) = maybe_file_handle { if let Some(file_handle) = maybe_file_handle {
let _ = sender.send(file_handle); let _ = sender.send(channel_text(file_handle).await);
ctx.request_repaint(); 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), 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 transform = egui::emath::RectTransform::from_to(self.from_rect, viewport_rect);
let mut painter = Painter::new(ui, transform); let mut painter = Painter::new(ui, transform);
@ -156,9 +161,12 @@ impl eframe::App for App {
width: 12.0, width: 12.0,
}); });
painter.paint_shape(&dot_shape, egui::Color32::from_rgb(255, 0, 0)); if let Some(layout) = &self.layout {
painter.paint_shape(&seg_shape, egui::Color32::from_rgb(128, 128, 128)); for node in layout.nodes() {
painter.paint_shape(&bend_shape, egui::Color32::from_rgb(255, 255, 0)); let shape = node.primitive(layout).shape();
painter.paint_shape(&shape, egui::Color32::from_rgb(255, 0, 0));
}
}
}) })
}); });
@ -177,3 +185,15 @@ fn execute<F: Future<Output = ()> + Send + 'static>(f: F) {
fn execute<F: Future<Output = ()> + 'static>(f: F) { fn execute<F: Future<Output = ()> + 'static>(f: F) {
wasm_bindgen_futures::spawn_local(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()
}

View File

@ -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")?; //let design = DsnDesign::load_from_file("tests/data/test/test.dsn")?;
//dbg!(&design); //dbg!(&design);
let layout = design.make_layout(); let layout = design.make_layout();
let board = Board::new(layout); let board = Board::new(layout);
let mut router = Router::new(board); 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( render_times(
&mut event_pump, &mut event_pump,
@ -333,12 +338,17 @@ fn render_times(
} => break 'running, } => break 'running,
Event::MouseWheel { y, .. } => { Event::MouseWheel { y, .. } => {
view.zoom *= f32::powf(1.4, y as f32); view.zoom *= f32::powf(1.4, y as f32);
}, }
Event::MouseMotion { xrel, yrel, mousestate, .. } => { Event::MouseMotion {
xrel,
yrel,
mousestate,
..
} => {
if mousestate.left() { if mousestate.left() {
view.pan += vec2f(xrel as f32, yrel as f32) / view.zoom; view.pan += vec2f(xrel as f32, yrel as f32) / view.zoom;
} }
}, }
_ => {} _ => {}
} }
} }

View File

@ -60,7 +60,7 @@ impl<'a> Painter<'a> {
// XXX: points represented as arrays can't be conveniently converted to vector types // 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 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); 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 self.canvas
.set_stroke_style(ColorU::new(100, 100, 100, 255)); .set_stroke_style(ColorU::new(100, 100, 100, 255));
self.canvas self.canvas
@ -72,7 +72,7 @@ impl<'a> Painter<'a> {
path.move_to(vec2f(from.x() as f32, from.y() as f32)); path.move_to(vec2f(from.x() as f32, from.y() as f32));
path.line_to(vec2f(to.x() as f32, to.y() as f32)); path.line_to(vec2f(to.x() as f32, to.y() as f32));
self.canvas.set_stroke_style(color); 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); self.canvas.stroke_path(path);
} }
} }

View File

@ -29,6 +29,10 @@ pub struct DsnDesign {
impl DsnDesign { impl DsnDesign {
pub fn load_from_file(filename: &str) -> Result<Self, LoadingError> { pub fn load_from_file(filename: &str) -> Result<Self, LoadingError> {
let contents = std::fs::read_to_string(filename)?; let contents = std::fs::read_to_string(filename)?;
Self::load_from_string(contents)
}
pub fn load_from_string(contents: String) -> Result<Self, LoadingError> {
let pcb = de::from_str::<DsnFile>(&contents) let pcb = de::from_str::<DsnFile>(&contents)
.map_err(|err| LoadingError::Syntax(err))? .map_err(|err| LoadingError::Syntax(err))?
.pcb; .pcb;

View File

@ -1,4 +1,4 @@
mod de; mod de;
pub mod design; pub mod design;
mod rules; pub mod rules;
mod structure; mod structure;