use crossterm::style::Color;
pub const BUTTON_NORMAL: u8 = 1; pub const BUTTON_DEFAULT: u8 = 2; pub const BUTTON_SELECTED: u8 = 3; pub const BUTTON_DISABLED: u8 = 4; pub const BUTTON_SHORTCUT: u8 = 7; pub const BUTTON_SHADOW: u8 = 8;
pub const INPUT_NORMAL: u8 = 1; pub const INPUT_FOCUSED: u8 = 2; pub const INPUT_SELECTED: u8 = 3; pub const INPUT_ARROWS: u8 = 4;
pub const SCROLLBAR_PAGE: u8 = 1; pub const SCROLLBAR_ARROWS: u8 = 2; pub const SCROLLBAR_INDICATOR: u8 = 3;
pub const LISTBOX_NORMAL: u8 = 1; pub const LISTBOX_FOCUSED: u8 = 2; pub const LISTBOX_SELECTED: u8 = 3; pub const LISTBOX_DIVIDER: u8 = 4;
pub const CLUSTER_NORMAL: u8 = 1; pub const CLUSTER_FOCUSED: u8 = 2; pub const CLUSTER_SHORTCUT: u8 = 3; pub const CLUSTER_DISABLED: u8 = 4;
pub const LABEL_NORMAL: u8 = 1; pub const LABEL_SELECTED: u8 = 2; pub const LABEL_SHORTCUT: u8 = 3;
pub const STATIC_TEXT_NORMAL: u8 = 1;
pub const PARAM_TEXT_NORMAL: u8 = 1;
pub const STATUSLINE_NORMAL: u8 = 1; pub const STATUSLINE_SHORTCUT: u8 = 2; pub const STATUSLINE_SELECTED: u8 = 3; pub const STATUSLINE_SELECTED_SHORTCUT: u8 = 4;
pub const FRAME_INACTIVE: u8 = 1; pub const FRAME_ACTIVE_BORDER: u8 = 2; pub const FRAME_TITLE: u8 = 2; pub const FRAME_ICON: u8 = 3;
pub const WINDOW_BACKGROUND: u8 = 1; pub const BLUE_WINDOW_BACKGROUND: u8 = 5;
pub const EDITOR_NORMAL: u8 = 1; pub const EDITOR_SELECTED: u8 = 2; pub const EDITOR_CURSOR: u8 = 2;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum TvColor {
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Magenta = 5,
Brown = 6,
LightGray = 7,
DarkGray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
LightMagenta = 13,
Yellow = 14,
White = 15,
}
impl TvColor {
pub fn to_ansi_code(self) -> u8 {
match self {
TvColor::Black => 0,
TvColor::Blue => 4, TvColor::Green => 2,
TvColor::Cyan => 6, TvColor::Red => 1, TvColor::Magenta => 5,
TvColor::Brown => 3, TvColor::LightGray => 7,
TvColor::DarkGray => 8,
TvColor::LightBlue => 12, TvColor::LightGreen => 10,
TvColor::LightCyan => 14, TvColor::LightRed => 9, TvColor::LightMagenta => 13,
TvColor::Yellow => 11, TvColor::White => 15,
}
}
pub fn to_crossterm(self) -> Color {
match self {
TvColor::Black => Color::Rgb { r: 0, g: 0, b: 0 },
TvColor::Blue => Color::Rgb { r: 0, g: 0, b: 170 },
TvColor::Green => Color::Rgb { r: 0, g: 170, b: 0 },
TvColor::Cyan => Color::Rgb {
r: 0,
g: 170,
b: 170,
},
TvColor::Red => Color::Rgb { r: 170, g: 0, b: 0 },
TvColor::Magenta => Color::Rgb {
r: 170,
g: 0,
b: 170,
},
TvColor::Brown => Color::Rgb {
r: 170,
g: 85,
b: 0,
},
TvColor::LightGray => Color::Rgb {
r: 170,
g: 170,
b: 170,
},
TvColor::DarkGray => Color::Rgb {
r: 85,
g: 85,
b: 85,
},
TvColor::LightBlue => Color::Rgb {
r: 85,
g: 85,
b: 255,
},
TvColor::LightGreen => Color::Rgb {
r: 85,
g: 255,
b: 85,
},
TvColor::LightCyan => Color::Rgb {
r: 85,
g: 255,
b: 255,
},
TvColor::LightRed => Color::Rgb {
r: 255,
g: 85,
b: 85,
},
TvColor::LightMagenta => Color::Rgb {
r: 255,
g: 85,
b: 255,
},
TvColor::Yellow => Color::Rgb {
r: 255,
g: 255,
b: 85,
},
TvColor::White => Color::Rgb {
r: 255,
g: 255,
b: 255,
},
}
}
pub fn to_rgb(self) -> (u8, u8, u8) {
match self {
TvColor::Black => (0, 0, 0),
TvColor::Blue => (0, 0, 170),
TvColor::Green => (0, 170, 0),
TvColor::Cyan => (0, 170, 170),
TvColor::Red => (170, 0, 0),
TvColor::Magenta => (170, 0, 170),
TvColor::Brown => (170, 85, 0),
TvColor::LightGray => (170, 170, 170),
TvColor::DarkGray => (85, 85, 85),
TvColor::LightBlue => (85, 85, 255),
TvColor::LightGreen => (85, 255, 85),
TvColor::LightCyan => (85, 255, 255),
TvColor::LightRed => (255, 85, 85),
TvColor::LightMagenta => (255, 85, 255),
TvColor::Yellow => (255, 255, 85),
TvColor::White => (255, 255, 255),
}
}
pub fn from_rgb(r: u8, g: u8, b: u8) -> Self {
let all_colors = [
TvColor::Black,
TvColor::Blue,
TvColor::Green,
TvColor::Cyan,
TvColor::Red,
TvColor::Magenta,
TvColor::Brown,
TvColor::LightGray,
TvColor::DarkGray,
TvColor::LightBlue,
TvColor::LightGreen,
TvColor::LightCyan,
TvColor::LightRed,
TvColor::LightMagenta,
TvColor::Yellow,
TvColor::White,
];
let mut best_color = TvColor::Black;
let mut best_distance = u32::MAX;
for &color in &all_colors {
let (cr, cg, cb) = color.to_rgb();
let distance = (r as i32 - cr as i32).pow(2) as u32
+ (g as i32 - cg as i32).pow(2) as u32
+ (b as i32 - cb as i32).pow(2) as u32;
if distance < best_distance {
best_distance = distance;
best_color = color;
}
}
best_color
}
pub fn from_u8(n: u8) -> Self {
match n & 0x0F {
0 => TvColor::Black,
1 => TvColor::Blue,
2 => TvColor::Green,
3 => TvColor::Cyan,
4 => TvColor::Red,
5 => TvColor::Magenta,
6 => TvColor::Brown,
7 => TvColor::LightGray,
8 => TvColor::DarkGray,
9 => TvColor::LightBlue,
10 => TvColor::LightGreen,
11 => TvColor::LightCyan,
12 => TvColor::LightRed,
13 => TvColor::LightMagenta,
14 => TvColor::Yellow,
15 => TvColor::White,
_ => TvColor::LightGray,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Attr {
pub fg: TvColor,
pub bg: TvColor,
}
impl Attr {
pub const fn new(fg: TvColor, bg: TvColor) -> Self {
Self { fg, bg }
}
pub fn from_u8(byte: u8) -> Self {
Self {
fg: TvColor::from_u8(byte & 0x0F),
bg: TvColor::from_u8((byte >> 4) & 0x0F),
}
}
pub fn to_u8(self) -> u8 {
(self.fg as u8) | ((self.bg as u8) << 4)
}
pub fn swap(self) -> Self {
Self {
fg: self.bg,
bg: self.fg,
}
}
pub fn darken(&self, factor: f32) -> Self {
let darken_color = |color: TvColor| -> TvColor {
let (r, g, b) = color.to_rgb();
let new_r = ((r as f32) * factor).min(255.0) as u8;
let new_g = ((g as f32) * factor).min(255.0) as u8;
let new_b = ((b as f32) * factor).min(255.0) as u8;
TvColor::from_rgb(new_r, new_g, new_b)
};
Self {
fg: darken_color(self.fg),
bg: darken_color(self.bg),
}
}
}
pub mod colors {
use super::*;
pub const NORMAL: Attr = Attr::new(TvColor::LightGray, TvColor::Blue);
pub const HIGHLIGHTED: Attr = Attr::new(TvColor::Yellow, TvColor::Blue);
pub const SELECTED: Attr = Attr::new(TvColor::White, TvColor::Cyan);
pub const DISABLED: Attr = Attr::new(TvColor::DarkGray, TvColor::Blue);
pub const MENU_NORMAL: Attr = Attr::new(TvColor::Black, TvColor::LightGray);
pub const MENU_SELECTED: Attr = Attr::new(TvColor::White, TvColor::Green);
pub const MENU_DISABLED: Attr = Attr::new(TvColor::DarkGray, TvColor::LightGray);
pub const MENU_SHORTCUT: Attr = Attr::new(TvColor::Red, TvColor::LightGray);
pub const DIALOG_NORMAL: Attr = Attr::new(TvColor::Black, TvColor::LightGray); pub const DIALOG_FRAME: Attr = Attr::new(TvColor::White, TvColor::LightGray); pub const DIALOG_FRAME_ACTIVE: Attr = Attr::new(TvColor::White, TvColor::LightGray); pub const DIALOG_TITLE: Attr = Attr::new(TvColor::White, TvColor::LightGray); pub const DIALOG_SHORTCUT: Attr = Attr::new(TvColor::Red, TvColor::LightGray);
pub const BUTTON_NORMAL: Attr = Attr::new(TvColor::Black, TvColor::Green); pub const BUTTON_DEFAULT: Attr = Attr::new(TvColor::LightGreen, TvColor::Green); pub const BUTTON_SELECTED: Attr = Attr::new(TvColor::White, TvColor::Green); pub const BUTTON_DISABLED: Attr = Attr::new(TvColor::DarkGray, TvColor::Green); pub const BUTTON_SHORTCUT: Attr = Attr::new(TvColor::Yellow, TvColor::Green); pub const BUTTON_SHADOW: Attr = Attr::new(TvColor::LightGray, TvColor::DarkGray);
pub const STATUS_NORMAL: Attr = Attr::new(TvColor::Black, TvColor::LightGray);
pub const STATUS_SHORTCUT: Attr = Attr::new(TvColor::Red, TvColor::LightGray);
pub const STATUS_SELECTED: Attr = Attr::new(TvColor::White, TvColor::Green);
pub const STATUS_SELECTED_SHORTCUT: Attr = Attr::new(TvColor::Yellow, TvColor::Green);
pub const INPUT_NORMAL: Attr = Attr::new(TvColor::Yellow, TvColor::Blue); pub const INPUT_FOCUSED: Attr = Attr::new(TvColor::Yellow, TvColor::Blue); pub const INPUT_SELECTED: Attr = Attr::new(TvColor::Cyan, TvColor::Cyan); pub const INPUT_ARROWS: Attr = Attr::new(TvColor::Red, TvColor::Cyan);
pub const EDITOR_NORMAL: Attr = Attr::new(TvColor::White, TvColor::Blue);
pub const EDITOR_SELECTED: Attr = Attr::new(TvColor::Black, TvColor::Cyan);
pub const LISTBOX_NORMAL: Attr = Attr::new(TvColor::Black, TvColor::LightGray);
pub const LISTBOX_FOCUSED: Attr = Attr::new(TvColor::Black, TvColor::White);
pub const LISTBOX_SELECTED: Attr = Attr::new(TvColor::White, TvColor::Blue);
pub const LISTBOX_SELECTED_FOCUSED: Attr = Attr::new(TvColor::White, TvColor::Cyan);
pub const SCROLLBAR_PAGE: Attr = Attr::new(TvColor::DarkGray, TvColor::LightGray);
pub const SCROLLBAR_INDICATOR: Attr = Attr::new(TvColor::Blue, TvColor::LightGray);
pub const SCROLLBAR_ARROW: Attr = Attr::new(TvColor::Black, TvColor::LightGray);
pub const SCROLLER_NORMAL: Attr = Attr::new(TvColor::Black, TvColor::LightGray);
pub const SCROLLER_SELECTED: Attr = Attr::new(TvColor::White, TvColor::Blue);
pub const DESKTOP: Attr = Attr::new(TvColor::LightGray, TvColor::DarkGray);
pub const SYNTAX_NORMAL: Attr = Attr::new(TvColor::LightGray, TvColor::Blue);
pub const SYNTAX_KEYWORD: Attr = Attr::new(TvColor::Yellow, TvColor::Blue);
pub const SYNTAX_STRING: Attr = Attr::new(TvColor::LightRed, TvColor::Blue);
pub const SYNTAX_COMMENT: Attr = Attr::new(TvColor::White, TvColor::Blue);
pub const SYNTAX_NUMBER: Attr = Attr::new(TvColor::LightMagenta, TvColor::Blue);
pub const SYNTAX_OPERATOR: Attr = Attr::new(TvColor::White, TvColor::Blue);
pub const SYNTAX_IDENTIFIER: Attr = Attr::new(TvColor::LightGray, TvColor::Blue);
pub const SYNTAX_TYPE: Attr = Attr::new(TvColor::LightGreen, TvColor::Blue);
pub const SYNTAX_PREPROCESSOR: Attr = Attr::new(TvColor::White, TvColor::Blue);
pub const SYNTAX_FUNCTION: Attr = Attr::new(TvColor::White, TvColor::Blue);
pub const SYNTAX_SPECIAL: Attr = Attr::new(TvColor::White, TvColor::Blue);
pub const HELP_NORMAL: Attr = Attr::new(TvColor::Black, TvColor::LightGray);
pub const HELP_FOCUSED: Attr = Attr::new(TvColor::Black, TvColor::White);
}
#[derive(Debug, Clone)]
pub struct Palette {
data: Vec<u8>,
}
impl Palette {
pub fn new() -> Self {
Self { data: Vec::new() }
}
pub fn from_slice(data: &[u8]) -> Self {
Self {
data: data.to_vec(),
}
}
pub fn get(&self, index: usize) -> u8 {
if index == 0 || index > self.data.len() {
0
} else {
self.data[index - 1]
}
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
}
impl Default for Palette {
fn default() -> Self {
Self::new()
}
}
pub mod palettes {
use std::cell::RefCell;
thread_local! {
static CUSTOM_APP_PALETTE: RefCell<Option<Vec<u8>>> = RefCell::new(None);
}
pub fn set_custom_palette(palette: Option<Vec<u8>>) {
CUSTOM_APP_PALETTE.with(|p| {
*p.borrow_mut() = palette;
});
}
pub fn get_app_palette() -> Vec<u8> {
CUSTOM_APP_PALETTE.with(|p| {
if let Some(custom) = p.borrow().as_ref() {
custom.clone()
} else {
CP_APP_COLOR.to_vec()
}
})
}
#[rustfmt::skip]
pub const CP_APP_COLOR: &[u8] = &[
0x71, 0x70, 0x78, 0x74, 0x20, 0x28, 0x24, 0x17, 0x1F, 0x1A, 0x31, 0x31, 0x1E, 0x71, 0x00, 0x30, 0x3F, 0x3A, 0x13, 0x13, 0x3E, 0x21, 0x00,
0x70, 0x7F, 0x7A, 0x13, 0x13, 0x70, 0x7F, 0x00, 0x70, 0x7F, 0x7A, 0x13, 0x13, 0x70, 0x70, 0x7F, 0x7E, 0x20, 0x2B, 0x2F, 0x78, 0x2E, 0x70, 0x30, 0x3F, 0x3E, 0x1F, 0x2F, 0x1A, 0x20, 0x72, 0x31, 0x31, 0x30, 0x2F, 0x3E, 0x31, 0x13, 0x38, 0x00, ];
#[rustfmt::skip]
pub const CP_BLUE_WINDOW: &[u8] = &[
8, 9, 10, 11, 12, 13, 14, 15, ];
#[rustfmt::skip]
pub const CP_CYAN_WINDOW: &[u8] = &[
16, 17, 18, 19, 20, 21, 22, 23, ];
#[rustfmt::skip]
pub const CP_GRAY_WINDOW: &[u8] = &[
24, 25, 26, 27, 28, 29, 30, 31, ];
#[rustfmt::skip]
pub const CP_GRAY_DIALOG: &[u8] = &[
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, ];
#[rustfmt::skip]
pub const CP_BLUE_DIALOG: &[u8] = &[
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, ];
#[rustfmt::skip]
pub const CP_BUTTON: &[u8] = &[
10, 11, 12, 13, 14, 14, 14, 15, ];
#[rustfmt::skip]
pub const CP_STATIC_TEXT: &[u8] = &[
6, ];
#[rustfmt::skip]
pub const CP_INPUT_LINE: &[u8] = &[
19, 19, 20, 21, ];
#[rustfmt::skip]
pub const CP_LABEL: &[u8] = &[
7, 8, 9, 9, 13, 13, ];
#[rustfmt::skip]
pub const CP_LISTBOX: &[u8] = &[
26, 26, 27, 28, ];
#[rustfmt::skip]
pub const CP_SCROLLBAR: &[u8] = &[
4, 5, 5, ];
#[rustfmt::skip]
pub const CP_SCROLLER: &[u8] = &[
6, 7, ];
#[rustfmt::skip]
pub const CP_CLUSTER: &[u8] = &[
16, 17, 18, 19, ];
#[rustfmt::skip]
pub const CP_STATUSLINE: &[u8] = &[
2, 4, 45, 41, ];
#[rustfmt::skip]
pub const CP_MENU_BAR: &[u8] = &[
2, 5, 3, 4, ];
#[rustfmt::skip]
pub const CP_MEMO: &[u8] = &[
26, 27, ];
#[rustfmt::skip]
pub const CP_INDICATOR: &[u8] = &[
2, 3, ];
#[rustfmt::skip]
pub const CP_HELP_VIEWER: &[u8] = &[
1, 2, 6, 2, 3, 4, ];
#[rustfmt::skip]
pub const CP_EDITOR: &[u8] = &[
6, 7, ];
#[rustfmt::skip]
pub const CP_HISTORY_VIEWER: &[u8] = &[
6, 6, 7, 6, 6, ];
#[rustfmt::skip]
pub const CP_HISTORY: &[u8] = &[
22, 23, ];
#[rustfmt::skip]
pub const CP_BACKGROUND: &[u8] = &[
1, ];
}