Skip to main content

fyroxed_base/settings/
mod.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21use crate::{
22    fyrox::core::{log::Log, reflect::prelude::*},
23    settings::{
24        build::BuildSettings, camera::CameraSettings, debugging::DebuggingSettings,
25        general::GeneralSettings, graphics::GraphicsSettings, keys::KeyBindings, log::LogSettings,
26        model::ModelSettings, move_mode::MoveInteractionModeSettings, navmesh::NavmeshSettings,
27        recent::RecentFiles, rotate_mode::RotateInteractionModeSettings, scene::SceneSettings,
28        selection::SelectionSettings, windows::WindowsSettings,
29    },
30};
31use ron::ser::PrettyConfig;
32use serde::{Deserialize, Serialize};
33use std::{
34    collections::HashMap,
35    fmt::Display,
36    fs::File,
37    io::Write,
38    ops::{Deref, DerefMut},
39    path::PathBuf,
40    sync::mpsc::Sender,
41};
42
43pub mod build;
44pub mod camera;
45pub mod debugging;
46pub mod general;
47pub mod graphics;
48pub mod keys;
49pub mod log;
50pub mod model;
51pub mod move_mode;
52pub mod navmesh;
53pub mod recent;
54pub mod rotate_mode;
55pub mod scene;
56pub mod selection;
57pub mod windows;
58
59#[derive(Deserialize, Serialize, PartialEq, Clone, Default, Debug, Reflect)]
60pub struct SettingsData {
61    #[reflect(tag = "Group.Selection")]
62    pub selection: SelectionSettings,
63    #[reflect(tag = "Group.Graphics")]
64    pub graphics: GraphicsSettings,
65    #[reflect(tag = "Group.Build")]
66    #[serde(default)]
67    pub build: BuildSettings,
68    #[reflect(tag = "Group.General")]
69    #[serde(default)]
70    pub general: GeneralSettings,
71    #[reflect(tag = "Group.Debugging")]
72    pub debugging: DebuggingSettings,
73    #[reflect(tag = "Group.MoveMode")]
74    pub move_mode_settings: MoveInteractionModeSettings,
75    #[reflect(tag = "Group.RotateMode")]
76    pub rotate_mode_settings: RotateInteractionModeSettings,
77    #[reflect(tag = "Group.Model")]
78    pub model: ModelSettings,
79    #[reflect(tag = "Group.Camera")]
80    pub camera: CameraSettings,
81    #[reflect(tag = "Group.Navmesh")]
82    pub navmesh: NavmeshSettings,
83    #[reflect(tag = "Group.KeyBindings")]
84    pub key_bindings: KeyBindings,
85    #[reflect(tag = "Group.Log")]
86    #[reflect(hidden)]
87    #[serde(default)]
88    pub log: LogSettings,
89    #[reflect(hidden)]
90    pub scene_settings: HashMap<PathBuf, SceneSettings>,
91    #[reflect(hidden)]
92    pub recent: RecentFiles,
93    #[serde(default)]
94    #[reflect(hidden)]
95    pub windows: WindowsSettings,
96}
97
98pub enum SettingsMessage {
99    Changed,
100}
101
102#[derive(Default)]
103pub struct Settings {
104    settings: SettingsData,
105    need_save: bool,
106    pub subscribers: Vec<Sender<SettingsMessage>>,
107}
108
109impl Deref for Settings {
110    type Target = SettingsData;
111
112    fn deref(&self) -> &Self::Target {
113        &self.settings
114    }
115}
116
117impl DerefMut for Settings {
118    fn deref_mut(&mut self) -> &mut Self::Target {
119        self.need_save = true;
120
121        self.subscribers
122            .retain_mut(|subscriber| subscriber.send(SettingsMessage::Changed).is_ok());
123
124        &mut self.settings
125    }
126}
127
128impl Settings {
129    pub fn load() -> Result<Self, SettingsError> {
130        let settings = SettingsData::load()?;
131        Log::set_log_info(settings.log.log_info);
132        Log::set_log_warning(settings.log.log_warning);
133        Log::set_log_error(settings.log.log_error);
134        Ok(Settings {
135            settings,
136            need_save: false,
137            subscribers: Default::default(),
138        })
139    }
140
141    pub fn data_mut(&mut self) -> &mut SettingsData {
142        &mut self.settings
143    }
144
145    pub fn force_save(&mut self) {
146        self.need_save = false;
147        Log::verify(self.settings.save());
148    }
149
150    pub fn try_save(&mut self) -> bool {
151        if self.need_save {
152            self.need_save = false;
153            Log::verify(self.settings.save());
154            true
155        } else {
156            false
157        }
158    }
159}
160
161#[derive(Debug)]
162pub enum SettingsError {
163    Io(std::io::Error),
164    RonSpanned(ron::error::SpannedError),
165    Ron(ron::Error),
166}
167
168impl std::error::Error for SettingsError {}
169
170impl Display for SettingsError {
171    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172        match self {
173            SettingsError::Io(error) => Display::fmt(error, f),
174            SettingsError::RonSpanned(error) => Display::fmt(error, f),
175            SettingsError::Ron(error) => Display::fmt(error, f),
176        }
177    }
178}
179
180impl From<std::io::Error> for SettingsError {
181    fn from(e: std::io::Error) -> Self {
182        Self::Io(e)
183    }
184}
185
186impl From<ron::error::SpannedError> for SettingsError {
187    fn from(e: ron::error::SpannedError) -> Self {
188        Self::RonSpanned(e)
189    }
190}
191
192impl From<ron::Error> for SettingsError {
193    fn from(e: ron::Error) -> Self {
194        Self::Ron(e)
195    }
196}
197
198impl SettingsData {
199    const FILE_NAME: &'static str = "settings.ron";
200
201    fn full_path() -> PathBuf {
202        Self::FILE_NAME.into()
203    }
204
205    pub fn load() -> Result<Self, SettingsError> {
206        let file = File::open(Self::full_path())?;
207        Ok(ron::de::from_reader(file)?)
208    }
209
210    fn save(&mut self) -> Result<(), SettingsError> {
211        let mut file = File::create(Self::full_path())?;
212        self.recent.deduplicate_and_refresh();
213
214        file.write_all(ron::ser::to_string_pretty(self, PrettyConfig::default())?.as_bytes())?;
215
216        Ok(())
217    }
218}