use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
pub struct Color {
r: f32,
g: f32,
b: f32,
a: f32,
}
fn to_f32(c: u8) -> f32 {
c as f32 / 255f32
}
fn to_u8(c: f32) -> u8 {
(c * 255f32) as u8
}
fn validate_f32(f: f32) -> bool {
f >= 0.0 && f <= 1.0
}
fn validate_f32_all(f: [f32; 4]) -> bool {
if !f.into_iter().all(validate_f32) {
log::warn!(
"f32 values {:?} are not in the valid color range. Using solid black instead xyz",
f
);
return false;
}
true
}
impl Color {
pub const BLACK: Self = Self {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0,
};
pub fn new(r: u8, g: u8, b: u8) -> Self {
Self {
r: to_f32(r),
g: to_f32(g),
b: to_f32(b),
a: 1.0,
}
}
pub fn new_straight(r: u8, g: u8, b: u8, a: u8) -> Self {
Self::new_f32_straight(to_f32(r), to_f32(g), to_f32(b), to_f32(a))
}
pub fn new_f32_premultiplied(r: f32, g: f32, b: f32, a: f32) -> Self {
if !validate_f32_all([r, g, b, a]) {
Self::BLACK
} else if r > a || g > a || b > a {
log::warn!(
"f32 values {:?} are not valid for a premultiplied color. Using solid black instead.",
[r, g, b, a]
);
Self::BLACK
} else {
Self { r, g, b, a }
}
}
pub fn new_f32_straight(r: f32, g: f32, b: f32, a: f32) -> Self {
if !validate_f32_all([r, g, b, a]) {
Self::BLACK
} else {
Self {
r: r * a,
g: g * a,
b: b * a,
a,
}
}
}
pub fn new_f32(r: f32, g: f32, b: f32) -> Self {
Self { r, g, b, a: 1.0 }
}
pub fn to_f32_premultiplied(&self) -> [f32; 4] {
[self.r, self.g, self.b, self.a]
}
pub fn to_f32_straight(&self) -> [f32; 4] {
if self.a == 0.0 {
[0.0, 0.0, 0.0, 0.0]
} else {
let a = self.a;
[self.r / a, self.g / a, self.b / a, a]
}
}
pub fn to_u8_straight(&self) -> [u8; 4] {
let [r, g, b, a] = self.to_f32_straight();
[to_u8(r), to_u8(g), to_u8(b), to_u8(a)]
}
}
pub fn reset_sizes() {
get!().reset_sizes();
}
pub fn reset_colors() {
get!().reset_colors();
}
pub fn get_font() -> String {
get!().get_font()
}
pub fn set_font(font: &str) {
get!().set_font(font)
}
pub fn set_bar_font(font: &str) {
get!().set_bar_font(font)
}
pub fn set_title_font(font: &str) {
get!().set_title_font(font)
}
pub fn reset_font() {
get!().reset_font()
}
#[non_exhaustive]
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Default)]
pub enum BarPosition {
#[default]
Top,
Bottom,
}
pub fn set_bar_position(position: BarPosition) {
get!().set_bar_position(position);
}
pub fn get_bar_position() -> BarPosition {
get!(BarPosition::Top).get_bar_position()
}
pub fn set_egui_proportional_fonts<'a>(fonts: impl IntoIterator<Item = &'a str>) {
get!().set_egui_fonts(Some(fonts.into_iter().collect()), None);
}
pub fn set_egui_monospace_fonts<'a>(fonts: impl IntoIterator<Item = &'a str>) {
get!().set_egui_fonts(None, Some(fonts.into_iter().collect()));
}
pub mod colors {
use {
crate::theme::Color,
serde::{Deserialize, Serialize},
};
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct Colorable(#[doc(hidden)] pub u32);
impl Colorable {
pub fn set(self, r: u8, g: u8, b: u8) {
let color = Color::new(r, g, b);
get!().set_color(self, color);
}
pub fn set_color(self, color: Color) {
get!().set_color(self, color);
}
pub fn get(self) -> Color {
get!(Color::BLACK).get_color(self)
}
}
macro_rules! colors {
($($(#[$attr:meta])* const $n:expr => $name:ident,)*) => {
$(
$(#[$attr])*
pub const $name: Colorable = Colorable($n);
)*
}
}
colors! {
const 01 => UNFOCUSED_TITLE_BACKGROUND_COLOR,
const 02 => FOCUSED_TITLE_BACKGROUND_COLOR,
const 03 => FOCUSED_INACTIVE_TITLE_BACKGROUND_COLOR,
const 04 => BACKGROUND_COLOR,
const 05 => BAR_BACKGROUND_COLOR,
const 06 => SEPARATOR_COLOR,
const 07 => BORDER_COLOR,
const 08 => UNFOCUSED_TITLE_TEXT_COLOR,
const 09 => FOCUSED_TITLE_TEXT_COLOR,
const 10 => FOCUSED_INACTIVE_TITLE_TEXT_COLOR,
const 11 => BAR_STATUS_TEXT_COLOR,
const 12 => CAPTURED_UNFOCUSED_TITLE_BACKGROUND_COLOR,
const 13 => CAPTURED_FOCUSED_TITLE_BACKGROUND_COLOR,
const 14 => ATTENTION_REQUESTED_BACKGROUND_COLOR,
const 15 => HIGHLIGHT_COLOR,
}
pub fn set_color(element: Colorable, color: Color) {
get!().set_color(element, color);
}
pub fn get_color(element: Colorable) -> Color {
get!(Color::BLACK).get_color(element)
}
}
pub mod sized {
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct Resizable(#[doc(hidden)] pub u32);
impl Resizable {
pub fn get(self) -> i32 {
get!(0).get_size(self)
}
pub fn set(self, size: i32) {
get!().set_size(self, size)
}
}
macro_rules! sizes {
($($(#[$attr:meta])* const $n:expr => $name:ident,)*) => {
$(
$(#[$attr])*
pub const $name: Resizable = Resizable($n);
)*
}
}
sizes! {
const 01 => TITLE_HEIGHT,
const 02 => BORDER_WIDTH,
const 03 => BAR_HEIGHT,
const 04 => BAR_SEPARATOR_WIDTH,
}
}