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"]
|
||||
|
||||
[features]
|
||||
egui = ["dep:egui", "dep:eframe"]
|
||||
egui = ["dep:eframe", "dep:egui"]
|
||||
sdl2 = ["dep:sdl2"]
|
||||
|
||||
[dependencies]
|
||||
rfd = "0.14.0"
|
||||
gl = "0.14.0"
|
||||
pathfinder_canvas = { 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"
|
||||
enum_dispatch = "0.3.12"
|
||||
itertools = "0.8.2"
|
||||
futures = "0.3.30"
|
||||
contracts = "0.6.3"
|
||||
log = "0.4"
|
||||
|
||||
|
|
@ -41,16 +43,16 @@ log = "0.4"
|
|||
version = "1"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.egui]
|
||||
optional = true
|
||||
version = "0.26.0"
|
||||
|
||||
[dependencies.eframe]
|
||||
optional = true
|
||||
version = "0.26.0"
|
||||
default-features = false
|
||||
features = ["accesskit", "default_fonts", "glow", "persistence"]
|
||||
|
||||
[dependencies.egui]
|
||||
optional = true
|
||||
version = "0.26.0"
|
||||
|
||||
[dependencies.sdl2]
|
||||
optional = true
|
||||
version = "0.35.2"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
use futures::executor;
|
||||
use std::{
|
||||
future::Future,
|
||||
sync::mpsc::{channel, Receiver, Sender},
|
||||
};
|
||||
|
||||
use topola::{
|
||||
layout::geometry::shape::{BendShape, DotShape, SegShape, Shape},
|
||||
dsn::design::DsnDesign,
|
||||
geometry::shape::{BendShape, DotShape, SegShape, Shape},
|
||||
math::Circle,
|
||||
};
|
||||
|
||||
|
|
@ -12,8 +19,10 @@ pub struct App {
|
|||
// Example stuff:
|
||||
label: String,
|
||||
|
||||
#[serde(skip)] // Don't serialize this field.
|
||||
value: f32,
|
||||
//#[serde(skip)] // Don't serialize this field.
|
||||
//text_channel: (Sender<String>, Receiver<String>),
|
||||
#[serde(skip)]
|
||||
design: Option<DsnDesign>,
|
||||
}
|
||||
|
||||
impl Default for App {
|
||||
|
|
@ -21,7 +30,8 @@ impl Default for App {
|
|||
Self {
|
||||
// Example stuff:
|
||||
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) {
|
||||
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
|
||||
egui::menu::bar(ui, |ui| {
|
||||
let is_web = cfg!(target_arch = "wasm32");
|
||||
if !is_web {
|
||||
ui.menu_button("File", |ui| {
|
||||
if ui.button("Quit").clicked() {
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
||||
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();
|
||||
}
|
||||
});
|
||||
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);
|
||||
});
|
||||
|
|
@ -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 geo::Point;
|
||||
use topola::layout::geometry::shape::Shape;
|
||||
use topola::geometry::shape::Shape;
|
||||
|
||||
pub struct Painter<'a> {
|
||||
ui: &'a mut egui::Ui,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ impl Rules {
|
|||
pub fn from_pcb(pcb: &Pcb) -> Self {
|
||||
// keeping this as a separate iter pass because it might be moved into a different struct later?
|
||||
let net_ids = HashMap::from_iter(
|
||||
pcb.network.classes
|
||||
pcb.network
|
||||
.classes
|
||||
.iter()
|
||||
.flat_map(|class| &class.nets)
|
||||
.enumerate()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use serde::{Deserialize, Deserializer, de::Error};
|
||||
use serde::{de::Error, Deserialize, Deserializer};
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename = "pcb")]
|
||||
|
|
@ -251,15 +251,16 @@ pub struct Point {
|
|||
}
|
||||
|
||||
fn de_points<'de, D>(deserializer: D) -> Result<Vec<Point>, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Vec::<f32>::deserialize(deserializer)?
|
||||
.chunks(2)
|
||||
.map(|pair| {
|
||||
let x = pair[0];
|
||||
let y = *pair.get(1).ok_or(
|
||||
Error::custom("expected paired x y coordinates, list ended at x")
|
||||
)?;
|
||||
let y = *pair.get(1).ok_or(Error::custom(
|
||||
"expected paired x y coordinates, list ended at x",
|
||||
))?;
|
||||
|
||||
Ok(Point { x, y })
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue