use super::{EventConfig, EventConfigMsg, EventWindowConfig};
use super::{FontConfig, FontConfigMsg, ThemeConfig, ThemeConfigMsg};
use crate::ConfigAction;
use crate::config::Shortcuts;
use crate::theme::TextClass;
use core::f32;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::cell::{Ref, RefCell};
use std::rc::Rc;
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum ConfigMsg {
Event(EventConfigMsg),
Font(FontConfigMsg),
Theme(ThemeConfigMsg),
}
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Config {
#[cfg_attr(feature = "serde", serde(default))]
pub event: EventConfig,
#[cfg_attr(feature = "serde", serde(default))]
pub font: FontConfig,
#[cfg_attr(feature = "serde", serde(default = "Shortcuts::platform_defaults"))]
pub shortcuts: Shortcuts,
#[cfg_attr(feature = "serde", serde(default))]
pub theme: ThemeConfig,
#[cfg_attr(feature = "serde", serde(skip))]
is_dirty: bool,
}
impl Default for Config {
fn default() -> Self {
Config {
event: EventConfig::default(),
font: Default::default(),
shortcuts: Shortcuts::platform_defaults(),
theme: Default::default(),
is_dirty: false,
}
}
}
impl Config {
pub(crate) fn init(&mut self) {
self.font.init();
}
#[inline]
pub fn is_dirty(&self) -> bool {
self.is_dirty
}
pub(crate) fn write_if_dirty(&mut self, writer: &mut dyn FnMut(&Self)) {
if self.is_dirty {
writer(self);
self.is_dirty = false;
}
}
}
#[derive(Clone, Debug)]
pub struct WindowConfig {
pub(super) config: Rc<RefCell<Config>>,
pub(super) scale_factor: f32,
pub(super) kinetic_decay_sub: f32,
pub(super) scroll_dist: f32,
pub(super) pan_dist_thresh: f32,
pub(super) double_click_dist_thresh: f32,
pub(crate) alt_bypass: bool,
pub(crate) nav_focus: bool,
}
impl WindowConfig {
pub(crate) fn new(config: Rc<RefCell<Config>>) -> Self {
WindowConfig {
config,
scale_factor: f32::NAN,
kinetic_decay_sub: f32::NAN,
scroll_dist: f32::NAN,
pan_dist_thresh: f32::NAN,
double_click_dist_thresh: f32::NAN,
alt_bypass: false,
nav_focus: true,
}
}
pub(crate) fn update(&mut self, scale_factor: f32) {
let base = self.config.borrow();
self.scale_factor = scale_factor;
self.kinetic_decay_sub = base.event.kinetic_decay_sub * scale_factor;
let dpem = base.font.get_dpem(TextClass::Standard) * scale_factor;
self.scroll_dist = base.event.scroll_dist_em * dpem;
self.pan_dist_thresh = base.event.pan_dist_thresh * scale_factor;
self.double_click_dist_thresh = base.event.double_click_dist_thresh * scale_factor;
}
pub fn base(&self) -> Ref<'_, Config> {
self.config.borrow()
}
pub fn clone_base(&self) -> Rc<RefCell<Config>> {
self.config.clone()
}
pub fn update_base<F: FnOnce(&mut Config)>(&self, f: F) -> ConfigAction {
if let Ok(mut c) = self.config.try_borrow_mut() {
c.is_dirty = true;
f(&mut c);
ConfigAction::all()
} else {
ConfigAction::empty()
}
}
pub fn event(&self) -> EventWindowConfig<'_> {
EventWindowConfig(self)
}
pub fn update_event<F: FnOnce(&mut EventConfig) -> ConfigAction>(&self, f: F) -> ConfigAction {
if let Ok(mut c) = self.config.try_borrow_mut() {
c.is_dirty = true;
f(&mut c.event)
} else {
ConfigAction::empty()
}
}
pub fn font(&self) -> Ref<'_, FontConfig> {
Ref::map(self.config.borrow(), |c| &c.font)
}
pub fn set_font_size(&self, pt_size: f32) -> ConfigAction {
if let Ok(mut c) = self.config.try_borrow_mut() {
c.is_dirty = true;
c.font.set_size(pt_size)
} else {
ConfigAction::empty()
}
}
pub fn shortcuts(&self) -> Ref<'_, Shortcuts> {
Ref::map(self.config.borrow(), |c| &c.shortcuts)
}
pub fn theme(&self) -> Ref<'_, ThemeConfig> {
Ref::map(self.config.borrow(), |c| &c.theme)
}
pub fn update_theme<F: FnOnce(&mut ThemeConfig) -> ConfigAction>(&self, f: F) -> ConfigAction {
if let Ok(mut c) = self.config.try_borrow_mut() {
c.is_dirty = true;
f(&mut c.theme)
} else {
ConfigAction::empty()
}
}
pub fn update_shortcuts<F: FnOnce(&mut Shortcuts)>(&self, f: F) -> ConfigAction {
if let Ok(mut c) = self.config.try_borrow_mut() {
c.is_dirty = true;
f(&mut c.shortcuts);
}
ConfigAction::empty()
}
pub fn scale_factor(&self) -> f32 {
debug_assert!(self.scale_factor.is_finite());
self.scale_factor
}
pub fn change_config(&self, msg: ConfigMsg) -> ConfigAction {
match msg {
ConfigMsg::Event(msg) => self.update_event(|ev| ev.change_config(msg)),
ConfigMsg::Font(FontConfigMsg::Size(size)) => self.set_font_size(size),
ConfigMsg::Theme(msg) => self.update_theme(|theme| theme.change_config(msg)),
}
}
}