diff options
Diffstat (limited to 'src/bin/ttyplay/event.rs')
-rw-r--r-- | src/bin/ttyplay/event.rs | 156 |
1 files changed, 156 insertions, 0 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<Pending>, + cvar: async_std::sync::Condvar, +} + +impl Reader { + pub fn new( + input: async_std::channel::Receiver<Event>, + ) -> async_std::sync::Arc<Self> { + 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<Event> { + 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<textmode::Key>, + frame_loaded: Option<usize>, + done_loading: bool, + pause: bool, + paused: Option<bool>, + frame_controls: std::collections::VecDeque<MoveFrame>, + 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<Event> { + 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 + } + } +} |