Migrate topmost widget to AsyncWidget

This commit is contained in:
Joscha 2023-02-18 21:20:40 +01:00
parent 8de5bf87af
commit d5b6dd9802

View file

@ -16,7 +16,8 @@ use parking_lot::FairMutex;
use tokio::sync::mpsc::error::TryRecvError; use tokio::sync::mpsc::error::TryRecvError;
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
use tokio::task; use tokio::task;
use toss::Terminal; use toss::widgets::BoxedAsync;
use toss::{Terminal, WidgetExt};
use crate::config::Config; use crate::config::Config;
use crate::logger::{LogMsg, Logger}; use crate::logger::{LogMsg, Logger};
@ -27,9 +28,8 @@ pub use self::chat::ChatMsg;
use self::chat::ChatState; use self::chat::ChatState;
use self::input::{key, InputEvent, KeyBindingsList}; use self::input::{key, InputEvent, KeyBindingsList};
use self::rooms::Rooms; use self::rooms::Rooms;
use self::widgets::layer::Layer;
use self::widgets::list::ListState; use self::widgets::list::ListState;
use self::widgets::BoxedWidget; use self::widgets::WidgetWrapper;
/// Time to spend batch processing events before redrawing the screen. /// Time to spend batch processing events before redrawing the screen.
const EVENT_PROCESSING_TIME: Duration = Duration::from_millis(1000 / 15); // 15 fps const EVENT_PROCESSING_TIME: Duration = Duration::from_millis(1000 / 15); // 15 fps
@ -143,20 +143,27 @@ impl Ui {
terminal: &mut Terminal, terminal: &mut Terminal,
mut event_rx: UnboundedReceiver<UiEvent>, mut event_rx: UnboundedReceiver<UiEvent>,
crossterm_lock: Arc<FairMutex<()>>, crossterm_lock: Arc<FairMutex<()>>,
) -> io::Result<()> { ) -> Result<(), UiError> {
// Initial render so we don't show a blank screen until the first event let mut redraw = true;
terminal.autoresize()?;
terminal.frame().reset();
self.widget().await.render(terminal.frame()).await;
terminal.present()?;
loop { loop {
// 1. Handle events (in batches) // Redraw if necessary
if redraw {
redraw = false;
terminal.present_async_widget(self.widget().await).await?;
if terminal.measuring_required() {
let _guard = crossterm_lock.lock();
terminal.measure_widths()?;
ok_or_return!(self.event_tx.send(UiEvent::GraphemeWidthsChanged), Ok(()));
}
}
// Handle events (in batches)
let mut event = match event_rx.recv().await { let mut event = match event_rx.recv().await {
Some(event) => event, Some(event) => event,
None => return Ok(()), None => return Ok(()),
}; };
let mut redraw = false;
let end_time = Instant::now() + EVENT_PROCESSING_TIME; let end_time = Instant::now() + EVENT_PROCESSING_TIME;
loop { loop {
match self.handle_event(terminal, &crossterm_lock, event).await { match self.handle_event(terminal, &crossterm_lock, event).await {
@ -173,33 +180,23 @@ impl Ui {
Err(TryRecvError::Disconnected) => return Ok(()), Err(TryRecvError::Disconnected) => return Ok(()),
}; };
} }
if redraw {
// 2. Draw and present resulting state
terminal.autoresize()?;
self.widget().await.render(terminal.frame()).await;
terminal.present()?;
// 3. Measure grapheme widths
if terminal.measuring_required() {
let _guard = crossterm_lock.lock();
terminal.measure_widths()?;
ok_or_return!(self.event_tx.send(UiEvent::GraphemeWidthsChanged), Ok(()));
}
}
} }
} }
async fn widget(&mut self) -> BoxedWidget { async fn widget(&mut self) -> BoxedAsync<'_, UiError> {
let widget = match self.mode { let widget = match self.mode {
Mode::Main => self.rooms.widget().await, Mode::Main => WidgetWrapper::new(self.rooms.widget().await).boxed_async(),
Mode::Log => self.log_chat.widget(String::new(), true).into(), Mode::Log => {
WidgetWrapper::new(self.log_chat.widget(String::new(), true)).boxed_async()
}
}; };
if let Some(key_bindings_list) = &self.key_bindings_list { if let Some(key_bindings_list) = &self.key_bindings_list {
let mut bindings = KeyBindingsList::new(key_bindings_list); let mut bindings = KeyBindingsList::new(key_bindings_list);
self.list_key_bindings(&mut bindings).await; self.list_key_bindings(&mut bindings).await;
Layer::new(vec![widget, bindings.widget()]).into() WidgetWrapper::new(bindings.widget())
.above(widget)
.boxed_async()
} else { } else {
widget widget
} }