2022-02-17 16:06:28 -06:00
|
|
|
|
use std::{num::ParseFloatError, str::FromStr};
|
|
|
|
|
|
|
|
|
|
use tui::style::{Color, Modifier, Style};
|
|
|
|
|
|
|
|
|
|
use crate::RenderingMode;
|
|
|
|
|
|
2022-03-18 10:43:43 -05:00
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
2022-02-17 16:06:28 -06:00
|
|
|
|
pub struct RinkColor {
|
|
|
|
|
pub color: Color,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
pub alpha: u8,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for RinkColor {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
color: Color::Black,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 0,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RinkColor {
|
|
|
|
|
pub fn blend(self, other: Color) -> Color {
|
|
|
|
|
if self.color == Color::Reset {
|
|
|
|
|
Color::Reset
|
2022-03-18 10:43:43 -05:00
|
|
|
|
} else if self.alpha == 0 {
|
2022-02-22 19:41:45 -06:00
|
|
|
|
other
|
2022-02-17 16:06:28 -06:00
|
|
|
|
} else {
|
2022-03-18 10:43:43 -05:00
|
|
|
|
let [sr, sg, sb] = to_rgb(self.color).map(|e| e as u16);
|
|
|
|
|
let [or, og, ob] = to_rgb(other).map(|e| e as u16);
|
2022-03-30 20:45:41 -05:00
|
|
|
|
let sa = self.alpha as u16;
|
2022-03-18 10:43:43 -05:00
|
|
|
|
let rsa = 255 - sa;
|
2022-02-22 19:41:45 -06:00
|
|
|
|
Color::Rgb(
|
2022-03-18 10:43:43 -05:00
|
|
|
|
((sr * sa + or * rsa) / 255) as u8,
|
|
|
|
|
((sg * sa + og * rsa) / 255) as u8,
|
|
|
|
|
((sb * sa + ob * rsa) / 255) as u8,
|
2022-02-22 19:41:45 -06:00
|
|
|
|
)
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_value(
|
|
|
|
|
v: &str,
|
|
|
|
|
current_max_output: f32,
|
|
|
|
|
required_max_output: f32,
|
|
|
|
|
) -> Result<f32, ParseFloatError> {
|
2022-02-22 19:41:45 -06:00
|
|
|
|
if let Some(stripped) = v.strip_suffix('%') {
|
|
|
|
|
Ok((stripped.trim().parse::<f32>()? / 100.0) * required_max_output)
|
2022-02-17 16:06:28 -06:00
|
|
|
|
} else {
|
|
|
|
|
Ok((v.trim().parse::<f32>()? / current_max_output) * required_max_output)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct ParseColorError;
|
|
|
|
|
|
|
|
|
|
fn parse_hex(color: &str) -> Result<Color, ParseColorError> {
|
|
|
|
|
let mut values = [0, 0, 0];
|
|
|
|
|
let mut color_ok = true;
|
|
|
|
|
for i in 0..values.len() {
|
|
|
|
|
if let Ok(v) = u8::from_str_radix(&color[(1 + 2 * i)..(1 + 2 * (i + 1))], 16) {
|
|
|
|
|
values[i] = v;
|
|
|
|
|
} else {
|
|
|
|
|
color_ok = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if color_ok {
|
|
|
|
|
Ok(Color::Rgb(values[0], values[1], values[2]))
|
|
|
|
|
} else {
|
|
|
|
|
Err(ParseColorError)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_rgb(color: &str) -> Result<Color, ParseColorError> {
|
|
|
|
|
let mut values = [0, 0, 0];
|
|
|
|
|
let mut color_ok = true;
|
|
|
|
|
for (v, i) in color.split(',').zip(0..values.len()) {
|
|
|
|
|
if let Ok(v) = parse_value(v.trim(), 255.0, 255.0) {
|
|
|
|
|
values[i] = v as u8;
|
|
|
|
|
} else {
|
|
|
|
|
color_ok = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if color_ok {
|
|
|
|
|
Ok(Color::Rgb(values[0], values[1], values[2]))
|
|
|
|
|
} else {
|
|
|
|
|
Err(ParseColorError)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_hsl(color: &str) -> Result<Color, ParseColorError> {
|
|
|
|
|
let mut values = [0.0, 0.0, 0.0];
|
|
|
|
|
let mut color_ok = true;
|
|
|
|
|
for (v, i) in color.split(',').zip(0..values.len()) {
|
|
|
|
|
if let Ok(v) = parse_value(v.trim(), if i == 0 { 360.0 } else { 100.0 }, 1.0) {
|
|
|
|
|
values[i] = v;
|
|
|
|
|
} else {
|
|
|
|
|
color_ok = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if color_ok {
|
|
|
|
|
let [h, s, l] = values;
|
|
|
|
|
let rgb = if s == 0.0 {
|
|
|
|
|
[l as u8; 3]
|
|
|
|
|
} else {
|
|
|
|
|
fn hue_to_rgb(p: f32, q: f32, mut t: f32) -> f32 {
|
|
|
|
|
if t < 0.0 {
|
|
|
|
|
t += 1.0;
|
|
|
|
|
}
|
|
|
|
|
if t > 1.0 {
|
|
|
|
|
t -= 1.0;
|
|
|
|
|
}
|
|
|
|
|
if t < 1.0 / 6.0 {
|
|
|
|
|
p + (q - p) * 6.0 * t
|
|
|
|
|
} else if t < 1.0 / 2.0 {
|
|
|
|
|
q
|
|
|
|
|
} else if t < 2.0 / 3.0 {
|
|
|
|
|
p + (q - p) * (2.0 / 3.0 - t) * 6.0
|
|
|
|
|
} else {
|
|
|
|
|
p
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let q = if l < 0.5 {
|
|
|
|
|
l * (1.0 + s)
|
|
|
|
|
} else {
|
|
|
|
|
l + s - l * s
|
|
|
|
|
};
|
|
|
|
|
let p = 2.0 * l - q;
|
|
|
|
|
[
|
|
|
|
|
(hue_to_rgb(p, q, h + 1.0 / 3.0) * 255.0) as u8,
|
|
|
|
|
(hue_to_rgb(p, q, h) * 255.0) as u8,
|
|
|
|
|
(hue_to_rgb(p, q, h - 1.0 / 3.0) * 255.0) as u8,
|
|
|
|
|
]
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(Color::Rgb(rgb[0], rgb[1], rgb[2]))
|
|
|
|
|
} else {
|
|
|
|
|
Err(ParseColorError)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FromStr for RinkColor {
|
|
|
|
|
type Err = ParseColorError;
|
|
|
|
|
|
|
|
|
|
fn from_str(color: &str) -> Result<Self, Self::Err> {
|
|
|
|
|
match color {
|
|
|
|
|
"red" => Ok(RinkColor {
|
|
|
|
|
color: Color::Red,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"black" => Ok(RinkColor {
|
|
|
|
|
color: Color::Black,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"green" => Ok(RinkColor {
|
|
|
|
|
color: Color::Green,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"yellow" => Ok(RinkColor {
|
|
|
|
|
color: Color::Yellow,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"blue" => Ok(RinkColor {
|
|
|
|
|
color: Color::Blue,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"magenta" => Ok(RinkColor {
|
|
|
|
|
color: Color::Magenta,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"cyan" => Ok(RinkColor {
|
|
|
|
|
color: Color::Cyan,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"gray" => Ok(RinkColor {
|
|
|
|
|
color: Color::Gray,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"darkgray" => Ok(RinkColor {
|
|
|
|
|
color: Color::DarkGray,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
// light red does not exist
|
|
|
|
|
"orangered" => Ok(RinkColor {
|
|
|
|
|
color: Color::LightRed,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"lightgreen" => Ok(RinkColor {
|
|
|
|
|
color: Color::LightGreen,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"lightyellow" => Ok(RinkColor {
|
|
|
|
|
color: Color::LightYellow,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"lightblue" => Ok(RinkColor {
|
|
|
|
|
color: Color::LightBlue,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
// light magenta does not exist
|
|
|
|
|
"orchid" => Ok(RinkColor {
|
|
|
|
|
color: Color::LightMagenta,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"lightcyan" => Ok(RinkColor {
|
|
|
|
|
color: Color::LightCyan,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
"white" => Ok(RinkColor {
|
|
|
|
|
color: Color::White,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
_ => {
|
|
|
|
|
if color.len() == 7 && color.starts_with('#') {
|
|
|
|
|
parse_hex(color).map(|c| RinkColor {
|
|
|
|
|
color: c,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
})
|
2022-02-22 19:41:45 -06:00
|
|
|
|
} else if let Some(stripped) = color.strip_prefix("rgb(") {
|
|
|
|
|
let color_values = stripped.trim_end_matches(')');
|
2022-02-17 17:30:11 -06:00
|
|
|
|
if color.matches(',').count() == 3 {
|
2022-02-17 16:06:28 -06:00
|
|
|
|
let (alpha, rgb_values) =
|
|
|
|
|
color_values.rsplit_once(',').ok_or(ParseColorError)?;
|
|
|
|
|
if let Ok(a) = alpha.parse() {
|
|
|
|
|
parse_rgb(rgb_values).map(|c| RinkColor { color: c, alpha: a })
|
|
|
|
|
} else {
|
|
|
|
|
Err(ParseColorError)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
parse_rgb(color_values).map(|c| RinkColor {
|
|
|
|
|
color: c,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
})
|
|
|
|
|
}
|
2022-02-22 19:41:45 -06:00
|
|
|
|
} else if let Some(stripped) = color.strip_prefix("rgba(") {
|
|
|
|
|
let color_values = stripped.trim_end_matches(')');
|
2022-02-17 16:06:28 -06:00
|
|
|
|
if color.matches(',').count() == 3 {
|
|
|
|
|
let (rgb_values, alpha) =
|
|
|
|
|
color_values.rsplit_once(',').ok_or(ParseColorError)?;
|
|
|
|
|
if let Ok(a) = parse_value(alpha, 1.0, 1.0) {
|
2022-03-18 10:43:43 -05:00
|
|
|
|
parse_rgb(rgb_values).map(|c| RinkColor {
|
|
|
|
|
color: c,
|
|
|
|
|
alpha: (a * 255.0) as u8,
|
|
|
|
|
})
|
2022-02-17 16:06:28 -06:00
|
|
|
|
} else {
|
|
|
|
|
Err(ParseColorError)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
parse_rgb(color_values).map(|c| RinkColor {
|
|
|
|
|
color: c,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
})
|
|
|
|
|
}
|
2022-02-22 19:41:45 -06:00
|
|
|
|
} else if let Some(stripped) = color.strip_prefix("hsl(") {
|
|
|
|
|
let color_values = stripped.trim_end_matches(')');
|
2022-02-17 16:06:28 -06:00
|
|
|
|
if color.matches(',').count() == 3 {
|
|
|
|
|
let (rgb_values, alpha) =
|
|
|
|
|
color_values.rsplit_once(',').ok_or(ParseColorError)?;
|
|
|
|
|
if let Ok(a) = parse_value(alpha, 1.0, 1.0) {
|
2022-03-18 10:43:43 -05:00
|
|
|
|
parse_hsl(rgb_values).map(|c| RinkColor {
|
|
|
|
|
color: c,
|
|
|
|
|
alpha: (a * 255.0) as u8,
|
|
|
|
|
})
|
2022-02-17 16:06:28 -06:00
|
|
|
|
} else {
|
|
|
|
|
Err(ParseColorError)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
parse_hsl(color_values).map(|c| RinkColor {
|
|
|
|
|
color: c,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
})
|
|
|
|
|
}
|
2022-02-22 19:41:45 -06:00
|
|
|
|
} else if let Some(stripped) = color.strip_prefix("hsla(") {
|
|
|
|
|
let color_values = stripped.trim_end_matches(')');
|
2022-02-17 16:06:28 -06:00
|
|
|
|
if color.matches(',').count() == 3 {
|
|
|
|
|
let (rgb_values, alpha) =
|
|
|
|
|
color_values.rsplit_once(',').ok_or(ParseColorError)?;
|
|
|
|
|
if let Ok(a) = parse_value(alpha, 1.0, 1.0) {
|
2022-03-18 10:43:43 -05:00
|
|
|
|
parse_hsl(rgb_values).map(|c| RinkColor {
|
|
|
|
|
color: c,
|
|
|
|
|
alpha: (a * 255.0) as u8,
|
|
|
|
|
})
|
2022-02-17 16:06:28 -06:00
|
|
|
|
} else {
|
|
|
|
|
Err(ParseColorError)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
parse_hsl(color_values).map(|c| RinkColor {
|
|
|
|
|
color: c,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Err(ParseColorError)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn to_rgb(c: Color) -> [u8; 3] {
|
|
|
|
|
match c {
|
|
|
|
|
Color::Black => [0, 0, 0],
|
|
|
|
|
Color::Red => [255, 0, 0],
|
|
|
|
|
Color::Green => [0, 128, 0],
|
|
|
|
|
Color::Yellow => [255, 255, 0],
|
|
|
|
|
Color::Blue => [0, 0, 255],
|
|
|
|
|
Color::Magenta => [255, 0, 255],
|
|
|
|
|
Color::Cyan => [0, 255, 255],
|
|
|
|
|
Color::Gray => [128, 128, 128],
|
|
|
|
|
Color::DarkGray => [169, 169, 169],
|
|
|
|
|
Color::LightRed => [255, 69, 0],
|
|
|
|
|
Color::LightGreen => [144, 238, 144],
|
|
|
|
|
Color::LightYellow => [255, 255, 224],
|
|
|
|
|
Color::LightBlue => [173, 216, 230],
|
|
|
|
|
Color::LightMagenta => [218, 112, 214],
|
|
|
|
|
Color::LightCyan => [224, 255, 255],
|
|
|
|
|
Color::White => [255, 255, 255],
|
|
|
|
|
Color::Rgb(r, g, b) => [r, g, b],
|
|
|
|
|
Color::Indexed(idx) => match idx {
|
|
|
|
|
16..=231 => {
|
|
|
|
|
let v = idx - 16;
|
|
|
|
|
// add 3 to round up
|
2022-02-27 07:56:08 -06:00
|
|
|
|
let r = ((v as u16 / 36) * 255 + 3) / 5;
|
|
|
|
|
let g = (((v as u16 % 36) / 6) * 255 + 3) / 5;
|
|
|
|
|
let b = ((v as u16 % 6) * 255 + 3) / 5;
|
2022-02-17 16:06:28 -06:00
|
|
|
|
[r as u8, g as u8, b as u8]
|
|
|
|
|
}
|
|
|
|
|
232..=255 => {
|
|
|
|
|
let l = (idx - 232) / 24;
|
|
|
|
|
[l; 3]
|
|
|
|
|
}
|
|
|
|
|
// rink will never generate these colors, but they might be on the screen from another program
|
|
|
|
|
_ => [0, 0, 0],
|
|
|
|
|
},
|
2022-02-17 17:30:11 -06:00
|
|
|
|
Color::Reset => [0, 0, 0],
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn convert(mode: RenderingMode, c: Color) -> Color {
|
|
|
|
|
if let Color::Reset = c {
|
|
|
|
|
c
|
|
|
|
|
} else {
|
|
|
|
|
match mode {
|
|
|
|
|
crate::RenderingMode::BaseColors => match c {
|
|
|
|
|
Color::Rgb(_, _, _) => panic!("cannot convert rgb color to base color"),
|
|
|
|
|
Color::Indexed(_) => panic!("cannot convert Ansi color to base color"),
|
|
|
|
|
_ => c,
|
|
|
|
|
},
|
|
|
|
|
crate::RenderingMode::Rgb => {
|
|
|
|
|
let rgb = to_rgb(c);
|
|
|
|
|
Color::Rgb(rgb[0], rgb[1], rgb[2])
|
|
|
|
|
}
|
|
|
|
|
crate::RenderingMode::Ansi => match c {
|
|
|
|
|
Color::Indexed(_) => c,
|
|
|
|
|
_ => {
|
|
|
|
|
let rgb = to_rgb(c);
|
|
|
|
|
// 16-231: 6 × 6 × 6 color cube
|
2022-02-27 07:56:08 -06:00
|
|
|
|
// 232-255: 23 step grayscale
|
2022-02-17 16:06:28 -06:00
|
|
|
|
if rgb[0] == rgb[1] && rgb[1] == rgb[2] {
|
|
|
|
|
let idx = 232 + (rgb[0] as u16 * 23 / 255) as u8;
|
|
|
|
|
Color::Indexed(idx)
|
|
|
|
|
} else {
|
2022-02-27 06:52:35 -06:00
|
|
|
|
let r = (rgb[0] as u16 * 5) / 255;
|
|
|
|
|
let g = (rgb[1] as u16 * 5) / 255;
|
|
|
|
|
let b = (rgb[2] as u16 * 5) / 255;
|
2022-02-17 16:06:28 -06:00
|
|
|
|
let idx = 16 + r * 36 + g * 6 + b;
|
|
|
|
|
Color::Indexed(idx as u8)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn rgb_to_ansi() {
|
2022-02-27 07:56:08 -06:00
|
|
|
|
for idx in 17..=231 {
|
2022-02-17 16:06:28 -06:00
|
|
|
|
let idxed = Color::Indexed(idx);
|
|
|
|
|
let rgb = to_rgb(idxed);
|
|
|
|
|
// gray scale colors have two equivelent repersentations
|
|
|
|
|
let color = Color::Rgb(rgb[0], rgb[1], rgb[2]);
|
|
|
|
|
let converted = convert(RenderingMode::Ansi, color);
|
|
|
|
|
if let Color::Indexed(i) = converted {
|
|
|
|
|
if rgb[0] != rgb[1] || rgb[1] != rgb[2] {
|
|
|
|
|
assert_eq!(idxed, converted);
|
|
|
|
|
} else {
|
2022-02-22 19:41:45 -06:00
|
|
|
|
assert!(i >= 232);
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
panic!("color is not indexed")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for idx in 232..=255 {
|
|
|
|
|
let idxed = Color::Indexed(idx);
|
|
|
|
|
let rgb = to_rgb(idxed);
|
|
|
|
|
assert!(rgb[0] == rgb[1] && rgb[1] == rgb[2]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 10:43:43 -05:00
|
|
|
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
2022-02-17 16:06:28 -06:00
|
|
|
|
pub struct RinkStyle {
|
|
|
|
|
pub fg: Option<RinkColor>,
|
|
|
|
|
pub bg: Option<RinkColor>,
|
|
|
|
|
pub add_modifier: Modifier,
|
|
|
|
|
pub sub_modifier: Modifier,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for RinkStyle {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
fg: Some(RinkColor {
|
|
|
|
|
color: Color::White,
|
2022-03-18 10:43:43 -05:00
|
|
|
|
alpha: 255,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}),
|
|
|
|
|
bg: None,
|
|
|
|
|
add_modifier: Modifier::empty(),
|
|
|
|
|
sub_modifier: Modifier::empty(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RinkStyle {
|
|
|
|
|
pub fn add_modifier(mut self, m: Modifier) -> Self {
|
|
|
|
|
self.sub_modifier.remove(m);
|
|
|
|
|
self.add_modifier.insert(m);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn remove_modifier(mut self, m: Modifier) -> Self {
|
|
|
|
|
self.add_modifier.remove(m);
|
|
|
|
|
self.sub_modifier.insert(m);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn merge(mut self, other: RinkStyle) -> Self {
|
|
|
|
|
self.fg = self.fg.or(other.fg);
|
|
|
|
|
self.add_modifier(other.add_modifier)
|
|
|
|
|
.remove_modifier(other.sub_modifier)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-09 13:30:44 -05:00
|
|
|
|
impl From<RinkStyle> for Style {
|
|
|
|
|
fn from(val: RinkStyle) -> Self {
|
2022-02-17 16:06:28 -06:00
|
|
|
|
Style {
|
2022-03-09 13:30:44 -05:00
|
|
|
|
fg: val.fg.map(|c| c.color),
|
|
|
|
|
bg: val.bg.map(|c| c.color),
|
|
|
|
|
add_modifier: val.add_modifier,
|
|
|
|
|
sub_modifier: val.sub_modifier,
|
2022-02-17 16:06:28 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|