mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-04-03 21:40:44 +02:00
Compare commits
3 commits
bea88ac58d
...
0af46acf36
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0af46acf36 | ||
|
|
c0d8c5f1bb | ||
|
|
dae4d5a140 |
10 changed files with 135 additions and 85 deletions
31
src/draw.rs
31
src/draw.rs
|
|
@ -1,6 +1,12 @@
|
||||||
use crate::{*, lang::*, color::*, space::*};
|
use crate::{*, lang::*, color::*, space::*};
|
||||||
|
|
||||||
/// Drawable that supports dynamic dispatch.
|
/// Drawable that supports dynamic dispatch.
|
||||||
|
///
|
||||||
|
/// Drawables are composable, e.g. the [when] and [either] conditionals
|
||||||
|
/// or the layout constraints.
|
||||||
|
///
|
||||||
|
/// Drawables are consumable, i.e. the [Draw::draw] method receives an
|
||||||
|
/// owned `self` and does not return it, consuming the drawable.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use tengri::draw::*;
|
/// use tengri::draw::*;
|
||||||
|
|
@ -20,25 +26,29 @@ use crate::{*, lang::*, color::*, space::*};
|
||||||
pub trait Draw<T: Screen> {
|
pub trait Draw<T: Screen> {
|
||||||
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>>;
|
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Screen> Draw<T> for () {
|
impl<T: Screen> Draw<T> for () {
|
||||||
fn draw (self, __: &mut T) -> Usually<XYWH<T::Unit>> {
|
fn draw (self, __: &mut T) -> Usually<XYWH<T::Unit>> {
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Screen, D: Draw<T>> Draw<T> for Option<D> {
|
impl<T: Screen, D: Draw<T>> Draw<T> for Option<D> {
|
||||||
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>> {
|
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>> {
|
||||||
Ok(self.map(|draw|draw.draw(to)).transpose()?.unwrap_or_default())
|
Ok(self.map(|draw|draw.draw(to)).transpose()?.unwrap_or_default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn thunk <T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>> (draw: F) -> Thunk<T, F> {
|
||||||
|
Thunk(draw, std::marker::PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
/// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
|
/// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
|
||||||
pub struct Thunk<T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>>(
|
pub struct Thunk<T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>>(
|
||||||
pub F,
|
pub F,
|
||||||
std::marker::PhantomData<T>
|
std::marker::PhantomData<T>
|
||||||
);
|
);
|
||||||
pub const fn thunk <T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>> (draw: F) -> Thunk<T, F> {
|
|
||||||
Thunk(draw, std::marker::PhantomData)
|
|
||||||
}
|
|
||||||
impl<T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>> Draw<T> for Thunk<T, F> {
|
impl<T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>> Draw<T> for Thunk<T, F> {
|
||||||
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>> {
|
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>> {
|
||||||
(self.0)(to)
|
(self.0)(to)
|
||||||
|
|
@ -76,8 +86,8 @@ pub const fn either <T: Screen> (condition: bool, a: impl Draw<T>, b: impl Draw<
|
||||||
///
|
///
|
||||||
/// impl Screen for TestOut {
|
/// impl Screen for TestOut {
|
||||||
/// type Unit = u16;
|
/// type Unit = u16;
|
||||||
/// fn place <T: Draw<Self> + ?Sized> (&mut self, area: impl TwoD<u16>, _: &T) {
|
/// fn place_at <T: Draw<Self> + ?Sized> (&mut self, area: impl TwoD<u16>, _: &T) {
|
||||||
/// println!("place: {area:?}");
|
/// println!("placed: {area:?}");
|
||||||
/// ()
|
/// ()
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
|
|
@ -101,3 +111,14 @@ pub trait Screen: Space<Self::Unit> + Send + Sync + Sized {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emit a [Draw]able.
|
||||||
|
pub trait View<T: Screen> {
|
||||||
|
fn view (&self) -> impl Draw<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Screen, V: View<T>> Draw<T> for &V {
|
||||||
|
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>> {
|
||||||
|
self.view().draw(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
26
src/eval.rs
26
src/eval.rs
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::*;
|
use crate::{*, term::*, draw::*, ratatui::prelude::*};
|
||||||
|
use dizzle::*;
|
||||||
|
|
||||||
/// Interpret layout operation.
|
/// Interpret layout operation.
|
||||||
///
|
///
|
||||||
|
|
@ -165,7 +166,7 @@ use crate::*;
|
||||||
/// impl Understand<Tui, ()> for State {}
|
/// impl Understand<Tui, ()> for State {}
|
||||||
/// # fn main () -> tengri::Usually<()> {
|
/// # fn main () -> tengri::Usually<()> {
|
||||||
/// let state = State;
|
/// let state = State;
|
||||||
/// let mut out = TuiOut::default();
|
/// let mut out = Tui::default();
|
||||||
/// tengri::eval_view_tui(&state, &mut out, "")?;
|
/// tengri::eval_view_tui(&state, &mut out, "")?;
|
||||||
/// tengri::eval_view_tui(&state, &mut out, "text Hello world!")?;
|
/// tengri::eval_view_tui(&state, &mut out, "text Hello world!")?;
|
||||||
/// tengri::eval_view_tui(&state, &mut out, "fg (g 0) (text Hello world!)")?;
|
/// tengri::eval_view_tui(&state, &mut out, "fg (g 0) (text Hello world!)")?;
|
||||||
|
|
@ -174,9 +175,9 @@ use crate::*;
|
||||||
/// # Ok(()) }
|
/// # Ok(()) }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn eval_view_tui <'a, S> (
|
pub fn eval_view_tui <'a, S> (
|
||||||
state: &S, output: &mut Buffer, expr: impl Expression + 'a
|
state: &S, output: &mut Tui, expr: impl Expression + 'a
|
||||||
) -> Usually<bool> where
|
) -> Usually<bool> where
|
||||||
S: Understand<TuiOut, ()>
|
S: Understand<Tui, ()>
|
||||||
+ for<'b>Namespace<'b, bool>
|
+ for<'b>Namespace<'b, bool>
|
||||||
+ for<'b>Namespace<'b, u16>
|
+ for<'b>Namespace<'b, u16>
|
||||||
+ for<'b>Namespace<'b, Color>
|
+ for<'b>Namespace<'b, Color>
|
||||||
|
|
@ -199,18 +200,21 @@ pub fn eval_view_tui <'a, S> (
|
||||||
Some("fg") => {
|
Some("fg") => {
|
||||||
let arg0 = arg0?.expect("fg: expected arg 0 (color)");
|
let arg0 = arg0?.expect("fg: expected arg 0 (color)");
|
||||||
let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("fg: {arg0:?}: not a color"));
|
let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("fg: {arg0:?}: not a color"));
|
||||||
let thunk = Thunk::new(move|output: &mut Buffer|state.understand(output, &arg1).unwrap());
|
output.place(&fg(color, thunk(move|output: &mut Tui|{
|
||||||
output.place(&TuiOut::fg(color, thunk))
|
state.understand(output, &arg1)?;
|
||||||
|
// FIXME?: don't max out the used area?
|
||||||
|
Ok(output.area().into())
|
||||||
|
})))
|
||||||
},
|
},
|
||||||
|
|
||||||
Some("bg") => {
|
Some("bg") => {
|
||||||
//panic!("expr: {expr:?}\nhead: {head:?}\nfrags: {frags:?}\nargs: {args:?}\narg0: {arg0:?}\ntail0: {tail0:?}\narg1: {arg1:?}\ntail1: {tail1:?}\narg2: {arg2:?}");
|
|
||||||
//panic!("head: {head:?}\narg0: {arg0:?}\narg1: {arg1:?}\narg2: {arg2:?}");;
|
|
||||||
//panic!("head: {head:?}\narg0: {arg0:?}\narg1: {arg1:?}\narg2: {arg2:?}");
|
|
||||||
let arg0 = arg0?.expect("bg: expected arg 0 (color)");
|
let arg0 = arg0?.expect("bg: expected arg 0 (color)");
|
||||||
let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("bg: {arg0:?}: not a color"));
|
let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("bg: {arg0:?}: not a color"));
|
||||||
let thunk = Thunk::new(move|output: &mut Buffer|state.understand(output, &arg1).unwrap());
|
output.place(&bg(color, thunk(move|output: &mut Tui|{
|
||||||
output.place(&TuiOut::bg(color, thunk))
|
state.understand(output, &arg1)?;
|
||||||
|
// FIXME?: don't max out the used area?
|
||||||
|
Ok(output.area().into())
|
||||||
|
})))
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => return Ok(false)
|
_ => return Ok(false)
|
||||||
|
|
|
||||||
10
src/exit.rs
Normal file
10
src/exit.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
use std::sync::{Arc, atomic::AtomicBool};
|
||||||
|
use crate::Usually;
|
||||||
|
|
||||||
|
#[derive(Clone)] pub struct Exit(Arc<AtomicBool>);
|
||||||
|
|
||||||
|
impl Exit {
|
||||||
|
pub fn run <T> (run: impl Fn(Self)->Usually<T>) -> Usually<T> {
|
||||||
|
run(Self(Arc::new(AtomicBool::new(false))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::play::Thread;
|
use crate::task::Task;
|
||||||
|
|
||||||
use ::std::sync::{Arc, RwLock, atomic::{AtomicBool, Ordering::*}};
|
use ::std::sync::{Arc, RwLock, atomic::{AtomicBool, Ordering::*}};
|
||||||
use ::std::time::Duration;
|
use ::std::time::Duration;
|
||||||
|
|
@ -10,10 +10,10 @@ use ::crossterm::event::{
|
||||||
/// Spawn the TUI input thread which reads keys from the terminal.
|
/// Spawn the TUI input thread which reads keys from the terminal.
|
||||||
pub fn tui_input <T: Do<TuiEvent, Usually<T>> + Send + Sync + 'static> (
|
pub fn tui_input <T: Do<TuiEvent, Usually<T>> + Send + Sync + 'static> (
|
||||||
exited: &Arc<AtomicBool>, state: &Arc<RwLock<T>>, poll: Duration
|
exited: &Arc<AtomicBool>, state: &Arc<RwLock<T>>, poll: Duration
|
||||||
) -> Result<Thread, std::io::Error> {
|
) -> Result<Task, std::io::Error> {
|
||||||
let exited = exited.clone();
|
let exited = exited.clone();
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
Thread::new_poll(exited.clone(), poll, move |_| {
|
Task::new_poll(exited.clone(), poll, move |_| {
|
||||||
let event = read().unwrap();
|
let event = read().unwrap();
|
||||||
match event {
|
match event {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,14 @@ pub(crate) use ::{
|
||||||
|
|
||||||
#[cfg(feature = "lang")] pub extern crate dizzle as lang;
|
#[cfg(feature = "lang")] pub extern crate dizzle as lang;
|
||||||
#[cfg(feature = "lang")] pub use ::dizzle::{self, Usually, Perhaps, impl_default};
|
#[cfg(feature = "lang")] pub use ::dizzle::{self, Usually, Perhaps, impl_default};
|
||||||
|
#[cfg(feature = "lang")] pub mod eval;
|
||||||
|
|
||||||
#[cfg(feature = "time")] pub mod time;
|
#[cfg(feature = "time")] pub mod time;
|
||||||
|
|
||||||
#[cfg(feature = "play")] pub mod play;
|
#[cfg(feature = "play")] pub mod play;
|
||||||
|
#[cfg(feature = "play")] pub mod exit;
|
||||||
|
#[cfg(feature = "play")] pub mod task;
|
||||||
|
|
||||||
#[cfg(feature = "sing")] pub extern crate jack;
|
#[cfg(feature = "sing")] pub extern crate jack;
|
||||||
#[cfg(feature = "sing")] pub mod sing;
|
#[cfg(feature = "sing")] pub mod sing;
|
||||||
#[cfg(feature = "sing")] pub use ::jack::{*, contrib::{*, ClosureProcessHandler}};
|
#[cfg(feature = "sing")] pub use ::jack::{*, contrib::{*, ClosureProcessHandler}};
|
||||||
|
|
|
||||||
62
src/play.rs
62
src/play.rs
|
|
@ -1,65 +1,5 @@
|
||||||
use crate::{*, time::*, lang::*};
|
use crate::{*, time::*, lang::*};
|
||||||
use ::std::{thread::JoinHandle, time::Duration};
|
use ::std::{thread::JoinHandle, time::Duration};
|
||||||
#[cfg(feature = "term")] use ::crossterm::event::poll;
|
|
||||||
|
|
||||||
#[derive(Clone)] pub struct Exit(Arc<AtomicBool>);
|
|
||||||
|
|
||||||
impl Exit {
|
|
||||||
pub fn run <T> (run: impl Fn(Self)->Usually<T>) -> Usually<T> {
|
|
||||||
run(Self(Arc::new(AtomicBool::new(false))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)] pub struct Thread {
|
|
||||||
/// Exit flag.
|
|
||||||
pub exit: Arc<AtomicBool>,
|
|
||||||
/// Performance counter.
|
|
||||||
pub perf: Arc<PerfModel>,
|
|
||||||
/// Use this to wait for the thread to finish.
|
|
||||||
pub join: JoinHandle<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Thread {
|
|
||||||
/// Spawn a TUI thread that runs `callt least one, then repeats until `exit`.
|
|
||||||
pub fn new <F> (exit: Arc<AtomicBool>, mut call: F) -> Result<Self, std::io::Error>
|
|
||||||
where F: FnMut(&PerfModel)->() + Send + Sync + 'static
|
|
||||||
{
|
|
||||||
let perf = Arc::new(PerfModel::default());
|
|
||||||
Ok(Self {
|
|
||||||
exit: exit.clone(),
|
|
||||||
perf: perf.clone(),
|
|
||||||
join: std::thread::Builder::new().name("tengri tui output".into()).spawn(move || {
|
|
||||||
while !exit.fetch_and(true, Relaxed) {
|
|
||||||
let _ = perf.cycle(&mut call);
|
|
||||||
}
|
|
||||||
})?.into()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Spawn a thread that runs `call` least one, then repeats
|
|
||||||
/// until `exit`, sleeping for `time` msec after every iteration.
|
|
||||||
pub fn new_sleep <F> (
|
|
||||||
exit: Arc<AtomicBool>, time: Duration, mut call: F
|
|
||||||
) -> Result<Self, std::io::Error>
|
|
||||||
where F: FnMut(&PerfModel)->() + Send + Sync + 'static
|
|
||||||
{
|
|
||||||
Self::new(exit, move |perf| { let _ = call(perf); std::thread::sleep(time); })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Spawn a thread that uses [crossterm::event::poll]
|
|
||||||
/// to run `call` every `time` msec.
|
|
||||||
#[cfg(feature = "term")] pub fn new_poll <F> (
|
|
||||||
exit: Arc<AtomicBool>, time: Duration, mut call: F
|
|
||||||
) -> Result<Self, std::io::Error>
|
|
||||||
where F: FnMut(&PerfModel)->() + Send + Sync + 'static
|
|
||||||
{
|
|
||||||
Self::new(exit, move |perf| { if poll(time).is_ok() { let _ = call(perf); } })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn join (self) -> Result<(), Box<dyn std::any::Any + Send>> {
|
|
||||||
self.join.join()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Define an enum containing commands, and implement [Command] trait for over given `State`.
|
/// Define an enum containing commands, and implement [Command] trait for over given `State`.
|
||||||
#[macro_export] macro_rules! def_command (
|
#[macro_export] macro_rules! def_command (
|
||||||
|
|
@ -82,7 +22,7 @@ impl Thread {
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Implement [Handle] for given `State` and `handler`.
|
/// Implement [Handle] for given `State` and `handler`.
|
||||||
#[macro_export] macro_rules! handle {
|
#[macro_export] macro_rules! impl_handle {
|
||||||
(|$self:ident:$State:ty,$input:ident|$handler:expr) => {
|
(|$self:ident:$State:ty,$input:ident|$handler:expr) => {
|
||||||
impl<E: Engine> ::tengri::Handle<E> for $State {
|
impl<E: Engine> ::tengri::Handle<E> for $State {
|
||||||
fn handle (&mut $self, $input: &E) -> Perhaps<E::Handled> {
|
fn handle (&mut $self, $input: &E) -> Perhaps<E::Handled> {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,11 @@ use crate::{*, draw::*};
|
||||||
///
|
///
|
||||||
#[cfg_attr(test, derive(Arbitrary))] #[derive(Copy, Clone, Debug, Default, PartialEq)]
|
#[cfg_attr(test, derive(Arbitrary))] #[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||||
pub struct XYWH<N: Coord>(pub N, pub N, pub N, pub N);
|
pub struct XYWH<N: Coord>(pub N, pub N, pub N, pub N);
|
||||||
|
impl From<&ratatui::prelude::Rect> for XYWH<u16> {
|
||||||
|
fn from (rect: &ratatui::prelude::Rect) -> Self {
|
||||||
|
Self(rect.x, rect.y, rect.width, rect.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<N: Coord> X<N> for XYWH<N> { fn x (&self) -> N { self.0 } fn w (&self) -> N { self.2 } }
|
impl<N: Coord> X<N> for XYWH<N> { fn x (&self) -> N { self.0 } fn w (&self) -> N { self.2 } }
|
||||||
impl<N: Coord> Y<N> for XYWH<N> { fn y (&self) -> N { self.0 } fn h (&self) -> N { self.2 } }
|
impl<N: Coord> Y<N> for XYWH<N> { fn y (&self) -> N { self.0 } fn h (&self) -> N { self.2 } }
|
||||||
impl<N: Coord> XYWH<N> {
|
impl<N: Coord> XYWH<N> {
|
||||||
|
|
|
||||||
65
src/task.rs
Normal file
65
src/task.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
use std::{
|
||||||
|
time::Duration,
|
||||||
|
sync::{Arc, atomic::{AtomicBool, Ordering::*}},
|
||||||
|
thread::{Builder, JoinHandle, sleep},
|
||||||
|
};
|
||||||
|
#[cfg(feature = "term")] use ::crossterm::event::poll;
|
||||||
|
use crate::time::PerfModel;
|
||||||
|
|
||||||
|
#[derive(Debug)] pub struct Task {
|
||||||
|
/// Exit flag.
|
||||||
|
pub exit: Arc<AtomicBool>,
|
||||||
|
/// Performance counter.
|
||||||
|
pub perf: Arc<PerfModel>,
|
||||||
|
/// Use this to wait for the thread to finish.
|
||||||
|
pub join: JoinHandle<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Task {
|
||||||
|
/// Spawn a TUI thread that runs `callt least one, then repeats until `exit`.
|
||||||
|
pub fn new <F> (exit: Arc<AtomicBool>, mut call: F) -> Result<Self, std::io::Error>
|
||||||
|
where F: FnMut(&PerfModel)->() + Send + Sync + 'static
|
||||||
|
{
|
||||||
|
let perf = Arc::new(PerfModel::default());
|
||||||
|
Ok(Self {
|
||||||
|
exit: exit.clone(),
|
||||||
|
perf: perf.clone(),
|
||||||
|
join: Builder::new().name("tengri tui output".into()).spawn(move || {
|
||||||
|
while !exit.fetch_and(true, Relaxed) {
|
||||||
|
let _ = perf.cycle(&mut call);
|
||||||
|
}
|
||||||
|
})?.into()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Spawn a thread that runs `call` least one, then repeats
|
||||||
|
/// until `exit`, sleeping for `time` msec after every iteration.
|
||||||
|
pub fn new_sleep <F> (
|
||||||
|
exit: Arc<AtomicBool>, time: Duration, mut call: F
|
||||||
|
) -> Result<Self, std::io::Error>
|
||||||
|
where F: FnMut(&PerfModel)->() + Send + Sync + 'static
|
||||||
|
{
|
||||||
|
Self::new(exit, move |perf| {
|
||||||
|
let _ = call(perf);
|
||||||
|
sleep(time);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Spawn a thread that uses [crossterm::event::poll]
|
||||||
|
/// to run `call` every `time` msec.
|
||||||
|
#[cfg(feature = "term")] pub fn new_poll <F> (
|
||||||
|
exit: Arc<AtomicBool>, time: Duration, mut call: F
|
||||||
|
) -> Result<Self, std::io::Error>
|
||||||
|
where F: FnMut(&PerfModel)->() + Send + Sync + 'static
|
||||||
|
{
|
||||||
|
Self::new(exit, move |perf| {
|
||||||
|
if poll(time).is_ok() {
|
||||||
|
let _ = call(perf);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn join (self) -> Result<(), Box<dyn std::any::Any + Send>> {
|
||||||
|
self.join.join()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{*, lang::*, play::*, draw::*, space::{*, Split::*}, color::*, text::*};
|
use crate::{*, lang::*, play::*, draw::*, space::{*, Split::*}, color::*, text::*, task::*};
|
||||||
use unicode_width::{UnicodeWidthStr, UnicodeWidthChar};
|
use unicode_width::{UnicodeWidthStr, UnicodeWidthChar};
|
||||||
use rand::distributions::uniform::UniformSampler;
|
use rand::distributions::uniform::UniformSampler;
|
||||||
use ::{
|
use ::{
|
||||||
|
|
@ -509,14 +509,14 @@ pub fn tui_output <W: Write + Send + Sync + 'static, T: Draw<Tui> + Send + Sync
|
||||||
exited: &Arc<AtomicBool>,
|
exited: &Arc<AtomicBool>,
|
||||||
state: &Arc<RwLock<T>>,
|
state: &Arc<RwLock<T>>,
|
||||||
sleep: Duration
|
sleep: Duration
|
||||||
) -> Usually<Thread> {
|
) -> Usually<Task> {
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
tui_setup()?;
|
tui_setup()?;
|
||||||
let mut backend = CrosstermBackend::new(output);
|
let mut backend = CrosstermBackend::new(output);
|
||||||
let Size { width, height } = backend.size().expect("get size failed");
|
let Size { width, height } = backend.size().expect("get size failed");
|
||||||
let mut buffer_a = Buffer::empty(Rect { x: 0, y: 0, width, height });
|
let mut buffer_a = Buffer::empty(Rect { x: 0, y: 0, width, height });
|
||||||
let mut buffer_b = Buffer::empty(Rect { x: 0, y: 0, width, height });
|
let mut buffer_b = Buffer::empty(Rect { x: 0, y: 0, width, height });
|
||||||
Ok(Thread::new_sleep(exited.clone(), sleep, move |perf| {
|
Ok(Task::new_sleep(exited.clone(), sleep, move |perf| {
|
||||||
let Size { width, height } = backend.size().expect("get size failed");
|
let Size { width, height } = backend.size().expect("get size failed");
|
||||||
if let Ok(state) = state.try_read() {
|
if let Ok(state) = state.try_read() {
|
||||||
tui_resize(&mut backend, &mut buffer_a, Rect { x: 0, y: 0, width, height });
|
tui_resize(&mut backend, &mut buffer_a, Rect { x: 0, y: 0, width, height });
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,12 @@ pub(crate) use ::unicode_width::*;
|
||||||
self.as_str().draw(to)
|
self.as_str().draw(to)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Draw<Tui> for &std::sync::Arc<str> {
|
impl Draw<Tui> for std::sync::Arc<str> {
|
||||||
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> {
|
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> {
|
||||||
self.as_ref().draw(to)
|
self.as_ref().draw(to)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Draw<Tui> for std::sync::Arc<str> {
|
impl Draw<Tui> for &std::sync::Arc<str> {
|
||||||
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> {
|
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> {
|
||||||
self.as_ref().draw(to)
|
self.as_ref().draw(to)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue