use crate::core_game_engine::Button;
use crate::settings::SlotMachine;
#[derive(
PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug, serde::Serialize, serde::Deserialize,
)]
#[serde(
into = "CompactTuiSymbols<String>",
try_from = "CompactTuiSymbols<String>"
)]
pub struct TuiSymbols {
pub blocky_title_logo: bool,
pub menu_pointers: [String; 2],
pub headingline: [char; 1],
pub boardframe: [char; 8],
pub boardframe2: Option<[char; 4]>,
pub holdframe: [char; 4],
pub nextframe: [char; 7],
pub buttons: [char; Button::VARIANTS.len()],
pub timer: Vec<String>,
pub progressbar: (Vec<char>, char),
}
pub fn tui_symbols_presets() -> SlotMachine<TuiSymbols> {
let slots = vec![
("ASCII".to_owned(), TuiSymbols::ascii()),
("Frame UTF8".to_owned(), TuiSymbols::unicode()),
(
"Rounded frame UTF8".to_owned(),
TuiSymbols::rounded_unicode(),
),
("No frame UTF8".to_owned(), TuiSymbols::borderless_unicode()),
(
"No hold/next-frame UTF8".to_owned(),
TuiSymbols::borderless_hold_next_unicode(),
),
("Braille".to_owned(), TuiSymbols::braille()),
("Elektronika 60".to_owned(), TuiSymbols::elektronika_60()),
];
SlotMachine::with_unmodifiable_slots(slots, "TUI symbols".to_owned())
}
impl TuiSymbols {
pub fn ascii() -> Self {
CompactTuiSymbols {
blocky_title_logo: false,
menu_pointers: [">>", "<<"].map(|s| s.to_owned()),
headingline: "-",
boardframe: "+-+|#=#|",
boardframe2: None,
holdframe: "-+|+",
nextframe: "-+|+++-",
buttons: "<>LR@v!w{}H",
timer: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
.map(|s| s.to_owned())
.into(),
progressbar: (" .:!", '|'),
}
.try_into()
.unwrap()
}
pub fn unicode() -> TuiSymbols {
CompactTuiSymbols {
blocky_title_logo: true,
menu_pointers: ["▶", "◀"].map(|s| s.to_owned()), headingline: "─",
boardframe: "╓╴╖║╜▀╙║",
boardframe2: None,
holdframe: "─┌│└",
nextframe: "─┐│┤┘┬╴",
buttons: "←→↺↻↔↓↨⇓⇐⇒⇋", timer: ["⠈", "⠘", "⠸", "⢸", "⣸", "⣼", "⣾", "⣿"]
.map(|s| s.to_owned())
.into(),
progressbar: (" ▏▎▍▌▋▊▉", '█'),
}
.try_into()
.unwrap()
}
pub fn rounded_unicode() -> TuiSymbols {
CompactTuiSymbols {
blocky_title_logo: true,
menu_pointers: ["▶", "◀"].map(|s| s.to_owned()),
headingline: "─",
boardframe: "╓╴╖║╜▀╙║",
boardframe2: None,
holdframe: "─╭│╰",
nextframe: "─╮│┤╯┬╴",
buttons: "←→↺↻↔↓↨⇓⇐⇒⇋",
timer: ["⠈", "⠘", "⠸", "⢸", "⣸", "⣼", "⣾", "⣿"]
.map(|s| s.to_owned())
.into(),
progressbar: (" ▏▎▍▌▋▊▉", '█'),
}
.try_into()
.unwrap()
}
pub fn borderless_unicode() -> Self {
CompactTuiSymbols {
blocky_title_logo: true,
menu_pointers: ["▶", "◀"].map(|s| s.to_owned()),
headingline: " ",
boardframe: " ",
boardframe2: None,
holdframe: " ",
nextframe: " ",
buttons: "←→↺↻↔↓↨⇓⇐⇒⇋",
timer: ["⠈", "⠘", "⠸", "⢸", "⣸", "⣼", "⣾", "⣿"]
.map(|s| s.to_owned())
.into(),
progressbar: (" ▏▎▍▌▋▊▉", '█'),
}
.try_into()
.unwrap()
}
pub fn borderless_hold_next_unicode() -> Self {
CompactTuiSymbols {
blocky_title_logo: true,
menu_pointers: ["▶", "◀"].map(|s| s.to_owned()),
headingline: "─",
boardframe: "╓╴╖║╜▀╙║",
boardframe2: None,
holdframe: " ",
nextframe: " ",
buttons: "←→↺↻↔↓↨⇓⇐⇒⇋",
timer: ["⠈", "⠘", "⠸", "⢸", "⣸", "⣼", "⣾", "⣿"]
.map(|s| s.to_owned())
.into(),
progressbar: (" ▏▎▍▌▋▊▉", '█'),
}
.try_into()
.unwrap()
}
pub fn braille() -> TuiSymbols {
CompactTuiSymbols {
blocky_title_logo: true,
menu_pointers: ["⠕⠕", "⠪⠪"].map(|s| s.to_owned()), headingline: "⠒",
boardframe: "⡖⠂⢲⢸⠚⠒⠓⡇",
boardframe2: None,
holdframe: "⠒⡖⡇⠓",
nextframe: "⠒⢲⢸⢺⠚⢲⠂",
buttons: "←→↺↻↔↓↨⇓⇐⇒⇋",
timer: ["⠈", "⠘", "⠸", "⢸", "⣸", "⣼", "⣾", "⣿"]
.map(|s| s.to_owned())
.into(),
progressbar: (" ⡀⡄⡆⡇⡏⡟⡿", '⣿'),
}
.try_into()
.unwrap()
}
pub fn elektronika_60() -> Self {
CompactTuiSymbols {
blocky_title_logo: false,
menu_pointers: [">>", "<<"].map(|s| s.to_owned()),
headingline: "=",
boardframe: " !!=!!",
boardframe2: Some(r"<\/>"),
holdframe: " ",
nextframe: " ",
buttons: "<>LR@v!w{}H",
timer: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
.map(|s| s.to_owned())
.into(),
progressbar: (" .:!", '|'),
}
.try_into()
.unwrap()
}
}
impl<S: AsRef<str>> TryFrom<CompactTuiSymbols<S>> for TuiSymbols {
type Error = String;
fn try_from(value: CompactTuiSymbols<S>) -> Result<Self, Self::Error> {
fn fmt_err(vec: Vec<char>) -> String {
format!("Could not convert {vec:?}")
}
let menuglyphs = value
.headingline
.as_ref()
.chars()
.collect::<Vec<char>>()
.try_into()
.map_err(fmt_err)?;
let frameglyphs = value
.boardframe
.as_ref()
.chars()
.collect::<Vec<char>>()
.try_into()
.map_err(fmt_err)?;
let frame2glyphs = if let Some(frame2) = value.boardframe2 {
Some(
frame2
.as_ref()
.chars()
.collect::<Vec<char>>()
.try_into()
.map_err(fmt_err)?,
)
} else {
None
};
let holdglyphs = value
.holdframe
.as_ref()
.chars()
.collect::<Vec<char>>()
.try_into()
.map_err(fmt_err)?;
let nextglyphs = value
.nextframe
.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(TuiSymbols {
blocky_title_logo: value.blocky_title_logo,
menu_pointers: value.menu_pointers,
headingline: menuglyphs,
boardframe: frameglyphs,
boardframe2: frame2glyphs,
holdframe: holdglyphs,
nextframe: nextglyphs,
buttons: buttonsglyphs,
timer: value.timer,
progressbar: progressbarglyphs,
})
}
}
#[derive(
PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug, serde::Serialize, serde::Deserialize,
)]
pub struct CompactTuiSymbols<T> {
pub blocky_title_logo: bool,
pub menu_pointers: [String; 2],
pub headingline: T,
pub boardframe: T,
pub boardframe2: Option<T>,
pub holdframe: T,
pub nextframe: T,
pub buttons: T,
pub timer: Vec<String>,
pub progressbar: (T, char),
}
impl From<TuiSymbols> for CompactTuiSymbols<String> {
fn from(value: TuiSymbols) -> Self {
CompactTuiSymbols {
blocky_title_logo: value.blocky_title_logo,
menu_pointers: value.menu_pointers,
headingline: value.headingline.iter().collect(),
boardframe: value.boardframe.iter().collect(),
boardframe2: value.boardframe2.map(|frame2| frame2.iter().collect()),
holdframe: value.holdframe.iter().collect(),
nextframe: value.nextframe.iter().collect(),
buttons: value.buttons.iter().collect(),
timer: value.timer,
progressbar: (value.progressbar.0.iter().collect(), value.progressbar.1),
}
}
}