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