tweaked project mode layout +unsaved detection

This commit is contained in:
WanderingPenwing 2024-03-01 21:37:20 +01:00
parent 024c8579f6
commit d5c5ab9dba
5 changed files with 225 additions and 217 deletions

View file

@ -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

View file

@ -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

1
calcifer.project Normal file
View file

@ -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":[]}]}

View file

@ -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) => (),
}
}

View file

@ -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<Category>,
pub categories: Vec<Category>,
}
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<Category>,
pub selected_item: Location,
pub item_window: sub_windows::ProjectItemWindow,
was_moving: bool,
pub categories: Vec<Category>,
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::<ProjectSave>(&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::<ProjectSave>(&json) {
Ok(project_save) => self.categories = project_save.categories,
Err(_err) => self.categories = vec![Category::create()],
}
}
pub fn save_to_code(&self) -> Result<String, std::io::Error> {
Ok(serde_json::to_string(&ProjectSave::from_project(self))?)
}
pub fn save_to_code(&self) -> Result<String, std::io::Error> {
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<Item>,
name: String,
pub content: Vec<Item>,
}
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;
}