tweaked project mode layout +unsaved detection
This commit is contained in:
parent
024c8579f6
commit
d5c5ab9dba
|
@ -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
|
||||
|
|
|
@ -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
1
calcifer.project
Normal 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":[]}]}
|
|
@ -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) => (),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue