diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 86 | ||||
| -rw-r--r-- | src/wasm.rs | 29 |
2 files changed, 88 insertions, 27 deletions
diff --git a/src/main.rs b/src/main.rs index 0ca84de..25c6062 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,9 @@ mod node; mod preview; mod snarl_ext; mod types; +#[cfg(target_arch = "wasm32")] +mod wasm; + use node::{AnyNode, ConcreteNode}; use snarl_ext::{Compilable, WithSignatures}; use types::{Dimension, FloatPrecision, ScalarType, Type}; @@ -199,8 +202,6 @@ impl App { }); // let snarl = Snarl::new(); - info!("about to init"); - App { snarl, viewer: Viewer { dirty: true }, @@ -212,24 +213,57 @@ impl App { impl eframe::App for App { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { - // The top panel is often a good place for a menu bar: - egui::MenuBar::new().ui(ui, |ui| { - #[cfg(not(target_arch = "wasm32"))] - { - ui.menu_button("File", |ui| { - if ui.button("Quit").clicked() { - ctx.send_viewport_cmd(egui::ViewportCommand::Close); + egui::widgets::global_theme_preference_switch(ui); + + ui.menu_button("File", |ui| { + if ui.button("Open").clicked() { + #[cfg(not(target_arch = "wasm32"))] + if let Some(path) = rfd::FileDialog::new() + .add_filter("Nodetoy shader", &["nt.json"]) + .pick_file() + { + let file = std::fs::File::open(path).unwrap(); + self.snarl = + serde_json::from_reader::<_, Snarl<AnyNode>>(file).unwrap(); + self.viewer.dirty = true; } - }); - ui.add_space(16.0); - } - egui::widgets::global_theme_preference_switch(ui); + #[cfg(target_arch = "wasm32")] + web_sys::window() + .unwrap() + .alert_with_message( + "To open an .nt.json file, please drag it onto the canvas.", + ) + .unwrap(); + } - if ui.button("Clear All").clicked() { - self.snarl = Snarl::default(); - } + #[cfg(not(target_arch = "wasm32"))] + if ui.button("Save").clicked() { + if let Some(path) = rfd::FileDialog::new() + .add_filter("Nodetoy shader", &["nt.json"]) + .save_file() + { + let file = std::fs::File::create(path).unwrap(); + serde_json::to_writer(file, &self.snarl).unwrap(); + } + } + + #[cfg(target_arch = "wasm32")] + if ui.button("Download").clicked() { + wasm::download_file(&self.snarl, "shader.nt.json") + .expect("successful download"); + } + + if ui.button("Clear All").clicked() { + self.snarl = Snarl::default(); + } + + #[cfg(not(target_arch = "wasm32"))] + if ui.button("Quit").clicked() { + ctx.send_viewport_cmd(egui::ViewportCommand::Close); + } + }); }); }); @@ -254,6 +288,13 @@ impl eframe::App for App { } } } + + ui.input(|i| { + if let Some(data) = i.raw.dropped_files.first().and_then(|f| f.bytes.as_ref()) { + self.snarl = serde_json::from_slice(data).unwrap(); + self.viewer.dirty = true; + } + }); }); egui::SidePanel::right("preview").show(ctx, |ui| { @@ -283,27 +324,18 @@ fn main() -> eframe::Result<()> { }; eframe::run_native( - "egui-snarl demo", + "nodetoy", native_options, Box::new(|cx| Ok(Box::new(App::new(cx)))), ) } -#[cfg(target_arch = "wasm32")] -fn get_canvas_element() -> Option<web_sys::HtmlCanvasElement> { - use eframe::wasm_bindgen::JsCast; - - let document = web_sys::window()?.document()?; - let canvas = document.get_element_by_id("egui_snarl_demo")?; - canvas.dyn_into::<web_sys::HtmlCanvasElement>().ok() -} - // When compiling to web using trunk: #[cfg(target_arch = "wasm32")] fn main() { eframe::WebLogger::init(log::LevelFilter::Debug).ok(); - let canvas = get_canvas_element().expect("Failed to find canvas with id 'egui_snarl_demo'"); + let canvas = wasm::get_canvas_element().expect("failed to find canvas"); let web_options = eframe::WebOptions::default(); diff --git a/src/wasm.rs b/src/wasm.rs new file mode 100644 index 0000000..6ce45e0 --- /dev/null +++ b/src/wasm.rs @@ -0,0 +1,29 @@ +use web_sys::js_sys::Array; +use web_sys::wasm_bindgen::{JsCast, JsValue}; +use web_sys::{Blob, BlobPropertyBag, HtmlAnchorElement, HtmlCanvasElement, Url}; + +pub fn get_canvas_element() -> Option<HtmlCanvasElement> { + let document = web_sys::window()?.document()?; + let canvas = document.get_element_by_id("nodetoy")?; + canvas.dyn_into::<HtmlCanvasElement>().ok() +} + +pub fn download_file<T: serde::Serialize>(value: &T, filename: &str) -> Result<(), JsValue> { + let json = serde_json::to_string(value).unwrap(); + let parts = Array::of1(&JsValue::from_str(&json)); + let opts = BlobPropertyBag::new(); + opts.set_type("application/json"); + + let blob = Blob::new_with_str_sequence_and_options(&parts, &opts)?; + let url = Url::create_object_url_with_blob(&blob)?; + + let document = web_sys::window().unwrap().document().unwrap(); + let a: HtmlAnchorElement = document.create_element("a")?.dyn_into()?; + + a.set_href(&url); + a.set_download(filename); + a.click(); + + Url::revoke_object_url(&url)?; + Ok(()) +} |
