From fcb1b7abbaac6e084681686619104e80340914db Mon Sep 17 00:00:00 2001 From: Penwing Date: Thu, 25 Jan 2024 08:48:32 +0100 Subject: [PATCH] better ui organisation --- src/calcifer.rs | 58 ++++++++++++++++++----------------- src/calcifer/app_base.rs | 10 +++--- src/main.rs | 66 +++++++++++++++++++++++++--------------- src/tools/confirm.rs | 7 ++--- src/tools/mod.rs | 42 +++++++++++++------------ src/tools/profiler.rs | 38 +++++++++++++++++++++++ src/tools/settings.rs | 54 ++++++++++++++++++++++++++++++++ 7 files changed, 195 insertions(+), 80 deletions(-) create mode 100644 src/tools/profiler.rs create mode 100644 src/tools/settings.rs diff --git a/src/calcifer.rs b/src/calcifer.rs index eda52ea..0c38cfd 100644 --- a/src/calcifer.rs +++ b/src/calcifer.rs @@ -4,55 +4,34 @@ use std::{env, path::Path, cmp::max}; use crate::tools; use crate::Calcifer; -use crate::TIME_LABELS; use crate::PATH_ROOT; use crate::MAX_TABS; pub mod code_editor; use code_editor::CodeEditor; -use code_editor::themes::DEFAULT_THEMES; mod app_base; impl Calcifer { pub fn draw_settings(&mut self, ctx: &egui::Context) { - egui::TopBottomPanel::top("settings") + egui::SidePanel::left("settings") .resizable(false) + .exact_width(self.font_size * 1.8) .show(ctx, |ui| { - ui.horizontal(|ui| { - if ui.add(egui::Button::new("open file")).clicked() { + ui.vertical(|ui| { + if ui.add(egui::Button::new("📁")).clicked() { if let Some(path) = rfd::FileDialog::new().set_directory(Path::new(&PATH_ROOT)).pick_file() { self.open_file(Some(&path)); } } ui.separator(); - - ui.label("Theme "); - egui::ComboBox::from_label("") - .selected_text(format!("{}", self.theme.name)) - .show_ui(ui, |ui| { - ui.style_mut().wrap = Some(false); - ui.set_min_width(60.0); - for theme in DEFAULT_THEMES { - ui.selectable_value(&mut self.theme, theme, theme.name); - } - }); - + self.tree_display = self.toggle(ui, self.tree_display, "🗐"); ui.separator(); - self.tree_display = self.toggle(ui, self.tree_display, "Tree"); + self.settings_menu.visible = self.toggle(ui, self.settings_menu.visible, "⚙"); ui.separator(); - self.debug_display = self.toggle(ui, self.debug_display, "Debug"); + self.profiler_menu.visible = self.toggle(ui, self.profiler_menu.visible, "🗠"); ui.separator(); - - if self.debug_display { - let combined_string: Vec = TIME_LABELS.into_iter().zip(self.time_watch.clone().into_iter()) - .map(|(s, v)| format!("{} : {:.1} ms", s, v)).collect(); - - let mut result = combined_string.join(" ; "); - result.push_str(&format!(" total : {:.1}", self.time_watch.clone().iter().sum::())); - ui.label(result); - } }); }); } @@ -202,4 +181,27 @@ impl Calcifer { .with_numlines(true) .show(ui, &mut current_tab.code, &mut current_tab.saved, &mut current_tab.last_cursor, &mut current_tab.scroll_offset, override_cursor); } + + pub fn draw_windows(&mut self, ctx: &egui::Context) { + if self.search.visible { + self.search.show(ctx, &mut self.tabs, &mut self.selected_tab); + } + if self.close_tab_confirm.visible { + self.close_tab_confirm.show(ctx); + } + if self.refresh_confirm.visible { + self.refresh_confirm.show(ctx); + } + if self.profiler_menu.visible { + self.profiler_menu.show(ctx, self.time_watch.clone()); + } + if self.settings_menu.visible { + self.settings_menu.show(ctx); + } + if self.settings_menu.updated { + self.theme = self.settings_menu.theme.clone(); + } + + self.handle_confirm(); + } } diff --git a/src/calcifer/app_base.rs b/src/calcifer/app_base.rs index 6098d9c..ea90c9e 100644 --- a/src/calcifer/app_base.rs +++ b/src/calcifer/app_base.rs @@ -1,5 +1,6 @@ use std::{path::PathBuf, fs, path::Path, cmp::min, io}; use eframe::egui; +use egui::Color32; use crate::Calcifer; use crate::tools; @@ -62,6 +63,7 @@ impl Calcifer { let mut new = Self { theme: DEFAULT_THEMES[min(app_state.theme, DEFAULT_THEMES.len() - 1)], tabs: Vec::new(), + settings_menu: tools::settings::SettingsWindow::new(DEFAULT_THEMES[app_state.theme]), ..Default::default() }; @@ -150,13 +152,13 @@ impl Calcifer { pub fn toggle(&self, ui: &mut egui::Ui, display : bool, title : &str) -> bool { - let text = if display.clone() { - format!("hide {}", title) + let color = if display.clone() { + Color32::from_hex(self.theme.functions).expect("Could not convert color to hex (functions)") } else { - format!("show {}", title) + Color32::from_hex(self.theme.bg).expect("Could not convert color to hex (bg)") }; - if ui.add(egui::Button::new(text)).clicked() { + if ui.add(egui::Button::new(title).fill(color)).clicked() { return !display } return display diff --git a/src/main.rs b/src/main.rs index c3615ab..cf0fec5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,9 @@ mod calcifer; use eframe::egui; use calcifer::code_editor::ColorTheme; use std::{path::Path, sync::Arc, time, thread}; +use egui::FontFamily::Proportional; +use egui::FontId; +use egui::TextStyle::{Small, Button, Body, Heading, Monospace}; use calcifer::code_editor::themes::DEFAULT_THEMES; @@ -24,7 +27,7 @@ use build::TITLE; const TERMINAL_HEIGHT : f32 = 200.0; const RED : egui::Color32 = egui::Color32::from_rgb(235, 108, 99); -const TIME_LABELS : [&str; 5] = ["settings", "tree", "terminal", "tabs", "content"]; +const TIME_LABELS : [&str; 7] = ["input", "settings", "tree", "terminal", "tabs", "content", "windows"]; const MAX_FPS : f32 = 30.0; const PATH_ROOT : &str = "/home/penwing/Documents/"; const DISPLAY_PATH_DEPTH : usize = 3; @@ -68,18 +71,19 @@ struct Calcifer { theme: ColorTheme, font_size: f32, - - search: tools::search::SearchWindow, - - debug_display: bool, - time_watch: Vec, - next_frame: time::Instant, tree_display: bool, close_tab_confirm: tools::confirm::ConfirmWindow, tab_to_close: usize, refresh_confirm: tools::confirm::ConfirmWindow, + + search: tools::search::SearchWindow, + settings_menu: tools::settings::SettingsWindow, + profiler_menu: tools::profiler::ProfilerWindow, + + time_watch: Vec, + next_frame: time::Instant, } @@ -94,18 +98,19 @@ impl Default for Calcifer { theme: DEFAULT_THEMES[0], font_size: 14.0, - - search: tools::search::SearchWindow::default(), - - debug_display: false, - time_watch: vec![0.0; TIME_LABELS.len()], - next_frame: time::Instant::now(), tree_display: false, close_tab_confirm: tools::confirm::ConfirmWindow::new("You have some unsaved changes, Do you still want to close this document ?", "Confirm Close"), tab_to_close: 0, refresh_confirm: tools::confirm::ConfirmWindow::new("You have some unsaved changes, Do you still want to refresh this document ?", "Confirm Refresh"), + + search: tools::search::SearchWindow::default(), + settings_menu: tools::settings::SettingsWindow::new(DEFAULT_THEMES[0]), + profiler_menu: tools::profiler::ProfilerWindow::new(), + + time_watch: vec![0.0; TIME_LABELS.len()], + next_frame: time::Instant::now(), } } } @@ -118,6 +123,17 @@ impl eframe::App for Calcifer { let mut watch = time::Instant::now(); + let mut style = (*ctx.style()).clone(); + style.text_styles = [ + (Heading, FontId::new(self.font_size * 1.6, Proportional)), + (Body, FontId::new(self.font_size, Proportional)), + (Monospace, FontId::new(self.font_size, Proportional)), + (Button, FontId::new(self.font_size, Proportional)), + (Small, FontId::new(self.font_size, Proportional)), + ] + .into(); + ctx.set_style(style); + if ctx.input( |i| i.key_pressed(egui::Key::T) && i.modifiers.ctrl) && !self.refresh_confirm.visible { if self.tabs[self.selected_tab.to_index()].saved { self.tabs[self.selected_tab.to_index()].refresh(); @@ -155,35 +171,37 @@ impl eframe::App for Calcifer { self.search.initialized = !self.search.visible.clone(); } - self.draw_settings(ctx); - self.time_watch[0] = watch.elapsed().as_micros() as f32 / 1000.0; watch = time::Instant::now(); - self.draw_tree_panel(ctx); + self.draw_settings(ctx); self.time_watch[1] = watch.elapsed().as_micros() as f32 / 1000.0; watch = time::Instant::now(); - self.draw_terminal_panel(ctx); + self.draw_tree_panel(ctx); self.time_watch[2] = watch.elapsed().as_micros() as f32 / 1000.0; watch = time::Instant::now(); - self.draw_tab_panel(ctx); + self.draw_terminal_panel(ctx); self.time_watch[3] = watch.elapsed().as_micros() as f32 / 1000.0; watch = time::Instant::now(); - self.draw_content_panel(ctx); + self.draw_tab_panel(ctx); self.time_watch[4] = watch.elapsed().as_micros() as f32 / 1000.0; - - self.search.show(ctx, &mut self.tabs, &mut self.selected_tab); - self.close_tab_confirm.show(ctx, &mut self.tabs, &mut self.selected_tab); - self.refresh_confirm.show(ctx, &mut self.tabs, &mut self.selected_tab); + watch = time::Instant::now(); - self.handle_confirm(); + self.draw_content_panel(ctx); + + self.time_watch[5] = watch.elapsed().as_micros() as f32 / 1000.0; + watch = time::Instant::now(); + + self.draw_windows(ctx); + + self.time_watch[6] = watch.elapsed().as_micros() as f32 / 1000.0; } fn on_exit(&mut self, _gl : std::option::Option<&eframe::glow::Context>) { diff --git a/src/tools/confirm.rs b/src/tools/confirm.rs index 9cf6a99..e029a5a 100644 --- a/src/tools/confirm.rs +++ b/src/tools/confirm.rs @@ -1,5 +1,4 @@ use eframe::egui; -use crate::tools::{Tab, TabNumber}; pub struct ConfirmWindow { @@ -21,18 +20,18 @@ impl ConfirmWindow { } - pub fn show(&mut self, ctx: &egui::Context, tabs: &mut Vec, selected_tab: &mut TabNumber) { + pub fn show(&mut self, ctx: &egui::Context) { let mut visible = self.visible.clone(); egui::Window::new(self.id.clone()) .open(&mut visible) //I want it to be able to change its visibility (if user close manually) .vscroll(true) .hscroll(true) - .show(ctx, |ui| self.ui(ui, tabs, selected_tab)); //but I want to edit the rest of the parameters and maybe close automatically + .show(ctx, |ui| self.ui(ui)); //but I want to edit the rest of the parameters and maybe close automatically self.visible = self.visible.clone() && visible; } - fn ui(&mut self, ui: &mut egui::Ui, _tabs: &mut Vec, _selected_tab: &mut TabNumber) { + fn ui(&mut self, ui: &mut egui::Ui) { ui.set_min_width(250.0); ui.label(self.prompt.clone()); ui.vertical_centered(|ui| { diff --git a/src/tools/mod.rs b/src/tools/mod.rs index 31c0111..1dabf7d 100644 --- a/src/tools/mod.rs +++ b/src/tools/mod.rs @@ -8,6 +8,8 @@ use toml::Value; //my tools; pub mod search; pub mod confirm; +pub mod settings; +pub mod profiler; pub mod terminal; pub use terminal::*; @@ -27,16 +29,16 @@ pub fn save_state(state: &AppState, file_path: &str) -> Result<(), std::io::Erro let serialized_state = serde_json::to_string(state)?; if let Some(parent_dir) = Path::new(file_path).parent() { - fs::create_dir_all(parent_dir)?; - } + fs::create_dir_all(parent_dir)?; + } let mut file = OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(file_path)?; + .write(true) + .create(true) + .truncate(true) + .open(file_path)?; - file.write_all(serialized_state.as_bytes())?; + file.write_all(serialized_state.as_bytes())?; println!("Saved state at {}", file_path); @@ -110,21 +112,21 @@ pub fn format_path(path: &Path) -> String { } pub fn version() -> String { - // Read the contents of the Cargo.toml file - let toml_content = fs::read_to_string("Cargo.toml").expect("Failed to read Cargo.toml"); + // Read the contents of the Cargo.toml file + let toml_content = fs::read_to_string("Cargo.toml").expect("Failed to read Cargo.toml"); - // Parse the TOML content - let toml: Value = toml::from_str(&toml_content).expect("Failed to parse TOML"); + // Parse the TOML content + let toml: Value = toml::from_str(&toml_content).expect("Failed to parse TOML"); - // Extract version information - if let Some(package) = toml.get("package") { - if let Some(version) = package.get("version") { - if let Some(version_string) = version.as_str() { - println!("Version: {}", version_string); - return version_string.to_string() - } - } - } + // Extract version information + if let Some(package) = toml.get("package") { + if let Some(version) = package.get("version") { + if let Some(version_string) = version.as_str() { + println!("Version: {}", version_string); + return version_string.to_string() + } + } + } return "".to_string() } diff --git a/src/tools/profiler.rs b/src/tools/profiler.rs new file mode 100644 index 0000000..fd83d86 --- /dev/null +++ b/src/tools/profiler.rs @@ -0,0 +1,38 @@ +use eframe::egui; +use crate::TIME_LABELS; + + +pub struct ProfilerWindow { + pub visible: bool, +} + + +impl ProfilerWindow { + pub fn new() -> Self { + Self { + visible: false, + } + } + + + pub fn show(&mut self, ctx: &egui::Context, time_watch: Vec) { + let mut visible = self.visible.clone(); + egui::Window::new("Profiler") + .open(&mut visible) //I want it to be able to change its visibility (if user close manually) + .vscroll(true) + .hscroll(true) + .show(ctx, |ui| self.ui(ui, time_watch)); //but I want to edit the rest of the parameters and maybe close automatically + self.visible = self.visible.clone() && visible; + } + + + fn ui(&mut self, ui: &mut egui::Ui, time_watch: Vec) { + ui.set_min_width(100.0); + + for (index, entry) in TIME_LABELS.iter().enumerate() { + ui.label(format!("{} : {:.1} ms", entry, time_watch[index])); + } + ui.separator(); + ui.label(&format!("total : {:.1} ms", time_watch.clone().iter().sum::())); + } +} \ No newline at end of file diff --git a/src/tools/settings.rs b/src/tools/settings.rs new file mode 100644 index 0000000..1c690a7 --- /dev/null +++ b/src/tools/settings.rs @@ -0,0 +1,54 @@ +use eframe::egui; +use crate::ColorTheme; +use crate::DEFAULT_THEMES; + + +pub struct SettingsWindow { + pub visible: bool, + pub updated: bool, + pub theme: ColorTheme, +} + + +impl SettingsWindow { + pub fn new(theme : ColorTheme) -> Self { + Self { + visible: false, + updated: false, + theme, + } + } + + + pub fn show(&mut self, ctx: &egui::Context) { + let mut visible = self.visible.clone(); + egui::Window::new("Settings") + .open(&mut visible) //I want it to be able to change its visibility (if user close manually) + .vscroll(true) + .hscroll(true) + .show(ctx, |ui| self.ui(ui)); //but I want to edit the rest of the parameters and maybe close automatically + self.visible = self.visible.clone() && visible; + } + + + fn ui(&mut self, ui: &mut egui::Ui) { + ui.set_min_width(250.0); + ui.horizontal(|ui| { + ui.label("Theme "); + + let previous_theme = self.theme.clone(); + egui::ComboBox::from_label("") + .selected_text(format!("{}", self.theme.name)) + .show_ui(ui, |ui| { + ui.style_mut().wrap = Some(false); + ui.set_min_width(60.0); + for theme in DEFAULT_THEMES { + ui.selectable_value(&mut self.theme, theme, theme.name); + } + }); + if self.theme != previous_theme { + self.updated = true; + } + }); + } +} \ No newline at end of file