use crate::errors::{ErrorKind, FormError};
use std::fmt::Display;
#[derive(Debug, PartialEq, Clone, Eq, serde::Serialize, Copy, Hash)]
pub enum Color {
RGB {
red: u8,
green: u8,
blue: u8,
},
System {
index: u8,
},
}
impl Display for Color {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut predefined = false;
let mut vb_color_name = "";
if let Some((name, _)) = PREDEFINED_COLORS.iter().find(|(_, color)| color == self) {
predefined = true;
vb_color_name = name;
}
match self {
Color::RGB { red, green, blue } if predefined => {
write!(
f,
"{vb_color_name} RGB({red}, {green}, {blue}) - {}",
self.to_vb_string()
)
}
Color::System { index } if predefined => {
write!(
f,
"{vb_color_name} System({}) - {}",
index,
self.to_vb_string()
)
}
Color::RGB { red, green, blue } => {
write!(f, "RGB({red}, {green}, {blue}) = {}", self.to_vb_string())
}
Color::System { index } => {
write!(f, "System({}) = {}", index, self.to_vb_string())
}
}
}
}
impl Color {
#[must_use]
pub fn to_vb_string(&self) -> String {
match self {
Color::RGB { red, green, blue } => {
format!("&H00{blue:02X}{green:02X}{red:02X}&")
}
Color::System { index } => {
format!("&H80{index:06X}&")
}
}
}
}
pub const PREDEFINED_COLORS: [(&str, Color); 24] = [
("vbBlack", VB_BLACK),
("vbWhite", VB_WHITE),
("vbRed", VB_RED),
("vbGreen", VB_GREEN),
("vbBlue", VB_BLUE),
("vbYellow", VB_YELLOW),
("vbMagenta", VB_MAGENTA),
("vbCyan", VB_CYAN),
("vbScrollBars", VB_SCROLL_BARS),
("vbDesktop", VB_DESKTOP),
("vbActiveTitleBar", VB_ACTIVE_TITLE_BAR),
("vbInactiveTitleBar", VB_INACTIVE_TITLE_BAR),
("vbMenuBar", VB_MENU_BAR),
("vbWindowBackground", VB_WINDOW_BACKGROUND),
("vbWindowFrame", VB_WINDOW_FRAME),
("vbMenuText", VB_MENU_TEXT),
("vbWindowText", VB_WINDOW_TEXT),
("vbTitleBarText", VB_TITLE_BAR_TEXT),
("vbActiveBorder", VB_ACTIVE_BORDER),
("vbInactiveBorder", VB_INACTIVE_BORDER),
("vbApplicationWorkspace", VB_APPLICATION_WORKSPACE),
("vbHighlight", VB_HIGHLIGHT),
("vbHighlightText", VB_HIGHLIGHT_TEXT),
("vbButtonFace", VB_BUTTON_FACE),
];
pub const VB_BLACK: Color = Color::RGB {
red: 0x00,
green: 0x00,
blue: 0x00,
};
pub const VB_WHITE: Color = Color::RGB {
red: 0xFF,
green: 0xFF,
blue: 0xFF,
};
pub const VB_RED: Color = Color::RGB {
red: 0xFF,
green: 0x00,
blue: 0x00,
};
pub const VB_GREEN: Color = Color::RGB {
red: 0x00,
green: 0xFF,
blue: 0x00,
};
pub const VB_BLUE: Color = Color::RGB {
red: 0x00,
green: 0x00,
blue: 0xFF,
};
pub const VB_YELLOW: Color = Color::RGB {
red: 0xFF,
green: 0xFF,
blue: 0x00,
};
pub const VB_MAGENTA: Color = Color::RGB {
red: 0xFF,
green: 0x00,
blue: 0xFF,
};
pub const VB_CYAN: Color = Color::RGB {
red: 0x00,
green: 0xFF,
blue: 0xFF,
};
pub const VB_SCROLL_BARS: Color = Color::System { index: 0x00 };
pub const VB_DESKTOP: Color = Color::System { index: 0x01 };
pub const VB_ACTIVE_TITLE_BAR: Color = Color::System { index: 0x02 };
pub const VB_INACTIVE_TITLE_BAR: Color = Color::System { index: 0x03 };
pub const VB_MENU_BAR: Color = Color::System { index: 0x04 };
pub const VB_WINDOW_BACKGROUND: Color = Color::System { index: 0x05 };
pub const VB_WINDOW_FRAME: Color = Color::System { index: 0x06 };
pub const VB_MENU_TEXT: Color = Color::System { index: 0x07 };
pub const VB_WINDOW_TEXT: Color = Color::System { index: 0x08 };
pub const VB_TITLE_BAR_TEXT: Color = Color::System { index: 0x09 };
pub const VB_ACTIVE_BORDER: Color = Color::System { index: 0x0A };
pub const VB_INACTIVE_BORDER: Color = Color::System { index: 0x0B };
pub const VB_APPLICATION_WORKSPACE: Color = Color::System { index: 0x0C };
pub const VB_HIGHLIGHT: Color = Color::System { index: 0x0D };
pub const VB_HIGHLIGHT_TEXT: Color = Color::System { index: 0x0E };
pub const VB_BUTTON_FACE: Color = Color::System { index: 0x0F };
pub const VB_3D_FACE: Color = Color::System { index: 0x0F };
pub const VB_3D_SHADOW: Color = Color::System { index: 0x10 };
pub const VB_BUTTON_SHADOW: Color = Color::System { index: 0x10 };
pub const VB_GRAY_TEXT: Color = Color::System { index: 0x11 };
pub const VB_BUTTON_TEXT: Color = Color::System { index: 0x12 };
pub const VB_INACTIVE_CAPTION_TEXT: Color = Color::System { index: 0x13 };
pub const VB_3D_HIGHLIGHT: Color = Color::System { index: 0x14 };
pub const VB_3D_DK_SHADOW: Color = Color::System { index: 0x15 };
pub const VB_3D_LIGHT: Color = Color::System { index: 0x16 };
pub const VB_INFO_TEXT: Color = Color::System { index: 0x17 };
pub const VB_MSG_BOX: Color = Color::System { index: 0x17 };
pub const VB_INFO_BACKGROUND: Color = Color::System { index: 0x18 };
pub const VB_MSG_BOX_TEXT: Color = Color::System { index: 0x18 };
impl Color {
#[must_use]
pub fn new(red: u8, green: u8, blue: u8) -> Self {
Color::RGB { red, green, blue }
}
#[must_use]
pub fn system(index: u8) -> Self {
Color::System { index }
}
#[must_use]
pub fn rgb(red: u8, green: u8, blue: u8) -> Self {
Color::RGB { red, green, blue }
}
pub fn from_hex(input: &str) -> Result<Color, ErrorKind> {
let kind_ascii = &input[2..4];
let kind = u8::from_str_radix(kind_ascii, 16)
.map_err(|_| ErrorKind::Form(FormError::HexColorParseError))?;
if kind == 0x80 {
let index = u8::from_str_radix(&input[8..10], 16)
.map_err(|_| ErrorKind::Form(FormError::HexColorParseError))?;
return Ok(Color::system(index));
} else if kind != 0x00 {
return Err(ErrorKind::Form(FormError::HexColorParseError));
}
let blue_ascii = &input[4..6];
let green_ascii = &input[6..8];
let red_ascii = &input[8..10];
let blue = u8::from_str_radix(blue_ascii, 16)
.map_err(|_| ErrorKind::Form(FormError::HexColorParseError))?;
let green = u8::from_str_radix(green_ascii, 16)
.map_err(|_| ErrorKind::Form(FormError::HexColorParseError))?;
let red = u8::from_str_radix(red_ascii, 16)
.map_err(|_| ErrorKind::Form(FormError::HexColorParseError))?;
Ok(Color::new(red, green, blue))
}
}