mirror of https://codeberg.org/topola/topola.git
egui: implement basic input file selection from dialog
Imported layout is not displayed yet.
This commit is contained in:
parent
d5d26cdaeb
commit
fd4eb0b4dd
12
Cargo.toml
12
Cargo.toml
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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");
|
ui.menu_button("File", |ui| {
|
||||||
if !is_web {
|
if ui.button("Open").clicked() {
|
||||||
ui.menu_button("File", |ui| {
|
// `Context` is cheap to clone as it's wrapped in an `Arc`.
|
||||||
if ui.button("Quit").clicked() {
|
let ctx = ui.ctx().clone();
|
||||||
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
// 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();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
ui.add_space(16.0);
|
//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() {
|
||||||
|
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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 })
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue