From c574a3b530aea38c14d8299cbe46d8ffab30d07b Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 4 Dec 2021 22:10:54 -0500 Subject: filter unnecessary events --- src/bin/ttyplay/event.rs | 156 +++++++++++++++++++++++++++++++++++++++++++++++ src/bin/ttyplay/main.rs | 28 +++++---- 2 files changed, 172 insertions(+), 12 deletions(-) diff --git a/src/bin/ttyplay/event.rs b/src/bin/ttyplay/event.rs index 55f4da1..618478c 100644 --- a/src/bin/ttyplay/event.rs +++ b/src/bin/ttyplay/event.rs @@ -11,3 +11,159 @@ pub enum Event { ToggleUi, Quit, } + +enum MoveFrame { + First, + Last, + Next, + Previous, +} + +pub struct Reader { + pending: async_std::sync::Mutex, + cvar: async_std::sync::Condvar, +} + +impl Reader { + pub fn new( + input: async_std::channel::Receiver, + ) -> async_std::sync::Arc { + let this = Self { + pending: async_std::sync::Mutex::new(Pending::new()), + cvar: async_std::sync::Condvar::new(), + }; + let this = async_std::sync::Arc::new(this); + { + let this = this.clone(); + async_std::task::spawn(async move { + while let Ok(event) = input.recv().await { + this.event(event).await; + } + this.event(Event::Quit).await; + }); + } + this + } + + pub async fn read(&self) -> Option { + let mut pending = self + .cvar + .wait_until(self.pending.lock().await, |pending| { + pending.has_event() + }) + .await; + pending.get_event() + } + + async fn event(&self, event: Event) { + let mut pending = self.pending.lock().await; + pending.event(event); + self.cvar.notify_one(); + } +} + +#[derive(Default)] +struct Pending { + render: Option<(usize, vt100::Screen)>, + key: std::collections::VecDeque, + frame_loaded: Option, + done_loading: bool, + pause: bool, + paused: Option, + frame_controls: std::collections::VecDeque, + toggle_ui: bool, + quit: bool, +} + +impl Pending { + fn new() -> Self { + Self::default() + } + + fn event(&mut self, event: Event) { + match event { + Event::Render((idx, screen)) => { + self.render = Some((idx, screen)); + } + Event::Key(key) => { + self.key.push_back(key); + } + Event::FrameLoaded(idx) => { + if let Some(idx) = idx { + self.frame_loaded = Some(idx); + } else { + self.done_loading = true; + } + } + Event::Pause => { + self.pause = !self.pause; + } + Event::Paused(paused) => { + self.paused = Some(paused); + } + Event::FirstFrame => { + self.frame_controls.push_back(MoveFrame::First); + } + Event::LastFrame => { + self.frame_controls.push_back(MoveFrame::Last); + } + Event::NextFrame => { + self.frame_controls.push_back(MoveFrame::Next); + } + Event::PreviousFrame => { + self.frame_controls.push_back(MoveFrame::Previous); + } + Event::ToggleUi => { + self.toggle_ui = !self.toggle_ui; + } + Event::Quit => { + self.quit = true; + } + } + } + + fn has_event(&self) -> bool { + self.render.is_some() + || !self.key.is_empty() + || self.frame_loaded.is_some() + || self.done_loading + || self.pause + || self.paused.is_some() + || !self.frame_controls.is_empty() + || self.toggle_ui + || self.quit + } + + fn get_event(&mut self) -> Option { + if self.quit { + self.quit = false; + Some(Event::Quit) + } else if let Some(key) = self.key.pop_front() { + Some(Event::Key(key)) + } else if self.pause { + self.pause = false; + Some(Event::Pause) + } else if let Some(dir) = self.frame_controls.pop_front() { + match dir { + MoveFrame::First => Some(Event::FirstFrame), + MoveFrame::Last => Some(Event::LastFrame), + MoveFrame::Next => Some(Event::NextFrame), + MoveFrame::Previous => Some(Event::PreviousFrame), + } + } else if self.toggle_ui { + self.toggle_ui = false; + Some(Event::ToggleUi) + } else if let Some(paused) = self.paused.take() { + Some(Event::Paused(paused)) + } else if let Some(frame) = self.frame_loaded.take() { + Some(Event::FrameLoaded(Some(frame))) + } else if self.done_loading { + self.done_loading = false; + Some(Event::FrameLoaded(None)) + } else if let Some((idx, screen)) = self.render.take() { + Some(Event::Render((idx, screen))) + } else { + None + } + } +} diff --git a/src/bin/ttyplay/main.rs b/src/bin/ttyplay/main.rs index 01eecbc..a51435c 100644 --- a/src/bin/ttyplay/main.rs +++ b/src/bin/ttyplay/main.rs @@ -1,6 +1,7 @@ #![warn(clippy::pedantic)] #![warn(clippy::nursery)] #![allow(clippy::missing_const_for_fn)] +#![allow(clippy::struct_excessive_bools)] use async_std::prelude::FutureExt as _; @@ -170,18 +171,19 @@ async fn async_main(opt: Opt) -> anyhow::Result<()> { let mut display = display::Display::new(); let mut current_screen = vt100::Parser::default().screen().clone(); + let events = event::Reader::new(event_r); loop { - let event = event_r.recv().await?; + let event = events.read().await; match event { - event::Event::Render((idx, screen)) => { + Some(event::Event::Render((idx, screen))) => { current_screen = screen.clone(); display.current_frame(idx); display.render(&screen, &mut output).await?; } - event::Event::Key(key) => { + Some(event::Event::Key(key)) => { input::handle(key, event_w.clone()).await?; } - event::Event::FrameLoaded(n) => { + Some(event::Event::FrameLoaded(n)) => { if let Some(n) = n { display.total_frames(n); } else { @@ -189,40 +191,42 @@ async fn async_main(opt: Opt) -> anyhow::Result<()> { } display.render(¤t_screen, &mut output).await?; } - event::Event::Pause => timer_w.send(TimerAction::Pause).await?, - event::Event::Paused(paused) => { + Some(event::Event::Pause) => { + timer_w.send(TimerAction::Pause).await?; + } + Some(event::Event::Paused(paused)) => { display.paused(paused); display.render(¤t_screen, &mut output).await?; } - event::Event::FirstFrame => { + Some(event::Event::FirstFrame) => { timer_w.send(TimerAction::GotoFrame(0)).await?; } - event::Event::LastFrame => { + Some(event::Event::LastFrame) => { timer_w .send(TimerAction::GotoFrame( display.get_total_frames() - 1, )) .await?; } - event::Event::NextFrame => { + Some(event::Event::NextFrame) => { timer_w .send(TimerAction::GotoFrame( display.get_current_frame() + 1, )) .await?; } - event::Event::PreviousFrame => { + Some(event::Event::PreviousFrame) => { timer_w .send(TimerAction::GotoFrame( display.get_current_frame() - 1, )) .await?; } - event::Event::ToggleUi => { + Some(event::Event::ToggleUi) => { display.toggle_ui(); display.render(¤t_screen, &mut output).await?; } - event::Event::Quit => { + Some(event::Event::Quit) | None => { timer_w.send(TimerAction::Quit).await?; break; } -- cgit v1.2.3-54-g00ecf