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

View file

@ -8,3 +8,5 @@ winit = "0.30.12"
raidillon_core = { path = "../core" }
raidillon_assets = { path = "../asset" }
glam = "0.30.5"
serde = "1.0.228"
toml = "0.9.8"

View file

@ -1,8 +1,9 @@
use std::{cell::RefCell, rc::Rc};
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Mutex, RwLock};
use winit::event::Event;
use raidillon_assets::ModelManagerRef;
use raidillon_core::EguiQueue;
use crate::settings::Settings;
#[derive(Clone)]
pub struct PlatformContext {
@ -13,6 +14,7 @@ pub struct PlatformContext {
pub time_ctx: TimeContext,
pub window: Arc<Mutex<winit::window::Window>>,
pub egui_queue: Rc<RefCell<EguiQueue>>,
pub settings: Arc<RwLock<Settings>>,
}
#[derive(Clone)]

View file

@ -2,6 +2,7 @@ pub mod platform;
mod camera;
mod event;
pub mod context;
pub mod settings;
pub use platform::Platform;
pub use camera::Camera;

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);
},
}
}
}