make pausing on focus loss toggleable

This commit is contained in:
Sallai József 2022-07-25 11:41:20 +03:00
parent 2a792db797
commit fee63f2600
6 changed files with 145 additions and 36 deletions

View File

@ -116,10 +116,14 @@
"language": "Language...",
"game_timing": {
"entry": "Game timing:",
"50tps": "50tps (freeware)",
"60tps": "60tps (CS+)"
"behavior": "Behavior...",
"behavior_menu": {
"game_timing": {
"entry": "Game timing:",
"50tps": "50tps (freeware)",
"60tps": "60tps (CS+)"
},
"pause_on_focus_loss": "Pause on focus loss:"
}
}
},

View File

@ -105,11 +105,17 @@
},
"soundtrack": "サウンドトラック: {soundtrack}"
},
"language": "言語",
"game_timing": {
"entry": "ゲームのタイミング:",
"50tps": "50tps (freeware)",
"60tps": "60tps (CS+)"
"behavior": "動作",
"behavior_menu": {
"game_timing": {
"entry": "ゲームのタイミング:",
"50tps": "50tps (freeware)",
"60tps": "60tps (CS+)"
},
"pause_on_focus_loss": "フォーカスが外れた時のポーズ:"
}
}
},

View File

@ -237,8 +237,25 @@ impl BackendEventLoop for SDL2EventLoop {
state.shutdown();
}
Event::Window { win_event, .. } => match win_event {
WindowEvent::FocusGained | WindowEvent::Shown => {}
WindowEvent::FocusLost | WindowEvent::Hidden => {}
WindowEvent::FocusGained | WindowEvent::Shown => {
if state.settings.pause_on_focus_loss {
{
let mut mutex = GAME_SUSPENDED.lock().unwrap();
*mutex = false;
}
state.sound_manager.resume();
game.loops = 0;
}
}
WindowEvent::FocusLost | WindowEvent::Hidden => {
if state.settings.pause_on_focus_loss {
let mut mutex = GAME_SUSPENDED.lock().unwrap();
*mutex = true;
state.sound_manager.pause();
}
}
WindowEvent::SizeChanged(width, height) => {
ctx.screen_size = (width.max(1) as f32, height.max(1) as f32);

View File

@ -22,6 +22,7 @@ enum CurrentMenu {
SoundMenu,
SoundtrackMenu,
LanguageMenu,
BehaviorMenu,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
@ -29,7 +30,7 @@ enum MainMenuEntry {
Graphics,
Sound,
Language,
GameTiming,
Behavior,
DiscordLink,
Back,
}
@ -101,6 +102,19 @@ impl Default for LanguageMenuEntry {
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum BehaviorMenuEntry {
GameTiming,
PauseOnFocusLoss,
Back,
}
impl Default for BehaviorMenuEntry {
fn default() -> Self {
BehaviorMenuEntry::GameTiming
}
}
pub struct SettingsMenu {
current: CurrentMenu,
main: Menu<MainMenuEntry>,
@ -108,6 +122,7 @@ pub struct SettingsMenu {
sound: Menu<SoundMenuEntry>,
soundtrack: Menu<SoundtrackMenuEntry>,
language: Menu<LanguageMenuEntry>,
behavior: Menu<BehaviorMenuEntry>,
pub on_title: bool,
}
@ -120,8 +135,18 @@ impl SettingsMenu {
let sound = Menu::new(0, 0, 260, 0);
let soundtrack = Menu::new(0, 0, 260, 0);
let language = Menu::new(0, 0, 120, 0);
let behavior = Menu::new(0, 0, 220, 0);
SettingsMenu { current: CurrentMenu::MainMenu, main, graphics, sound, soundtrack, language, on_title: false }
SettingsMenu {
current: CurrentMenu::MainMenu,
main,
graphics,
sound,
soundtrack,
language,
behavior,
on_title: false,
}
}
pub fn init(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
@ -251,14 +276,7 @@ impl SettingsMenu {
self.main.push_entry(MainMenuEntry::Language, MenuEntry::Active(state.t("menus.options_menu.language")));
}
self.main.push_entry(
MainMenuEntry::GameTiming,
MenuEntry::Options(
state.t("menus.options_menu.game_timing.entry"),
if state.settings.timing_mode == TimingMode::_50Hz { 0 } else { 1 },
vec![state.t("menus.options_menu.game_timing.50tps"), state.t("menus.options_menu.game_timing.60tps")],
),
);
self.main.push_entry(MainMenuEntry::Behavior, MenuEntry::Active(state.t("menus.options_menu.behavior")));
self.main.push_entry(MainMenuEntry::DiscordLink, MenuEntry::Active(DISCORD_LINK.to_owned()));
@ -334,6 +352,28 @@ impl SettingsMenu {
self.soundtrack.push_entry(SoundtrackMenuEntry::Back, MenuEntry::Active(state.t("common.back")));
self.behavior.push_entry(
BehaviorMenuEntry::GameTiming,
MenuEntry::Options(
state.t("menus.options_menu.behavior_menu.game_timing.entry"),
if state.settings.timing_mode == TimingMode::_50Hz { 0 } else { 1 },
vec![
state.t("menus.options_menu.behavior_menu.game_timing.50tps"),
state.t("menus.options_menu.behavior_menu.game_timing.60tps"),
],
),
);
self.behavior.push_entry(
BehaviorMenuEntry::PauseOnFocusLoss,
MenuEntry::Toggle(
state.t("menus.options_menu.behavior_menu.pause_on_focus_loss"),
state.settings.pause_on_focus_loss,
),
);
self.behavior.push_entry(BehaviorMenuEntry::Back, MenuEntry::Active(state.t("common.back")));
self.update_sizes(state);
Ok(())
@ -364,6 +404,11 @@ impl SettingsMenu {
self.language.update_height();
self.language.x = ((state.canvas_size.0 - self.language.width as f32) / 2.0).floor() as isize;
self.language.y = ((state.canvas_size.1 - self.language.height as f32) / 2.0).floor() as isize;
self.behavior.update_width(state);
self.behavior.update_height();
self.behavior.x = ((state.canvas_size.0 - self.behavior.width as f32) / 2.0).floor() as isize;
self.behavior.y = 30 + ((state.canvas_size.1 - self.behavior.height as f32) / 2.0).floor() as isize;
}
pub fn tick(
@ -387,21 +432,8 @@ impl SettingsMenu {
self.language.selected = LanguageMenuEntry::Language(state.settings.locale);
self.current = CurrentMenu::LanguageMenu;
}
MenuSelectionResult::Selected(MainMenuEntry::GameTiming, toggle) => {
if let MenuEntry::Options(_, value, _) = toggle {
match state.settings.timing_mode {
TimingMode::_50Hz => {
state.settings.timing_mode = TimingMode::_60Hz;
*value = 1;
}
TimingMode::_60Hz => {
state.settings.timing_mode = TimingMode::_50Hz;
*value = 0;
}
_ => {}
}
let _ = state.settings.save(ctx);
}
MenuSelectionResult::Selected(MainMenuEntry::Behavior, _) => {
self.current = CurrentMenu::BehaviorMenu;
}
MenuSelectionResult::Selected(MainMenuEntry::DiscordLink, _) => {
if let Err(e) = webbrowser::open(DISCORD_LINK) {
@ -655,6 +687,36 @@ impl SettingsMenu {
}
_ => (),
},
CurrentMenu::BehaviorMenu => match self.behavior.tick(controller, state) {
MenuSelectionResult::Selected(BehaviorMenuEntry::GameTiming, toggle) => {
if let MenuEntry::Options(_, value, _) = toggle {
match state.settings.timing_mode {
TimingMode::_50Hz => {
state.settings.timing_mode = TimingMode::_60Hz;
*value = 1;
}
TimingMode::_60Hz => {
state.settings.timing_mode = TimingMode::_50Hz;
*value = 0;
}
_ => {}
}
let _ = state.settings.save(ctx);
}
}
MenuSelectionResult::Selected(BehaviorMenuEntry::PauseOnFocusLoss, toggle) => {
if let MenuEntry::Toggle(_, value) = toggle {
state.settings.pause_on_focus_loss = !state.settings.pause_on_focus_loss;
let _ = state.settings.save(ctx);
*value = state.settings.pause_on_focus_loss;
}
}
MenuSelectionResult::Selected(BehaviorMenuEntry::Back, _) | MenuSelectionResult::Canceled => {
self.current = CurrentMenu::MainMenu;
}
_ => (),
},
}
Ok(())
}
@ -666,6 +728,7 @@ impl SettingsMenu {
CurrentMenu::SoundMenu => self.sound.draw(state, ctx)?,
CurrentMenu::SoundtrackMenu => self.soundtrack.draw(state, ctx)?,
CurrentMenu::LanguageMenu => self.language.draw(state, ctx)?,
CurrentMenu::BehaviorMenu => self.behavior.draw(state, ctx)?,
}
Ok(())

View File

@ -24,6 +24,7 @@ pub struct JukeboxScene {
frame: Frame,
stage: Stage,
textures: StageTexturePaths,
previous_pause_on_focus_loss_setting: bool,
}
impl JukeboxScene {
@ -58,6 +59,7 @@ impl JukeboxScene {
frame: Frame::new(),
stage: fake_stage,
textures,
previous_pause_on_focus_loss_setting: true,
}
}
}
@ -97,6 +99,9 @@ impl Scene for JukeboxScene {
self.soundtracks.iter().position(|s| s == &state.settings.soundtrack).unwrap_or(0);
self.selected_soundtrack = selected_soundtrack_index;
self.previous_pause_on_focus_loss_setting = state.settings.pause_on_focus_loss;
state.settings.pause_on_focus_loss = false;
Ok(())
}
@ -151,6 +156,7 @@ impl Scene for JukeboxScene {
}
if self.controller.trigger_back() {
state.settings.pause_on_focus_loss = self.previous_pause_on_focus_loss_setting;
state.next_scene = Some(Box::new(TitleScene::new()));
}

View File

@ -34,6 +34,8 @@ pub struct Settings {
pub sfx_volume: f32,
#[serde(default = "default_timing")]
pub timing_mode: TimingMode,
#[serde(default = "default_pause_on_focus_loss")]
pub pause_on_focus_loss: bool,
#[serde(default = "default_interpolation")]
pub organya_interpolation: InterpolationMode,
#[serde(default = "default_controller_type")]
@ -79,7 +81,7 @@ fn default_true() -> bool {
#[inline(always)]
fn current_version() -> u32 {
14
15
}
#[inline(always)]
@ -127,6 +129,11 @@ fn default_controller_type() -> ControllerType {
ControllerType::Keyboard
}
#[inline(always)]
fn default_pause_on_focus_loss() -> bool {
true
}
impl Settings {
pub fn load(ctx: &Context) -> GameResult<Settings> {
if let Ok(file) = user_open(ctx, "/settings.json") {
@ -223,6 +230,11 @@ impl Settings {
self.player2_controller_button_map = player_default_controller_button_map();
}
if self.version == 14 {
self.version = 15;
self.pause_on_focus_loss = default_pause_on_focus_loss();
}
if self.version != initial_version {
log::info!("Upgraded configuration file from version {} to {}.", initial_version, self.version);
}
@ -281,6 +293,7 @@ impl Default for Settings {
bgm_volume: 1.0,
sfx_volume: 1.0,
timing_mode: default_timing(),
pause_on_focus_loss: default_pause_on_focus_loss(),
organya_interpolation: InterpolationMode::Linear,
player1_controller_type: default_controller_type(),
player2_controller_type: default_controller_type(),