use crate::chord::FretID;
use crate::diagram::CHART_WIDTH;
use crate::note::Note;
use std::fmt;
pub struct StringDiagram {
root: Note,
base_fret: FretID,
fret: FretID,
note: Note,
root_width: usize,
}
impl StringDiagram {
pub fn new(root: Note, base_fret: FretID, fret: FretID, note: Note, root_width: usize) -> Self {
Self {
root,
base_fret,
fret,
note,
root_width,
}
}
}
impl fmt::Display for StringDiagram {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let root = format!("{:width$}", self.root.to_string(), width = self.root_width);
let nut = match self.base_fret {
1 => "||",
_ => "-|",
};
let sym = match self.fret {
0 => "o",
_ => " ",
};
let mut string = "".to_owned();
for i in self.base_fret..self.base_fret + CHART_WIDTH {
let c = match self.fret {
fret if fret == i => "o",
_ => "-",
};
string.push_str(&format!("-{}-|", c));
}
write!(f, "{} {}{}{}- {}", root, sym, nut, string, self.note)
}
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
use std::str::FromStr;
#[rstest(
root_name,
base_fret,
fret,
note_name,
diagram,
case("C", 1, 0, "C", "C o||---|---|---|---|- C"),
case("C", 1, 4, "E", "C ||---|---|---|-o-|- E"),
case("C", 1, 2, "D", "C ||---|-o-|---|---|- D"),
case("G", 1, 4, "B", "G ||---|---|---|-o-|- B"),
case("C", 5, 7, "G", "C -|---|---|-o-|---|- G"),
case("C", 1, 1, "C#", "C ||-o-|---|---|---|- C#"),
case("C", 1, 1, "Db", "C ||-o-|---|---|---|- Db"),
case("C", 5, 6, "F#", "C -|---|-o-|---|---|- F#"),
case("C", 5, 6, "Gb", "C -|---|-o-|---|---|- Gb"),
case("F#", 1, 0, "F#", "F# o||---|---|---|---|- F#"),
case("F#", 1, 4, "A#", "F# ||---|---|---|-o-|- A#"),
case("F#", 5, 7, "D", "F# -|---|---|-o-|---|- D")
)]
fn test_format_line(
root_name: &str,
base_fret: FretID,
fret: FretID,
note_name: &str,
diagram: &str,
) {
let root = Note::from_str(root_name).unwrap();
let note = Note::from_str(note_name).unwrap();
let root_width = root_name.len();
let sd = StringDiagram::new(root, base_fret, fret, note, root_width);
assert_eq!(sd.to_string(), diagram);
}
}