aboutsummaryrefslogtreecommitdiffstats
path: root/src/bin/ttyplay/event.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/ttyplay/event.rs')
-rw-r--r--src/bin/ttyplay/event.rs156
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
+ }
+ }
+}