finally another commit
This commit is contained in:
+239
-155
@@ -1,3 +1,5 @@
|
||||
use walkdir::{DirEntry, WalkDir};
|
||||
|
||||
use crate::{
|
||||
PROJECT_FOLDER, RightPanelContent,
|
||||
content_editor::MainEditor,
|
||||
@@ -14,7 +16,6 @@ pub struct Explorer {
|
||||
notes: Vec<Note>,
|
||||
documents: Vec<MainEditor>,
|
||||
tags: Vec<Tag>,
|
||||
assets: Vec<Asset>,
|
||||
}
|
||||
|
||||
impl Explorer {
|
||||
@@ -25,7 +26,6 @@ impl Explorer {
|
||||
notes: Vec::new(),
|
||||
documents: Vec::new(),
|
||||
tags: Vec::new(),
|
||||
assets: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,161 +43,122 @@ impl Explorer {
|
||||
self.load_objects().expect("Failed to load objects");
|
||||
self.load_notes().expect("Failed to load notes");
|
||||
self.load_documents().expect("Failed to load documents");
|
||||
self.load_assets().expect("Failed to load assets");
|
||||
self.load_tags().expect("Failed to load tags");
|
||||
|
||||
ui.vertical(|ui| {
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("templates"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Templates");
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::template(Some(Template::default())));
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
for template in &self.templates {
|
||||
let id = ui.make_persistent_id(template.name.clone());
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
id,
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
// load the template
|
||||
if ui.selectable_label(false, template.name.clone()).clicked() {
|
||||
*to_load = Some(RightPanelContent::template(Some(template.clone())));
|
||||
}
|
||||
self.render_templates(ui, to_load);
|
||||
self.render_notes(ui, to_load);
|
||||
self.render_doc_root(ui, load_doc);
|
||||
self.render_tags(ui, to_load);
|
||||
self.render_assets(ui, to_load);
|
||||
});
|
||||
}
|
||||
|
||||
// create a new object based on this template
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::object(Some(ObjectInstance::new(
|
||||
template,
|
||||
))));
|
||||
}
|
||||
})
|
||||
.body(|ui| {
|
||||
for object in &self.objects {
|
||||
if object.template_id == template.id {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
|
||||
// load the object
|
||||
if ui.selectable_label(false, &object.name).clicked() {
|
||||
*to_load =
|
||||
Some(RightPanelContent::object(Some(object.clone())));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
fn render_templates(&mut self, ui: &mut egui::Ui, to_load: &mut Option<RightPanelContent>) {
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("templates"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Templates");
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::template(Some(Template::default())));
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
for template in &self.templates {
|
||||
let id = ui.make_persistent_id(template.name.clone());
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
id,
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
// load the template
|
||||
if ui.selectable_label(false, template.name.clone()).clicked() {
|
||||
*to_load = Some(RightPanelContent::template(Some(template.clone())));
|
||||
}
|
||||
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("notes"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Notes");
|
||||
// create a new object based on this template
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::note(Some(Note::default())));
|
||||
*to_load = Some(RightPanelContent::object(Some(ObjectInstance::new(
|
||||
template,
|
||||
))));
|
||||
}
|
||||
})
|
||||
.body(|ui| {
|
||||
for object in &self.objects {
|
||||
if object.template_id == template.id {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
|
||||
// load the object
|
||||
if ui.selectable_label(false, &object.name).clicked() {
|
||||
*to_load =
|
||||
Some(RightPanelContent::object(Some(object.clone())));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
for note in &self.notes {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// load the note
|
||||
if ui.selectable_label(false, ¬e.name).clicked() {
|
||||
*to_load = Some(RightPanelContent::note(Some(note.clone())));
|
||||
}
|
||||
});
|
||||
fn render_notes(&mut self, ui: &mut egui::Ui, to_load: &mut Option<RightPanelContent>) {
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("notes"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Notes");
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::note(Some(Note::default())));
|
||||
}
|
||||
});
|
||||
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("projects"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
})
|
||||
.body(|ui| {
|
||||
for note in &self.notes {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Projects");
|
||||
if ui.button("+").clicked() {
|
||||
*load_doc = Some(MainEditor::open(ContentSection::new()));
|
||||
ui.add_space(10.0);
|
||||
|
||||
// load the note
|
||||
if ui.selectable_label(false, ¬e.name).clicked() {
|
||||
*to_load = Some(RightPanelContent::note(Some(note.clone())));
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
// Convert MainEditor vec to ContentSection vec
|
||||
let content_sections: Vec<ContentSection> = self
|
||||
.documents
|
||||
.iter()
|
||||
.map(|doc| doc.content.clone())
|
||||
.collect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Self::render_document_tree(ui, &content_sections, None, load_doc);
|
||||
});
|
||||
|
||||
self.tags = Tag::load_all();
|
||||
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("tags"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Tags");
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::Tag(Tag::default()));
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
for tag in &mut self.tags {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
|
||||
// load the tag
|
||||
if tag.list_ui(ui).clicked() {
|
||||
*to_load = Some(RightPanelContent::Tag(tag.clone()));
|
||||
}
|
||||
});
|
||||
fn render_doc_root(&self, ui: &mut egui::Ui, load_doc: &mut Option<MainEditor>) {
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("projects"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Projects");
|
||||
if ui.button("+").clicked() {
|
||||
*load_doc = Some(MainEditor::open(ContentSection::new()));
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
// Convert MainEditor vec to ContentSection vec
|
||||
let content_sections: Vec<ContentSection> = self
|
||||
.documents
|
||||
.iter()
|
||||
.map(|doc| doc.content.clone())
|
||||
.collect();
|
||||
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("assets"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Assets");
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
for asset in &mut self.assets {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
|
||||
// load the asset
|
||||
if ui.selectable_label(false, &asset.name).clicked() {
|
||||
*to_load = Some(RightPanelContent::Asset(Box::new(asset.clone())));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Self::render_doc_branch(ui, &content_sections, None, load_doc);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -209,7 +170,7 @@ impl Explorer {
|
||||
///
|
||||
/// `load_doc` is a mutable reference to a `MainEditor`. When a document is clicked, it
|
||||
/// is loaded into the `MainEditor` and returned as `Some`.
|
||||
fn render_document_tree(
|
||||
fn render_doc_branch(
|
||||
ui: &mut egui::Ui,
|
||||
documents: &[ContentSection],
|
||||
parent_id: Option<&str>,
|
||||
@@ -243,15 +204,135 @@ impl Explorer {
|
||||
})
|
||||
.body(|ui| {
|
||||
// recursive call to render the next level of documents
|
||||
Self::render_document_tree(ui, documents, Some(&doc.id), load_doc);
|
||||
Self::render_doc_branch(ui, documents, Some(&doc.id), load_doc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn render_tags(&mut self, ui: &mut egui::Ui, to_load: &mut Option<RightPanelContent>) {
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("tags"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Tags");
|
||||
if ui.button("+").clicked() {
|
||||
*to_load = Some(RightPanelContent::Tag(Tag::default()));
|
||||
}
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
for tag in &mut self.tags {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
|
||||
// load the tag
|
||||
if tag.list_ui(ui).clicked() {
|
||||
*to_load = Some(RightPanelContent::Tag(tag.clone()));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn render_assets(&mut self, ui: &mut egui::Ui, to_load: &mut Option<RightPanelContent>) {
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id("assets"),
|
||||
true,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Assets");
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
let mut entries: Vec<_> = WalkDir::new(PROJECT_FOLDER.join("assets"))
|
||||
.min_depth(1)
|
||||
.max_depth(1) // Only immediate children
|
||||
.sort_by(|a, b| {
|
||||
// Directories first, then files
|
||||
let a_is_dir = a.file_type().is_dir();
|
||||
let b_is_dir = b.file_type().is_dir();
|
||||
if a_is_dir == b_is_dir {
|
||||
a.file_name().cmp(b.file_name())
|
||||
} else if a_is_dir {
|
||||
std::cmp::Ordering::Less
|
||||
} else {
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
})
|
||||
.into_iter()
|
||||
.filter_map(Result::ok)
|
||||
.collect();
|
||||
|
||||
for entry in entries {
|
||||
self.render_entry(ui, to_load, &entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn render_entry(
|
||||
&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
to_load: &mut Option<RightPanelContent>,
|
||||
entry: &DirEntry,
|
||||
) {
|
||||
let file_type = entry.file_type();
|
||||
let is_dir = file_type.is_dir();
|
||||
let file_name = entry.file_name().to_string_lossy();
|
||||
let path = entry.path();
|
||||
|
||||
if is_dir {
|
||||
let entries: Vec<_> = WalkDir::new(path)
|
||||
.min_depth(1)
|
||||
.max_depth(1)
|
||||
.sort_by(|a, b| a.file_name().cmp(b.file_name()))
|
||||
.into_iter()
|
||||
.filter_map(Result::ok)
|
||||
.collect();
|
||||
|
||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||
ui.ctx(),
|
||||
ui.make_persistent_id(&file_name),
|
||||
false,
|
||||
)
|
||||
.show_header(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(file_name);
|
||||
let clicked = ui.button("+").on_hover_text("Add new item").clicked();
|
||||
});
|
||||
})
|
||||
.body(|ui| {
|
||||
// recursive call to render the next level of documents
|
||||
for entry in entries {
|
||||
self.render_entry(ui, to_load, &entry);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Handle file
|
||||
if ui
|
||||
.selectable_label(false, format!("📄 {file_name}"))
|
||||
.clicked()
|
||||
{
|
||||
// use asset::load to get the file at the path
|
||||
let asset_path = path.strip_prefix(PROJECT_FOLDER.join("assets")).unwrap();
|
||||
let asset = Asset::open(asset_path.to_string_lossy().to_string());
|
||||
*to_load = Some(RightPanelContent::Asset(Box::new(asset)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// load templates from the templates folder
|
||||
fn load_templates(&mut self) -> std::io::Result<()> {
|
||||
let templates_folder = PROJECT_FOLDER.join("templates");
|
||||
if !templates_folder.exists() {
|
||||
std::fs::create_dir_all(&templates_folder)?;
|
||||
}
|
||||
let mut templates = Vec::new();
|
||||
for entry in std::fs::read_dir(PROJECT_FOLDER.join("templates")).unwrap() {
|
||||
for entry in std::fs::read_dir(&templates_folder).unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
match Template::load(path.file_stem().unwrap().to_str().unwrap()) {
|
||||
Ok(t) => templates.push(t),
|
||||
@@ -265,8 +346,12 @@ impl Explorer {
|
||||
|
||||
// load objects from the objects folder
|
||||
fn load_objects(&mut self) -> std::io::Result<()> {
|
||||
let objects_folder = PROJECT_FOLDER.join("objects");
|
||||
if !objects_folder.exists() {
|
||||
std::fs::create_dir_all(&objects_folder)?;
|
||||
}
|
||||
let mut objects = Vec::new();
|
||||
for entry in std::fs::read_dir(PROJECT_FOLDER.join("objects")).unwrap() {
|
||||
for entry in std::fs::read_dir(&objects_folder).unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
match ObjectInstance::load(path.file_stem().unwrap().to_str().unwrap()) {
|
||||
Ok(o) => objects.push(o),
|
||||
@@ -280,9 +365,13 @@ impl Explorer {
|
||||
|
||||
// load notes from the notes folder
|
||||
fn load_notes(&mut self) -> std::io::Result<()> {
|
||||
let notes_folder = PROJECT_FOLDER.join("notes");
|
||||
if !notes_folder.exists() {
|
||||
std::fs::create_dir_all(¬es_folder)?;
|
||||
}
|
||||
let mut notes = Vec::new();
|
||||
|
||||
for entry in std::fs::read_dir(PROJECT_FOLDER.join("notes")).unwrap() {
|
||||
for entry in std::fs::read_dir(¬es_folder).unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
match Note::load(path.file_stem().unwrap().to_str().unwrap()) {
|
||||
Ok(note) => notes.push(note),
|
||||
@@ -297,9 +386,13 @@ impl Explorer {
|
||||
|
||||
// load documents from the documents folder
|
||||
fn load_documents(&mut self) -> std::io::Result<()> {
|
||||
let documents_folder = PROJECT_FOLDER.join("documents");
|
||||
if !documents_folder.exists() {
|
||||
std::fs::create_dir_all(&documents_folder)?;
|
||||
}
|
||||
let mut documents = Vec::new();
|
||||
|
||||
for entry in std::fs::read_dir(PROJECT_FOLDER.join("documents")).unwrap() {
|
||||
for entry in std::fs::read_dir(&documents_folder).unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
match ContentSection::load(path.file_stem().unwrap().to_str().unwrap()) {
|
||||
Ok(document) => documents.push(MainEditor::open(document)),
|
||||
@@ -312,17 +405,8 @@ impl Explorer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load_assets(&mut self) -> std::io::Result<()> {
|
||||
let mut assets = Vec::new();
|
||||
for entry in std::fs::read_dir(PROJECT_FOLDER.join("assets")).unwrap() {
|
||||
let path = entry.unwrap().path();
|
||||
assets.push(Asset::open(
|
||||
path.file_stem().unwrap().to_str().unwrap().to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
self.assets = assets;
|
||||
|
||||
fn load_tags(&mut self) -> std::io::Result<()> {
|
||||
self.tags = Tag::load_all();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user