Add a fast-forward command
This commit is contained in:
+133
-30
@@ -1,13 +1,13 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::{HashMap, HashSet, hash_map::Entry},
|
||||
collections::{HashMap, hash_map::Entry},
|
||||
fmt::Display,
|
||||
str::FromStr,
|
||||
sync::{Arc, Mutex, RwLock},
|
||||
};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use egui::{Key, KeyboardShortcut, Modifiers};
|
||||
use egui::{Event, Key, KeyboardShortcut, Modifiers};
|
||||
use gilrs::{Axis, Button, Gamepad, GamepadId, ev::Code};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use winit::keyboard::{KeyCode, PhysicalKey};
|
||||
@@ -468,19 +468,21 @@ pub enum Command {
|
||||
OpenRom,
|
||||
Quit,
|
||||
FrameAdvance,
|
||||
FastForward(u32),
|
||||
Reset,
|
||||
PauseResume,
|
||||
// if you update this, update Command::all and add a default
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn all() -> [Self; 5] {
|
||||
pub fn all() -> [Self; 6] {
|
||||
[
|
||||
Self::OpenRom,
|
||||
Self::Quit,
|
||||
Self::PauseResume,
|
||||
Self::Reset,
|
||||
Self::FrameAdvance,
|
||||
Self::FastForward(0),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -491,6 +493,7 @@ impl Command {
|
||||
Self::PauseResume => "Pause/Resume",
|
||||
Self::Reset => "Reset",
|
||||
Self::FrameAdvance => "Frame Advance",
|
||||
Self::FastForward(_) => "Fast Forward",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -532,6 +535,10 @@ impl Default for Shortcuts {
|
||||
Command::FrameAdvance,
|
||||
KeyboardShortcut::new(Modifiers::NONE, Key::F6),
|
||||
);
|
||||
shortcuts.set(
|
||||
Command::FastForward(0),
|
||||
KeyboardShortcut::new(Modifiers::NONE, Key::Space),
|
||||
);
|
||||
shortcuts
|
||||
}
|
||||
}
|
||||
@@ -557,13 +564,11 @@ impl Shortcuts {
|
||||
}
|
||||
}
|
||||
|
||||
fn save(&self) -> PersistedShortcuts {
|
||||
let mut shortcuts = PersistedShortcuts { shortcuts: vec![] };
|
||||
fn save(&self, saved: &mut PersistedSettings) {
|
||||
for command in Command::all() {
|
||||
let shortcut = self.by_command.get(&command).copied();
|
||||
shortcuts.shortcuts.push((command, shortcut));
|
||||
saved.shortcuts.push((command, shortcut));
|
||||
}
|
||||
shortcuts
|
||||
}
|
||||
}
|
||||
|
||||
@@ -589,52 +594,123 @@ fn specificity(modifiers: egui::Modifiers) -> usize {
|
||||
mods
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct PersistedShortcuts {
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
struct PersistedSettings {
|
||||
shortcuts: Vec<(Command, Option<KeyboardShortcut>)>,
|
||||
#[serde(default)]
|
||||
ff_settings: FastForwardSettings,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
struct ShortcutState {
|
||||
ff_toggled: bool,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Settings {
|
||||
shortcuts: Shortcuts,
|
||||
ff_settings: FastForwardSettings,
|
||||
state: ShortcutState,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
fn save(&self) -> PersistedSettings {
|
||||
let mut saved = PersistedSettings {
|
||||
shortcuts: vec![],
|
||||
ff_settings: self.ff_settings.clone(),
|
||||
};
|
||||
self.shortcuts.save(&mut saved);
|
||||
saved
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ShortcutProvider {
|
||||
persistence: Persistence,
|
||||
shortcuts: Arc<Mutex<Shortcuts>>,
|
||||
settings: Arc<Mutex<Settings>>,
|
||||
}
|
||||
|
||||
impl ShortcutProvider {
|
||||
pub fn new(persistence: Persistence) -> Self {
|
||||
let mut shortcuts = Shortcuts::default();
|
||||
if let Ok(saved) = persistence.load_config::<PersistedShortcuts>("shortcuts") {
|
||||
let mut settings = Settings::default();
|
||||
if let Ok(saved) = persistence.load_config::<PersistedSettings>("shortcuts") {
|
||||
for (command, shortcut) in saved.shortcuts {
|
||||
if let Some(shortcut) = shortcut {
|
||||
shortcuts.set(command, shortcut);
|
||||
settings.shortcuts.set(command, shortcut);
|
||||
} else {
|
||||
shortcuts.unset(command);
|
||||
settings.shortcuts.unset(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
settings.ff_settings = saved.ff_settings;
|
||||
};
|
||||
Self {
|
||||
persistence,
|
||||
shortcuts: Arc::new(Mutex::new(shortcuts)),
|
||||
settings: Arc::new(Mutex::new(settings)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shortcut_for(&self, command: Command) -> Option<KeyboardShortcut> {
|
||||
let lock = self.shortcuts.lock().unwrap();
|
||||
lock.by_command.get(&command).copied()
|
||||
let lock = self.settings.lock().unwrap();
|
||||
lock.shortcuts.by_command.get(&command).copied()
|
||||
}
|
||||
|
||||
pub fn consume_all(&self, input: &mut egui::InputState) -> HashSet<Command> {
|
||||
let lock = self.shortcuts.lock().unwrap();
|
||||
lock.all
|
||||
.iter()
|
||||
.filter_map(|(command, shortcut)| input.consume_shortcut(shortcut).then_some(*command))
|
||||
.collect()
|
||||
pub fn ff_settings(&self) -> FastForwardSettings {
|
||||
let lock = self.settings.lock().unwrap();
|
||||
lock.ff_settings.clone()
|
||||
}
|
||||
|
||||
pub fn consume_all(&self, input: &mut egui::InputState) -> Vec<Command> {
|
||||
let mut lock = self.settings.lock().unwrap();
|
||||
let mut state = lock.state.clone();
|
||||
let mut consumed = vec![];
|
||||
for (command, shortcut) in &lock.shortcuts.all {
|
||||
input.events.retain(|event| {
|
||||
let Event::Key {
|
||||
key,
|
||||
pressed,
|
||||
repeat,
|
||||
modifiers,
|
||||
..
|
||||
} = event
|
||||
else {
|
||||
return true;
|
||||
};
|
||||
if shortcut.logical_key != *key || !shortcut.modifiers.contains(*modifiers) {
|
||||
return true;
|
||||
}
|
||||
if matches!(command, Command::FastForward(_)) {
|
||||
if *repeat {
|
||||
return true;
|
||||
}
|
||||
let sped_up = if lock.ff_settings.toggle {
|
||||
if !*pressed {
|
||||
return true;
|
||||
}
|
||||
state.ff_toggled = !state.ff_toggled;
|
||||
state.ff_toggled
|
||||
} else {
|
||||
*pressed
|
||||
};
|
||||
let speed = if sped_up { lock.ff_settings.speed } else { 1 };
|
||||
consumed.push(Command::FastForward(speed));
|
||||
false
|
||||
} else {
|
||||
if !*pressed {
|
||||
return true;
|
||||
}
|
||||
consumed.push(*command);
|
||||
false
|
||||
}
|
||||
});
|
||||
}
|
||||
lock.state = state;
|
||||
consumed
|
||||
}
|
||||
|
||||
pub fn set(&self, command: Command, shortcut: KeyboardShortcut) {
|
||||
let updated = {
|
||||
let mut lock = self.shortcuts.lock().unwrap();
|
||||
lock.set(command, shortcut);
|
||||
let mut lock = self.settings.lock().unwrap();
|
||||
lock.shortcuts.set(command, shortcut);
|
||||
lock.save()
|
||||
};
|
||||
let _ = self.persistence.save_config("shortcuts", &updated);
|
||||
@@ -642,8 +718,20 @@ impl ShortcutProvider {
|
||||
|
||||
pub fn unset(&self, command: Command) {
|
||||
let updated = {
|
||||
let mut lock = self.shortcuts.lock().unwrap();
|
||||
lock.unset(command);
|
||||
let mut lock = self.settings.lock().unwrap();
|
||||
lock.shortcuts.unset(command);
|
||||
lock.save()
|
||||
};
|
||||
let _ = self.persistence.save_config("shortcuts", &updated);
|
||||
}
|
||||
|
||||
pub fn update_ff_settings(&self, ff_settings: FastForwardSettings) {
|
||||
let updated = {
|
||||
let mut lock = self.settings.lock().unwrap();
|
||||
lock.ff_settings = ff_settings;
|
||||
if !lock.ff_settings.toggle {
|
||||
lock.state.ff_toggled = false;
|
||||
}
|
||||
lock.save()
|
||||
};
|
||||
let _ = self.persistence.save_config("shortcuts", &updated);
|
||||
@@ -651,10 +739,25 @@ impl ShortcutProvider {
|
||||
|
||||
pub fn reset(&self) {
|
||||
let updated = {
|
||||
let mut lock = self.shortcuts.lock().unwrap();
|
||||
*lock = Shortcuts::default();
|
||||
let mut lock = self.settings.lock().unwrap();
|
||||
*lock = Settings::default();
|
||||
lock.save()
|
||||
};
|
||||
let _ = self.persistence.save_config("shortcuts", &updated);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct FastForwardSettings {
|
||||
pub toggle: bool,
|
||||
pub speed: u32,
|
||||
}
|
||||
|
||||
impl Default for FastForwardSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
toggle: false,
|
||||
speed: 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user