use falling_tetromino_engine::Button;
use crate::tui_settings::SlotMachine;
#[derive(
PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug, serde::Serialize, serde::Deserialize,
)]
#[serde(into = "TuiStyleCompact<String>", try_from = "TuiStyleCompact<String>")]
pub struct TuiStyle {
pub is_title_unicode: bool,
pub menuglyphs: [char; 1],
pub frameglyphs: [char; 8],
pub frame2glyphs: Option<[char; 4]>,
pub holdglyphs: [char; 4],
pub nextglyphs: [char; 7],
pub buttonsglyphs: [char; Button::VARIANTS.len()],
pub countdownglyphs: Vec<String>,
pub progressbarglyphs: (Vec<char>, char),
}
pub fn default_tui_style_slots() -> SlotMachine<TuiStyle> {
let slots = vec![
("ASCII".to_owned(), TuiStyle::ascii()),
("Unicode".to_owned(), TuiStyle::unicode()),
("Elektronika 60".to_owned(), TuiStyle::elektronika_60()),
];
SlotMachine::with_unmodifiable_slots(slots, "TUI style".to_owned())
}
impl TuiStyle {
pub fn ascii() -> Self {
TuiStyleCompact {
is_title_unicode: false,
menuglyphs: "-",
frame: "+-+|#=#|",
frame2: None,
hold: "-+|+",
next: "-+|+++-",
buttons: "<>LR@v!w{}H",
countdown: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
.map(|s| s.to_owned())
.into(),
progressbar: (" .:!", '|'),
}
.try_into()
.unwrap()
}
pub fn unicode() -> TuiStyle {
TuiStyleCompact {
is_title_unicode: true,
menuglyphs: "─",
frame: "╓╴╖║╜▀╙║",
frame2: None,
hold: "─┌│└",
next: "─┐│┤┘┬╴",
buttons: "←→↺↻↔↓⤓⇓⇐⇒⇋",
countdown: ["⡀", "⡄", "⡆", "⡇", "⡏", "⡟", "⡿", "⣿"]
.map(|s| s.to_owned())
.into(),
progressbar: (" ▏▎▍▌▋▊▉", '█'),
}
.try_into()
.unwrap()
}
pub fn elektronika_60() -> Self {
TuiStyleCompact {
is_title_unicode: false,
menuglyphs: "=",
frame: " !!=!!",
frame2: Some(r"<\/>"),
hold: " ",
next: " ",
buttons: "<>LR@v!w{}H",
countdown: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
.map(|s| s.to_owned())
.into(),
progressbar: (" .:!", '|'),
}
.try_into()
.unwrap()
}
}
impl<S: AsRef<str>> TryFrom<TuiStyleCompact<S>> for TuiStyle {
type Error = String;
fn try_from(value: TuiStyleCompact<S>) -> Result<Self, Self::Error> {
fn fmt_err(vec: Vec<char>) -> String {
format!("Could not convert {vec:?}")
}
let menuglyphs = value
.menuglyphs
.as_ref()
.chars()
.collect::<Vec<char>>()
.try_into()
.map_err(fmt_err)?;
let frameglyphs = value
.frame
.as_ref()
.chars()
.collect::<Vec<char>>()
.try_into()
.map_err(fmt_err)?;
let frame2glyphs = if let Some(frame2) = value.frame2 {
Some(
frame2
.as_ref()
.chars()
.collect::<Vec<char>>()
.try_into()
.map_err(fmt_err)?,
)
} else {
None
};
let holdglyphs = value
.hold
.as_ref()
.chars()
.collect::<Vec<char>>()
.try_into()
.map_err(fmt_err)?;
let nextglyphs = value
.next
.as_ref()
.chars()
.collect::<Vec<char>>()
.try_into()
.map_err(fmt_err)?;
let buttonsglyphs = value
.buttons
.as_ref()
.chars()
.collect::<Vec<char>>()
.try_into()
.map_err(fmt_err)?;
let progressbarglyphs = (
value.progressbar.0.as_ref().chars().collect::<Vec<char>>(),
value.progressbar.1,
);
Ok(TuiStyle {
is_title_unicode: value.is_title_unicode,
menuglyphs,
frameglyphs,
frame2glyphs,
holdglyphs,
nextglyphs,
buttonsglyphs,
countdownglyphs: value.countdown,
progressbarglyphs,
})
}
}
#[derive(
PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug, serde::Serialize, serde::Deserialize,
)]
pub struct TuiStyleCompact<T> {
pub is_title_unicode: bool,
pub menuglyphs: T,
pub frame: T,
pub frame2: Option<T>,
pub hold: T,
pub next: T,
pub buttons: T,
pub countdown: Vec<String>,
pub progressbar: (T, char),
}
impl From<TuiStyle> for TuiStyleCompact<String> {
fn from(value: TuiStyle) -> Self {
TuiStyleCompact {
is_title_unicode: value.is_title_unicode,
menuglyphs: value.menuglyphs.iter().collect(),
frame: value.frameglyphs.iter().collect(),
frame2: value.frame2glyphs.map(|frame2| frame2.iter().collect()),
hold: value.holdglyphs.iter().collect(),
next: value.nextglyphs.iter().collect(),
buttons: value.buttonsglyphs.iter().collect(),
countdown: value.countdownglyphs,
progressbar: (
value.progressbarglyphs.0.iter().collect(),
value.progressbarglyphs.1,
),
}
}
}