egui: implement basic input file selection from dialog

Imported layout is not displayed yet.
This commit is contained in:
Mikolaj Wielgus 2024-03-02 06:54:12 +00:00
parent d5d26cdaeb
commit fd4eb0b4dd
5 changed files with 69 additions and 24 deletions

View File

@ -16,10 +16,11 @@ name = "topola-sdl2-demo"
required-features = ["sdl2"] required-features = ["sdl2"]
[features] [features]
egui = ["dep:egui", "dep:eframe"] egui = ["dep:eframe", "dep:egui"]
sdl2 = ["dep:sdl2"] sdl2 = ["dep:sdl2"]
[dependencies] [dependencies]
rfd = "0.14.0"
gl = "0.14.0" gl = "0.14.0"
pathfinder_canvas = { git = "https://github.com/servo/pathfinder" } pathfinder_canvas = { git = "https://github.com/servo/pathfinder" }
pathfinder_geometry = { git = "https://github.com/servo/pathfinder" } pathfinder_geometry = { git = "https://github.com/servo/pathfinder" }
@ -34,6 +35,7 @@ petgraph = "0.6.3"
spade = "2.2.0" spade = "2.2.0"
enum_dispatch = "0.3.12" enum_dispatch = "0.3.12"
itertools = "0.8.2" itertools = "0.8.2"
futures = "0.3.30"
contracts = "0.6.3" contracts = "0.6.3"
log = "0.4" log = "0.4"
@ -41,16 +43,16 @@ log = "0.4"
version = "1" version = "1"
features = ["derive"] features = ["derive"]
[dependencies.egui]
optional = true
version = "0.26.0"
[dependencies.eframe] [dependencies.eframe]
optional = true optional = true
version = "0.26.0" version = "0.26.0"
default-features = false default-features = false
features = ["accesskit", "default_fonts", "glow", "persistence"] features = ["accesskit", "default_fonts", "glow", "persistence"]
[dependencies.egui]
optional = true
version = "0.26.0"
[dependencies.sdl2] [dependencies.sdl2]
optional = true optional = true
version = "0.35.2" version = "0.35.2"

View File

@ -1,5 +1,12 @@
use futures::executor;
use std::{
future::Future,
sync::mpsc::{channel, Receiver, Sender},
};
use topola::{ use topola::{
layout::geometry::shape::{BendShape, DotShape, SegShape, Shape}, dsn::design::DsnDesign,
geometry::shape::{BendShape, DotShape, SegShape, Shape},
math::Circle, math::Circle,
}; };
@ -12,8 +19,10 @@ pub struct App {
// Example stuff: // Example stuff:
label: String, label: String,
#[serde(skip)] // Don't serialize this field. //#[serde(skip)] // Don't serialize this field.
value: f32, //text_channel: (Sender<String>, Receiver<String>),
#[serde(skip)]
design: Option<DsnDesign>,
} }
impl Default for App { impl Default for App {
@ -21,7 +30,8 @@ impl Default for App {
Self { Self {
// Example stuff: // Example stuff:
label: "Hello World!".to_owned(), label: "Hello World!".to_owned(),
value: 2.7, //text_channel: channel(),
design: None,
} }
} }
} }
@ -48,15 +58,36 @@ impl eframe::App for App {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
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| {
let is_web = cfg!(target_arch = "wasm32");
if !is_web {
ui.menu_button("File", |ui| { ui.menu_button("File", |ui| {
if ui.button("Open").clicked() {
// `Context` is cheap to clone as it's wrapped in an `Arc`.
let ctx = ui.ctx().clone();
// NOTE: This requires Zenity to be installed on your system.
// Doing this synchronously may not work on WASM. I haven't tested this
// yet, so I'm leaving a commented-out asynchronous version further below.
let maybe_path = rfd::FileDialog::new().pick_file();
if let Some(path) = maybe_path {
self.design = DsnDesign::load_from_file(path.to_str().unwrap()).ok();
}
//let task = rfd::AsyncFileDialog::new().pick_file();
/*execute(async move {
let file = task.await;
if let Some(file) = file {
let text = file.read().await;
let _ = sender.send(String::from_utf8_lossy(&text).to_string());
ctx.request_repaint();
}
});*/
}
if ui.button("Quit").clicked() { if ui.button("Quit").clicked() {
ctx.send_viewport_cmd(egui::ViewportCommand::Close); ctx.send_viewport_cmd(egui::ViewportCommand::Close);
} }
}); });
ui.add_space(16.0); ui.add_space(16.0);
}
egui::widgets::global_dark_light_mode_buttons(ui); egui::widgets::global_dark_light_mode_buttons(ui);
}); });
@ -105,3 +136,13 @@ impl eframe::App for App {
}); });
} }
} }
#[cfg(not(target_arch = "wasm32"))]
fn execute<F: Future<Output = ()> + Send + 'static>(f: F) {
std::thread::spawn(move || futures::executor::block_on(f));
}
#[cfg(target_arch = "wasm32")]
fn execute<F: Future<Output = ()> + 'static>(f: F) {
wasm_bindgen_futures::spawn_local(f);
}

View File

@ -1,6 +1,6 @@
use egui::{emath::RectTransform, epaint, Color32, Pos2, Ui}; use egui::{emath::RectTransform, epaint, Color32, Pos2, Ui};
use geo::Point; use geo::Point;
use topola::layout::geometry::shape::Shape; use topola::geometry::shape::Shape;
pub struct Painter<'a> { pub struct Painter<'a> {
ui: &'a mut egui::Ui, ui: &'a mut egui::Ui,

View File

@ -35,7 +35,8 @@ impl Rules {
pub fn from_pcb(pcb: &Pcb) -> Self { pub fn from_pcb(pcb: &Pcb) -> Self {
// keeping this as a separate iter pass because it might be moved into a different struct later? // keeping this as a separate iter pass because it might be moved into a different struct later?
let net_ids = HashMap::from_iter( let net_ids = HashMap::from_iter(
pcb.network.classes pcb.network
.classes
.iter() .iter()
.flat_map(|class| &class.nets) .flat_map(|class| &class.nets)
.enumerate() .enumerate()

View File

@ -1,4 +1,4 @@
use serde::{Deserialize, Deserializer, de::Error}; use serde::{de::Error, Deserialize, Deserializer};
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
#[serde(rename = "pcb")] #[serde(rename = "pcb")]
@ -251,15 +251,16 @@ pub struct Point {
} }
fn de_points<'de, D>(deserializer: D) -> Result<Vec<Point>, D::Error> fn de_points<'de, D>(deserializer: D) -> Result<Vec<Point>, D::Error>
where D: Deserializer<'de> where
D: Deserializer<'de>,
{ {
Vec::<f32>::deserialize(deserializer)? Vec::<f32>::deserialize(deserializer)?
.chunks(2) .chunks(2)
.map(|pair| { .map(|pair| {
let x = pair[0]; let x = pair[0];
let y = *pair.get(1).ok_or( let y = *pair.get(1).ok_or(Error::custom(
Error::custom("expected paired x y coordinates, list ended at x") "expected paired x y coordinates, list ended at x",
)?; ))?;
Ok(Point { x, y }) Ok(Point { x, y })
}) })