From d5c5ab9dbaecb3c5ef00c172a3600f21c61631d1 Mon Sep 17 00:00:00 2001 From: WanderingPenwing Date: Fri, 1 Mar 2024 21:37:20 +0100 Subject: [PATCH] tweaked project mode layout +unsaved detection --- Cargo.toml | 2 +- README.md | 5 +- calcifer.project | 1 + src/core/ui.rs | 7 +- src/panels/project_mode.rs | 427 +++++++++++++++++++------------------ 5 files changed, 225 insertions(+), 217 deletions(-) create mode 100644 calcifer.project diff --git a/Cargo.toml b/Cargo.toml index 101ce31..dbaa77c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "calcifer" -version = "1.1.0" +version = "1.2.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md index 6c7363c..78c9f2a 100644 --- a/README.md +++ b/README.md @@ -48,5 +48,6 @@ Real Ui Better error handling -# releases : -latest : command can fetch multiple lines in the buffer in one frame +#1.2.0 : +Project mode (when opening a .project file) +Support for js diff --git a/calcifer.project b/calcifer.project new file mode 100644 index 0000000..c2adc41 --- /dev/null +++ b/calcifer.project @@ -0,0 +1 @@ +{"categories":[{"name":"to do","content":[{"name":"clean up","description":"using the feedback from ourstory discord","id":1},{"name":"be able to delete item","description":"in project mode add a button in item edit window to delete an item","id":4},{"name":"be able to delete category","description":"in project mode, if no focus and name is empty => delete category\n\nalready did xD I am a geniius\nfor clarification, I had a loong pause in develompent, and had forgotten I had this implemented, and while looking for where to code it, i found at the exact right place, the exact code needed","id":5},{"name":"update category layout","description":"take inspo form tab layout (number of column is max( min col, n_col +1)\nor scroll ?","id":6},{"name":"keep tree in save","description":"keep track of the opened tabs and reopens them\n","id":1},{"name":"u","description":"// Hello there","id":2},{"name":"less enter trigger (project)","description":"if in a textbox, don't open the item window when enter is pressed","id":3}]},{"name":"in progress","content":[]},{"name":"done","content":[{"name":"mark tab as unsaved (project)","description":"when modifying a project, mark it as unsaved","id":2},{"name":"fix + color in project","description":"the '+' to add an item has a wrong color if last item in list is selected","id":3}]},{"name":"bugs","content":[]},{"name":"+","content":[]}]} \ No newline at end of file diff --git a/src/core/ui.rs b/src/core/ui.rs index 5730202..bc436c2 100644 --- a/src/core/ui.rs +++ b/src/core/ui.rs @@ -357,7 +357,12 @@ impl Calcifer { } match self.project_content.save_to_code() { - Ok(code) => current_tab.code = code, + Ok(code) => { + if current_tab.code != code { + current_tab.code = code; + current_tab.saved = false; + } + } Err(_err) => (), } } diff --git a/src/panels/project_mode.rs b/src/panels/project_mode.rs index fca4142..3a6b304 100644 --- a/src/panels/project_mode.rs +++ b/src/panels/project_mode.rs @@ -1,8 +1,9 @@ use eframe::egui; use serde::{Deserialize, Serialize}; use std::{ - cmp::min, - sync::atomic::{AtomicUsize, Ordering}, + cmp::min, + cmp::max, + sync::atomic::{AtomicUsize, Ordering}, }; use crate::core::hex_str_to_color; @@ -12,262 +13,262 @@ use crate::MAX_PROJECT_COLUMNS; #[derive(Serialize, Deserialize)] pub struct ProjectSave { - pub categories: Vec, + pub categories: Vec, } impl ProjectSave { - pub fn from_project(project: &Project) -> Self { - Self { - categories: project.categories.clone(), - } - } + pub fn from_project(project: &Project) -> Self { + Self { + categories: project.categories.clone(), + } + } } pub struct Project { - pub categories: Vec, - pub selected_item: Location, - pub item_window: sub_windows::ProjectItemWindow, - was_moving: bool, + pub categories: Vec, + pub selected_item: Location, + pub item_window: sub_windows::ProjectItemWindow, + was_moving: bool, } impl Project { - pub fn new() -> Self { - Self { - categories: vec![Category::create()], - selected_item: Location::zero(), - was_moving: false, - item_window: sub_windows::ProjectItemWindow::new(), - } - } + pub fn new() -> Self { + Self { + categories: vec![Category::create()], + selected_item: Location::zero(), + was_moving: false, + item_window: sub_windows::ProjectItemWindow::new(), + } + } - pub fn update_from_code(&mut self, json: String) { - match serde_json::from_str::(&json) { - Ok(project_save) => self.categories = project_save.categories, - Err(_err) => self.categories = vec![Category::create()], - } - } + pub fn update_from_code(&mut self, json: String) { + match serde_json::from_str::(&json) { + Ok(project_save) => self.categories = project_save.categories, + Err(_err) => self.categories = vec![Category::create()], + } + } - pub fn save_to_code(&self) -> Result { - Ok(serde_json::to_string(&ProjectSave::from_project(self))?) - } + pub fn save_to_code(&self) -> Result { + Ok(serde_json::to_string(&ProjectSave::from_project(self))?) + } - fn add_category(&mut self) { - let last = self.categories.len() - 1; - self.categories[last].initialize(); - if self.categories.len() < MAX_PROJECT_COLUMNS { - self.categories.push(Category::create()); - } - } + fn add_category(&mut self) { + let last = self.categories.len() - 1; + self.categories[last].initialize(); + self.categories.push(Category::create()); + } - fn delete_category(&mut self, index: usize) { - self.categories.remove(index); - let last = self.categories.len() - 1; - if self.categories[last].name != "+" { - self.categories.push(Category::create()); - } - } + fn delete_category(&mut self, index: usize) { + self.categories.remove(index); + let last = self.categories.len() - 1; + if self.categories[last].name != "+" { + self.categories.push(Category::create()); + } + } } #[derive(Clone, Serialize, Deserialize)] pub struct Category { - name: String, - pub content: Vec, + name: String, + pub content: Vec, } impl Category { - fn create() -> Self { - Self { - name: "+".into(), - content: vec![], - } - } + fn create() -> Self { + Self { + name: "+".into(), + content: vec![], + } + } - fn initialize(&mut self) { - self.name = "untitled".into(); - } + fn initialize(&mut self) { + self.name = "untitled".into(); + } } #[derive(Clone, Hash, Serialize, Deserialize)] pub struct Item { - pub name: String, - pub description: String, - id: usize, + pub name: String, + pub description: String, + id: usize, } impl Item { - fn new(name: &str) -> Self { - Self { - name: name.to_string(), - description: "// Hello there".to_string(), - id: get_id(), - } - } + fn new(name: &str) -> Self { + Self { + name: name.to_string(), + description: "// Hello there".to_string(), + id: get_id(), + } + } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Location { - pub category: usize, - pub row: usize, + pub category: usize, + pub row: usize, } impl Location { - fn zero() -> Self { - Self { - category: 0, - row: 0, - } - } + fn zero() -> Self { + Self { + category: 0, + row: 0, + } + } } fn get_id() -> usize { - static COUNTER: AtomicUsize = AtomicUsize::new(1); - COUNTER.fetch_add(1, Ordering::Relaxed) + static COUNTER: AtomicUsize = AtomicUsize::new(1); + COUNTER.fetch_add(1, Ordering::Relaxed) } pub fn draw_project(ui: &mut egui::Ui, theme: ColorTheme, project: &mut Project) { - ui.columns(MAX_PROJECT_COLUMNS, |uis| { - for (category_index, category) in project.categories.clone().into_iter().enumerate() { - let ui = &mut uis[category_index]; + ui.columns(max(MAX_PROJECT_COLUMNS, project.categories.len() + 1) , |uis| { + for (category_index, category) in project.categories.clone().into_iter().enumerate() { + let ui = &mut uis[category_index]; - if category.name == "+" { - if ui.add(egui::Button::new("+")).clicked() { - project.add_category(); - } - continue; - } else { - let response = ui.add( - egui::TextEdit::singleline(&mut project.categories[category_index].name) - .desired_width(f32::INFINITY), - ); - if response.lost_focus() && project.categories[category_index].name.is_empty() { - project.delete_category(category_index); - } - } + if category.name == "+" { + if ui.add(egui::Button::new("+")).clicked() { + project.add_category(); + } + continue; + } else { + let response = ui.add( + egui::TextEdit::singleline(&mut project.categories[category_index].name) + .desired_width(f32::INFINITY), + ); + if response.lost_focus() && project.categories[category_index].name.is_empty() { + project.delete_category(category_index); + } + } - ui.separator(); + ui.separator(); - for (item_index, item) in category.content.iter().enumerate() { - if project.selected_item - == (Location { - category: category_index, - row: item_index, - }) - { - ui.style_mut().visuals.override_text_color = Some(hex_str_to_color(theme.bg)); - ui.add( - egui::Button::new(item.name.clone()) - .fill(hex_str_to_color(theme.functions)), - ); - } else { - ui.style_mut().visuals.override_text_color = - Some(hex_str_to_color(theme.literals)); - if ui - .add(egui::Button::new(item.name.clone()).fill(hex_str_to_color(theme.bg))) - .clicked() - { - project.selected_item = Location { - category: category_index, - row: item_index, - }; - } - } - } - if category.name != "+" && ui.add(egui::Button::new("+")).clicked() { - project.categories[category_index] - .content - .push(Item::new("item")); - } - // if category.name != "+" { - // if ui.add(egui::Button::new("+")).clicked() { - // project.categories[category_index] - // .content - // .push(Item::new("item")); - // } - // } - } - }); + for (item_index, item) in category.content.iter().enumerate() { + if project.selected_item + == (Location { + category: category_index, + row: item_index, + }) + { + ui.style_mut().visuals.override_text_color = Some(hex_str_to_color(theme.bg)); + ui.add( + egui::Button::new(item.name.clone()) + .fill(hex_str_to_color(theme.functions)), + ); + } else { + ui.style_mut().visuals.override_text_color = + Some(hex_str_to_color(theme.literals)); + if ui + .add(egui::Button::new(item.name.clone()).fill(hex_str_to_color(theme.bg))) + .clicked() + { + project.selected_item = Location { + category: category_index, + row: item_index, + }; + } + } + } + ui.style_mut().visuals.override_text_color = + Some(hex_str_to_color(theme.literals)); + if category.name != "+" && ui.add(egui::Button::new("+")).clicked() { + project.categories[category_index] + .content + .push(Item::new("item")); + } + // if category.name != "+" { + // if ui.add(egui::Button::new("+")).clicked() { + // project.categories[category_index] + // .content + // .push(Item::new("item")); + // } + // } + } + }); - let mut moved = false; - let category = project.selected_item.category; - let row = project.selected_item.row; + let mut moved = false; + let category = project.selected_item.category; + let row = project.selected_item.row; - if ui.input(|i| i.key_pressed(egui::Key::ArrowLeft) && i.modifiers.shift) - && project.selected_item.category > 0 - { - moved = true; - if !project.was_moving { - let temp = project.categories[category].content[row].clone(); - project.categories[category - 1].content.push(temp); - project.categories[category].content.remove(row); - project.selected_item.category -= 1; - project.selected_item.row = project.categories[category - 1].content.len() - 1; - } - } else if ui.input(|i| i.key_pressed(egui::Key::ArrowRight) && i.modifiers.shift) - && project.selected_item.category < project.categories.len() - 2 - { - moved = true; - if !project.was_moving { - let temp = project.categories[category].content[row].clone(); - project.categories[category + 1].content.push(temp); - project.categories[category].content.remove(row); - project.selected_item.category += 1; - project.selected_item.row = project.categories[category + 1].content.len() - 1; - } - } else if ui.input(|i| i.key_pressed(egui::Key::ArrowUp) && i.modifiers.shift) - && project.selected_item.row > 0 - { - moved = true; - if !project.was_moving { - let temp = project.categories[category].content[row].clone(); - project.categories[category].content[row] = - project.categories[category].content[row - 1].clone(); - project.categories[category].content[row - 1] = temp.clone(); - project.selected_item.row -= 1; - } - } else if ui.input(|i| i.key_pressed(egui::Key::ArrowDown) && i.modifiers.shift) { - moved = true; - if !project.was_moving { - let temp = project.categories[category].content[row].clone(); - project.categories[category].content[row] = - project.categories[category].content[row + 1].clone(); - project.categories[category].content[row + 1] = temp.clone(); - project.selected_item.row += 1; - } - } else if ui.input(|i| i.key_pressed(egui::Key::ArrowLeft)) - && project.selected_item.category > 0 - { - moved = true; - if !project.was_moving { - project.selected_item.category -= 1; - project.selected_item.row = min( - project.categories[category].content.len() - 1, - project.selected_item.row, - ); - } - } else if ui.input(|i| i.key_pressed(egui::Key::ArrowRight)) - && project.selected_item.category < project.categories.len() - 2 - { - moved = true; - if !project.was_moving { - project.selected_item.category += 1; - project.selected_item.row = min( - project.categories[category].content.len() - 1, - project.selected_item.row, - ); - } - } else if ui.input(|i| i.key_pressed(egui::Key::ArrowUp)) && project.selected_item.row > 0 { - moved = true; - if !project.was_moving { - project.selected_item.row -= 1; - } - } else if ui.input(|i| i.key_pressed(egui::Key::ArrowDown)) - && project.selected_item.row < project.categories[category].content.len() - 1 - { - moved = true; - if !project.was_moving { - project.selected_item.row += 1; - } - } + if ui.input(|i| i.key_pressed(egui::Key::ArrowLeft) && i.modifiers.shift) + && project.selected_item.category > 0 + { + moved = true; + if !project.was_moving { + let temp = project.categories[category].content[row].clone(); + project.categories[category - 1].content.push(temp); + project.categories[category].content.remove(row); + project.selected_item.category -= 1; + project.selected_item.row = project.categories[category - 1].content.len() - 1; + } + } else if ui.input(|i| i.key_pressed(egui::Key::ArrowRight) && i.modifiers.shift) + && project.selected_item.category < project.categories.len() - 2 + { + moved = true; + if !project.was_moving { + let temp = project.categories[category].content[row].clone(); + project.categories[category + 1].content.push(temp); + project.categories[category].content.remove(row); + project.selected_item.category += 1; + project.selected_item.row = project.categories[category + 1].content.len() - 1; + } + } else if ui.input(|i| i.key_pressed(egui::Key::ArrowUp) && i.modifiers.shift) + && project.selected_item.row > 0 + { + moved = true; + if !project.was_moving { + let temp = project.categories[category].content[row].clone(); + project.categories[category].content[row] = + project.categories[category].content[row - 1].clone(); + project.categories[category].content[row - 1] = temp.clone(); + project.selected_item.row -= 1; + } + } else if ui.input(|i| i.key_pressed(egui::Key::ArrowDown) && i.modifiers.shift) { + moved = true; + if !project.was_moving { + let temp = project.categories[category].content[row].clone(); + project.categories[category].content[row] = + project.categories[category].content[row + 1].clone(); + project.categories[category].content[row + 1] = temp.clone(); + project.selected_item.row += 1; + } + } else if ui.input(|i| i.key_pressed(egui::Key::ArrowLeft)) + && project.selected_item.category > 0 + { + moved = true; + if !project.was_moving { + project.selected_item.category -= 1; + project.selected_item.row = min( + project.categories[category].content.len() - 1, + project.selected_item.row, + ); + } + } else if ui.input(|i| i.key_pressed(egui::Key::ArrowRight)) + && project.selected_item.category < project.categories.len() - 2 + { + moved = true; + if !project.was_moving { + project.selected_item.category += 1; + project.selected_item.row = min( + project.categories[category].content.len() - 1, + project.selected_item.row, + ); + } + } else if ui.input(|i| i.key_pressed(egui::Key::ArrowUp)) && project.selected_item.row > 0 { + moved = true; + if !project.was_moving { + project.selected_item.row -= 1; + } + } else if ui.input(|i| i.key_pressed(egui::Key::ArrowDown)) + && project.selected_item.row < project.categories[category].content.len() - 1 + { + moved = true; + if !project.was_moving { + project.selected_item.row += 1; + } + } - project.was_moving = moved; + project.was_moving = moved; }