From 3bbe52b797469f42d22b2731ec99520717519fa8 Mon Sep 17 00:00:00 2001 From: Joscha Date: Wed, 20 Jul 2022 22:56:00 +0200 Subject: [PATCH] Render entire UI using widgets --- src/ui.rs | 35 ++++++++++++++++++++++------------- src/ui/rooms.rs | 13 ++++++------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/ui.rs b/src/ui.rs index c4b11f2..0b70c50 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -14,7 +14,6 @@ use parking_lot::FairMutex; use tokio::sync::mpsc::error::TryRecvError; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio::task; -use toss::frame::Frame; use toss::terminal::Terminal; use crate::logger::{LogMsg, Logger}; @@ -22,7 +21,7 @@ use crate::vault::Vault; use self::chat::ChatState; use self::rooms::Rooms; -use self::widgets::Widget; +use self::widgets::BoxedWidget; #[derive(Debug)] pub enum UiEvent { @@ -121,26 +120,32 @@ impl Ui { mut event_rx: UnboundedReceiver, crossterm_lock: Arc>, ) -> anyhow::Result<()> { - loop { - // 1. Render current state - terminal.autoresize()?; - self.render(terminal.frame()).await?; - terminal.present()?; + // Initial render so we don't show a blank screen until the first event + terminal.autoresize()?; + terminal.frame().reset(); + self.widget().await.render(terminal.frame()).await; + terminal.present()?; - // 2. Measure widths if required + loop { + // 1. Measure grapheme widths if required if terminal.measuring_required() { let _guard = crossterm_lock.lock(); terminal.measure_widths()?; self.event_tx.send(UiEvent::Redraw)?; } - // 3. Handle events (in batches) + // 2. Handle events (in batches) let mut event = match event_rx.recv().await { Some(event) => event, None => return Ok(()), }; terminal.autoresize()?; loop { + // Render in-between events so the next event is handled in an + // up-to-date state. The results of these intermediate renders + // will be thrown away before the final render. + self.widget().await.render(terminal.frame()).await; + let result = match event { UiEvent::Redraw => EventHandleResult::Continue, UiEvent::Term(Event::Key(event)) => { @@ -160,15 +165,19 @@ impl Ui { Err(TryRecvError::Disconnected) => return Ok(()), }; } + + // 3. Render and present final state + terminal.frame().reset(); + self.widget().await.render(terminal.frame()).await; + terminal.present()?; } } - async fn render(&mut self, frame: &mut Frame) -> anyhow::Result<()> { + async fn widget(&mut self) -> BoxedWidget { match self.mode { - Mode::Main => self.rooms.render(frame).await, - Mode::Log => Box::new(self.log_chat.widget()).render(frame).await, + Mode::Main => self.rooms.widget().await, + Mode::Log => self.log_chat.widget().into(), } - Ok(()) } async fn handle_key_event( diff --git a/src/ui/rooms.rs b/src/ui/rooms.rs index b00cb8e..b216696 100644 --- a/src/ui/rooms.rs +++ b/src/ui/rooms.rs @@ -6,7 +6,6 @@ use crossterm::event::{KeyCode, KeyEvent}; use crossterm::style::{ContentStyle, Stylize}; use parking_lot::FairMutex; use tokio::sync::mpsc; -use toss::frame::Frame; use toss::styled::Styled; use toss::terminal::Terminal; @@ -18,7 +17,7 @@ use super::room::EuphRoom; use super::widgets::background::Background; use super::widgets::list::{List, ListState}; use super::widgets::text::Text; -use super::widgets::Widget; +use super::widgets::BoxedWidget; use super::{util, UiEvent}; pub struct Rooms { @@ -67,14 +66,14 @@ impl Rooms { rooms } - pub async fn render(&mut self, frame: &mut Frame) { + pub async fn widget(&mut self) -> BoxedWidget { if let Some(room) = &self.focus { let actual_room = self.euph_rooms.entry(room.clone()).or_insert_with(|| { EuphRoom::new(self.vault.euph(room.clone()), self.ui_event_tx.clone()) }); - actual_room.widget().await.render(frame).await; + actual_room.widget().await } else { - self.render_rooms(frame).await; + self.rooms_widget().await } } @@ -148,11 +147,11 @@ impl Rooms { } } - async fn render_rooms(&mut self, frame: &mut Frame) { + async fn rooms_widget(&mut self) -> BoxedWidget { let rooms = self.stabilize_rooms().await; let mut list = self.list.list().focus(true); self.render_rows(&mut list, rooms).await; - Box::new(list).render(frame).await; + list.into() } pub async fn handle_key_event(