Add Settings with fullscreen and windowed options, a config file

(settings.toml) to persist settings, fix a bug in platform code where
innner window size wasn't updated on resize, various other tweaks
This commit is contained in:
reo 2025-12-09 17:52:17 +03:00
parent b17a7636d8
commit f5a16213fa
10 changed files with 277 additions and 19 deletions

101
platform/src/settings.rs Normal file
View file

@ -0,0 +1,101 @@
use winit::dpi::LogicalSize;
use winit::window::{Fullscreen, Window};
use serde::{Serialize, Deserialize};
use std::error::Error;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
pub fn default_config_path() -> PathBuf {
let exe_path = std::env::current_exe().unwrap();
let exe_dir = exe_path
.parent()
.ok_or_else(|| std::io::Error::new(std::io::ErrorKind::Other, "executable has no parent")).unwrap();
exe_dir.join("settings.toml")
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum WindowMode {
BorderlessFullscreen,
#[default]
Windowed,
}
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Settings {
pub display_settings: DisplaySettings,
}
impl Settings {
pub fn load_from_file(path: impl AsRef<Path>) -> Result<Self, Box<dyn Error>> {
let path = path.as_ref();
let text = fs::read_to_string(path)?;
let settings: Settings = toml::from_str(&text)?;
Ok(settings)
}
pub fn save_to_file(&self, path: impl AsRef<Path>) -> Result<(), Box<dyn Error>> {
let path = path.as_ref();
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
let toml_str = toml::to_string_pretty(self)?;
fs::write(path, toml_str)?;
Ok(())
}
pub fn load_or_default(path: impl AsRef<Path>) -> Result<Self, Box<dyn Error>> {
let path = path.as_ref();
match fs::read_to_string(path) {
Ok(text) => {
let settings: Settings = toml::from_str(&text)?;
Ok(settings)
}
Err(err) if err.kind() == io::ErrorKind::NotFound => {
let settings = Settings::default();
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
let toml_str = toml::to_string_pretty(&settings)?;
fs::write(path, toml_str)?;
Ok(settings)
}
Err(err) => Err(Box::new(err)),
}
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct DisplaySettings {
pub fullscreen_mode: WindowMode,
#[serde(skip)]
pub dirty: bool,
}
impl Default for DisplaySettings {
fn default() -> Self {
Self {
fullscreen_mode: WindowMode::Windowed,
dirty: false,
}
}
}
impl DisplaySettings {
pub fn apply(&self, window: &Window) {
// apply fullscreen mode
match self.fullscreen_mode {
WindowMode::BorderlessFullscreen => {
let monitor = window.current_monitor().or_else(|| window.primary_monitor());
window.set_fullscreen(Some(Fullscreen::Borderless(monitor)));
}
WindowMode::Windowed => {
window.set_fullscreen(None);
},
}
}
}