diff --git a/src/app.rs b/src/app.rs index 3eadf7f..fd0c637 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,8 +1,9 @@ -use std::fs::DirEntry; -use std::ops::DerefMut; -use std::sync::Arc; +use std::sync::mpsc; +use std::collections::HashMap; -use egui::mutex::Mutex; +use crate::templates::{self, Template}; + +use egui::{Align, Layout}; #[cfg(target_arch = "wasm32")] use wasm_bindgen_futures; #[cfg(target_arch = "wasm32")] @@ -11,7 +12,7 @@ use web_sys; #[cfg(not(target_arch = "wasm32"))] use smol; -use tinytemplate; +use tinytemplate::TinyTemplate; /// We derive Deserialize/Serialize so we can persist app state on shutdown. #[derive(serde::Deserialize, serde::Serialize)] @@ -25,12 +26,20 @@ pub struct TemplateApp { #[serde(skip)] // This how you opt-out of serialization of a field value: f32, - #[serde(skip)] - templates: Vec, + + templates: HashMap, + active_template: String, #[serde(skip)] - cont_mux: Arc>, - content: String, + preview_text: String, + + #[serde(skip)] + messaging: (mpsc::Sender, mpsc::Receiver), +} + +pub enum Message { + AddTemplate(Template), + } impl Default for TemplateApp { @@ -40,9 +49,10 @@ impl Default for TemplateApp { init: false, label: "Hello World!".to_owned(), value: 2.7, - templates: Vec::new(), - cont_mux: Arc::new(Mutex::new(String::new())), - content: "No File selected".to_string(), + templates: HashMap::new(), + active_template: "Select a template".to_string(), + preview_text: "No File Selected".to_string(), + messaging: mpsc::channel(), } } } @@ -61,6 +71,7 @@ impl TemplateApp { Default::default() } } + } impl eframe::App for TemplateApp { @@ -74,12 +85,19 @@ impl eframe::App for TemplateApp { // Put your widgets into a `SidePanel`, `TopBottomPanel`, `CentralPanel`, `Window` or `Area`. // For inspiration and more examples, go to https://emilk.github.io/egui + let is_web = cfg!(target_arch = "wasm32"); + + for i in self.messaging.1.try_iter() { + match i { + Message::AddTemplate(t) => add_template(&mut self.templates, t.name.clone(), t), + } + } + 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| { // NOTE: no File->Quit on web pages! - let is_web = cfg!(target_arch = "wasm32"); if !is_web { ui.menu_button("File", |ui| { if ui.button("Quit").clicked() { @@ -92,40 +110,67 @@ impl eframe::App for TemplateApp { }); }); - egui::CentralPanel::default().show(ctx, |ui| { - // The central panel the region left after adding TopPanel's and SidePanel's - ui.heading("eframe template"); - - ui.horizontal(|ui| { - ui.label("Write something: "); - ui.text_edit_singleline(&mut self.label); - }); - - ui.add(egui::Slider::new(&mut self.value, 0.0..=10.0).text("value")); - if ui.button("test").clicked() { - self.value += 1.0; - } - - if ui.button("rfd").clicked() { - let file = test_async(self.cont_mux.clone()); - } - self.content = self.cont_mux.lock().clone(); - - ui.text_edit_multiline(&mut self.content); - - ui.separator(); - - ui.add(egui::github_link_file!( - "https://github.com/emilk/eframe_template/blob/main/", - "Source code." - )); - - + egui::TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| { ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| { powered_by_egui_and_eframe(ui); egui::warn_if_debug_build(ui); }); }); + + egui::CentralPanel::default().show(ctx, |ui| { + // The central panel the region left after adding TopPanel's and SidePanel's + egui::containers::Sides::new().show(ui, |ui|{ + ui.with_layout(Layout::top_down(Align::LEFT), |ui| { + ui.heading("eframe template"); + + ui.horizontal(|ui| { + ui.label("Write something: "); + ui.text_edit_singleline(&mut self.label); + }); + + if ui.button("test").clicked() { + self.value += 1.0; + } + + if ui.button("rfd").clicked() { + test_async(self.messaging.0.clone()); + } + + ui.separator(); + + if self.templates.is_empty() { + + } + + egui::containers::ComboBox::from_label("Select a template") + .selected_text(self.active_template.clone()) + .show_ui(ui, |x| { + for (name, _) in self.templates.iter() { + x.selectable_value(&mut self.active_template, name.clone(), name.clone()); + } + }); + + ui.separator(); + + ui.add(egui::github_link_file!( + "https://github.com/emilk/eframe_template/blob/main/", + "Source code." + )); + }); + }, |ui| { + let selected = match self.templates.get(&self.active_template.clone()) { + Some(t) => { + let text = t.text_files.iter().next(); + match text { + Some(t) => t.1.clone(), + None => "No File Selected".to_string(), + } + }, + None => "No File Selected".to_string() + }; + ui.label(selected); + }); + }); } } @@ -143,7 +188,7 @@ fn powered_by_egui_and_eframe(ui: &mut egui::Ui) { }); } -fn test_async(test: Arc>) { +fn test_async(test: mpsc::Sender) { // Spawn dialog on main thread let task = rfd::AsyncFileDialog::new().pick_file(); @@ -154,6 +199,7 @@ fn test_async(test: Arc>) { if let Some(file) = file { // If you care about wasm support you just read() the file + let name = file.file_name(); let output = file.read().await; let string_data = match String::from_utf8(output) { @@ -164,9 +210,7 @@ fn test_async(test: Arc>) { #[cfg(target_arch = "wasm32")] web_sys::console::log_1(&string_data.clone().into()); - let mut t = test.lock(); - let a = t.deref_mut(); - *a = string_data; + let _ = test.send(Message::AddTemplate(Template::new(string_data))); } }); } @@ -183,6 +227,7 @@ fn execute + 'static>(f: F) { web_sys::console::log_1(&"Async End".into()); } -enum FileError { - Unknown, + +fn add_template(map: &mut HashMap, label: String, template: Template) { + map.insert(label, template); } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index fbae77a..e6eefc9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ #![warn(clippy::all, rust_2018_idioms)] mod app; +mod templates; + pub use app::TemplateApp; diff --git a/src/templates.rs b/src/templates.rs new file mode 100644 index 0000000..8f99884 --- /dev/null +++ b/src/templates.rs @@ -0,0 +1,52 @@ +use std::hash::Hash; + + + +#[derive(serde::Serialize, serde::Deserialize, Eq)] +#[serde(default)] +pub struct Template { + pub name: String, + pub text_files: Vec<(String, String)>, + pub images: Vec<(String, Vec)>, + pub config: String, +} + +impl Template { + pub fn new(name: String) -> Self { + Self { + name, + text_files: Vec::new(), + images: Vec::new(), + config: String::new(), + } + } +} + +impl Default for Template { + fn default() -> Self { + Self { + name: "New_Template".to_string(), + text_files: Vec::new(), + images: Vec::new(), + config: String::new() } + } +} + +impl PartialEq for Template { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} + +impl PartialEq for Template { + fn eq(&self, other: &String) -> bool { + &self.name == other + } +} + +impl Hash for Template { + fn hash(&self, state: &mut H) { + self.name.hash(state); + } +} +