Migrate topmost widget to AsyncWidget
This commit is contained in:
parent
8de5bf87af
commit
d5b6dd9802
1 changed files with 26 additions and 29 deletions
55
src/ui.rs
55
src/ui.rs
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue