use crate::{ColorsSrgb, ThemeConfig};
use kas::text::fonts::{fonts, AddMode, FontSelector};
use kas::theme::TextClass;
use kas::TkAction;
use std::collections::BTreeMap;
use std::time::Duration;
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "config", derive(serde::Serialize, serde::Deserialize))]
pub struct Config {
#[cfg_attr(feature = "config", serde(skip))]
dirty: bool,
#[cfg_attr(feature = "config", serde(default = "defaults::font_size"))]
font_size: f32,
#[cfg_attr(feature = "config", serde(default))]
active_scheme: String,
#[cfg_attr(feature = "config", serde(default = "defaults::color_schemes"))]
color_schemes: BTreeMap<String, ColorsSrgb>,
#[cfg_attr(feature = "config", serde(default))]
font_aliases: BTreeMap<String, FontAliases>,
#[cfg_attr(feature = "config", serde(default))]
fonts: BTreeMap<TextClass, FontSelector<'static>>,
#[cfg_attr(feature = "config", serde(default = "defaults::cursor_blink_rate_ms"))]
cursor_blink_rate_ms: u32,
#[cfg_attr(feature = "config", serde(default = "defaults::transition_fade_ms"))]
transition_fade_ms: u32,
#[cfg_attr(feature = "config", serde(default))]
raster: RasterConfig,
}
impl Default for Config {
fn default() -> Self {
Config {
dirty: false,
font_size: defaults::font_size(),
active_scheme: Default::default(),
color_schemes: defaults::color_schemes(),
font_aliases: Default::default(),
fonts: defaults::fonts(),
cursor_blink_rate_ms: defaults::cursor_blink_rate_ms(),
transition_fade_ms: defaults::transition_fade_ms(),
raster: Default::default(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "config", derive(serde::Serialize, serde::Deserialize))]
pub struct RasterConfig {
#[cfg_attr(feature = "config", serde(default))]
pub mode: u8,
#[cfg_attr(feature = "config", serde(default = "defaults::scale_steps"))]
pub scale_steps: u8,
#[cfg_attr(feature = "config", serde(default = "defaults::subpixel_threshold"))]
pub subpixel_threshold: u8,
#[cfg_attr(feature = "config", serde(default = "defaults::subpixel_steps"))]
pub subpixel_steps: u8,
}
impl Default for RasterConfig {
fn default() -> Self {
RasterConfig {
mode: 0,
scale_steps: defaults::scale_steps(),
subpixel_threshold: defaults::subpixel_threshold(),
subpixel_steps: defaults::subpixel_steps(),
}
}
}
impl Config {
#[inline]
pub fn font_size(&self) -> f32 {
self.font_size
}
#[inline]
pub fn active_scheme(&self) -> &str {
&self.active_scheme
}
#[inline]
pub fn color_schemes_iter(&self) -> impl Iterator<Item = (&str, &ColorsSrgb)> {
self.color_schemes.iter().map(|(s, t)| (s.as_str(), t))
}
#[inline]
pub fn get_color_scheme(&self, name: &str) -> Option<ColorsSrgb> {
self.color_schemes.get(name).cloned()
}
#[inline]
pub fn get_active_scheme(&self) -> Option<ColorsSrgb> {
self.color_schemes.get(&self.active_scheme).cloned()
}
#[inline]
pub fn iter_fonts(&self) -> impl Iterator<Item = (&TextClass, &FontSelector<'static>)> {
self.fonts.iter()
}
#[inline]
pub fn cursor_blink_rate(&self) -> Duration {
Duration::from_millis(self.cursor_blink_rate_ms as u64)
}
#[inline]
pub fn transition_fade_duration(&self) -> Duration {
Duration::from_millis(self.transition_fade_ms as u64)
}
}
impl Config {
pub fn set_font_size(&mut self, pt_size: f32) {
self.dirty = true;
self.font_size = pt_size;
}
pub fn set_active_scheme(&mut self, scheme: impl ToString) {
self.dirty = true;
self.active_scheme = scheme.to_string();
}
}
impl Config {
#[allow(clippy::float_cmp)]
pub fn apply_config(&mut self, other: &Config) -> TkAction {
let action = if self.font_size != other.font_size {
TkAction::RESIZE | TkAction::THEME_UPDATE
} else if self != other {
TkAction::REDRAW
} else {
TkAction::empty()
};
*self = other.clone();
action
}
}
impl ThemeConfig for Config {
#[cfg(feature = "config")]
#[inline]
fn is_dirty(&self) -> bool {
self.dirty
}
fn apply_startup(&self) {
if !self.font_aliases.is_empty() {
fonts().update_db(|db| {
for (family, aliases) in self.font_aliases.iter() {
db.add_aliases(
family.to_string().into(),
aliases.list.iter().map(|s| s.to_string().into()),
aliases.mode,
);
}
});
}
}
#[inline]
fn raster(&self) -> &RasterConfig {
&self.raster
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "config", derive(serde::Serialize, serde::Deserialize))]
pub struct FontAliases {
#[cfg_attr(feature = "config", serde(default = "defaults::add_mode"))]
mode: AddMode,
list: Vec<String>,
}
mod defaults {
use super::*;
#[cfg(feature = "config")]
pub fn add_mode() -> AddMode {
AddMode::Prepend
}
pub fn font_size() -> f32 {
10.0
}
pub fn color_schemes() -> BTreeMap<String, ColorsSrgb> {
let mut schemes = BTreeMap::new();
schemes.insert("light".to_string(), ColorsSrgb::light());
schemes.insert("dark".to_string(), ColorsSrgb::dark());
schemes.insert("blue".to_string(), ColorsSrgb::blue());
schemes
}
pub fn fonts() -> BTreeMap<TextClass, FontSelector<'static>> {
let mut selector = FontSelector::new();
selector.set_families(vec!["serif".into()]);
let list = [
(TextClass::Edit(false), selector.clone()),
(TextClass::Edit(true), selector),
];
list.iter().cloned().collect()
}
pub fn cursor_blink_rate_ms() -> u32 {
600
}
pub fn transition_fade_ms() -> u32 {
150
}
pub fn scale_steps() -> u8 {
4
}
pub fn subpixel_threshold() -> u8 {
0
}
pub fn subpixel_steps() -> u8 {
5
}
}