use crate::core::{ControlSpec, CursorSpec, StyleSpec};
use once_cell::sync::Lazy;
use std::convert::Into;
use std::fmt;
pub struct ThemePreset {
pub name: &'static str,
pub style: StyleSpec,
pub cursor: CursorSpec,
pub control: ControlSpec,
}
impl ThemePreset {
pub fn to_style(&self) -> StyleSpec {
self.style.clone()
}
pub fn to_cursor(&self) -> CursorSpec {
self.cursor.clone()
}
pub fn to_control(&self) -> ControlSpec {
self.control.clone()
}
}
#[derive(Debug)]
pub enum ThemeError {
NotFound(String),
}
impl fmt::Display for ThemeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ThemeError::NotFound(name) => write!(f, "Theme `{}` not found.", name),
}
}
}
impl std::error::Error for ThemeError {}
pub fn resolve_theme(
name: Option<&str>,
) -> Result<(StyleSpec, CursorSpec, ControlSpec), ThemeError> {
if let Some(name) = name {
match get_theme_by_name(name) {
Some(theme) => Ok((theme.to_style(), theme.to_cursor(), theme.to_control())),
None => Err(ThemeError::NotFound(name.to_string())),
}
} else {
Ok((
StyleSpec::default(),
CursorSpec::default(),
ControlSpec::default(),
))
}
}
pub static RETRO_TTY: Lazy<ThemePreset> = Lazy::new(|| ThemePreset {
name: "Retro TTY",
style: StyleSpec {
font_size: 18,
font_family: "PxPlus IBM VGA8".into(),
text_color: Some("#00FF00".into()),
background_color: Some("#000000".into()),
},
cursor: CursorSpec {
char: "|".into(),
offset_x: 20,
color: Some("#00FF00".into()),
blink: true,
blink_ms: 800,
opacity: 1.0,
},
control: ControlSpec {
frame_delay: Some(60),
fade_duration: Some(100),
..Default::default()
},
});
pub static DOS_CLASSIC: Lazy<ThemePreset> = Lazy::new(|| ThemePreset {
name: "DOS Classic",
style: StyleSpec {
font_size: 18,
font_family: "Courier New".into(),
text_color: Some("#C0C0C0".into()),
background_color: Some("#000000".into()),
},
cursor: CursorSpec {
char: "_".into(),
offset_x: 20,
color: None,
blink: true,
blink_ms: 700,
opacity: 1.0,
},
control: ControlSpec {
frame_delay: Some(70),
fade_duration: Some(100),
..Default::default()
},
});
pub static DOS_BLUE: Lazy<ThemePreset> = Lazy::new(|| ThemePreset {
name: "DOS Blue",
style: StyleSpec {
font_size: 18,
font_family: "PxPlus IBM VGA8".into(),
text_color: Some("#FFFFFF".into()),
background_color: Some("#0000AA".into()), },
cursor: CursorSpec {
char: "β".into(),
offset_x: 20,
color: Some("#FFFFFF".into()),
blink: true,
blink_ms: 650,
opacity: 0.9,
},
control: ControlSpec {
frame_delay: Some(80),
fade_duration: Some(100),
..Default::default()
},
});
pub static SOLARIZED_DARK: Lazy<ThemePreset> = Lazy::new(|| ThemePreset {
name: "Solarized Dark",
style: StyleSpec {
font_size: 18,
font_family: "Fira Code".into(),
text_color: Some("#839496".into()),
background_color: Some("#002b36".into()),
},
cursor: CursorSpec {
char: "β".into(),
offset_x: 20,
color: Some("#93a1a1".into()),
blink: true,
blink_ms: 850,
opacity: 0.9,
},
control: ControlSpec {
frame_delay: Some(60),
fade_duration: Some(100),
..Default::default()
},
});
pub static GRUVBOX_DARK: Lazy<ThemePreset> = Lazy::new(|| ThemePreset {
name: "Gruvbox Dark",
style: StyleSpec {
font_size: 18,
font_family: "Source Code Pro".into(),
text_color: Some("#ebdbb2".into()),
background_color: Some("#282828".into()),
},
cursor: CursorSpec {
char: "β".into(),
offset_x: 20,
color: Some("#fe8019".into()),
blink: true,
blink_ms: 750,
opacity: 1.0,
},
control: ControlSpec {
frame_delay: Some(60),
fade_duration: Some(100),
..Default::default()
},
});
pub static LIGHT_SHELL: Lazy<ThemePreset> = Lazy::new(|| ThemePreset {
name: "Light Shell",
style: StyleSpec {
font_size: 18,
font_family: "Monospace".into(),
text_color: Some("#444444".into()),
background_color: Some("#ffffff".into()),
},
cursor: CursorSpec {
char: "|".into(),
offset_x: 20,
color: Some("#888888".into()),
blink: true,
blink_ms: 1000,
opacity: 0.7,
},
control: ControlSpec {
frame_delay: Some(60),
fade_duration: Some(100),
..Default::default()
},
});
pub static SOLARIZED_LIGHT: Lazy<ThemePreset> = Lazy::new(|| ThemePreset {
name: "Solarized Light",
style: StyleSpec {
font_size: 18,
font_family: "Monospace".into(),
text_color: Some("#586e75".into()),
background_color: Some("#fdf6e3".into()),
},
cursor: CursorSpec {
char: "|".into(),
offset_x: 20,
color: Some("#657b83".into()),
blink: true,
blink_ms: 850,
opacity: 0.9,
},
control: ControlSpec {
frame_delay: Some(60),
fade_duration: Some(100),
..Default::default()
},
});
pub static NEON_NIGHT: Lazy<ThemePreset> = Lazy::new(|| ThemePreset {
name: "Neon Night",
style: StyleSpec {
font_size: 18,
font_family: "Cascadia Mono".into(),
text_color: Some("#FF00FF".into()),
background_color: Some("#0f0f1a".into()),
},
cursor: CursorSpec {
char: "οΉ".into(),
offset_x: 20,
color: Some("#FF00FF".into()),
blink: true,
blink_ms: 650,
opacity: 0.9,
},
control: ControlSpec {
frame_delay: Some(75),
fade_duration: Some(100),
..Default::default()
},
});
pub static POKE_TERMINAL: Lazy<ThemePreset> = Lazy::new(|| ThemePreset {
name: "Poke Terminal",
style: StyleSpec {
font_size: 18,
font_family: "Monospace".into(),
text_color: Some("#FFD700".into()),
background_color: Some("#2b2b2b".into()),
},
cursor: CursorSpec {
char: "β‘".into(), offset_x: 30,
color: Some("#FFD700".into()),
blink: true,
blink_ms: 800,
opacity: 1.0,
},
control: ControlSpec {
frame_delay: Some(50),
fade_duration: Some(100),
..Default::default()
},
});
pub fn all_presets() -> Vec<&'static ThemePreset> {
vec![
&RETRO_TTY,
&DOS_CLASSIC,
&DOS_BLUE,
&SOLARIZED_DARK,
&GRUVBOX_DARK,
&LIGHT_SHELL,
&SOLARIZED_LIGHT,
&NEON_NIGHT,
&POKE_TERMINAL,
]
}
pub fn get_theme_by_name(name: &str) -> Option<&'static ThemePreset> {
let normalized = name.to_lowercase().replace('_', " ");
all_presets()
.into_iter()
.find(|preset| preset.name.to_lowercase() == normalized)
}