add panel using cnx
This commit is contained in:
parent
0174eeb4cc
commit
4036ed42f0
File diff suppressed because it is too large
Load Diff
|
@ -17,6 +17,12 @@ toml = "0.8.8"
|
|||
which = "6.0.0"
|
||||
log = "0.4"
|
||||
pretty_env_logger = "0.5"
|
||||
cnx = { git = "https://github.com/mjkillough/cnx.git", rev = "7845d99baa296901171c083db61588a62f9a8b34" }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.4.0"
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
strip = "debuginfo"
|
||||
lto = "fat"
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
use std::{os::unix::process::ExitStatusExt, process::Output};
|
||||
|
||||
use log::error;
|
||||
|
||||
use crate::hlwm::command::CommandError;
|
||||
|
||||
pub fn check_status(output: &Output) -> Result<(), CommandError> {
|
||||
let exit_status = output.status;
|
||||
if let Some(code) = exit_status.code() {
|
||||
if code == 0 {
|
||||
return Ok(());
|
||||
} else {
|
||||
let output = String::from_utf8(output.stdout.clone())
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_string();
|
||||
error!("command failed with error code [{code}]");
|
||||
if !output.is_empty() {
|
||||
error!("command output: {output}");
|
||||
}
|
||||
return Err(CommandError::StatusCode(
|
||||
code,
|
||||
if output.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(output)
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(signal) = exit_status.signal() {
|
||||
return Err(CommandError::KilledBySignal {
|
||||
signal,
|
||||
core_dumped: exit_status.core_dumped(),
|
||||
});
|
||||
}
|
||||
if let Some(signal) = exit_status.stopped_signal() {
|
||||
return Err(CommandError::StoppedBySignal(signal));
|
||||
}
|
||||
|
||||
Err(CommandError::OtherExitStatus(exit_status))
|
||||
}
|
|
@ -60,8 +60,13 @@ pub enum ConfigError {
|
|||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Config {
|
||||
pub font: Option<String>,
|
||||
pub font_bold: Option<String>,
|
||||
pub font: String,
|
||||
pub font_bold: String,
|
||||
/// Pango font for use where pango fonts are
|
||||
/// used (i.e. panel)
|
||||
pub font_pango: String,
|
||||
/// Bold version of `font_pango`
|
||||
pub font_pango_bold: String,
|
||||
pub mod_key: Key,
|
||||
pub keybinds: Vec<Keybind>,
|
||||
pub mousebinds: Vec<Mousebind>,
|
||||
|
@ -210,9 +215,9 @@ impl Config {
|
|||
fn attrs_set(&self) -> Result<Vec<HlwmCommand>, ConfigError> {
|
||||
info!("loading attr settings command set");
|
||||
Ok([
|
||||
(Self::FONT, self.font.clone()),
|
||||
(Self::FONT, Some(self.font.clone())),
|
||||
(Self::MOD_KEY, Some(self.mod_key.to_string())),
|
||||
(Self::FONT_BOLD, self.font_bold.clone()),
|
||||
(Self::FONT_BOLD, Some(self.font_bold.clone())),
|
||||
(
|
||||
Self::SERVICES,
|
||||
if self.services.len() == 0 {
|
||||
|
@ -393,16 +398,14 @@ impl Config {
|
|||
Config {
|
||||
font: setting(
|
||||
Self::FONT,
|
||||
|f| -> Result<_, Infallible> { Ok(Some(f.to_string())) },
|
||||
|f| -> Result<_, Infallible> { Ok(f.to_string()) },
|
||||
default.font,
|
||||
),
|
||||
mod_key: setting(Self::MOD_KEY, Key::from_str, default.mod_key),
|
||||
font_bold: Some(
|
||||
client
|
||||
.get_attr(ThemeAttr::TitleFont(String::new()).attr_path())
|
||||
.map(|a| a.to_string())
|
||||
.unwrap_or(default.font_bold.unwrap()),
|
||||
),
|
||||
font_bold: client
|
||||
.get_attr(ThemeAttr::TitleFont(String::new()).attr_path())
|
||||
.map(|a| a.to_string())
|
||||
.unwrap_or(default.font_bold),
|
||||
services: setting(
|
||||
Self::SERVICES,
|
||||
|v| serde_json::de::from_str(v),
|
||||
|
@ -508,6 +511,45 @@ pub struct Theme {
|
|||
pub attributes: Vec<ThemeAttr>,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
impl Theme {
|
||||
pub fn active_color(&self) -> Option<Color> {
|
||||
for attr in &self.attributes {
|
||||
if let ThemeAttr::ActiveColor(col) = attr {
|
||||
return Some(col.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn normal_color(&self) -> Option<Color> {
|
||||
for attr in &self.attributes {
|
||||
if let ThemeAttr::NormalColor(col) = attr {
|
||||
return Some(col.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn urgent_color(&self) -> Option<Color> {
|
||||
for attr in &self.attributes {
|
||||
if let ThemeAttr::UrgentColor(col) = attr {
|
||||
return Some(col.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn text_color(&self) -> Option<Color> {
|
||||
for attr in &self.attributes {
|
||||
if let ThemeAttr::TitleColor(col) = attr {
|
||||
return Some(col.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Error)]
|
||||
pub enum InclusiveError {
|
||||
#[error("out of range")]
|
||||
|
@ -712,8 +754,8 @@ impl Default for Config {
|
|||
|
||||
Self {
|
||||
mod_key,
|
||||
font: Some(String::from("-*-fixed-medium-*-*-*-12-*-*-*-*-*-*-*")),
|
||||
font_bold: Some(font_bold.clone()),
|
||||
font: String::from("-*-fixed-medium-*-*-*-12-*-*-*-*-*-*-*"),
|
||||
font_bold: font_bold.clone(),
|
||||
keybinds: vec![
|
||||
Keybind::new(
|
||||
[mod_key, Key::Shift, Key::Char('r')].into_iter(),
|
||||
|
@ -944,6 +986,8 @@ impl Default for Config {
|
|||
Setting::FrameBorderActiveColor(active_color.clone()),
|
||||
Setting::FrameBgActiveColor(active_color.clone()),
|
||||
],
|
||||
font_pango: String::from("Monospace 9"),
|
||||
font_pango_bold: String::from("Monospace Bold 9"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,426 +0,0 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use serde::{de::Unexpected, Deserialize, Serialize};
|
||||
use strum::IntoEnumIterator;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::hlwm::StringParseError;
|
||||
|
||||
use super::hex::{HexError, ParseHex};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Color {
|
||||
RGB { r: u8, g: u8, b: u8 },
|
||||
X11(X11Color),
|
||||
}
|
||||
|
||||
impl Serialize for Color {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Color {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct ExpectedColor;
|
||||
impl serde::de::Expected for ExpectedColor {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("an X11 color string or a hex color string")
|
||||
}
|
||||
}
|
||||
let str_val: String = Deserialize::deserialize(deserializer)?;
|
||||
Ok(Color::from_str(&str_val).map_err(|_| {
|
||||
serde::de::Error::invalid_value(Unexpected::Str(&str_val), &ExpectedColor)
|
||||
})?)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Color {
|
||||
fn default() -> Self {
|
||||
Self::RGB {
|
||||
r: Default::default(),
|
||||
g: Default::default(),
|
||||
b: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Error)]
|
||||
pub enum ParseError {
|
||||
#[error("length must be either 6 characters or 7 with '#' prefix")]
|
||||
InvalidLength,
|
||||
#[error("invalid hex value: [{0}]")]
|
||||
HexError(#[from] HexError),
|
||||
}
|
||||
|
||||
impl FromStr for Color {
|
||||
type Err = ParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if let Ok(x11) = X11Color::from_str(s) {
|
||||
return Ok(Self::X11(x11));
|
||||
}
|
||||
Self::from_hex(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub const BLACK: Color = Color::rgb(0, 0, 0);
|
||||
|
||||
pub fn from_hex(hex: &str) -> Result<Self, ParseError> {
|
||||
let expected_len = if hex.starts_with('#') { 7 } else { 6 };
|
||||
if hex.len() != expected_len {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
let hex = hex.strip_prefix('#').unwrap_or(hex);
|
||||
|
||||
Ok(Self::RGB {
|
||||
r: (&hex[0..2]).parse_hex()?,
|
||||
g: (&hex[2..4]).parse_hex()?,
|
||||
b: (&hex[4..6]).parse_hex()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
|
||||
Self::RGB { r, g, b }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Color {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Color::RGB { r, g, b } => write!(f, "#{r:02X}{g:02X}{b:02X}"),
|
||||
Color::X11(color) => f.write_str(&color.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, strum::Display, strum::EnumIter, PartialEq, Eq)]
|
||||
pub enum X11Color {
|
||||
GhostWhite,
|
||||
WhiteSmoke,
|
||||
FloralWhite,
|
||||
OldLace,
|
||||
AntiqueWhite,
|
||||
PapayaWhip,
|
||||
BlanchedAlmond,
|
||||
PeachPuff,
|
||||
NavajoWhite,
|
||||
LemonChiffon,
|
||||
MintCream,
|
||||
AliceBlue,
|
||||
LavenderBlush,
|
||||
MistyRose,
|
||||
DarkSlateGray,
|
||||
DarkSlateGrey,
|
||||
DimGray,
|
||||
DimGrey,
|
||||
SlateGray,
|
||||
SlateGrey,
|
||||
LightSlateGray,
|
||||
LightSlateGrey,
|
||||
X11Gray,
|
||||
X11Grey,
|
||||
WebGray,
|
||||
WebGrey,
|
||||
LightGrey,
|
||||
LightGray,
|
||||
MidnightBlue,
|
||||
NavyBlue,
|
||||
CornflowerBlue,
|
||||
DarkSlateBlue,
|
||||
SlateBlue,
|
||||
MediumSlateBlue,
|
||||
LightSlateBlue,
|
||||
MediumBlue,
|
||||
RoyalBlue,
|
||||
DodgerBlue,
|
||||
DeepSkyBlue,
|
||||
SkyBlue,
|
||||
LightSkyBlue,
|
||||
SteelBlue,
|
||||
LightSteelBlue,
|
||||
LightBlue,
|
||||
PowderBlue,
|
||||
PaleTurquoise,
|
||||
DarkTurquoise,
|
||||
MediumTurquoise,
|
||||
LightCyan,
|
||||
CadetBlue,
|
||||
MediumAquamarine,
|
||||
DarkGreen,
|
||||
DarkOliveGreen,
|
||||
DarkSeaGreen,
|
||||
SeaGreen,
|
||||
MediumSeaGreen,
|
||||
LightSeaGreen,
|
||||
PaleGreen,
|
||||
SpringGreen,
|
||||
LawnGreen,
|
||||
X11Green,
|
||||
WebGreen,
|
||||
MediumSpringGreen,
|
||||
GreenYellow,
|
||||
LimeGreen,
|
||||
YellowGreen,
|
||||
ForestGreen,
|
||||
OliveDrab,
|
||||
DarkKhaki,
|
||||
PaleGoldenrod,
|
||||
LightGoldenrodYellow,
|
||||
LightYellow,
|
||||
LightGoldenrod,
|
||||
DarkGoldenrod,
|
||||
RosyBrown,
|
||||
IndianRed,
|
||||
SaddleBrown,
|
||||
SandyBrown,
|
||||
DarkSalmon,
|
||||
LightSalmon,
|
||||
DarkOrange,
|
||||
LightCoral,
|
||||
OrangeRed,
|
||||
HotPink,
|
||||
DeepPink,
|
||||
LightPink,
|
||||
PaleVioletRed,
|
||||
X11Maroon,
|
||||
WebMaroon,
|
||||
MediumVioletRed,
|
||||
VioletRed,
|
||||
MediumOrchid,
|
||||
DarkOrchid,
|
||||
DarkViolet,
|
||||
BlueViolet,
|
||||
X11Purple,
|
||||
WebPurple,
|
||||
MediumPurple,
|
||||
AntiqueWhite1,
|
||||
AntiqueWhite2,
|
||||
AntiqueWhite3,
|
||||
AntiqueWhite4,
|
||||
PeachPuff1,
|
||||
PeachPuff2,
|
||||
PeachPuff3,
|
||||
PeachPuff4,
|
||||
NavajoWhite1,
|
||||
NavajoWhite2,
|
||||
NavajoWhite3,
|
||||
NavajoWhite4,
|
||||
LemonChiffon1,
|
||||
LemonChiffon2,
|
||||
LemonChiffon3,
|
||||
LemonChiffon4,
|
||||
LavenderBlush1,
|
||||
LavenderBlush2,
|
||||
LavenderBlush3,
|
||||
LavenderBlush4,
|
||||
MistyRose1,
|
||||
MistyRose2,
|
||||
MistyRose3,
|
||||
MistyRose4,
|
||||
SlateBlue1,
|
||||
SlateBlue2,
|
||||
SlateBlue3,
|
||||
SlateBlue4,
|
||||
RoyalBlue1,
|
||||
RoyalBlue2,
|
||||
RoyalBlue3,
|
||||
RoyalBlue4,
|
||||
DodgerBlue1,
|
||||
DodgerBlue2,
|
||||
DodgerBlue3,
|
||||
DodgerBlue4,
|
||||
SteelBlue1,
|
||||
SteelBlue2,
|
||||
SteelBlue3,
|
||||
SteelBlue4,
|
||||
DeepSkyBlue1,
|
||||
DeepSkyBlue2,
|
||||
DeepSkyBlue3,
|
||||
DeepSkyBlue4,
|
||||
SkyBlue1,
|
||||
SkyBlue2,
|
||||
SkyBlue3,
|
||||
SkyBlue4,
|
||||
LightSkyBlue1,
|
||||
LightSkyBlue2,
|
||||
LightSkyBlue3,
|
||||
LightSkyBlue4,
|
||||
SlateGray1,
|
||||
SlateGray2,
|
||||
SlateGray3,
|
||||
SlateGray4,
|
||||
LightSteelBlue1,
|
||||
LightSteelBlue2,
|
||||
LightSteelBlue3,
|
||||
LightSteelBlue4,
|
||||
LightBlue1,
|
||||
LightBlue2,
|
||||
LightBlue3,
|
||||
LightBlue4,
|
||||
LightCyan1,
|
||||
LightCyan2,
|
||||
LightCyan3,
|
||||
LightCyan4,
|
||||
PaleTurquoise1,
|
||||
PaleTurquoise2,
|
||||
PaleTurquoise3,
|
||||
PaleTurquoise4,
|
||||
CadetBlue1,
|
||||
CadetBlue2,
|
||||
CadetBlue3,
|
||||
CadetBlue4,
|
||||
DarkSlateGray1,
|
||||
DarkSlateGray2,
|
||||
DarkSlateGray3,
|
||||
DarkSlateGray4,
|
||||
DarkSeaGreen1,
|
||||
DarkSeaGreen2,
|
||||
DarkSeaGreen3,
|
||||
DarkSeaGreen4,
|
||||
SeaGreen1,
|
||||
SeaGreen2,
|
||||
SeaGreen3,
|
||||
SeaGreen4,
|
||||
PaleGreen1,
|
||||
PaleGreen2,
|
||||
PaleGreen3,
|
||||
PaleGreen4,
|
||||
SpringGreen1,
|
||||
SpringGreen2,
|
||||
SpringGreen3,
|
||||
SpringGreen4,
|
||||
OliveDrab1,
|
||||
OliveDrab2,
|
||||
OliveDrab3,
|
||||
OliveDrab4,
|
||||
DarkOliveGreen1,
|
||||
DarkOliveGreen2,
|
||||
DarkOliveGreen3,
|
||||
DarkOliveGreen4,
|
||||
LightGoldenrod1,
|
||||
LightGoldenrod2,
|
||||
LightGoldenrod3,
|
||||
LightGoldenrod4,
|
||||
LightYellow1,
|
||||
LightYellow2,
|
||||
LightYellow3,
|
||||
LightYellow4,
|
||||
DarkGoldenrod1,
|
||||
DarkGoldenrod2,
|
||||
DarkGoldenrod3,
|
||||
DarkGoldenrod4,
|
||||
RosyBrown1,
|
||||
RosyBrown2,
|
||||
RosyBrown3,
|
||||
RosyBrown4,
|
||||
IndianRed1,
|
||||
IndianRed2,
|
||||
IndianRed3,
|
||||
IndianRed4,
|
||||
LightSalmon1,
|
||||
LightSalmon2,
|
||||
LightSalmon3,
|
||||
LightSalmon4,
|
||||
DarkOrange1,
|
||||
DarkOrange2,
|
||||
DarkOrange3,
|
||||
DarkOrange4,
|
||||
OrangeRed1,
|
||||
OrangeRed2,
|
||||
OrangeRed3,
|
||||
OrangeRed4,
|
||||
DeepPink1,
|
||||
DeepPink2,
|
||||
DeepPink3,
|
||||
DeepPink4,
|
||||
HotPink1,
|
||||
HotPink2,
|
||||
HotPink3,
|
||||
HotPink4,
|
||||
LightPink1,
|
||||
LightPink2,
|
||||
LightPink3,
|
||||
LightPink4,
|
||||
PaleVioletRed1,
|
||||
PaleVioletRed2,
|
||||
PaleVioletRed3,
|
||||
PaleVioletRed4,
|
||||
VioletRed1,
|
||||
VioletRed2,
|
||||
VioletRed3,
|
||||
VioletRed4,
|
||||
MediumOrchid1,
|
||||
MediumOrchid2,
|
||||
MediumOrchid3,
|
||||
MediumOrchid4,
|
||||
DarkOrchid1,
|
||||
DarkOrchid2,
|
||||
DarkOrchid3,
|
||||
DarkOrchid4,
|
||||
MediumPurple1,
|
||||
MediumPurple2,
|
||||
MediumPurple3,
|
||||
MediumPurple4,
|
||||
DarkGrey,
|
||||
DarkGray,
|
||||
DarkBlue,
|
||||
DarkCyan,
|
||||
DarkMagenta,
|
||||
DarkRed,
|
||||
LightGreen,
|
||||
RebeccaPurple,
|
||||
}
|
||||
|
||||
impl FromStr for X11Color {
|
||||
type Err = StringParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::iter()
|
||||
.into_iter()
|
||||
.find(|i| i.to_string() == s)
|
||||
.ok_or(StringParseError::UnknownValue)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{Color, X11Color};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ColorContainer {
|
||||
color: Color,
|
||||
}
|
||||
|
||||
fn color_serialize_deserialize(color: Color) {
|
||||
let original_color = color.clone();
|
||||
let color_str =
|
||||
toml::to_string_pretty(&ColorContainer { color }).expect("serialization failure");
|
||||
let color_parsed: ColorContainer =
|
||||
toml::from_str(color_str.as_str()).expect("deserialization failure");
|
||||
assert_eq!(original_color, color_parsed.color);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn color_serialize_deserialize_rgb() {
|
||||
color_serialize_deserialize(Color::RGB {
|
||||
r: 128,
|
||||
g: 128,
|
||||
b: 128,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn color_serialize_deserialize_x11() {
|
||||
color_serialize_deserialize(Color::X11(X11Color::HotPink2));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use serde::{de::Unexpected, Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
use super::hex::{HexError, ParseHex};
|
||||
|
||||
mod x11;
|
||||
pub use x11::X11Color;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Color {
|
||||
RGB { r: u8, g: u8, b: u8 },
|
||||
X11(X11Color),
|
||||
}
|
||||
|
||||
impl Serialize for Color {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Color {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
struct ExpectedColor;
|
||||
impl serde::de::Expected for ExpectedColor {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("an X11 color string or a hex color string")
|
||||
}
|
||||
}
|
||||
let str_val: String = Deserialize::deserialize(deserializer)?;
|
||||
Ok(Color::from_str(&str_val).map_err(|_| {
|
||||
serde::de::Error::invalid_value(Unexpected::Str(&str_val), &ExpectedColor)
|
||||
})?)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Color {
|
||||
fn default() -> Self {
|
||||
Self::RGB {
|
||||
r: Default::default(),
|
||||
g: Default::default(),
|
||||
b: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Error)]
|
||||
pub enum ParseError {
|
||||
#[error("length must be either 6 characters or 7 with '#' prefix")]
|
||||
InvalidLength,
|
||||
#[error("invalid hex value: [{0}]")]
|
||||
HexError(#[from] HexError),
|
||||
}
|
||||
|
||||
impl FromStr for Color {
|
||||
type Err = ParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if let Ok(x11) = X11Color::from_str(s) {
|
||||
return Ok(Self::X11(x11));
|
||||
}
|
||||
Self::from_hex(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub const BLACK: Color = Color::from_rgb(0, 0, 0);
|
||||
|
||||
pub fn from_hex(hex: &str) -> Result<Self, ParseError> {
|
||||
let expected_len = if hex.starts_with('#') { 7 } else { 6 };
|
||||
if hex.len() != expected_len {
|
||||
return Err(ParseError::InvalidLength);
|
||||
}
|
||||
let hex = hex.strip_prefix('#').unwrap_or(hex);
|
||||
|
||||
Ok(Self::RGB {
|
||||
r: (&hex[0..2]).parse_hex()?,
|
||||
g: (&hex[2..4]).parse_hex()?,
|
||||
b: (&hex[4..6]).parse_hex()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
|
||||
Self::RGB { r, g, b }
|
||||
}
|
||||
|
||||
pub const fn to_rgb(&self) -> (u8, u8, u8) {
|
||||
match self {
|
||||
Color::RGB { r, g, b } => (*r, *g, *b),
|
||||
Color::X11(xc) => xc.to_rgb(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Color {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Color::RGB { r, g, b } => write!(f, "#{r:02X}{g:02X}{b:02X}"),
|
||||
Color::X11(color) => f.write_str(&color.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Color> for cnx::text::Color {
|
||||
fn from(value: Color) -> Self {
|
||||
let (r, g, b) = value.to_rgb();
|
||||
cnx::text::Color::from_rgb(r, g, b)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{Color, X11Color};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ColorContainer {
|
||||
color: Color,
|
||||
}
|
||||
|
||||
fn color_serialize_deserialize(color: Color) {
|
||||
let original_color = color.clone();
|
||||
let color_str =
|
||||
toml::to_string_pretty(&ColorContainer { color }).expect("serialization failure");
|
||||
let color_parsed: ColorContainer =
|
||||
toml::from_str(color_str.as_str()).expect("deserialization failure");
|
||||
assert_eq!(original_color, color_parsed.color);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn color_serialize_deserialize_rgb() {
|
||||
color_serialize_deserialize(Color::RGB {
|
||||
r: 128,
|
||||
g: 128,
|
||||
b: 128,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn color_serialize_deserialize_x11() {
|
||||
color_serialize_deserialize(Color::X11(X11Color::HotPink2));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,728 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::hlwm::StringParseError;
|
||||
|
||||
macro_rules! color_impl {
|
||||
() => {};
|
||||
($($name:tt($($str:literal),+) => $r:literal, $g:literal, $b:literal,)+) => {
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum X11Color {
|
||||
$($name,)+
|
||||
}
|
||||
|
||||
impl X11Color {
|
||||
const ALL: [X11Color; 658] = [$(X11Color::$name,)+];
|
||||
pub const fn to_rgb(&self) -> (u8, u8, u8) {
|
||||
match self {
|
||||
$(X11Color::$name => ($r, $g, $b),)+
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter() -> std::array::IntoIter<X11Color, 658> {
|
||||
X11Color::ALL.into_iter()
|
||||
}
|
||||
|
||||
fn color_names(&self) -> Vec<&'static str> {
|
||||
match self {
|
||||
$(
|
||||
X11Color::$name => vec![$($str),+],
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for X11Color {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
$(
|
||||
X11Color::$name => f.write_str(color_impl!(First $($str,)+)),
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
(First $lit:literal, $($lit2:literal,)*) => {
|
||||
$lit
|
||||
};
|
||||
}
|
||||
|
||||
impl FromStr for X11Color {
|
||||
type Err = StringParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
X11Color::ALL
|
||||
.into_iter()
|
||||
.find(|c| c.color_names().into_iter().any(|n| n == s))
|
||||
.ok_or(StringParseError::UnknownValue)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for X11Color {
|
||||
fn default() -> Self {
|
||||
X11Color::Black
|
||||
}
|
||||
}
|
||||
|
||||
color_impl! {
|
||||
White("white") => 255,255,255,
|
||||
Red3("red3") => 205,0,0,
|
||||
VioletRed1("VioletRed1") => 255,62,150,
|
||||
Gray54("gray54") => 138,138,138,
|
||||
Gold1("gold1") => 255,215,0,
|
||||
Pink1("pink1") => 255,181,197,
|
||||
Grey76("grey76") => 194,194,194,
|
||||
Goldenrod("goldenrod") => 218,165,32,
|
||||
Wheat4("wheat4") => 139,126,102,
|
||||
Gray71("gray71") => 181,181,181,
|
||||
DarkTurquoise("dark turquoise", "DarkTurquoise") => 0,206,209,
|
||||
Plum4("plum4") => 139,102,139,
|
||||
Grey44("grey44") => 112,112,112,
|
||||
Grey15("grey15") => 38,38,38,
|
||||
Plum("plum") => 221,160,221,
|
||||
Gray55("gray55") => 140,140,140,
|
||||
Green2("green2") => 0,238,0,
|
||||
Grey65("grey65") => 166,166,166,
|
||||
MediumPurple1("MediumPurple1") => 171,130,255,
|
||||
DarkOliveGreen2("DarkOliveGreen2") => 188,238,104,
|
||||
Grey74("grey74") => 189,189,189,
|
||||
LightGoldenrod1("LightGoldenrod1") => 255,236,139,
|
||||
MistyRose2("MistyRose2") => 238,213,210,
|
||||
LightSalmon4("LightSalmon4") => 139,87,66,
|
||||
Ivory3("ivory3") => 205,205,193,
|
||||
DarkGray("dark gray", "DarkGray") => 169,169,169,
|
||||
SlateGray1("SlateGray1") => 198,226,255,
|
||||
BlanchedAlmond("blanched almond", "BlanchedAlmond") => 255,235,205,
|
||||
Gray8("gray8") => 20,20,20,
|
||||
Orange("orange") => 255,165,0,
|
||||
Cornsilk2("cornsilk2") => 238,232,205,
|
||||
Thistle2("thistle2") => 238,210,238,
|
||||
Gray91("gray91") => 232,232,232,
|
||||
MediumPurple4("MediumPurple4") => 93,71,139,
|
||||
Orchid4("orchid4") => 139,71,137,
|
||||
PaleTurquoise4("PaleTurquoise4") => 102,139,139,
|
||||
AntiqueWhite("antique white", "AntiqueWhite") => 250,235,215,
|
||||
Grey92("grey92") => 235,235,235,
|
||||
Lavender("lavender") => 230,230,250,
|
||||
Sienna("sienna") => 160,82,45,
|
||||
Tan("tan") => 210,180,140,
|
||||
LightYellow("light yellow", "LightYellow") => 255,255,224,
|
||||
Brown3("brown3") => 205,51,51,
|
||||
AliceBlue("alice blue", "AliceBlue") => 240,248,255,
|
||||
Grey96("grey96") => 245,245,245,
|
||||
GhostWhite("ghost white", "GhostWhite") => 248,248,255,
|
||||
PaleGoldenrod("pale goldenrod", "PaleGoldenrod") => 238,232,170,
|
||||
Gray96("gray96") => 245,245,245,
|
||||
Gray90("gray90") => 229,229,229,
|
||||
Gray85("gray85") => 217,217,217,
|
||||
Grey34("grey34") => 87,87,87,
|
||||
Khaki2("khaki2") => 238,230,133,
|
||||
Grey54("grey54") => 138,138,138,
|
||||
DarkGrey("dark grey", "DarkGrey") => 169,169,169,
|
||||
Gray42("gray42") => 107,107,107,
|
||||
Grey18("grey18") => 46,46,46,
|
||||
Gray17("gray17") => 43,43,43,
|
||||
OrangeRed3("OrangeRed3") => 205,55,0,
|
||||
Grey29("grey29") => 74,74,74,
|
||||
LightPink("light pink", "LightPink") => 255,182,193,
|
||||
Salmon4("salmon4") => 139,76,57,
|
||||
CadetBlue3("CadetBlue3") => 122,197,205,
|
||||
Grey36("grey36") => 92,92,92,
|
||||
Tomato2("tomato2") => 238,92,66,
|
||||
DeepPink("deep pink", "DeepPink") => 255,20,147,
|
||||
Cyan4("cyan4") => 0,139,139,
|
||||
LightCyan2("LightCyan2") => 209,238,238,
|
||||
Chartreuse1("chartreuse1") => 127,255,0,
|
||||
Gray62("gray62") => 158,158,158,
|
||||
Bisque4("bisque4") => 139,125,107,
|
||||
PaleTurquoise3("PaleTurquoise3") => 150,205,205,
|
||||
SpringGreen1("SpringGreen1") => 0,255,127,
|
||||
MediumTurquoise("medium turquoise", "MediumTurquoise") => 72,209,204,
|
||||
Grey39("grey39") => 99,99,99,
|
||||
SeaGreen2("SeaGreen2") => 78,238,148,
|
||||
Grey17("grey17") => 43,43,43,
|
||||
Grey6("grey6") => 15,15,15,
|
||||
Pink("pink") => 255,192,203,
|
||||
Cyan2("cyan2") => 0,238,238,
|
||||
LightCyan3("LightCyan3") => 180,205,205,
|
||||
Brown4("brown4") => 139,35,35,
|
||||
Chartreuse3("chartreuse3") => 102,205,0,
|
||||
GreenYellow("green yellow", "GreenYellow") => 173,255,47,
|
||||
DarkSeaGreen3("DarkSeaGreen3") => 155,205,155,
|
||||
Gray49("gray49") => 125,125,125,
|
||||
VioletRed("violet red", "VioletRed") => 208,32,144,
|
||||
PaleVioletRed1("PaleVioletRed1") => 255,130,171,
|
||||
RosyBrown4("RosyBrown4") => 139,105,105,
|
||||
Grey79("grey79") => 201,201,201,
|
||||
Honeydew("honeydew") => 240,255,240,
|
||||
Gray26("gray26") => 66,66,66,
|
||||
Grey40("grey40") => 102,102,102,
|
||||
MediumAquamarine("medium aquamarine", "MediumAquamarine") => 102,205,170,
|
||||
Gray89("gray89") => 227,227,227,
|
||||
Pink4("pink4") => 139,99,108,
|
||||
Grey95("grey95") => 242,242,242,
|
||||
Turquoise("turquoise") => 64,224,208,
|
||||
Azure3("azure3") => 193,205,205,
|
||||
NavajoWhite("navajo white", "NavajoWhite") => 255,222,173,
|
||||
AntiqueWhite4("AntiqueWhite4") => 139,131,120,
|
||||
PeachPuff("peach puff", "PeachPuff") => 255,218,185,
|
||||
Turquoise4("turquoise4") => 0,134,139,
|
||||
Gray68("gray68") => 173,173,173,
|
||||
Burlywood4("burlywood4") => 139,115,85,
|
||||
SlateBlue4("SlateBlue4") => 71,60,139,
|
||||
DodgerBlue2("DodgerBlue2") => 28,134,238,
|
||||
LightSlateGray("light slate gray", "LightSlateGray") => 119,136,153,
|
||||
Red1("red1") => 255,0,0,
|
||||
Yellow2("yellow2") => 238,238,0,
|
||||
Gray32("gray32") => 82,82,82,
|
||||
MistyRose("misty rose", "MistyRose") => 255,228,225,
|
||||
Cornsilk3("cornsilk3") => 205,200,177,
|
||||
RosyBrown3("RosyBrown3") => 205,155,155,
|
||||
Pink2("pink2") => 238,169,184,
|
||||
Gray6("gray6") => 15,15,15,
|
||||
Khaki3("khaki3") => 205,198,115,
|
||||
Turquoise2("turquoise2") => 0,229,238,
|
||||
PowderBlue("powder blue", "PowderBlue") => 176,224,230,
|
||||
Gray84("gray84") => 214,214,214,
|
||||
Grey59("grey59") => 150,150,150,
|
||||
Yellow3("yellow3") => 205,205,0,
|
||||
SpringGreen2("SpringGreen2") => 0,238,118,
|
||||
NavajoWhite1("NavajoWhite1") => 255,222,173,
|
||||
Gray38("gray38") => 97,97,97,
|
||||
AntiqueWhite2("AntiqueWhite2") => 238,223,204,
|
||||
Azure4("azure4") => 131,139,139,
|
||||
Green4("green4") => 0,139,0,
|
||||
Gray72("gray72") => 184,184,184,
|
||||
Gray31("gray31") => 79,79,79,
|
||||
SpringGreen4("SpringGreen4") => 0,139,69,
|
||||
DarkOrange1("DarkOrange1") => 255,127,0,
|
||||
LightGoldenrod4("LightGoldenrod4") => 139,129,76,
|
||||
DarkSeaGreen("dark sea green", "DarkSeaGreen") => 143,188,143,
|
||||
LightBlue("light blue", "LightBlue") => 173,216,230,
|
||||
DarkOliveGreen1("DarkOliveGreen1") => 202,255,112,
|
||||
Gray24("gray24") => 61,61,61,
|
||||
SeaGreen3("SeaGreen3") => 67,205,128,
|
||||
Grey69("grey69") => 176,176,176,
|
||||
Grey98("grey98") => 250,250,250,
|
||||
DarkCyan("dark cyan", "DarkCyan") => 0,139,139,
|
||||
Tomato4("tomato4") => 139,54,38,
|
||||
OliveDrab4("OliveDrab4") => 105,139,34,
|
||||
SlateBlue("slate blue", "SlateBlue") => 106,90,205,
|
||||
DarkSeaGreen4("DarkSeaGreen4") => 105,139,105,
|
||||
Gray0("gray0") => 0,0,0,
|
||||
Gray9("gray9") => 23,23,23,
|
||||
Gray60("gray60") => 153,153,153,
|
||||
Gray45("gray45") => 115,115,115,
|
||||
DarkBlue("dark blue", "DarkBlue") => 0,0,139,
|
||||
Gray41("gray41") => 105,105,105,
|
||||
LightBlue3("LightBlue3") => 154,192,205,
|
||||
Blue2("blue2") => 0,0,238,
|
||||
Gray48("gray48") => 122,122,122,
|
||||
LightGoldenrodYellow("light goldenrod yellow", "LightGoldenrodYellow") => 250,250,210,
|
||||
Seashell4("seashell4") => 139,134,130,
|
||||
Chocolate3("chocolate3") => 205,102,29,
|
||||
DarkOrange("dark orange", "DarkOrange") => 255,140,0,
|
||||
DarkGoldenrod1("DarkGoldenrod1") => 255,185,15,
|
||||
Aquamarine1("aquamarine1") => 127,255,212,
|
||||
Gray78("gray78") => 199,199,199,
|
||||
PaleVioletRed3("PaleVioletRed3") => 205,104,137,
|
||||
Thistle("thistle") => 216,191,216,
|
||||
LightSalmon1("LightSalmon1") => 255,160,122,
|
||||
Blue3("blue3") => 0,0,205,
|
||||
Gray1("gray1") => 3,3,3,
|
||||
Grey5("grey5") => 13,13,13,
|
||||
DeepSkyBlue1("DeepSkyBlue1") => 0,191,255,
|
||||
RoyalBlue4("RoyalBlue4") => 39,64,139,
|
||||
DeepPink4("DeepPink4") => 139,10,80,
|
||||
MediumPurple3("MediumPurple3") => 137,104,205,
|
||||
Yellow1("yellow1") => 255,255,0,
|
||||
Grey8("grey8") => 20,20,20,
|
||||
Blue1("blue1") => 0,0,255,
|
||||
IndianRed2("IndianRed2") => 238,99,99,
|
||||
SeaGreen4("SeaGreen4") => 46,139,87,
|
||||
MediumSeaGreen("medium sea green", "MediumSeaGreen") => 60,179,113,
|
||||
Orchid("orchid") => 218,112,214,
|
||||
RosyBrown2("RosyBrown2") => 238,180,180,
|
||||
Seashell("seashell") => 255,245,238,
|
||||
MediumPurple2("MediumPurple2") => 159,121,238,
|
||||
Tan3("tan3") => 205,133,63,
|
||||
Pink3("pink3") => 205,145,158,
|
||||
Maroon1("maroon1") => 255,52,179,
|
||||
Plum1("plum1") => 255,187,255,
|
||||
DebianRed("DebianRed") => 215,7,81,
|
||||
SaddleBrown("saddle brown", "SaddleBrown") => 139,69,19,
|
||||
Goldenrod4("goldenrod4") => 139,105,20,
|
||||
Khaki4("khaki4") => 139,134,78,
|
||||
Grey53("grey53") => 135,135,135,
|
||||
Gray58("gray58") => 148,148,148,
|
||||
Azure2("azure2") => 224,238,238,
|
||||
SlateGray4("SlateGray4") => 108,123,139,
|
||||
DodgerBlue4("DodgerBlue4") => 16,78,139,
|
||||
IndianRed3("IndianRed3") => 205,85,85,
|
||||
DarkKhaki("dark khaki", "DarkKhaki") => 189,183,107,
|
||||
Grey73("grey73") => 186,186,186,
|
||||
DodgerBlue3("DodgerBlue3") => 24,116,205,
|
||||
Tan1("tan1") => 255,165,79,
|
||||
OliveDrab2("OliveDrab2") => 179,238,58,
|
||||
Seashell3("seashell3") => 205,197,191,
|
||||
Gray30("gray30") => 77,77,77,
|
||||
Gray65("gray65") => 166,166,166,
|
||||
Orange4("orange4") => 139,90,0,
|
||||
Gray43("gray43") => 110,110,110,
|
||||
Grey12("grey12") => 31,31,31,
|
||||
Snow3("snow3") => 205,201,201,
|
||||
ForestGreen("forest green", "ForestGreen") => 34,139,34,
|
||||
DarkSlateBlue("dark slate blue", "DarkSlateBlue") => 72,61,139,
|
||||
Thistle1("thistle1") => 255,225,255,
|
||||
Grey45("grey45") => 115,115,115,
|
||||
DarkOrchid("dark orchid", "DarkOrchid") => 153,50,204,
|
||||
MediumOrchid1("MediumOrchid1") => 224,102,255,
|
||||
SkyBlue2("SkyBlue2") => 126,192,238,
|
||||
DarkViolet("dark violet", "DarkViolet") => 148,0,211,
|
||||
LightSteelBlue1("LightSteelBlue1") => 202,225,255,
|
||||
Blue4("blue4") => 0,0,139,
|
||||
LawnGreen("lawn green", "LawnGreen") => 124,252,0,
|
||||
LemonChiffon4("LemonChiffon4") => 139,137,112,
|
||||
SkyBlue1("SkyBlue1") => 135,206,255,
|
||||
Turquoise3("turquoise3") => 0,197,205,
|
||||
Gray64("gray64") => 163,163,163,
|
||||
Grey33("grey33") => 84,84,84,
|
||||
Orchid3("orchid3") => 205,105,201,
|
||||
Grey77("grey77") => 196,196,196,
|
||||
Grey81("grey81") => 207,207,207,
|
||||
DarkOrchid4("DarkOrchid4") => 104,34,139,
|
||||
Gray36("gray36") => 92,92,92,
|
||||
Gray5("gray5") => 13,13,13,
|
||||
Grey46("grey46") => 117,117,117,
|
||||
Khaki("khaki") => 240,230,140,
|
||||
Wheat2("wheat2") => 238,216,174,
|
||||
Cornsilk1("cornsilk1") => 255,248,220,
|
||||
Red2("red2") => 238,0,0,
|
||||
Gray20("gray20") => 51,51,51,
|
||||
OrangeRed("orange red", "OrangeRed") => 255,69,0,
|
||||
CadetBlue("cadet blue", "CadetBlue") => 95,158,160,
|
||||
Grey9("grey9") => 23,23,23,
|
||||
Gray37("gray37") => 94,94,94,
|
||||
SteelBlue3("SteelBlue3") => 79,148,205,
|
||||
Firebrick2("firebrick2") => 238,44,44,
|
||||
DarkSlateGrey("dark slate grey", "DarkSlateGrey") => 47,79,79,
|
||||
LemonChiffon3("LemonChiffon3") => 205,201,165,
|
||||
Violet("violet") => 238,130,238,
|
||||
Orchid1("orchid1") => 255,131,250,
|
||||
Yellow("yellow") => 255,255,0,
|
||||
LightBlue2("LightBlue2") => 178,223,238,
|
||||
Gray46("gray46") => 117,117,117,
|
||||
MediumSpringGreen("medium spring green", "MediumSpringGreen") => 0,250,154,
|
||||
LavenderBlush3("LavenderBlush3") => 205,193,197,
|
||||
VioletRed2("VioletRed2") => 238,58,140,
|
||||
Snow1("snow1") => 255,250,250,
|
||||
Azure("azure") => 240,255,255,
|
||||
MistyRose4("MistyRose4") => 139,125,123,
|
||||
Grey22("grey22") => 56,56,56,
|
||||
Sienna3("sienna3") => 205,104,57,
|
||||
Salmon3("salmon3") => 205,112,84,
|
||||
Burlywood1("burlywood1") => 255,211,155,
|
||||
LightCyan("light cyan", "LightCyan") => 224,255,255,
|
||||
Grey55("grey55") => 140,140,140,
|
||||
Grey31("grey31") => 79,79,79,
|
||||
AntiqueWhite3("AntiqueWhite3") => 205,192,176,
|
||||
MediumOrchid3("MediumOrchid3") => 180,82,205,
|
||||
Grey75("grey75") => 191,191,191,
|
||||
DarkSalmon("dark salmon", "DarkSalmon") => 233,150,122,
|
||||
HotPink2("HotPink2") => 238,106,167,
|
||||
Gray69("gray69") => 176,176,176,
|
||||
Gray52("gray52") => 133,133,133,
|
||||
Gray21("gray21") => 54,54,54,
|
||||
SlateGray2("SlateGray2") => 185,211,238,
|
||||
Grey100("grey100") => 255,255,255,
|
||||
VioletRed3("VioletRed3") => 205,50,120,
|
||||
DimGray("dim gray", "DimGray") => 105,105,105,
|
||||
RoyalBlue("royal blue", "RoyalBlue") => 65,105,225,
|
||||
Yellow4("yellow4") => 139,139,0,
|
||||
Gray39("gray39") => 99,99,99,
|
||||
YellowGreen("yellow green", "YellowGreen") => 154,205,50,
|
||||
Sienna1("sienna1") => 255,130,71,
|
||||
Grey83("grey83") => 212,212,212,
|
||||
Goldenrod1("goldenrod1") => 255,193,37,
|
||||
MidnightBlue("midnight blue", "MidnightBlue") => 25,25,112,
|
||||
Firebrick4("firebrick4") => 139,26,26,
|
||||
MediumOrchid4("MediumOrchid4") => 122,55,139,
|
||||
Gray82("gray82") => 209,209,209,
|
||||
Brown("brown") => 165,42,42,
|
||||
Grey24("grey24") => 61,61,61,
|
||||
DarkOrchid3("DarkOrchid3") => 154,50,205,
|
||||
Gainsboro("gainsboro") => 220,220,220,
|
||||
MediumSlateBlue("medium slate blue", "MediumSlateBlue") => 123,104,238,
|
||||
LightSkyBlue1("LightSkyBlue1") => 176,226,255,
|
||||
Seashell2("seashell2") => 238,229,222,
|
||||
PaleVioletRed("pale violet red", "PaleVioletRed") => 219,112,147,
|
||||
RoyalBlue2("RoyalBlue2") => 67,110,238,
|
||||
Gray4("gray4") => 10,10,10,
|
||||
LimeGreen("lime green", "LimeGreen") => 50,205,50,
|
||||
Maroon2("maroon2") => 238,48,167,
|
||||
Grey2("grey2") => 5,5,5,
|
||||
Grey11("grey11") => 28,28,28,
|
||||
SteelBlue("steel blue", "SteelBlue") => 70,130,180,
|
||||
Sienna2("sienna2") => 238,121,66,
|
||||
NavajoWhite4("NavajoWhite4") => 139,121,94,
|
||||
Grey25("grey25") => 64,64,64,
|
||||
DeepSkyBlue("deep sky blue", "DeepSkyBlue") => 0,191,255,
|
||||
Gray10("gray10") => 26,26,26,
|
||||
Salmon2("salmon2") => 238,130,98,
|
||||
LightGoldenrod2("LightGoldenrod2") => 238,220,130,
|
||||
HotPink1("HotPink1") => 255,110,180,
|
||||
Grey49("grey49") => 125,125,125,
|
||||
Bisque2("bisque2") => 238,213,183,
|
||||
Gray87("gray87") => 222,222,222,
|
||||
Linen("linen") => 250,240,230,
|
||||
Ivory1("ivory1") => 255,255,240,
|
||||
Gray61("gray61") => 156,156,156,
|
||||
LightSalmon2("LightSalmon2") => 238,149,114,
|
||||
Grey61("grey61") => 156,156,156,
|
||||
DarkGoldenrod2("DarkGoldenrod2") => 238,173,14,
|
||||
Cyan3("cyan3") => 0,205,205,
|
||||
Firebrick3("firebrick3") => 205,38,38,
|
||||
Grey48("grey48") => 122,122,122,
|
||||
LightSalmon("light salmon", "LightSalmon") => 255,160,122,
|
||||
Cornsilk4("cornsilk4") => 139,136,120,
|
||||
HotPink4("HotPink4") => 139,58,98,
|
||||
DarkOrange2("DarkOrange2") => 238,118,0,
|
||||
Goldenrod2("goldenrod2") => 238,180,34,
|
||||
Gray53("gray53") => 135,135,135,
|
||||
Grey85("grey85") => 217,217,217,
|
||||
LightCyan1("LightCyan1") => 224,255,255,
|
||||
PeachPuff3("PeachPuff3") => 205,175,149,
|
||||
Gray95("gray95") => 242,242,242,
|
||||
Grey80("grey80") => 204,204,204,
|
||||
RoyalBlue3("RoyalBlue3") => 58,95,205,
|
||||
Orange1("orange1") => 255,165,0,
|
||||
MediumOrchid2("MediumOrchid2") => 209,95,238,
|
||||
Grey86("grey86") => 219,219,219,
|
||||
Gray80("gray80") => 204,204,204,
|
||||
Grey3("grey3") => 8,8,8,
|
||||
Gray34("gray34") => 87,87,87,
|
||||
SpringGreen("spring green", "SpringGreen") => 0,255,127,
|
||||
Aquamarine2("aquamarine2") => 118,238,198,
|
||||
DarkOrange3("DarkOrange3") => 205,102,0,
|
||||
Brown2("brown2") => 238,59,59,
|
||||
Magenta1("magenta1") => 255,0,255,
|
||||
Grey37("grey37") => 94,94,94,
|
||||
Goldenrod3("goldenrod3") => 205,155,29,
|
||||
LavenderBlush("lavender blush", "LavenderBlush") => 255,240,245,
|
||||
Snow("snow") => 255,250,250,
|
||||
PaleGreen3("PaleGreen3") => 124,205,124,
|
||||
Gray99("gray99") => 252,252,252,
|
||||
Gray76("gray76") => 194,194,194,
|
||||
Tan2("tan2") => 238,154,73,
|
||||
LightCoral("light coral", "LightCoral") => 240,128,128,
|
||||
Grey10("grey10") => 26,26,26,
|
||||
Ivory4("ivory4") => 139,139,131,
|
||||
MediumVioletRed("medium violet red", "MediumVioletRed") => 199,21,133,
|
||||
Gray66("gray66") => 168,168,168,
|
||||
Magenta2("magenta2") => 238,0,238,
|
||||
Purple("purple") => 160,32,240,
|
||||
Gray81("gray81") => 207,207,207,
|
||||
Plum2("plum2") => 238,174,238,
|
||||
Peru("peru") => 205,133,63,
|
||||
PaleGreen2("PaleGreen2") => 144,238,144,
|
||||
Grey93("grey93") => 237,237,237,
|
||||
IndianRed4("IndianRed4") => 139,58,58,
|
||||
Grey58("grey58") => 148,148,148,
|
||||
Tomato1("tomato1") => 255,99,71,
|
||||
Aquamarine("aquamarine") => 127,255,212,
|
||||
LightYellow1("LightYellow1") => 255,255,224,
|
||||
Aquamarine4("aquamarine4") => 69,139,116,
|
||||
IndianRed("indian red", "IndianRed") => 205,92,92,
|
||||
Grey60("grey60") => 153,153,153,
|
||||
Black("black") => 0,0,0,
|
||||
LightSteelBlue2("LightSteelBlue2") => 188,210,238,
|
||||
Gray92("gray92") => 235,235,235,
|
||||
Grey0("grey0") => 0,0,0,
|
||||
LightSlateBlue("light slate blue", "LightSlateBlue") => 132,112,255,
|
||||
AntiqueWhite1("AntiqueWhite1") => 255,239,219,
|
||||
DarkOliveGreen("dark olive green", "DarkOliveGreen") => 85,107,47,
|
||||
Gray70("gray70") => 179,179,179,
|
||||
Gray44("gray44") => 112,112,112,
|
||||
LightGray("light gray", "LightGray") => 211,211,211,
|
||||
Gray23("gray23") => 59,59,59,
|
||||
Orange2("orange2") => 238,154,0,
|
||||
Gold("gold") => 255,215,0,
|
||||
Grey7("grey7") => 18,18,18,
|
||||
DeepSkyBlue3("DeepSkyBlue3") => 0,154,205,
|
||||
Wheat3("wheat3") => 205,186,150,
|
||||
Green3("green3") => 0,205,0,
|
||||
Chocolate("chocolate") => 210,105,30,
|
||||
OrangeRed1("OrangeRed1") => 255,69,0,
|
||||
DarkOrchid2("DarkOrchid2") => 178,58,238,
|
||||
Gray("gray") => 190,190,190,
|
||||
LightPink3("LightPink3") => 205,140,149,
|
||||
BlueViolet("blue violet", "BlueViolet") => 138,43,226,
|
||||
PaleTurquoise("pale turquoise", "PaleTurquoise") => 175,238,238,
|
||||
LavenderBlush2("LavenderBlush2") => 238,224,229,
|
||||
HotPink3("HotPink3") => 205,96,144,
|
||||
Gray27("gray27") => 69,69,69,
|
||||
DarkOliveGreen4("DarkOliveGreen4") => 110,139,61,
|
||||
Chocolate2("chocolate2") => 238,118,33,
|
||||
WhiteSmoke("white smoke", "WhiteSmoke") => 245,245,245,
|
||||
PaleTurquoise1("PaleTurquoise1") => 187,255,255,
|
||||
LightSkyBlue("light sky blue", "LightSkyBlue") => 135,206,250,
|
||||
SteelBlue1("SteelBlue1") => 99,184,255,
|
||||
Grey97("grey97") => 247,247,247,
|
||||
Bisque("bisque") => 255,228,196,
|
||||
Bisque3("bisque3") => 205,183,158,
|
||||
Blue("blue") => 0,0,255,
|
||||
LightSteelBlue("light steel blue", "LightSteelBlue") => 176,196,222,
|
||||
Grey51("grey51") => 130,130,130,
|
||||
MintCream("mint cream", "MintCream") => 245,255,250,
|
||||
MediumOrchid("medium orchid", "MediumOrchid") => 186,85,211,
|
||||
PaleVioletRed4("PaleVioletRed4") => 139,71,93,
|
||||
Gold2("gold2") => 238,201,0,
|
||||
Gray73("gray73") => 186,186,186,
|
||||
Grey99("grey99") => 252,252,252,
|
||||
Grey14("grey14") => 36,36,36,
|
||||
Cyan("cyan") => 0,255,255,
|
||||
Coral2("coral2") => 238,106,80,
|
||||
Gray93("gray93") => 237,237,237,
|
||||
LemonChiffon1("LemonChiffon1") => 255,250,205,
|
||||
NavajoWhite3("NavajoWhite3") => 205,179,139,
|
||||
Burlywood3("burlywood3") => 205,170,125,
|
||||
Bisque1("bisque1") => 255,228,196,
|
||||
Gray35("gray35") => 89,89,89,
|
||||
LightYellow4("LightYellow4") => 139,139,122,
|
||||
Snow4("snow4") => 139,137,137,
|
||||
Gray56("gray56") => 143,143,143,
|
||||
Gray59("gray59") => 150,150,150,
|
||||
Gray15("gray15") => 38,38,38,
|
||||
LightSteelBlue4("LightSteelBlue4") => 110,123,139,
|
||||
LightSteelBlue3("LightSteelBlue3") => 162,181,205,
|
||||
OliveDrab("olive drab", "OliveDrab") => 107,142,35,
|
||||
RosyBrown1("RosyBrown1") => 255,193,193,
|
||||
Grey84("grey84") => 214,214,214,
|
||||
Green1("green1") => 0,255,0,
|
||||
Gray63("gray63") => 161,161,161,
|
||||
LightPink4("LightPink4") => 139,95,101,
|
||||
Wheat("wheat") => 245,222,179,
|
||||
Gray14("gray14") => 36,36,36,
|
||||
Gray16("gray16") => 41,41,41,
|
||||
MediumBlue("medium blue", "MediumBlue") => 0,0,205,
|
||||
OrangeRed4("OrangeRed4") => 139,37,0,
|
||||
LightPink1("LightPink1") => 255,174,185,
|
||||
SlateBlue2("SlateBlue2") => 122,103,238,
|
||||
SandyBrown("sandy brown", "SandyBrown") => 244,164,96,
|
||||
Gray83("gray83") => 212,212,212,
|
||||
SkyBlue3("SkyBlue3") => 108,166,205,
|
||||
Moccasin("moccasin") => 255,228,181,
|
||||
Grey27("grey27") => 69,69,69,
|
||||
PaleTurquoise2("PaleTurquoise2") => 174,238,238,
|
||||
Firebrick("firebrick") => 178,34,34,
|
||||
Purple3("purple3") => 125,38,205,
|
||||
SkyBlue4("SkyBlue4") => 74,112,139,
|
||||
Gray67("gray67") => 171,171,171,
|
||||
Aquamarine3("aquamarine3") => 102,205,170,
|
||||
LightSkyBlue3("LightSkyBlue3") => 141,182,205,
|
||||
Magenta("magenta") => 255,0,255,
|
||||
Grey38("grey38") => 97,97,97,
|
||||
SeaGreen("sea green", "SeaGreen") => 46,139,87,
|
||||
Grey90("grey90") => 229,229,229,
|
||||
Chartreuse("chartreuse") => 127,255,0,
|
||||
DeepSkyBlue4("DeepSkyBlue4") => 0,104,139,
|
||||
VioletRed4("VioletRed4") => 139,34,82,
|
||||
DarkRed("dark red", "DarkRed") => 139,0,0,
|
||||
Gray25("gray25") => 64,64,64,
|
||||
Tan4("tan4") => 139,90,43,
|
||||
Grey47("grey47") => 120,120,120,
|
||||
SlateGrey("slate grey", "SlateGrey") => 112,128,144,
|
||||
IndianRed1("IndianRed1") => 255,106,106,
|
||||
LightGreen("light green", "LightGreen") => 144,238,144,
|
||||
Honeydew3("honeydew3") => 193,205,193,
|
||||
Orchid2("orchid2") => 238,122,233,
|
||||
Honeydew2("honeydew2") => 224,238,224,
|
||||
Snow2("snow2") => 238,233,233,
|
||||
OliveDrab3("OliveDrab3") => 154,205,50,
|
||||
Purple2("purple2") => 145,44,238,
|
||||
Gray47("gray47") => 120,120,120,
|
||||
Grey89("grey89") => 227,227,227,
|
||||
Coral1("coral1") => 255,114,86,
|
||||
Gray22("gray22") => 56,56,56,
|
||||
Gray74("gray74") => 189,189,189,
|
||||
Orange3("orange3") => 205,133,0,
|
||||
Maroon3("maroon3") => 205,41,144,
|
||||
Tomato3("tomato3") => 205,79,57,
|
||||
RosyBrown("rosy brown", "RosyBrown") => 188,143,143,
|
||||
Grey20("grey20") => 51,51,51,
|
||||
Gray51("gray51") => 130,130,130,
|
||||
DeepPink1("DeepPink1") => 255,20,147,
|
||||
DarkGoldenrod4("DarkGoldenrod4") => 139,101,8,
|
||||
Grey50("grey50") => 127,127,127,
|
||||
Tomato("tomato") => 255,99,71,
|
||||
Red("red") => 255,0,0,
|
||||
SteelBlue4("SteelBlue4") => 54,100,139,
|
||||
HotPink("hot pink", "HotPink") => 255,105,180,
|
||||
SkyBlue("sky blue", "SkyBlue") => 135,206,235,
|
||||
LightYellow3("LightYellow3") => 205,205,180,
|
||||
Gray33("gray33") => 84,84,84,
|
||||
Grey35("grey35") => 89,89,89,
|
||||
Grey88("grey88") => 224,224,224,
|
||||
CornflowerBlue("cornflower blue", "CornflowerBlue") => 100,149,237,
|
||||
Grey13("grey13") => 33,33,33,
|
||||
Grey19("grey19") => 48,48,48,
|
||||
Chartreuse2("chartreuse2") => 118,238,0,
|
||||
Grey72("grey72") => 184,184,184,
|
||||
SlateGray("slate gray", "SlateGray") => 112,128,144,
|
||||
CadetBlue2("CadetBlue2") => 142,229,238,
|
||||
NavajoWhite2("NavajoWhite2") => 238,207,161,
|
||||
Gray19("gray19") => 48,48,48,
|
||||
DarkOrange4("DarkOrange4") => 139,69,0,
|
||||
Turquoise1("turquoise1") => 0,245,255,
|
||||
LightPink2("LightPink2") => 238,162,173,
|
||||
LightBlue1("LightBlue1") => 191,239,255,
|
||||
Grey71("grey71") => 181,181,181,
|
||||
DimGrey("dim grey", "DimGrey") => 105,105,105,
|
||||
LightGoldenrod3("LightGoldenrod3") => 205,190,112,
|
||||
SlateGray3("SlateGray3") => 159,182,205,
|
||||
Grey78("grey78") => 199,199,199,
|
||||
Grey94("grey94") => 240,240,240,
|
||||
Azure1("azure1") => 240,255,255,
|
||||
Gray94("gray94") => 240,240,240,
|
||||
Grey62("grey62") => 158,158,158,
|
||||
Magenta4("magenta4") => 139,0,139,
|
||||
Coral3("coral3") => 205,91,69,
|
||||
Salmon("salmon") => 250,128,114,
|
||||
Khaki1("khaki1") => 255,246,143,
|
||||
Gray3("gray3") => 8,8,8,
|
||||
Brown1("brown1") => 255,64,64,
|
||||
Grey52("grey52") => 133,133,133,
|
||||
Grey21("grey21") => 54,54,54,
|
||||
LightSkyBlue4("LightSkyBlue4") => 96,123,139,
|
||||
Gold3("gold3") => 205,173,0,
|
||||
LavenderBlush4("LavenderBlush4") => 139,131,134,
|
||||
Honeydew1("honeydew1") => 240,255,240,
|
||||
DarkSlateGray("dark slate gray", "DarkSlateGray") => 47,79,79,
|
||||
Maroon("maroon") => 176,48,96,
|
||||
Wheat1("wheat1") => 255,231,186,
|
||||
Gray28("gray28") => 71,71,71,
|
||||
Gray40("gray40") => 102,102,102,
|
||||
Grey91("grey91") => 232,232,232,
|
||||
Gray57("gray57") => 145,145,145,
|
||||
Grey68("grey68") => 173,173,173,
|
||||
SpringGreen3("SpringGreen3") => 0,205,102,
|
||||
PeachPuff1("PeachPuff1") => 255,218,185,
|
||||
FloralWhite("floral white", "FloralWhite") => 255,250,240,
|
||||
Coral4("coral4") => 139,62,47,
|
||||
Gray50("gray50") => 127,127,127,
|
||||
Grey82("grey82") => 209,209,209,
|
||||
Gray86("gray86") => 219,219,219,
|
||||
Sienna4("sienna4") => 139,71,38,
|
||||
Grey57("grey57") => 145,145,145,
|
||||
Grey70("grey70") => 179,179,179,
|
||||
Grey63("grey63") => 161,161,161,
|
||||
DarkOliveGreen3("DarkOliveGreen3") => 162,205,90,
|
||||
Beige("beige") => 245,245,220,
|
||||
OldLace("old lace", "OldLace") => 253,245,230,
|
||||
Gray13("gray13") => 33,33,33,
|
||||
MediumPurple("medium purple", "MediumPurple") => 147,112,219,
|
||||
PaleGreen1("PaleGreen1") => 154,255,154,
|
||||
Grey43("grey43") => 110,110,110,
|
||||
Chocolate4("chocolate4") => 139,69,19,
|
||||
Chocolate1("chocolate1") => 255,127,36,
|
||||
DarkSeaGreen2("DarkSeaGreen2") => 180,238,180,
|
||||
Gray77("gray77") => 196,196,196,
|
||||
Maroon4("maroon4") => 139,28,98,
|
||||
Gray2("gray2") => 5,5,5,
|
||||
OrangeRed2("OrangeRed2") => 238,64,0,
|
||||
PaleGreen4("PaleGreen4") => 84,139,84,
|
||||
DarkGoldenrod3("DarkGoldenrod3") => 205,149,12,
|
||||
Grey67("grey67") => 171,171,171,
|
||||
PaleGreen("pale green", "PaleGreen") => 152,251,152,
|
||||
Grey1("grey1") => 3,3,3,
|
||||
PapayaWhip("papaya whip", "PapayaWhip") => 255,239,213,
|
||||
Gray11("gray11") => 28,28,28,
|
||||
Grey41("grey41") => 105,105,105,
|
||||
Gray98("gray98") => 250,250,250,
|
||||
Grey56("grey56") => 143,143,143,
|
||||
Plum3("plum3") => 205,150,205,
|
||||
DeepPink3("DeepPink3") => 205,16,118,
|
||||
Grey64("grey64") => 163,163,163,
|
||||
Grey26("grey26") => 66,66,66,
|
||||
DodgerBlue("dodger blue", "DodgerBlue") => 30,144,255,
|
||||
Grey42("grey42") => 107,107,107,
|
||||
SlateBlue3("SlateBlue3") => 105,89,205,
|
||||
Gold4("gold4") => 139,117,0,
|
||||
DarkOrchid1("DarkOrchid1") => 191,62,255,
|
||||
Grey("grey") => 190,190,190,
|
||||
Ivory("ivory") => 255,255,240,
|
||||
DarkSlateGray2("DarkSlateGray2") => 141,238,238,
|
||||
Gray12("gray12") => 31,31,31,
|
||||
Grey16("grey16") => 41,41,41,
|
||||
LightCyan4("LightCyan4") => 122,139,139,
|
||||
Burlywood2("burlywood2") => 238,197,145,
|
||||
LemonChiffon("lemon chiffon", "LemonChiffon") => 255,250,205,
|
||||
DeepPink2("DeepPink2") => 238,18,137,
|
||||
Gray7("gray7") => 18,18,18,
|
||||
Magenta3("magenta3") => 205,0,205,
|
||||
LightSalmon3("LightSalmon3") => 205,129,98,
|
||||
LemonChiffon2("LemonChiffon2") => 238,233,191,
|
||||
Gray79("gray79") => 201,201,201,
|
||||
DeepSkyBlue2("DeepSkyBlue2") => 0,178,238,
|
||||
Burlywood("burlywood") => 222,184,135,
|
||||
Grey30("grey30") => 77,77,77,
|
||||
Green("green") => 0,255,0,
|
||||
Navy("navy") => 0,0,128,
|
||||
Grey66("grey66") => 168,168,168,
|
||||
Grey87("grey87") => 222,222,222,
|
||||
Honeydew4("honeydew4") => 131,139,131,
|
||||
MistyRose1("MistyRose1") => 255,228,225,
|
||||
Gray18("gray18") => 46,46,46,
|
||||
Ivory2("ivory2") => 238,238,224,
|
||||
LavenderBlush1("LavenderBlush1") => 255,240,245,
|
||||
DodgerBlue1("DodgerBlue1") => 30,144,255,
|
||||
Chartreuse4("chartreuse4") => 69,139,0,
|
||||
MistyRose3("MistyRose3") => 205,183,181,
|
||||
Grey28("grey28") => 71,71,71,
|
||||
DarkSlateGray1("DarkSlateGray1") => 151,255,255,
|
||||
Coral("coral") => 255,127,80,
|
||||
Gray97("gray97") => 247,247,247,
|
||||
Firebrick1("firebrick1") => 255,48,48,
|
||||
DarkSeaGreen1("DarkSeaGreen1") => 193,255,193,
|
||||
LightGrey("light grey", "LightGrey") => 211,211,211,
|
||||
DarkSlateGray4("DarkSlateGray4") => 82,139,139,
|
||||
Cornsilk("cornsilk") => 255,248,220,
|
||||
Thistle3("thistle3") => 205,181,205,
|
||||
Grey4("grey4") => 10,10,10,
|
||||
DarkMagenta("dark magenta", "DarkMagenta") => 139,0,139,
|
||||
Cyan1("cyan1") => 0,255,255,
|
||||
Red4("red4") => 139,0,0,
|
||||
Salmon1("salmon1") => 255,140,105,
|
||||
PeachPuff4("PeachPuff4") => 139,119,101,
|
||||
LightBlue4("LightBlue4") => 104,131,139,
|
||||
SteelBlue2("SteelBlue2") => 92,172,238,
|
||||
LightSeaGreen("light sea green", "LightSeaGreen") => 32,178,170,
|
||||
CadetBlue4("CadetBlue4") => 83,134,139,
|
||||
NavyBlue("navy blue", "NavyBlue") => 0,0,128,
|
||||
SeaGreen1("SeaGreen1") => 84,255,159,
|
||||
DarkSlateGray3("DarkSlateGray3") => 121,205,205,
|
||||
Gray29("gray29") => 74,74,74,
|
||||
Grey23("grey23") => 59,59,59,
|
||||
LightYellow2("LightYellow2") => 238,238,209,
|
||||
LightSlateGrey("light slate grey", "LightSlateGrey") => 119,136,153,
|
||||
Gray88("gray88") => 224,224,224,
|
||||
Seashell1("seashell1") => 255,245,238,
|
||||
DarkGreen("dark green", "DarkGreen") => 0,100,0,
|
||||
DarkGoldenrod("dark goldenrod", "DarkGoldenrod") => 184,134,11,
|
||||
LightSkyBlue2("LightSkyBlue2") => 164,211,238,
|
||||
Thistle4("thistle4") => 139,123,139,
|
||||
Gray75("gray75") => 191,191,191,
|
||||
RoyalBlue1("RoyalBlue1") => 72,118,255,
|
||||
CadetBlue1("CadetBlue1") => 152,245,255,
|
||||
Gray100("gray100") => 255,255,255,
|
||||
OliveDrab1("OliveDrab1") => 192,255,62,
|
||||
Purple1("purple1") => 155,48,255,
|
||||
PeachPuff2("PeachPuff2") => 238,203,173,
|
||||
Purple4("purple4") => 85,26,139,
|
||||
SlateBlue1("SlateBlue1") => 131,111,255,
|
||||
PaleVioletRed2("PaleVioletRed2") => 238,121,159,
|
||||
Grey32("grey32") => 82,82,82,
|
||||
LightGoldenrod("light goldenrod", "LightGoldenrod") => 238,221,130,
|
||||
}
|
|
@ -11,6 +11,7 @@ use super::{
|
|||
hlwmbool::ToggleBool,
|
||||
hook::Hook,
|
||||
key::{KeyUnbind, Keybind, Mousebind},
|
||||
pad::Pad,
|
||||
rule::Rule,
|
||||
setting::{FrameLayout, Setting, SettingName},
|
||||
split,
|
||||
|
@ -164,6 +165,19 @@ pub enum HlwmCommand {
|
|||
Try(Box<HlwmCommand>),
|
||||
/// executes the provided command, but discards its output and only returns its exit code.
|
||||
Silent(Box<HlwmCommand>),
|
||||
/// Prints the rectangle of the specified monitor in the format: X Y W H
|
||||
/// If no monitor is given, then the current monitor is used.
|
||||
///
|
||||
/// If `without_pad` is supplied, then the remaining rect without the pad around this
|
||||
/// monitor is printed.
|
||||
MonitorRect {
|
||||
monitor: Option<Monitor>,
|
||||
without_pad: bool,
|
||||
},
|
||||
Pad {
|
||||
monitor: Monitor,
|
||||
pad: Pad,
|
||||
},
|
||||
}
|
||||
|
||||
impl FromStr for Box<HlwmCommand> {
|
||||
|
@ -469,64 +483,27 @@ impl HlwmCommand {
|
|||
index: _,
|
||||
skip_visible: _,
|
||||
} => {
|
||||
if args.contains(&"--skip-visible".to_string()) {
|
||||
Ok(HlwmCommand::MoveIndex {
|
||||
index: args
|
||||
.into_iter()
|
||||
.filter(|a| a != "--skip-visible")
|
||||
.next()
|
||||
.ok_or(CommandParseError::BadArgument {
|
||||
command: command.to_string(),
|
||||
})?
|
||||
.parse()?,
|
||||
skip_visible: true,
|
||||
})
|
||||
} else {
|
||||
Ok(HlwmCommand::MoveIndex {
|
||||
index: args
|
||||
.into_iter()
|
||||
.next()
|
||||
.ok_or(CommandParseError::BadArgument {
|
||||
command: command.to_string(),
|
||||
})?
|
||||
.parse()?,
|
||||
skip_visible: false,
|
||||
})
|
||||
}
|
||||
parse!(skip_visible: [Flag("--skip-visible")], index: FromStr => MoveIndex)
|
||||
}
|
||||
HlwmCommand::UseIndex {
|
||||
index: _,
|
||||
skip_visible: _,
|
||||
} => {
|
||||
if args.contains(&"--skip-visible".to_string()) {
|
||||
Ok(HlwmCommand::UseIndex {
|
||||
index: args
|
||||
.into_iter()
|
||||
.filter(|a| a != "--skip-visible")
|
||||
.next()
|
||||
.ok_or(CommandParseError::BadArgument {
|
||||
command: command.to_string(),
|
||||
})?
|
||||
.parse()?,
|
||||
skip_visible: true,
|
||||
})
|
||||
} else {
|
||||
Ok(HlwmCommand::UseIndex {
|
||||
index: args
|
||||
.into_iter()
|
||||
.next()
|
||||
.ok_or(CommandParseError::BadArgument {
|
||||
command: command.to_string(),
|
||||
})?
|
||||
.parse()?,
|
||||
skip_visible: false,
|
||||
})
|
||||
}
|
||||
parse!(skip_visible: [Flag("--skip-visible")], index: FromStr => UseIndex)
|
||||
}
|
||||
HlwmCommand::UseTag(_) => parse!(String => UseTag),
|
||||
HlwmCommand::MoveTag(_) => parse!(String => MoveTag),
|
||||
HlwmCommand::Try(_) => parse!(FromStrAll => Try),
|
||||
HlwmCommand::Silent(_) => parse!(FromStrAll => Silent),
|
||||
HlwmCommand::MonitorRect {
|
||||
monitor: _,
|
||||
without_pad: _,
|
||||
} => {
|
||||
parse!(without_pad: [Flag("-p")], monitor: [Option<FromStr>] => MonitorRect)
|
||||
}
|
||||
HlwmCommand::Pad { monitor: _, pad: _ } => {
|
||||
parse!(monitor: FromStr, pad: FromStrAll => Pad)
|
||||
}
|
||||
}?;
|
||||
|
||||
assert_eq!(command.to_string(), parsed_command.to_string());
|
||||
|
@ -732,6 +709,21 @@ impl ToCommandString for HlwmCommand {
|
|||
HlwmCommand::Try(cmd) | HlwmCommand::Silent(cmd) => {
|
||||
format!("{self}\t{}", cmd.to_command_string())
|
||||
}
|
||||
HlwmCommand::MonitorRect {
|
||||
monitor,
|
||||
without_pad,
|
||||
} => {
|
||||
let mut parts = Vec::with_capacity(3);
|
||||
parts.push(self.to_string());
|
||||
if let Some(monitor) = monitor {
|
||||
parts.push(monitor.to_string());
|
||||
}
|
||||
if *without_pad {
|
||||
parts.push("-p".to_string());
|
||||
}
|
||||
parts.join("\t")
|
||||
}
|
||||
HlwmCommand::Pad { monitor, pad } => format!("{self}\t{monitor}\t{pad}"),
|
||||
};
|
||||
if let Some(s) = cmd_string.strip_suffix('\t') {
|
||||
return s.to_string();
|
||||
|
@ -751,6 +743,7 @@ mod test {
|
|||
hlwmbool::ToggleBool,
|
||||
hook::Hook,
|
||||
key::{Key, KeyUnbind, MouseButton, Mousebind, MousebindAction},
|
||||
pad::Pad,
|
||||
rule::{Condition, Consequence, Rule, RuleOperator},
|
||||
setting::{Setting, SettingName},
|
||||
window::Window,
|
||||
|
@ -994,6 +987,23 @@ mod test {
|
|||
})),
|
||||
"silent\tmerge_tag\tdefault".into(),
|
||||
),
|
||||
HlwmCommand::MonitorRect {
|
||||
monitor: _,
|
||||
without_pad: _,
|
||||
} => (
|
||||
HlwmCommand::MonitorRect {
|
||||
monitor: Some(1),
|
||||
without_pad: true,
|
||||
},
|
||||
"monitor_rect\t1\t-p".into(),
|
||||
),
|
||||
HlwmCommand::Pad { monitor: _, pad: _ } => (
|
||||
HlwmCommand::Pad {
|
||||
monitor: 1,
|
||||
pad: Pad::UpRightDownLeft(2, 3, 4, 5),
|
||||
},
|
||||
"pad\t1\t2\t3\t4\t5".into(),
|
||||
),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
for (command, expected_string) in commands {
|
||||
|
|
|
@ -48,6 +48,17 @@ macro_rules! gen_parse {
|
|||
})
|
||||
}
|
||||
};
|
||||
(Argument $$args:ident: [Flag($pat:literal)]) => {
|
||||
{
|
||||
let mut args = $$args.clone().into_iter();
|
||||
let mut flag = false;
|
||||
if args.any(|i| i == $pat) {
|
||||
$$args = $$args.filter(|a| a != $pat).collect::<Vec<_>>().into_iter();
|
||||
flag = true;
|
||||
}
|
||||
flag
|
||||
}
|
||||
};
|
||||
(Argument $$args:ident: String) => {
|
||||
$$args
|
||||
.next()
|
||||
|
|
|
@ -2,7 +2,6 @@ use std::{
|
|||
convert::Infallible,
|
||||
fmt::Display,
|
||||
num::{ParseFloatError, ParseIntError},
|
||||
os::unix::process::ExitStatusExt,
|
||||
process::{self, Stdio},
|
||||
str::FromStr,
|
||||
};
|
||||
|
@ -12,6 +11,8 @@ use serde::{Deserialize, Serialize};
|
|||
use strum::IntoEnumIterator;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::cmd;
|
||||
|
||||
use self::{
|
||||
attribute::{Attribute, AttributeError},
|
||||
command::{CommandError, HlwmCommand},
|
||||
|
@ -28,6 +29,7 @@ mod hlwmbool;
|
|||
pub mod hook;
|
||||
pub mod key;
|
||||
mod octal;
|
||||
pub mod pad;
|
||||
pub mod rule;
|
||||
pub mod setting;
|
||||
mod split;
|
||||
|
@ -61,46 +63,15 @@ impl Client {
|
|||
let args = command.args();
|
||||
debug!("running command: [{}]", (&args).join(" "),);
|
||||
let output = Self::herbstclient()
|
||||
.arg("--no-newline")
|
||||
.args(args)
|
||||
.stderr(Stdio::null())
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()?
|
||||
.wait_with_output()?;
|
||||
let exit_status = output.status;
|
||||
if let Some(code) = exit_status.code() {
|
||||
if code == 0 {
|
||||
return Ok(output);
|
||||
} else {
|
||||
let output = String::from_utf8(output.stdout)
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_string();
|
||||
error!("command failed with error code [{code}]");
|
||||
if !output.is_empty() {
|
||||
error!("command output: {output}");
|
||||
}
|
||||
return Err(CommandError::StatusCode(
|
||||
code,
|
||||
if output.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(output)
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(signal) = exit_status.signal() {
|
||||
return Err(CommandError::KilledBySignal {
|
||||
signal,
|
||||
core_dumped: exit_status.core_dumped(),
|
||||
});
|
||||
}
|
||||
if let Some(signal) = exit_status.stopped_signal() {
|
||||
return Err(CommandError::StoppedBySignal(signal));
|
||||
}
|
||||
|
||||
Err(CommandError::OtherExitStatus(exit_status))
|
||||
cmd::check_status(&output)?;
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
pub fn execute_iter<I>(&self, commands: I) -> Result<(), (HlwmCommand, CommandError)>
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
use crate::hlwm::split;
|
||||
|
||||
use super::StringParseError;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Pad {
|
||||
Unchanged,
|
||||
Up(u32),
|
||||
UpRight(u32, u32),
|
||||
UpRightDown(u32, u32, u32),
|
||||
UpRightDownLeft(u32, u32, u32, u32),
|
||||
}
|
||||
|
||||
impl FromStr for Pad {
|
||||
type Err = StringParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let parts = split::tab_or_space(s);
|
||||
match parts.len() {
|
||||
0 => Err(StringParseError::InvalidLength(0, "pad")),
|
||||
1 => Ok(Pad::Up(parts[0].parse()?)),
|
||||
2 => Ok(Pad::UpRight(parts[0].parse()?, parts[1].parse()?)),
|
||||
3 => Ok(Pad::UpRightDown(
|
||||
parts[0].parse()?,
|
||||
parts[1].parse()?,
|
||||
parts[2].parse()?,
|
||||
)),
|
||||
_ => Ok(Pad::UpRightDownLeft(
|
||||
parts[0].parse()?,
|
||||
parts[1].parse()?,
|
||||
parts[2].parse()?,
|
||||
parts[3].parse()?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Pad {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Pad::Unchanged => Ok(()),
|
||||
Pad::Up(up) => f.write_str(&up.to_string()),
|
||||
Pad::UpRight(up, right) => write!(f, "{up}\t{right}"),
|
||||
Pad::UpRightDown(up, right, down) => write!(f, "{up}\t{right}\t{down}"),
|
||||
Pad::UpRightDownLeft(up, right, down, left) => {
|
||||
write!(f, "{up}\t{right}\t{down}\t{left}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Pad {
|
||||
fn default() -> Self {
|
||||
Pad::Unchanged
|
||||
}
|
||||
}
|
18
src/main.rs
18
src/main.rs
|
@ -5,8 +5,10 @@ use clap::{Parser, Subcommand};
|
|||
use config::Config;
|
||||
use log::{error, info};
|
||||
|
||||
pub mod cmd;
|
||||
mod config;
|
||||
mod hlwm;
|
||||
mod panel;
|
||||
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
#[command(name = "hlctl")]
|
||||
|
@ -19,13 +21,6 @@ struct Args {
|
|||
enum HlctlCommand {
|
||||
/// Initialize herbstluftwm, should be run from the autostart script
|
||||
Init,
|
||||
#[command(arg_required_else_help = true)]
|
||||
/// Draws notifications using dzen2
|
||||
Notify {
|
||||
/// Amount of seconds to persist for
|
||||
#[arg(short = 's', long = None, default_value_t = 1)]
|
||||
seconds: u8,
|
||||
},
|
||||
/// Save the currently loaded configuration to file
|
||||
#[command(long_about = r#"
|
||||
`save` Tries to find an existing config file. If not present, the default config is used.
|
||||
|
@ -34,7 +29,9 @@ enum HlctlCommand {
|
|||
|
||||
The configuration file located at $HOME/.config/herbstluftwm/hlctl.toml"#)]
|
||||
Save,
|
||||
/// Print the toml config to stdout
|
||||
PrintConfig,
|
||||
/// Start the top panel
|
||||
Panel,
|
||||
}
|
||||
|
||||
|
@ -44,10 +41,13 @@ fn main() {
|
|||
let args = Args::parse();
|
||||
match args.command {
|
||||
HlctlCommand::Init => init(),
|
||||
HlctlCommand::Notify { seconds } => println!("notify for {seconds}"),
|
||||
HlctlCommand::Save => save(),
|
||||
HlctlCommand::PrintConfig => print_config(),
|
||||
HlctlCommand::Panel => todo!(),
|
||||
HlctlCommand::Panel => {
|
||||
if let Err(err) = panel::panel(&merged_config()) {
|
||||
error!("panel: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
use cnx::{
|
||||
text::{Attributes, Font, Padding, PagerAttributes},
|
||||
widgets::{ActiveWindowTitle, Clock, Pager},
|
||||
Cnx,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
config::Config,
|
||||
hlwm::{
|
||||
color::{Color, X11Color},
|
||||
command::CommandError,
|
||||
},
|
||||
};
|
||||
|
||||
type Result<T> = std::result::Result<T, PanelError>;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum PanelError {
|
||||
#[error("command error: [{0}]")]
|
||||
CommandError(#[from] CommandError),
|
||||
#[error("io lib error: [{0}]")]
|
||||
IoError(#[from] std::io::Error),
|
||||
#[error("cnx panel error: [{0}]")]
|
||||
CnxPanelError(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
pub fn panel(config: &Config) -> Result<()> {
|
||||
let font = Font::new(&config.font_pango);
|
||||
let font_bold = Font::new(&config.font_pango_bold);
|
||||
let (active, normal, text) = (
|
||||
config
|
||||
.theme
|
||||
.active_color()
|
||||
.expect("could not get theme's active color"),
|
||||
config
|
||||
.theme
|
||||
.normal_color()
|
||||
.expect("could not get theme's normal color"),
|
||||
config
|
||||
.theme
|
||||
.text_color()
|
||||
.expect("could not get theme's text color"),
|
||||
);
|
||||
let attr = Attributes {
|
||||
font: font.clone(),
|
||||
fg_color: text.into(),
|
||||
bg_color: Some(Color::BLACK.into()),
|
||||
padding: Padding::new(10.0, 10.0, 0.0, 0.0),
|
||||
};
|
||||
let pager_attr = PagerAttributes {
|
||||
active_attr: Attributes {
|
||||
font: font_bold.clone(),
|
||||
fg_color: text.into(),
|
||||
bg_color: Some(active.into()),
|
||||
padding: Padding::new(8.0, 8.0, 0.0, 0.0),
|
||||
},
|
||||
inactive_attr: Attributes {
|
||||
font: font.clone(),
|
||||
fg_color: Color::X11(X11Color::DimGray).into(),
|
||||
bg_color: Some(Color::BLACK.into()),
|
||||
padding: Padding::new(5.0, 5.0, 0.0, 0.0),
|
||||
},
|
||||
non_empty_attr: Attributes {
|
||||
font: font.clone(),
|
||||
fg_color: text.into(),
|
||||
bg_color: Some(normal.into()),
|
||||
padding: Padding::new(5.0, 5.0, 0.0, 0.0),
|
||||
},
|
||||
};
|
||||
|
||||
let mut cnx = Cnx::new(cnx::Position::Top);
|
||||
cnx.add_widget(Pager::new(pager_attr));
|
||||
cnx.add_widget(ActiveWindowTitle::new(attr.clone()));
|
||||
cnx.add_widget(Clock::new(
|
||||
attr.clone(),
|
||||
Some(String::from("%H:%M %a %Y-%m-%d")),
|
||||
));
|
||||
cnx.run()?;
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue