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:
parent
b17a7636d8
commit
f5a16213fa
10 changed files with 277 additions and 19 deletions
32
Cargo.lock
generated
32
Cargo.lock
generated
|
|
@ -2192,6 +2192,8 @@ dependencies = [
|
||||||
"glam 0.30.9",
|
"glam 0.30.9",
|
||||||
"raidillon_assets",
|
"raidillon_assets",
|
||||||
"raidillon_core",
|
"raidillon_core",
|
||||||
|
"serde",
|
||||||
|
"toml",
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -2413,6 +2415,15 @@ dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
|
@ -2669,6 +2680,21 @@ dependencies = [
|
||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"serde_core",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_parser",
|
||||||
|
"toml_writer",
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
|
|
@ -2699,6 +2725,12 @@ dependencies = [
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_writer"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.41"
|
version = "0.1.41"
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ pub use raidillon_platform::{
|
||||||
Camera,
|
Camera,
|
||||||
PlatformContext,
|
PlatformContext,
|
||||||
TimeContext,
|
TimeContext,
|
||||||
|
settings::{Settings, WindowMode},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use raidillon_assets::{
|
pub use raidillon_assets::{
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@ use rapier3d::prelude::ColliderBuilder;
|
||||||
use winit::event::{Event, WindowEvent};
|
use winit::event::{Event, WindowEvent};
|
||||||
use systems::debug_camera::FPSDebugCameraSystem;
|
use systems::debug_camera::FPSDebugCameraSystem;
|
||||||
use crate::systems::common::should_draw_menu;
|
use crate::systems::common::should_draw_menu;
|
||||||
use crate::systems::{KeybindsSystem, KinematicCharacterController, MenuSystem, PhysicsSystem};
|
use crate::systems::{
|
||||||
|
DisplaySettings, KeybindsSystem, KinematicCharacterController, MenuSystem, PhysicsSystem
|
||||||
|
};
|
||||||
|
|
||||||
const TEST_GLTF: &str = "sphere.glb";
|
const TEST_GLTF: &str = "sphere.glb";
|
||||||
const PLANE_GLTF: &str = "plane.glb";
|
const PLANE_GLTF: &str = "plane.glb";
|
||||||
|
|
@ -97,23 +99,21 @@ impl System for MainSystem {
|
||||||
InputState,
|
InputState,
|
||||||
)>().unwrap();
|
)>().unwrap();
|
||||||
|
|
||||||
if should_draw_menu(scene) {
|
let mut egui_queue = pctx.egui_queue.borrow_mut();
|
||||||
let mut egui_queue = pctx.egui_queue.borrow_mut();
|
let time_ctx = pctx.time_ctx.clone();
|
||||||
let time_ctx = pctx.time_ctx.clone();
|
let mut character_pos = Vec3::ZERO;
|
||||||
let mut character_pos = Vec3::ZERO;
|
for (_ent, (tr, ch_component)) in scene.world.query::<(&Transform, &CharacterBodyComponent)>().iter() {
|
||||||
for (_ent, (tr, ch_component)) in scene.world.query::<(&Transform, &CharacterBodyComponent)>().iter() {
|
character_pos = tr.translation;
|
||||||
character_pos = tr.translation;
|
|
||||||
}
|
|
||||||
egui_queue.queue(move |egui_ctx| {
|
|
||||||
egui::Window::new("Debug").show(egui_ctx, |ui| {
|
|
||||||
ui.label("Hello World!");
|
|
||||||
ui.label(format!("Frame Delta: {}", time_ctx.frame_dt));
|
|
||||||
ui.label(format!("Fixed Delta: {}", time_ctx.fixed_dt));
|
|
||||||
ui.label(format!("FPS: {}", 1.0 / time_ctx.frame_dt));
|
|
||||||
ui.label(format!("Character POS: {}", character_pos));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
egui_queue.queue(move |egui_ctx| {
|
||||||
|
egui::Window::new("Debug").show(egui_ctx, |ui| {
|
||||||
|
ui.label("Hello World!");
|
||||||
|
ui.label(format!("Frame Delta: {:.3}", time_ctx.frame_dt));
|
||||||
|
ui.label(format!("Fixed Delta: {:.3}", time_ctx.fixed_dt));
|
||||||
|
ui.label(format!("FPS: {:.3}", 1.0 / time_ctx.frame_dt));
|
||||||
|
ui.label(format!("Character POS: {character_pos:.3}"));
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,6 +124,7 @@ fn main() {
|
||||||
.add_system::<KinematicCharacterController>()
|
.add_system::<KinematicCharacterController>()
|
||||||
.add_system::<FPSDebugCameraSystem>()
|
.add_system::<FPSDebugCameraSystem>()
|
||||||
.add_system::<MenuSystem>()
|
.add_system::<MenuSystem>()
|
||||||
|
.add_system::<DisplaySettings>()
|
||||||
.add_system::<MainSystem>()
|
.add_system::<MainSystem>()
|
||||||
.add_system::<UpdateAspectRatioSystem>()
|
.add_system::<UpdateAspectRatioSystem>()
|
||||||
.add_scene(MAIN_SCENE_ID, Scene::new(MAIN_SCENE_ID.to_owned(), None))
|
.add_scene(MAIN_SCENE_ID, Scene::new(MAIN_SCENE_ID.to_owned(), None))
|
||||||
|
|
|
||||||
92
game/src/systems/display_settings.rs
Normal file
92
game/src/systems/display_settings.rs
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use raidillon_app::prelude::*;
|
||||||
|
use crate::systems::common::should_draw_menu;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum SettingsTab {
|
||||||
|
Display,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SettingsTab {
|
||||||
|
fn default() -> Self {
|
||||||
|
SettingsTab::Display
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
struct DisplaySettingsUiState {
|
||||||
|
selected_fullscreen_mode: WindowMode,
|
||||||
|
active_tab: SettingsTab,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct DisplaySettings {
|
||||||
|
ui_state: Arc<Mutex<DisplaySettingsUiState>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl System for DisplaySettings {
|
||||||
|
fn load_world(&mut self, res: &mut EngineResources, scene: &mut Scene) {
|
||||||
|
let pctx = res.get_mut::<PlatformContext>().unwrap();
|
||||||
|
|
||||||
|
// sync the settings with UI state once
|
||||||
|
if let (Ok(settings_handle), Ok(mut state)) = (pctx.settings.read(), self.ui_state.lock()) {
|
||||||
|
state.selected_fullscreen_mode = settings_handle.display_settings.fullscreen_mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame_update(&mut self, res: &mut EngineResources, scene: &mut Scene) {
|
||||||
|
if should_draw_menu(scene) {
|
||||||
|
let pctx = res.get_mut::<PlatformContext>().unwrap();
|
||||||
|
let settings = pctx.settings.clone();
|
||||||
|
let ui_state = self.ui_state.clone();
|
||||||
|
|
||||||
|
pctx.egui_queue.borrow_mut().queue(move |egui_ctx| {
|
||||||
|
egui::Window::new("Settings").default_open(false).show(egui_ctx, |ui| {
|
||||||
|
let mut state = ui_state.lock().unwrap();
|
||||||
|
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.selectable_value(&mut state.active_tab, SettingsTab::Display, "Display Settings");
|
||||||
|
});
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
match state.active_tab {
|
||||||
|
SettingsTab::Display => {
|
||||||
|
ui.label("Window Mode");
|
||||||
|
egui::ComboBox::from_id_salt("window_mode")
|
||||||
|
.selected_text(window_mode_label(state.selected_fullscreen_mode))
|
||||||
|
.show_ui(ui, |ui| {
|
||||||
|
for mode in [
|
||||||
|
WindowMode::Windowed,
|
||||||
|
WindowMode::BorderlessFullscreen,
|
||||||
|
] {
|
||||||
|
ui.selectable_value(
|
||||||
|
&mut state.selected_fullscreen_mode,
|
||||||
|
mode,
|
||||||
|
window_mode_label(mode),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.add_space(8.0);
|
||||||
|
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||||
|
if ui.button("Apply").clicked() {
|
||||||
|
if let Ok(mut settings_handle) = settings.write() {
|
||||||
|
settings_handle.display_settings.fullscreen_mode = state.selected_fullscreen_mode;
|
||||||
|
settings_handle.display_settings.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_mode_label(mode: WindowMode) -> &'static str {
|
||||||
|
match mode {
|
||||||
|
WindowMode::Windowed => "Windowed",
|
||||||
|
WindowMode::BorderlessFullscreen => "Borderless Fullscreen",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,8 +4,10 @@ mod keybinds;
|
||||||
mod menu;
|
mod menu;
|
||||||
pub mod debug_camera;
|
pub mod debug_camera;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
mod display_settings;
|
||||||
|
|
||||||
pub use physics::PhysicsSystem;
|
pub use physics::PhysicsSystem;
|
||||||
pub use kinematic_character_controller::KinematicCharacterController;
|
pub use kinematic_character_controller::KinematicCharacterController;
|
||||||
pub use keybinds::KeybindsSystem;
|
pub use keybinds::KeybindsSystem;
|
||||||
pub use menu::MenuSystem;
|
pub use menu::MenuSystem;
|
||||||
|
pub use display_settings::DisplaySettings;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use raidillon_platform::{Platform, PlatformContext, TimeContext};
|
use raidillon_platform::{Platform, PlatformContext, TimeContext};
|
||||||
use glium::backend::glutin::Display;
|
use glium::backend::glutin::Display;
|
||||||
use glium::backend::glutin::SimpleWindowBuilder;
|
use glium::backend::glutin::SimpleWindowBuilder;
|
||||||
|
|
@ -19,6 +19,7 @@ use crate::GliumAssetManager;
|
||||||
use glam::Vec3;
|
use glam::Vec3;
|
||||||
use winit::event::DeviceEvent::MouseMotion;
|
use winit::event::DeviceEvent::MouseMotion;
|
||||||
use raidillon_core::EguiQueue;
|
use raidillon_core::EguiQueue;
|
||||||
|
use raidillon_platform::settings::{Settings, default_config_path};
|
||||||
|
|
||||||
pub struct GliumPlatform<E: EngineTrait<PlatformCtx = PlatformContext>> {
|
pub struct GliumPlatform<E: EngineTrait<PlatformCtx = PlatformContext>> {
|
||||||
event_loop: EventLoop<()>,
|
event_loop: EventLoop<()>,
|
||||||
|
|
@ -29,6 +30,7 @@ pub struct GliumPlatform<E: EngineTrait<PlatformCtx = PlatformContext>> {
|
||||||
engine: E,
|
engine: E,
|
||||||
time: time::Time,
|
time: time::Time,
|
||||||
egui_queue: Rc<RefCell<EguiQueue>>,
|
egui_queue: Rc<RefCell<EguiQueue>>,
|
||||||
|
settings: Arc<RwLock<Settings>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatform<E> {
|
impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatform<E> {
|
||||||
|
|
@ -57,6 +59,12 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
||||||
|
|
||||||
let egui_queue = Rc::new(RefCell::new(EguiQueue::new()));
|
let egui_queue = Rc::new(RefCell::new(EguiQueue::new()));
|
||||||
|
|
||||||
|
let settings = Arc::new(
|
||||||
|
RwLock::new(
|
||||||
|
Settings::load_or_default(default_config_path()).unwrap()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
event_loop,
|
event_loop,
|
||||||
window,
|
window,
|
||||||
|
|
@ -66,6 +74,7 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
||||||
engine,
|
engine,
|
||||||
time,
|
time,
|
||||||
egui_queue,
|
egui_queue,
|
||||||
|
settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,9 +91,18 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
||||||
time_ctx: self.construct_time_ctx(),
|
time_ctx: self.construct_time_ctx(),
|
||||||
window: self.window.clone(),
|
window: self.window.clone(),
|
||||||
egui_queue: self.egui_queue.clone(),
|
egui_queue: self.egui_queue.clone(),
|
||||||
|
settings: self.settings.clone(),
|
||||||
};
|
};
|
||||||
self.engine.initialize(ctx.clone());
|
self.engine.initialize(ctx.clone());
|
||||||
|
self.settings.read().unwrap().display_settings.apply(&*self.window.lock().unwrap());
|
||||||
|
|
||||||
let _ = &self.event_loop.run(move |event, el| {
|
let _ = &self.event_loop.run(move |event, el| {
|
||||||
|
let settings_handle = self.settings.read().unwrap();
|
||||||
|
if settings_handle.display_settings.dirty {
|
||||||
|
settings_handle.display_settings.apply(&*self.window.lock().unwrap());
|
||||||
|
}
|
||||||
|
drop(settings_handle);
|
||||||
|
|
||||||
self.rendering_system_manager
|
self.rendering_system_manager
|
||||||
.systems
|
.systems
|
||||||
.values_mut()
|
.values_mut()
|
||||||
|
|
@ -96,8 +114,14 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent { event, .. } => match event {
|
Event::WindowEvent { event, .. } => match event {
|
||||||
|
WindowEvent::Resized(size) => {
|
||||||
|
if size.width > 0 && size.height > 0 {
|
||||||
|
self.display.resize((size.width, size.height));
|
||||||
|
}
|
||||||
|
},
|
||||||
WindowEvent::CloseRequested => {
|
WindowEvent::CloseRequested => {
|
||||||
// TODO: Run uninitialize on renderer and engine
|
// TODO: Run uninitialize on renderer and engine
|
||||||
|
self.settings.read().unwrap().save_to_file(default_config_path());
|
||||||
el.exit();
|
el.exit();
|
||||||
},
|
},
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,5 @@ winit = "0.30.12"
|
||||||
raidillon_core = { path = "../core" }
|
raidillon_core = { path = "../core" }
|
||||||
raidillon_assets = { path = "../asset" }
|
raidillon_assets = { path = "../asset" }
|
||||||
glam = "0.30.5"
|
glam = "0.30.5"
|
||||||
|
serde = "1.0.228"
|
||||||
|
toml = "0.9.8"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use winit::event::Event;
|
use winit::event::Event;
|
||||||
use raidillon_assets::ModelManagerRef;
|
use raidillon_assets::ModelManagerRef;
|
||||||
use raidillon_core::EguiQueue;
|
use raidillon_core::EguiQueue;
|
||||||
|
use crate::settings::Settings;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PlatformContext {
|
pub struct PlatformContext {
|
||||||
|
|
@ -13,6 +14,7 @@ pub struct PlatformContext {
|
||||||
pub time_ctx: TimeContext,
|
pub time_ctx: TimeContext,
|
||||||
pub window: Arc<Mutex<winit::window::Window>>,
|
pub window: Arc<Mutex<winit::window::Window>>,
|
||||||
pub egui_queue: Rc<RefCell<EguiQueue>>,
|
pub egui_queue: Rc<RefCell<EguiQueue>>,
|
||||||
|
pub settings: Arc<RwLock<Settings>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ pub mod platform;
|
||||||
mod camera;
|
mod camera;
|
||||||
mod event;
|
mod event;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
|
pub mod settings;
|
||||||
|
|
||||||
pub use platform::Platform;
|
pub use platform::Platform;
|
||||||
pub use camera::Camera;
|
pub use camera::Camera;
|
||||||
|
|
|
||||||
101
platform/src/settings.rs
Normal file
101
platform/src/settings.rs
Normal 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);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue