tek/device/browse.rs
unspeaker ef81b085a0
Some checks failed
/ build (push) Has been cancelled
break up into crates again
2025-09-10 01:58:32 +03:00

220 lines
6.2 KiB
Rust

use crate::*;
use std::path::PathBuf;
use std::ffi::OsString;
#[derive(Clone, Debug)]
pub enum BrowseTarget {
SaveProject,
LoadProject,
ImportSample(Arc<RwLock<Option<Sample>>>),
ExportSample(Arc<RwLock<Option<Sample>>>),
ImportClip(Arc<RwLock<Option<MidiClip>>>),
ExportClip(Arc<RwLock<Option<MidiClip>>>),
}
impl PartialEq for BrowseTarget {
fn eq (&self, other: &Self) -> bool {
match self {
Self::ImportSample(_) => false,
Self::ExportSample(_) => false,
Self::ImportClip(_) => false,
Self::ExportClip(_) => false,
t => matches!(other, t)
}
}
}
/// Browses for phrase to import/export
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Browse {
pub cwd: PathBuf,
pub dirs: Vec<(OsString, String)>,
pub files: Vec<(OsString, String)>,
pub filter: String,
pub index: usize,
pub scroll: usize,
pub size: Measure<TuiOut>,
}
impl Browse {
pub fn new (cwd: Option<PathBuf>) -> Usually<Self> {
let cwd = if let Some(cwd) = cwd { cwd } else { std::env::current_dir()? };
let mut dirs = vec![];
let mut files = vec![];
for entry in std::fs::read_dir(&cwd)? {
let entry = entry?;
let name = entry.file_name();
let decoded = name.clone().into_string().unwrap_or_else(|_|"<unreadable>".to_string());
let meta = entry.metadata()?;
if meta.is_dir() {
dirs.push((name, format!("📁 {decoded}")));
} else if meta.is_file() {
files.push((name, format!("📄 {decoded}")));
}
}
Ok(Self {
cwd,
dirs,
files,
filter: "".to_string(),
index: 0,
scroll: 0,
size: Measure::new(),
})
}
pub fn len (&self) -> usize {
self.dirs.len() + self.files.len()
}
pub fn is_dir (&self) -> bool {
self.index < self.dirs.len()
}
pub fn is_file (&self) -> bool {
self.index >= self.dirs.len()
}
pub fn path (&self) -> PathBuf {
self.cwd.join(if self.is_dir() {
&self.dirs[self.index].0
} else if self.is_file() {
&self.files[self.index - self.dirs.len()].0
} else {
unreachable!()
})
}
pub fn chdir (&self) -> Usually<Self> {
Self::new(Some(self.path()))
}
}
impl Browse {
fn _todo_stub_path_buf (&self) -> PathBuf {
todo!()
}
fn _todo_stub_usize (&self) -> usize {
todo!()
}
fn _todo_stub_arc_str (&self) -> Arc<str> {
todo!()
}
}
def_command!(BrowseCommand: |browse: Browse| {
SetVisible => Ok(None),
SetPath { address: PathBuf } => Ok(None),
SetSearch { filter: Arc<str> } => Ok(None),
SetCursor { cursor: usize } => Ok(None),
});
impl HasContent<TuiOut> for Browse {
fn content (&self) -> impl Content<TuiOut> {
Map::south(1, ||EntriesIterator {
offset: 0,
index: 0,
length: self.dirs.len() + self.files.len(),
browser: self,
}, |entry, _index|Fill::X(Align::w(entry)))
}
}
struct EntriesIterator<'a> {
browser: &'a Browse,
offset: usize,
length: usize,
index: usize,
}
impl<'a> Iterator for EntriesIterator<'a> {
type Item = Modify<&'a str>;
fn next (&mut self) -> Option<Self::Item> {
let dirs = self.browser.dirs.len();
let files = self.browser.files.len();
let index = self.index;
if self.index < dirs {
self.index += 1;
Some(Tui::bold(true, self.browser.dirs[index].1.as_str()))
} else if self.index < dirs + files {
self.index += 1;
Some(Tui::bold(false, self.browser.files[index - dirs].1.as_str()))
} else {
None
}
}
}
// Commands supported by [Browse]
//#[derive(Debug, Clone, PartialEq)]
//pub enum BrowseCommand {
//Begin,
//Cancel,
//Confirm,
//Select(usize),
//Chdir(PathBuf),
//Filter(Arc<str>),
//}
//fn begin (browse: &mut Browse) => {
//unreachable!();
//}
//fn cancel (browse: &mut Browse) => {
//todo!()
////browse.mode = None;
////Ok(None)
//}
//fn confirm (browse: &mut Browse) => {
//todo!()
////Ok(match browse.mode {
////Some(PoolMode::Import(index, ref mut browse)) => {
////if browse.is_file() {
////let path = browse.path();
////browse.mode = None;
////let _undo = PoolClipCommand::import(browse, index, path)?;
////None
////} else if browse.is_dir() {
////browse.mode = Some(PoolMode::Import(index, browse.chdir()?));
////None
////} else {
////None
////}
////},
////Some(PoolMode::Export(index, ref mut browse)) => {
////todo!()
////},
////_ => unreachable!(),
////})
//}
//fn select (browse: &mut Browse, index: usize) => {
//todo!()
////Ok(match browse.mode {
////Some(PoolMode::Import(index, ref mut browse)) => {
////browse.index = index;
////None
////},
////Some(PoolMode::Export(index, ref mut browse)) => {
////browse.index = index;
////None
////},
////_ => unreachable!(),
////})
//}
//fn chdir (browse: &mut Browse, dir: PathBuf) => {
//todo!()
////Ok(match browse.mode {
////Some(PoolMode::Import(index, ref mut browse)) => {
////browse.mode = Some(PoolMode::Import(index, Browse::new(Some(dir))?));
////None
////},
////Some(PoolMode::Export(index, ref mut browse)) => {
////browse.mode = Some(PoolMode::Export(index, Browse::new(Some(dir))?));
////None
////},
////_ => unreachable!(),
////})
//}
//fn filter (browse: &mut Browse, filter: Arc<str>) => {
//todo!()
//}