kas_core/config/
config.rs1use super::{EventConfig, EventConfigMsg, EventWindowConfig};
9use super::{FontConfig, FontConfigMsg, ThemeConfig, ThemeConfigMsg};
10use crate::ConfigAction;
11use crate::config::Shortcuts;
12use crate::theme::TextClass;
13use core::f32;
14#[cfg(feature = "serde")]
15use serde::{Deserialize, Serialize};
16use std::cell::{Ref, RefCell};
17use std::rc::Rc;
18
19#[derive(Clone, Debug)]
21#[non_exhaustive]
22pub enum ConfigMsg {
23 Event(EventConfigMsg),
24 Font(FontConfigMsg),
25 Theme(ThemeConfigMsg),
26}
27
28#[derive(Debug, PartialEq)]
39#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
40pub struct Config {
41 #[cfg_attr(feature = "serde", serde(default))]
42 pub event: EventConfig,
43
44 #[cfg_attr(feature = "serde", serde(default))]
45 pub font: FontConfig,
46
47 #[cfg_attr(feature = "serde", serde(default = "Shortcuts::platform_defaults"))]
48 pub shortcuts: Shortcuts,
49
50 #[cfg_attr(feature = "serde", serde(default))]
51 pub theme: ThemeConfig,
52
53 #[cfg_attr(feature = "serde", serde(skip))]
54 is_dirty: bool,
55}
56
57impl Default for Config {
58 fn default() -> Self {
59 Config {
60 event: EventConfig::default(),
61 font: Default::default(),
62 shortcuts: Shortcuts::platform_defaults(),
63 theme: Default::default(),
64 is_dirty: false,
65 }
66 }
67}
68
69impl Config {
70 pub(crate) fn init(&mut self) {
72 self.font.init();
73 }
74
75 #[inline]
77 pub fn is_dirty(&self) -> bool {
78 self.is_dirty
79 }
80
81 pub(crate) fn write_if_dirty(&mut self, writer: &mut dyn FnMut(&Self)) {
82 if self.is_dirty {
83 writer(self);
84 self.is_dirty = false;
85 }
86 }
87}
88
89#[derive(Clone, Debug)]
91pub struct WindowConfig {
92 pub(super) config: Rc<RefCell<Config>>,
93 pub(super) scale_factor: f32,
94 pub(super) kinetic_decay_sub: f32,
95 pub(super) scroll_dist: f32,
96 pub(super) pan_dist_thresh: f32,
97 pub(super) double_click_dist_thresh: f32,
98 pub(crate) alt_bypass: bool,
99 pub(crate) nav_focus: bool,
101}
102
103impl WindowConfig {
104 pub(crate) fn new(config: Rc<RefCell<Config>>) -> Self {
108 WindowConfig {
109 config,
110 scale_factor: f32::NAN,
111 kinetic_decay_sub: f32::NAN,
112 scroll_dist: f32::NAN,
113 pan_dist_thresh: f32::NAN,
114 double_click_dist_thresh: f32::NAN,
115 alt_bypass: false,
116 nav_focus: true,
117 }
118 }
119
120 pub(crate) fn update(&mut self, scale_factor: f32) {
122 let base = self.config.borrow();
123 self.scale_factor = scale_factor;
124 self.kinetic_decay_sub = base.event.kinetic_decay_sub * scale_factor;
125 let dpem = base.font.get_dpem(TextClass::Standard) * scale_factor;
126 self.scroll_dist = base.event.scroll_dist_em * dpem;
127 self.pan_dist_thresh = base.event.pan_dist_thresh * scale_factor;
128 self.double_click_dist_thresh = base.event.double_click_dist_thresh * scale_factor;
129 }
130
131 pub fn base(&self) -> Ref<'_, Config> {
133 self.config.borrow()
134 }
135
136 pub fn clone_base(&self) -> Rc<RefCell<Config>> {
138 self.config.clone()
139 }
140
141 pub fn update_base<F: FnOnce(&mut Config)>(&self, f: F) -> ConfigAction {
153 if let Ok(mut c) = self.config.try_borrow_mut() {
154 c.is_dirty = true;
155 f(&mut c);
156
157 ConfigAction::all()
158 } else {
159 ConfigAction::empty()
160 }
161 }
162
163 pub fn event(&self) -> EventWindowConfig<'_> {
165 EventWindowConfig(self)
166 }
167
168 pub fn update_event<F: FnOnce(&mut EventConfig) -> ConfigAction>(&self, f: F) -> ConfigAction {
170 if let Ok(mut c) = self.config.try_borrow_mut() {
171 c.is_dirty = true;
172 f(&mut c.event)
173 } else {
174 ConfigAction::empty()
175 }
176 }
177
178 pub fn font(&self) -> Ref<'_, FontConfig> {
180 Ref::map(self.config.borrow(), |c| &c.font)
181 }
182
183 pub fn set_font_size(&self, pt_size: f32) -> ConfigAction {
191 if let Ok(mut c) = self.config.try_borrow_mut() {
192 c.is_dirty = true;
193 c.font.set_size(pt_size)
194 } else {
195 ConfigAction::empty()
196 }
197 }
198
199 pub fn shortcuts(&self) -> Ref<'_, Shortcuts> {
201 Ref::map(self.config.borrow(), |c| &c.shortcuts)
202 }
203
204 pub fn theme(&self) -> Ref<'_, ThemeConfig> {
206 Ref::map(self.config.borrow(), |c| &c.theme)
207 }
208
209 pub fn update_theme<F: FnOnce(&mut ThemeConfig) -> ConfigAction>(&self, f: F) -> ConfigAction {
211 if let Ok(mut c) = self.config.try_borrow_mut() {
212 c.is_dirty = true;
213
214 f(&mut c.theme)
215 } else {
216 ConfigAction::empty()
217 }
218 }
219
220 pub fn update_shortcuts<F: FnOnce(&mut Shortcuts)>(&self, f: F) -> ConfigAction {
222 if let Ok(mut c) = self.config.try_borrow_mut() {
223 c.is_dirty = true;
224
225 f(&mut c.shortcuts);
226 }
227
228 ConfigAction::empty()
229 }
230
231 pub fn scale_factor(&self) -> f32 {
233 debug_assert!(self.scale_factor.is_finite());
234 self.scale_factor
235 }
236
237 pub fn change_config(&self, msg: ConfigMsg) -> ConfigAction {
239 match msg {
240 ConfigMsg::Event(msg) => self.update_event(|ev| ev.change_config(msg)),
241 ConfigMsg::Font(FontConfigMsg::Size(size)) => self.set_font_size(size),
242 ConfigMsg::Theme(msg) => self.update_theme(|theme| theme.change_config(msg)),
243 }
244 }
245}