Created
November 10, 2022 20:41
-
-
Save rminderhoud/938ecebc4a49b75c93ffb3c345f84c52 to your computer and use it in GitHub Desktop.
Basic tree
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Some code that was written but never used for a project, keeping here as a reference for basic tree implementaiton in rust | |
#[derive(Debug, Default)] | |
struct FileTreeNode { | |
id: usize, | |
path: PathBuf, | |
parent: usize, | |
children: Vec<usize>, | |
} | |
impl FileTreeNode { | |
fn path_str(&self) -> String { | |
normalize_path_str(self.path.to_string_lossy()) | |
} | |
fn is_leaf(&self) -> bool { | |
self.children.is_empty() | |
} | |
} | |
/// Tree of nodes representing files and directories in a root directory | |
#[derive(Debug, Default)] | |
struct FileTree { | |
root_dir: PathBuf, | |
nodes: Vec<FileTreeNode>, | |
file_node_ids: Vec<usize>, | |
} | |
impl FileTree { | |
fn new(root: &Path) -> FileTree { | |
FileTree { | |
root_dir: root.into(), | |
..Default::default() | |
} | |
} | |
fn new_node(&mut self, parent: usize, p: &Path) -> usize { | |
let id = self.nodes.len(); | |
let node = FileTreeNode { | |
id, | |
path: p.to_path_buf(), | |
parent, | |
..Default::default() | |
}; | |
self.nodes.push(node); | |
return id; | |
} | |
fn valid_node(&self, id: usize) -> bool { | |
id < self.nodes.len() | |
} | |
} | |
/// Recursively build a `FileTree` from the root path | |
fn build_tree_nodes(tree: &mut FileTree, path: &Path, parent: usize) -> anyhow::Result<usize> { | |
let node_id = tree.new_node(parent, path); | |
debug!( | |
path = path.display().to_string(), | |
"Reading directory contents" | |
); | |
let mut dirs = Vec::new(); | |
let mut files = Vec::new(); | |
// Collect into files and dirs seperately so we can control the order when | |
// building our tree (insert dirs first) | |
for entry in fs::read_dir(path)? { | |
let entry = entry?; | |
let file_type = entry.file_type()?; | |
if file_type.is_file() { | |
files.push(entry); | |
} else if file_type.is_dir() { | |
dirs.push(entry); | |
} else { | |
continue; // Skip symlinks | |
} | |
} | |
for entry in dirs { | |
let dir_node_id = build_tree_nodes(tree, &entry.path(), node_id)?; | |
tree.nodes[node_id].children.push(dir_node_id); | |
} | |
for entry in files { | |
let file_node_id = tree.new_node(node_id, &entry.path()); | |
tree.nodes[node_id].children.push(file_node_id); | |
tree.file_node_ids.push(file_node_id); | |
} | |
debug!( | |
path = path.display().to_string(), | |
"Finished reading directory contents" | |
); | |
Ok(node_id) | |
} | |
fn build_tree(root: &Path) -> anyhow::Result<FileTree> { | |
let mut tree = FileTree::new(root); | |
build_tree_nodes(&mut tree, root, 0)?; | |
Ok(tree) | |
} | |
// egui rendering code | |
fn draw_tree_node(&self, ui: &mut egui::Ui, node_id: usize) { | |
let node = &self.file_tree.nodes[node_id]; | |
let node_name = node.path_str(); | |
// Node represents a file | |
if node.is_leaf() { | |
ui.indent(0, |ui| { | |
let mut checked = false; | |
ui.checkbox(&mut checked, node_name); | |
}); | |
return; | |
} | |
let id = ui.make_persistent_id(&node_name); | |
egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, false) | |
.show_header(ui, |ui| { | |
let mut b = false; | |
ui.checkbox(&mut b, node_name); | |
}) | |
.body(|ui| { | |
for child_node_id in node.children.iter() { | |
self.draw_tree_node(ui, *child_node_id) | |
} | |
}); | |
} | |
fn draw_tree(&self, ui: &mut egui::Ui) { | |
if self.file_tree_task_state == TaskState::Running { | |
ui.add(egui::Spinner::new()); | |
return; | |
} | |
if !self.file_tree.valid_node(0) { | |
debug!("No root node to draw"); | |
return; | |
} | |
self.draw_tree_node(ui, 0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment