From 50bb5b3c8b46334c67432146c260c6e29e85ebb7 Mon Sep 17 00:00:00 2001 From: Matt Fellenz Date: Fri, 3 Nov 2023 01:16:52 -0700 Subject: [PATCH] Adjust arrow-key navigation behavior First of all, add P and N as synonyms for the arrow keys, with Shift-N as a synonym for P. Next, make all these keys respect the slideshow behavior, meaning that if we are in a random slideshow, the keys will move the same as the slideshow. We allow Alt as a modifier to ignore the slideshow and move normally. --- src/app/mod.rs | 78 +++++++++++++++++++++++++++--------------- src/app/state/actor.rs | 21 +++--------- 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/src/app/mod.rs b/src/app/mod.rs index e2ab48a..77381e7 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -4,12 +4,13 @@ use std::sync::Arc; use ::image::ImageFormat; use eframe::CreationContext; use egui::style::Margin; -use egui::{Color32, Context, Frame, Painter, Rect, Rounding, Vec2}; +use egui::{Color32, Context, Frame, Modifiers, Painter, Rect, Rounding, Vec2}; pub use self::image::init_timezone; -use self::state::actor::{NavigationMode, NextPath}; +use self::state::actor::{NavigationMode, NextPath, NextPathMode}; use self::state::play::State as PlayState; use self::state::State as ImageState; +use crate::app::next_path::Direction; use crate::args::Args; use crate::config::Config; use crate::duration::Duration; @@ -207,6 +208,28 @@ fn show_fullscreen_toggle(ui: &mut egui::Ui, frame: &mut eframe::Frame) { } } +#[derive(Debug, Clone, Copy)] +enum MoveMode { + IgnoreSlideshow, + RespectSlideshow, +} + +impl App { + fn move_in(&mut self, direction: Direction, mode: MoveMode) { + let respect_slideshow = match mode { + MoveMode::IgnoreSlideshow => false, + MoveMode::RespectSlideshow => true, + }; + let mode = if respect_slideshow && self.slideshow.is_active() && self.config.slideshow.shuffle { + NextPathMode::Random + } else { + NextPathMode::Simple + }; + let direction = NextPath { direction, mode }; + self.image_state.next_path(direction); + } +} + impl App { fn show_actions_left(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { if let Some(current_path) = self.image_state.current_path() { @@ -425,11 +448,7 @@ impl App { .advance(&self.config, Duration::new_secs_f32_saturating(elapsed)); if next_from_slideshow { - if self.config.slideshow.shuffle { - self.move_in(NextPath::RANDOM); - } else { - self.move_right(); - } + self.move_in(Direction::Right, MoveMode::RespectSlideshow); } if let SlideshowState::Active { remaining } = self.slideshow { @@ -556,31 +575,34 @@ impl App { fn handle_global_keys(&mut self, ctx: &Context, _frame: &mut eframe::Frame) { use egui::Key; - let key = |key: Key| ctx.input_mut(|input| input.consume_key(egui::Modifiers::NONE, key)); - - if key(Key::ArrowRight) { - self.move_right(); - } - if key(Key::ArrowLeft) { - self.move_left(); + const KEYS: &[(Key, Modifiers, Direction)] = &[ + (Key::ArrowLeft, Modifiers::NONE, Direction::Left), + (Key::ArrowRight, Modifiers::NONE, Direction::Right), + (Key::P, Modifiers::NONE, Direction::Left), + (Key::N, Modifiers::NONE, Direction::Right), + (Key::N, Modifiers::SHIFT, Direction::Left), + ]; + + for &(key, modifiers, direction) in KEYS { + debug_assert!(!modifiers.contains(Modifiers::ALT)); + let mode = ctx.input_mut(|input| { + Some(if input.consume_key(modifiers, key) { + MoveMode::RespectSlideshow + } else if input.consume_key(modifiers | Modifiers::ALT, key) { + MoveMode::IgnoreSlideshow + } else { + return None; + }) + }); + if let Some(mode) = mode { + self.move_in(direction, mode); + } } - if ctx - .input_mut(|input| input.consume_key(egui::Modifiers::CTRL | egui::Modifiers::SHIFT, Key::I)) - { + + if ctx.input_mut(|input| input.consume_key(Modifiers::CTRL | Modifiers::SHIFT, Key::I)) { self.internal_open = !self.internal_open; } - } - - fn move_in(&mut self, direction: NextPath) { - self.image_state.next_path(direction); - } - - fn move_right(&mut self) { - self.move_in(NextPath::RIGHT); - } - fn move_left(&mut self) { - self.move_in(NextPath::LEFT); } fn handle_actor_responses(&mut self) { diff --git a/src/app/state/actor.rs b/src/app/state/actor.rs index b4c500b..562f715 100644 --- a/src/app/state/actor.rs +++ b/src/app/state/actor.rs @@ -36,21 +36,6 @@ pub struct NextPath { } impl NextPath { - pub const RIGHT: Self = Self { - direction: next_path::Direction::Right, - mode: NextPathMode::Simple, - }; - - pub const LEFT: Self = Self { - direction: next_path::Direction::Left, - mode: NextPathMode::Simple, - }; - - pub const RANDOM: Self = Self { - direction: next_path::Direction::Right, - mode: NextPathMode::Random, - }; - fn with_random_seed(self, seed: u64) -> next_path::NextPath { next_path::NextPath { direction: self.direction, @@ -296,7 +281,11 @@ impl Actor { std::fs::remove_file(&path)?; let should_go_to_next = Some(&*path) == self.state.current_path().map(|path| &**path); if should_go_to_next { - self.next_path(NextPath::RIGHT) + let args = NextPath { + direction: next_path::Direction::Right, + mode: NextPathMode::Simple, + }; + self.next_path(args) } else { Ok(Response::NoOp) }