|
|
|
@ -1,30 +1,34 @@ |
|
|
|
|
mod confirm; |
|
|
|
|
mod main_wnd; |
|
|
|
|
use async_channel::Sender; |
|
|
|
|
pub use confirm::{confirm_wnd, ConfirmWnd}; |
|
|
|
|
pub use confirm::ConfirmWnd; |
|
|
|
|
pub use main_wnd::MainWnd; |
|
|
|
|
|
|
|
|
|
use crate::tui::{ |
|
|
|
|
get_terminal, impls::Id, AsyncChannel, Backend, Frame, GEvent, RetVal, ReturnValue, |
|
|
|
|
GENERAL_EVENT_CHANNEL, |
|
|
|
|
get_terminal, impls::Id, AsyncChannel, Backend, Channel, Frame, GEvent, GENERAL_EVENT_CHANNEL, |
|
|
|
|
}; |
|
|
|
|
use anyhow::Result as AResult; |
|
|
|
|
use crossterm::event::KeyCode; |
|
|
|
|
use once_cell::sync::{Lazy, OnceCell}; |
|
|
|
|
use std::collections::BTreeMap; |
|
|
|
|
use std::sync::Arc; |
|
|
|
|
use std::sync::{Mutex as StdMutex, MutexGuard as StdMutexGuard}; |
|
|
|
|
use std::sync::{Arc, Mutex as StdMutex, MutexGuard as StdMutexGuard}; |
|
|
|
|
use tokio::sync::{Mutex, MutexGuard}; |
|
|
|
|
use tokio::task::{self, JoinHandle}; |
|
|
|
|
use tui::Terminal; |
|
|
|
|
|
|
|
|
|
static WINDOWS: Lazy<Arc<Mutex<WindowsHandler>>> = |
|
|
|
|
Lazy::new(|| Arc::new(Mutex::new(WindowsHandler::new(get_terminal().unwrap())))); |
|
|
|
|
static WINDOWS: Lazy<Arc<Mutex<WM>>> = |
|
|
|
|
Lazy::new(|| Arc::new(Mutex::new(WM::new(get_terminal().unwrap())))); |
|
|
|
|
|
|
|
|
|
static LAST_WND_ID: OnceCell<StdMutex<WndId>> = OnceCell::new(); |
|
|
|
|
|
|
|
|
|
static RETVAL: Lazy<Channel<ReturnVal>> = Lazy::new(|| Channel::new()); |
|
|
|
|
|
|
|
|
|
pub type SharedWnd = Arc<Mutex<dyn Window>>; |
|
|
|
|
|
|
|
|
|
pub enum ReturnVal { |
|
|
|
|
String(String), |
|
|
|
|
None, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)] |
|
|
|
|
pub enum WndEvent { |
|
|
|
|
Key(KeyCode), |
|
|
|
@ -51,7 +55,7 @@ impl Default for WndId { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[async_trait] |
|
|
|
|
pub trait Window: Id<WndId> + RetVal + Send { |
|
|
|
|
pub trait Window: Id<WndId> + Send { |
|
|
|
|
async fn handle_event(&mut self, ev: WndEvent) { |
|
|
|
|
match ev { |
|
|
|
|
WndEvent::Key(k) => { |
|
|
|
@ -60,22 +64,27 @@ pub trait Window: Id<WndId> + RetVal + Send { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async fn close(&mut self, force: bool) { |
|
|
|
|
let rv = self.retval(); |
|
|
|
|
ReturnValue::set(rv); |
|
|
|
|
async fn close(&mut self, force: bool, save_retval: bool) { |
|
|
|
|
let rv = if save_retval { |
|
|
|
|
self.retval() |
|
|
|
|
} else { |
|
|
|
|
ReturnVal::None |
|
|
|
|
}; |
|
|
|
|
RETVAL.send(rv); |
|
|
|
|
GENERAL_EVENT_CHANNEL.send(GEvent::CloseWnd { |
|
|
|
|
wid: self.id(), |
|
|
|
|
force, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn get_chan(&self) -> &'static AsyncChannel<WndEvent>; |
|
|
|
|
fn retval(&self) -> ReturnVal; |
|
|
|
|
|
|
|
|
|
fn into_shared(self) -> SharedWnd |
|
|
|
|
fn wait_retval(self) -> ReturnVal |
|
|
|
|
where |
|
|
|
|
Self: Sized + 'static, |
|
|
|
|
{ |
|
|
|
|
Arc::new(Mutex::new(self)) |
|
|
|
|
GENERAL_EVENT_CHANNEL.send(GEvent::CreateWnd(Arc::new(Mutex::new(self)))); |
|
|
|
|
RETVAL.recv() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async fn handle_update(&mut self) -> AResult<()>; |
|
|
|
@ -88,27 +97,28 @@ pub trait Window: Id<WndId> + RetVal + Send { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct WndLoop { |
|
|
|
|
upd_tx: Sender<WndEvent>, |
|
|
|
|
updater: JoinHandle<()>, |
|
|
|
|
chan: AsyncChannel<WndEvent>, |
|
|
|
|
wnd_loop: JoinHandle<()>, |
|
|
|
|
window: SharedWnd, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl WndLoop { |
|
|
|
|
pub async fn with_wnd(window: SharedWnd) -> Self { |
|
|
|
|
let wnd = window.clone(); |
|
|
|
|
let AsyncChannel { tx, rx } = wnd.lock().await.get_chan(); |
|
|
|
|
let chan = AsyncChannel::<WndEvent>::new(); |
|
|
|
|
let ch = chan.clone(); |
|
|
|
|
let wnd_loop = async move { |
|
|
|
|
loop { |
|
|
|
|
match rx.recv().await { |
|
|
|
|
match ch.recv().await { |
|
|
|
|
Ok(ev) => wnd.lock().await.handle_event(ev).await, |
|
|
|
|
Err(_) => break, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
WndLoop { |
|
|
|
|
upd_tx: tx.clone(), |
|
|
|
|
chan, |
|
|
|
|
window, |
|
|
|
|
updater: task::spawn(wnd_loop), |
|
|
|
|
wnd_loop: task::spawn(wnd_loop), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -116,17 +126,16 @@ impl WndLoop { |
|
|
|
|
let wnd_id = self.window.lock().await.id(); |
|
|
|
|
let event = ev.clone(); |
|
|
|
|
debug!(?event, ?wnd_id, "sending"); |
|
|
|
|
self.upd_tx.send(ev).await.expect("big zhopa"); |
|
|
|
|
self.chan.send(ev).await.expect("send failed"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct WindowsHandler { |
|
|
|
|
pub struct WM { |
|
|
|
|
queue: BTreeMap<WndId, WndLoop>, |
|
|
|
|
term: Terminal<Backend>, |
|
|
|
|
redraw_all: bool, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl WindowsHandler { |
|
|
|
|
impl WM { |
|
|
|
|
fn get_last_wnd(&self) -> &WndLoop { |
|
|
|
|
let last_id = self.queue.keys().rev().next().expect("No windows found"); |
|
|
|
|
self.queue.get(last_id).unwrap() |
|
|
|
@ -140,12 +149,11 @@ impl WindowsHandler { |
|
|
|
|
Self { |
|
|
|
|
term, |
|
|
|
|
queue: BTreeMap::new(), |
|
|
|
|
redraw_all: true, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub async fn push<W: Window + 'static>(&mut self, window: W) -> SharedWnd { |
|
|
|
|
self.push_dyn(window.into_shared()).await |
|
|
|
|
self.push_dyn(Arc::new(Mutex::new(window))).await |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub async fn push_new<W: Window + Default + 'static>(&mut self) -> SharedWnd { |
|
|
|
@ -165,17 +173,17 @@ impl WindowsHandler { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub async fn draw(&mut self) -> AResult<()> { |
|
|
|
|
let wids_to_redraw = if self.redraw_all { |
|
|
|
|
self.redraw_all = false; |
|
|
|
|
self.queue.keys().collect::<Vec<&WndId>>() |
|
|
|
|
} else { |
|
|
|
|
vec![self.queue.keys().last().unwrap()] |
|
|
|
|
}; |
|
|
|
|
for wid in wids_to_redraw { |
|
|
|
|
for wid in self.queue.keys().collect::<Vec<&WndId>>() { |
|
|
|
|
let mut wnd_locked = match self.queue.get(&wid) { |
|
|
|
|
Some(w) => w.window.lock().await, |
|
|
|
|
Some(w) => match w.window.try_lock() { |
|
|
|
|
Ok(w) => w, |
|
|
|
|
Err(_) => { |
|
|
|
|
warn!("Can't lock window {:?}", wid); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
None => { |
|
|
|
|
eprintln!("Can't redraw window {:?}, not found", wid); |
|
|
|
|
warn!("Can't redraw window {:?}, not found", wid); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
@ -188,14 +196,13 @@ impl WindowsHandler { |
|
|
|
|
let wnd = match self.queue.get(&wid) { |
|
|
|
|
Some(w) => w.clone(), |
|
|
|
|
None => { |
|
|
|
|
eprintln!("Can't close window {:?}, not found", wid); |
|
|
|
|
warn!("Can't close window {:?}, not found", wid); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
if wnd.window.lock().await.handle_close().await || force { |
|
|
|
|
let WndLoop { updater, .. } = self.queue.remove(&wid).unwrap(); |
|
|
|
|
updater.abort(); |
|
|
|
|
self.redraw_all = true; |
|
|
|
|
let WndLoop { wnd_loop, .. } = self.queue.remove(&wid).unwrap(); |
|
|
|
|
wnd_loop.abort(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if self.queue.is_empty() { |
|
|
|
|