mirror of
https://codeberg.org/unspeaker/perch.git
synced 2025-12-06 09:36:42 +01:00
120 lines
3.9 KiB
Rust
120 lines
3.9 KiB
Rust
use crate::*;
|
||
use crate::ratatui::style::Style;
|
||
|
||
pub struct Column<G, S, U> {
|
||
pub title: Arc<str>,
|
||
pub width: usize,
|
||
pub collapsed: bool,
|
||
pub getter: G,
|
||
pub setter: Option<S>,
|
||
pub styler: Option<U>,
|
||
}
|
||
|
||
type Getter<T> = fn(&T)->Option<Arc<str>>;
|
||
type Setter<T> = fn(&mut T, usize, &str);
|
||
type Styler<T> = fn(&T)->Option<Style>;
|
||
|
||
impl<G, S, U> Column<Getter<G>, Setter<S>, Styler<U>> {
|
||
pub fn new (
|
||
title: &impl AsRef<str>,
|
||
width: usize,
|
||
getter: Getter<G>,
|
||
) -> Self {
|
||
Self {
|
||
width,
|
||
title: title.as_ref().into(),
|
||
getter,
|
||
setter: None,
|
||
styler: None,
|
||
collapsed: false,
|
||
}
|
||
}
|
||
fn setter (mut self, setter: Setter<S>) -> Self {
|
||
self.setter = Some(setter);
|
||
self
|
||
}
|
||
fn styler (mut self, styler: Styler<U>) -> Self {
|
||
self.styler = Some(styler);
|
||
self
|
||
}
|
||
}
|
||
|
||
pub(crate) fn entries_under (
|
||
entries: &mut [Entry],
|
||
index: usize
|
||
) -> Option<Vec<(Arc<PathBuf>, Arc<RwLock<Metadata>>)>> {
|
||
let path = if let Some(Entry { path, info, .. }) = entries.get(index)
|
||
&& let Metadata::Directory { .. } = &*info.read().unwrap()
|
||
{
|
||
Some(path.clone())
|
||
} else {
|
||
None
|
||
};
|
||
if let Some(path) = path {
|
||
let mut others = vec![];
|
||
for other in entries.iter_mut() {
|
||
if other.path.starts_with(path.as_ref()) && !other.is_directory() {
|
||
others.push((other.path.clone(), other.info.clone()));
|
||
}
|
||
}
|
||
Some(others)
|
||
} else {
|
||
None
|
||
}
|
||
}
|
||
|
||
pub struct Columns<G, S, U>(pub Vec<Column<G, S, U>>);
|
||
|
||
macro_rules! setter {
|
||
($set:ident) => {{
|
||
fn $set (state: &mut Taggart, index: usize, value: &str) {
|
||
if let Some(entries) = entries_under(&mut state.entries, index) {
|
||
for (_path, entry) in entries.into_iter() {
|
||
if entry.write().unwrap().$set(&value) {
|
||
state.count_changes();
|
||
//state.tasks.retain(|t|{(t.path != p) || (t.item.key() != item.key())});
|
||
//state.tasks.push(Task { path: p, item, });
|
||
};
|
||
}
|
||
} else if let Some(entry) = state.entries.get_mut(index) {
|
||
//let p = entry.path.clone();
|
||
if entry.$set(&value) {
|
||
state.count_changes();
|
||
//state.tasks.retain(|t|{(t.path != p) || (t.item.key() != item.key())});
|
||
//state.tasks.push(Task { path: p, item, });
|
||
};
|
||
}
|
||
}
|
||
$set
|
||
}}
|
||
}
|
||
|
||
impl Default for Columns<
|
||
fn(&Entry)->Option<Arc<str>>,
|
||
fn(&mut Taggart, usize, &str),
|
||
fn(&Entry)->Option<Style>,
|
||
> {
|
||
fn default () -> Self {
|
||
Self(vec![
|
||
// Computed file hash
|
||
Column::new(&"Hash", 8, |entry: &Entry|entry.hash()),
|
||
// File size
|
||
Column::new(&"Size", 8, |entry: &Entry|entry.size()),
|
||
// Selected?
|
||
Column::new(&"∗", 1, |entry: &Entry|Some(" ".into())),
|
||
// File name
|
||
Column::new(&"File", 40, |entry: &Entry|entry.name()),
|
||
// Modified tags?
|
||
Column::new(&"~", 1, |entry: &Entry|if entry.is_modified() {
|
||
Some("~".into())
|
||
} else {
|
||
None
|
||
}),
|
||
Column::new(&"Artist", 15, |entry: &Entry|entry.artist()).setter(setter!(set_artist)),
|
||
Column::new(&"Year", 4, |entry: &Entry|entry.year()).setter(setter!(set_year)),
|
||
Column::new(&"Release", 15, |entry: &Entry|entry.album()).setter(setter!(set_album)),
|
||
Column::new(&"Track", 5, |entry: &Entry|entry.track()).setter(setter!(set_track)),
|
||
Column::new(&"Title", 40, |entry: &Entry|entry.title()).setter(setter!(set_title)),
|
||
])
|
||
}
|
||
}
|