use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextModeKind {
Mode40x25,
Mode80x25,
Mode80x43,
Mode80x50,
Mode160x50,
Mode160x100,
Mode320x100,
Mode320x200,
}
impl TextModeKind {
pub fn from_str(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"40x25" => Some(TextModeKind::Mode40x25),
"80x25" => Some(TextModeKind::Mode80x25),
"80x43" => Some(TextModeKind::Mode80x43),
"80x50" => Some(TextModeKind::Mode80x50),
"160x50" => Some(TextModeKind::Mode160x50),
"160x100" => Some(TextModeKind::Mode160x100),
"320x100" => Some(TextModeKind::Mode320x100),
"320x200" => Some(TextModeKind::Mode320x200),
_ => None,
}
}
#[allow(dead_code)]
pub fn all_modes() -> &'static [TextModeKind] {
&[
TextModeKind::Mode40x25,
TextModeKind::Mode80x25,
TextModeKind::Mode80x43,
TextModeKind::Mode80x50,
TextModeKind::Mode160x50,
TextModeKind::Mode160x100,
TextModeKind::Mode320x100,
TextModeKind::Mode320x200,
]
}
}
impl fmt::Display for TextModeKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TextModeKind::Mode40x25 => write!(f, "40x25"),
TextModeKind::Mode80x25 => write!(f, "80x25"),
TextModeKind::Mode80x43 => write!(f, "80x43"),
TextModeKind::Mode80x50 => write!(f, "80x50"),
TextModeKind::Mode160x50 => write!(f, "160x50"),
TextModeKind::Mode160x100 => write!(f, "160x100"),
TextModeKind::Mode320x100 => write!(f, "320x100"),
TextModeKind::Mode320x200 => write!(f, "320x200"),
}
}
}
#[derive(Debug, Clone)]
pub struct TextMode {
pub kind: TextModeKind,
pub cols: usize,
pub rows: usize,
pub char_width: usize,
pub char_height: usize,
}
impl TextMode {
pub fn new(kind: TextModeKind) -> Self {
let (cols, rows, char_width, char_height) = match kind {
TextModeKind::Mode40x25 => (40, 25, 16, 16),
TextModeKind::Mode80x25 => (80, 25, 8, 16),
TextModeKind::Mode80x43 => (80, 43, 8, 11),
TextModeKind::Mode80x50 => (80, 50, 8, 8),
TextModeKind::Mode160x50 => (160, 50, 8, 16),
TextModeKind::Mode160x100 => (160, 100, 8, 16),
TextModeKind::Mode320x100 => (320, 100, 8, 16),
TextModeKind::Mode320x200 => (320, 200, 8, 8),
};
TextMode {
kind,
cols,
rows,
char_width,
char_height,
}
}
#[allow(dead_code)]
pub fn pixel_width(&self) -> usize {
self.cols * self.char_width
}
#[allow(dead_code)]
pub fn pixel_height(&self) -> usize {
self.rows * self.char_height
}
#[inline(always)]
pub fn is_valid_position(&self, col: usize, row: usize) -> bool {
col < self.cols && row < self.rows
}
}
impl Default for TextMode {
fn default() -> Self {
TextMode::new(TextModeKind::Mode80x25)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mode_dimensions() {
let mode_80x25 = TextMode::new(TextModeKind::Mode80x25);
assert_eq!(mode_80x25.cols, 80);
assert_eq!(mode_80x25.rows, 25);
assert_eq!(mode_80x25.char_width, 8);
assert_eq!(mode_80x25.char_height, 16);
assert_eq!(mode_80x25.pixel_width(), 640);
assert_eq!(mode_80x25.pixel_height(), 400);
}
#[test]
fn test_mode_parsing() {
assert_eq!(
TextModeKind::from_str("80x25"),
Some(TextModeKind::Mode80x25)
);
assert_eq!(
TextModeKind::from_str("80x50"),
Some(TextModeKind::Mode80x50)
);
assert_eq!(TextModeKind::from_str("invalid"), None);
}
#[test]
fn test_mode_display() {
let mode = TextModeKind::Mode80x25;
assert_eq!(format!("{}", mode), "80x25");
}
}