mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-04-03 21:40:44 +02:00
Compare commits
3 commits
ce2eeaee7f
...
04db6f4af5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04db6f4af5 | ||
|
|
5ceceae523 | ||
|
|
2a7e981b9c |
6 changed files with 134 additions and 128 deletions
|
|
@ -1,36 +1,43 @@
|
||||||
|
#[cfg(test)] use proptest_derive::Arbitrary;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// A point (X, Y).
|
/// A point (X, Y).
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let xy: XY<u16> = XY(0, 0);
|
/// let xy = tengri::output::XY(0u16, 0);
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(test, derive(Arbitrary))]
|
#[cfg_attr(test, derive(Arbitrary))]
|
||||||
#[derive(Copy, Clone, Debug, Default)] pub struct XY<C: Coord>(pub C, pub C);
|
#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct XY<C: Coord>(
|
||||||
|
pub C, pub C
|
||||||
|
);
|
||||||
|
|
||||||
/// A size (Width, Height).
|
/// A size (Width, Height).
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let wh: WH<u16> = WH(0, 0);
|
/// let wh = tengri::output::WH(0u16, 0);
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(test, derive(Arbitrary))]
|
#[cfg_attr(test, derive(Arbitrary))]
|
||||||
#[derive(Copy, Clone, Debug, Default)] pub struct WH<C: Coord>(pub C, pub C);
|
#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct WH<C: Coord>(
|
||||||
|
pub C, pub C
|
||||||
|
);
|
||||||
|
|
||||||
/// Point with size.
|
/// Point with size.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let xywh: XYWH<u16> = XYWH(0, 0, 0, 0);
|
/// let xywh = tengri::output::XYWH(0u16, 0, 0, 0);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// * [ ] TODO: anchor field (determines at which corner/side is X0 Y0)
|
/// * [ ] TODO: anchor field (determines at which corner/side is X0 Y0)
|
||||||
///
|
///
|
||||||
#[cfg_attr(test, derive(Arbitrary))]
|
#[cfg_attr(test, derive(Arbitrary))]
|
||||||
#[derive(Copy, Clone, Debug, Default)] pub struct XYWH<C: Coord>(pub C, pub C, pub C, pub C);
|
#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct XYWH<C: Coord>(
|
||||||
|
pub C, pub C, pub C, pub C
|
||||||
|
);
|
||||||
|
|
||||||
/// A cardinal direction.
|
/// A cardinal direction.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let direction = Direction::Above;
|
/// let direction = tengri::output::Direction::Above;
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(test, derive(Arbitrary))]
|
#[cfg_attr(test, derive(Arbitrary))]
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)] pub enum Direction {
|
#[derive(Copy, Clone, PartialEq, Debug)] pub enum Direction {
|
||||||
|
|
@ -40,7 +47,7 @@ use crate::*;
|
||||||
/// 9th of area to place.
|
/// 9th of area to place.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let alignment = Align::Center;
|
/// let alignment = tengri::output::Alignment::Center;
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(test, derive(Arbitrary))]
|
#[cfg_attr(test, derive(Arbitrary))]
|
||||||
#[derive(Debug, Copy, Clone, Default)] pub enum Alignment {
|
#[derive(Debug, Copy, Clone, Default)] pub enum Alignment {
|
||||||
|
|
@ -50,7 +57,7 @@ use crate::*;
|
||||||
/// A widget that tracks its rendered width and height.
|
/// A widget that tracks its rendered width and height.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let measure = Measure::default();
|
/// let measure = tengri::output::Measure::<tengri::tui::TuiOut>::default();
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Default)] pub struct Measure<O: Out> {
|
#[derive(Default)] pub struct Measure<O: Out> {
|
||||||
pub __: PhantomData<O>,
|
pub __: PhantomData<O>,
|
||||||
|
|
@ -61,70 +68,80 @@ use crate::*;
|
||||||
/// Show an item only when a condition is true.
|
/// Show an item only when a condition is true.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let when = When(true, "Yes");
|
/// fn test () -> impl tengri::output::Draw<tengri::tui::TuiOut> {
|
||||||
|
/// tengri::output::when(true, "Yes")
|
||||||
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct When<O, T>(pub bool, pub T, pub PhantomData<O>);
|
pub struct When<O, T>(pub bool, pub T, pub PhantomData<O>);
|
||||||
|
pub const fn when<O, T>(condition: bool, content: T) -> When<O, T> {
|
||||||
|
When(condition, content, PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
/// Show one item if a condition is true and another if the condition is false.
|
/// Show one item if a condition is true and another if the condition is false.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let either = Either(true, "Yes", "No");
|
/// fn test () -> impl tengri::output::Draw<tengri::tui::TuiOut> {
|
||||||
|
/// tengri::output::either(true, "Yes", "No")
|
||||||
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Either<E: Out, A, B>(pub bool, pub A, pub B, pub PhantomData<E>);
|
pub struct Either<E, A, B>(pub bool, pub A, pub B, pub PhantomData<E>);
|
||||||
|
pub const fn either<E, A, B>(condition: bool, content_a: A, content_b: B) -> Either<E, A, B> {
|
||||||
|
Either(condition, content_a, content_b, PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
/// Increment X and/or Y coordinate.
|
/// Increment X and/or Y coordinate.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let pushed = Push::XY(2, 2, "Hello");
|
/// let pushed = tengri::output::Push::XY(2, 2, "Hello");
|
||||||
/// ```
|
/// ```
|
||||||
pub enum Push<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
pub enum Push<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
/// Decrement X and/or Y coordinate.
|
/// Decrement X and/or Y coordinate.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let pulled = Pull::XY(2, 2, "Hello");
|
/// let pulled = tengri::output::Pull::XY(2, 2, "Hello");
|
||||||
/// ```
|
/// ```
|
||||||
pub enum Pull<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
pub enum Pull<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
/// Set the content to fill the container.
|
/// Set the content to fill the container.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let filled = Fill::XY("Hello");
|
/// let filled = tengri::output::Fill::XY("Hello");
|
||||||
/// ```
|
/// ```
|
||||||
pub enum Fill<A> { X(A), Y(A), XY(A) }
|
pub enum Fill<A> { X(A), Y(A), XY(A) }
|
||||||
|
|
||||||
/// Set fixed size for content.
|
/// Set fixed size for content.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let fixed = Fixed::XY(3, 5, "Hello"); // 3x5
|
/// let fixed = tengri::output::Fixed::XY(3, 5, "Hello"); // 3x5
|
||||||
/// ```
|
/// ```
|
||||||
pub enum Fixed<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
pub enum Fixed<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
/// Set the maximum width and/or height of the content.
|
/// Set the maximum width and/or height of the content.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let maximum = Min::XY(3, 5, "Hello"); // 3x1
|
/// let maximum = tengri::output::Min::XY(3, 5, "Hello"); // 3x1
|
||||||
/// ```
|
/// ```
|
||||||
pub enum Max<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
pub enum Max<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
/// Set the minimum width and/or height of the content.
|
/// Set the minimum width and/or height of the content.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let minimam = Min::XY(3, 5, "Hello"); // 5x5
|
/// let minimam = tengri::output::Min::XY(3, 5, "Hello"); // 5x5
|
||||||
/// ```
|
/// ```
|
||||||
pub enum Min<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
pub enum Min<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
/// Decrease the width and/or height of the content.
|
/// Decrease the width and/or height of the content.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let shrunk = Shrink::XY(2, 0, "Hello"); // 1x1
|
/// let shrunk = tengri::output::Shrink::XY(2, 0, "Hello"); // 1x1
|
||||||
/// ```
|
/// ```
|
||||||
pub enum Shrink<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
pub enum Shrink<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
/// Increaase the width and/or height of the content.
|
/// Increaase the width and/or height of the content.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let expanded = Expand::XY(5, 3, "HELLO"); // 15x3
|
/// let expanded = tengri::output::Expand::XY(5, 3, "HELLO"); // 15x3
|
||||||
/// ```
|
/// ```
|
||||||
pub enum Expand<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
pub enum Expand<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
|
|
@ -134,9 +151,9 @@ pub enum Expand<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
/// ```
|
/// ```
|
||||||
/// use ::tengri::{output::*, tui::*};
|
/// use ::tengri::{output::*, tui::*};
|
||||||
/// let area = XYWH(10u16, 10, 20, 20);
|
/// let area = XYWH(10u16, 10, 20, 20);
|
||||||
/// fn test (area: XYWH<16>, item: &impl Draw<TuiOut>, expected: [u16;4]) {
|
/// fn test (area: XYWH<u16>, item: &impl Draw<TuiOut>, expected: [u16;4]) {
|
||||||
/// assert_eq!(Content::layout(item, area), expected);
|
/// //assert_eq!(Lay::layout(item, area), expected);
|
||||||
/// assert_eq!(Draw::layout(item, area), expected);
|
/// //assert_eq!(Draw::layout(item, area), expected);
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// let four = ||Fixed::XY(4, 4, "");
|
/// let four = ||Fixed::XY(4, 4, "");
|
||||||
|
|
@ -167,14 +184,17 @@ pub enum Pad<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
/// TODO DOCUMENTME
|
/// TODO DOCUMENTME
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let bounded = Bounded(XYWH(0, 0, 0, 0), "");
|
/// use tengri::output::{Bounded, XYWH};
|
||||||
|
/// let area = XYWH(0, 0, 0, 0);
|
||||||
|
/// let content = "";
|
||||||
|
/// let bounded: Bounded<tengri::tui::TuiOut, _> = Bounded(area, content);
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Bounded<O: Out, D>(pub XYWH<O::Unit>, pub D);
|
pub struct Bounded<O: Out, D>(pub XYWH<O::Unit>, pub D);
|
||||||
|
|
||||||
/// Draws items from an iterator.
|
/// Draws items from an iterator.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let map = Map(||[].iter(), |_|{});
|
/// // FIXME let map = tengri::output::Map(||[].iter(), |_|{});
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Map<O, A, B, I, F, G>
|
pub struct Map<O, A, B, I, F, G>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use proptest_derive::Arbitrary;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
#[test] fn test_area () {
|
#[test] fn test_area () {
|
||||||
assert_eq!(Area::center(&[10u16, 10, 20, 20]), [20, 20]);
|
assert_eq!(XYWH(10u16, 10, 20, 20).center(), XY(20, 20));
|
||||||
}
|
}
|
||||||
|
|
||||||
proptest! {
|
proptest! {
|
||||||
|
|
@ -19,7 +19,7 @@ proptest! {
|
||||||
h in u16::MIN..u16::MAX,
|
h in u16::MIN..u16::MAX,
|
||||||
a in u16::MIN..u16::MAX,
|
a in u16::MIN..u16::MAX,
|
||||||
) {
|
) {
|
||||||
let _ = d.split_fixed([x, y, w, h], a);
|
let _ = d.split_fixed(XYWH(x, y, w, h), a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,27 +32,27 @@ proptest! {
|
||||||
a in u16::MIN..u16::MAX,
|
a in u16::MIN..u16::MAX,
|
||||||
b in u16::MIN..u16::MAX,
|
b in u16::MIN..u16::MAX,
|
||||||
) {
|
) {
|
||||||
let _: [u16;4] = <[u16;4] as Area<u16>>::zero();
|
let _: XYWH<u16> = XYWH::zero();
|
||||||
let _: [u16;4] = <[u16;4] as Area<u16>>::from_position([a, b]);
|
//let _: XYWH<u16> = XYWH::from_position([a, b]);
|
||||||
let _: [u16;4] = <[u16;4] as Area<u16>>::from_size([a, b]);
|
//let _: XYWH<u16> = XYWH::from_size([a, b]);
|
||||||
let area: [u16;4] = [x, y, w, h];
|
let area: XYWH<u16> = XYWH(x, y, w, h);
|
||||||
let _ = area.expect_min(a, b);
|
//let _ = area.expect_min(a, b);
|
||||||
let _ = area.xy();
|
let _ = area.xy();
|
||||||
let _ = area.wh();
|
let _ = area.wh();
|
||||||
let _ = area.xywh();
|
//let _ = area.xywh();
|
||||||
let _ = area.clip_h(a);
|
let _ = area.clipped_h(a);
|
||||||
let _ = area.clip_w(b);
|
let _ = area.clipped_w(b);
|
||||||
let _ = area.clip([a, b]);
|
let _ = area.clipped(WH(a, b));
|
||||||
let _ = area.set_w(a);
|
//let _ = area.set_w(a);
|
||||||
let _ = area.set_h(b);
|
//let _ = area.set_h(b);
|
||||||
let _ = area.x2();
|
let _ = area.x2();
|
||||||
let _ = area.y2();
|
let _ = area.y2();
|
||||||
let _ = area.lrtb();
|
let _ = area.lrtb();
|
||||||
let _ = area.center();
|
let _ = area.center();
|
||||||
let _ = area.center_x(a);
|
|
||||||
let _ = area.center_y(b);
|
|
||||||
let _ = area.center_xy([a, b]);
|
|
||||||
let _ = area.centered();
|
let _ = area.centered();
|
||||||
|
let _ = area.centered_x(a);
|
||||||
|
let _ = area.centered_y(b);
|
||||||
|
let _ = area.centered_xy([a, b]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,15 +63,15 @@ proptest! {
|
||||||
a in u16::MIN..u16::MAX,
|
a in u16::MIN..u16::MAX,
|
||||||
b in u16::MIN..u16::MAX,
|
b in u16::MIN..u16::MAX,
|
||||||
) {
|
) {
|
||||||
let size = [x, y];
|
let size = WH(x, y);
|
||||||
let _ = size.w();
|
let _ = size.w();
|
||||||
let _ = size.h();
|
let _ = size.h();
|
||||||
let _ = size.wh();
|
let _ = size.wh();
|
||||||
let _ = size.clip_w(a);
|
let _ = size.clip_w(a);
|
||||||
let _ = size.clip_h(b);
|
let _ = size.clip_h(b);
|
||||||
let _ = size.expect_min(a, b);
|
//let _ = size.expect_min(a, b);
|
||||||
let _ = size.to_area_pos();
|
//let _ = size.to_area_pos();
|
||||||
let _ = size.to_area_size();
|
//let _ = size.to_area_size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,12 @@ use crate::*;
|
||||||
/// Drawing target.
|
/// Drawing target.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use crate::*;
|
/// use tengri::output::*;
|
||||||
/// struct TestOut([u16;4]);
|
/// struct TestOut(XYWH<u16>);
|
||||||
/// impl Out for TestOut {
|
/// impl Out for TestOut {
|
||||||
/// type Unit = u16;
|
/// type Unit = u16;
|
||||||
/// type Size = [u16;2];
|
/// fn area (&self) -> XYWH<u16> { self.0 }
|
||||||
/// type Area = [u16;4];
|
/// fn area_mut (&mut self) -> &mut XYWH<u16> { &mut self.0 }
|
||||||
/// fn area (&self) -> [u16;4] {
|
|
||||||
/// self.0
|
|
||||||
/// }
|
|
||||||
/// fn area_mut (&mut self) -> &mut [u16;4] {
|
|
||||||
/// &mut self.0
|
|
||||||
/// }
|
|
||||||
/// fn place_at <T: Draw<Self> + ?Sized> (&mut self, area: XYWH<u16>, _: &T) {
|
/// fn place_at <T: Draw<Self> + ?Sized> (&mut self, area: XYWH<u16>, _: &T) {
|
||||||
/// println!("place_at: {area:?}");
|
/// println!("place_at: {area:?}");
|
||||||
/// ()
|
/// ()
|
||||||
|
|
@ -22,7 +16,7 @@ use crate::*;
|
||||||
/// }
|
/// }
|
||||||
/// impl Draw<TestOut> for String {
|
/// impl Draw<TestOut> for String {
|
||||||
/// fn draw (&self, to: &mut TestOut) {
|
/// fn draw (&self, to: &mut TestOut) {
|
||||||
/// to.area_mut().set_w(self.len() as u16);
|
/// //to.area_mut().set_w(self.len() as u16);
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,16 @@
|
||||||
#![feature(type_changing_struct_update, trait_alias)]
|
#![feature(type_changing_struct_update, trait_alias)]
|
||||||
|
pub extern crate dizzle;
|
||||||
|
pub extern crate tengri_input;
|
||||||
|
pub extern crate tengri_output;
|
||||||
|
pub extern crate ratatui;
|
||||||
|
pub extern crate crossterm;
|
||||||
|
pub extern crate palette;
|
||||||
|
pub extern crate better_panic;
|
||||||
|
pub use ::tengri_output::PerfModel;
|
||||||
use std::{time::Duration, thread::{spawn, JoinHandle}, io::Write};
|
use std::{time::Duration, thread::{spawn, JoinHandle}, io::Write};
|
||||||
use unicode_width::*;
|
use unicode_width::*;
|
||||||
|
|
||||||
pub use ::{
|
|
||||||
dizzle,
|
|
||||||
tengri_input,
|
|
||||||
tengri_output::{self, PerfModel},
|
|
||||||
ratatui,
|
|
||||||
crossterm,
|
|
||||||
palette,
|
|
||||||
better_panic,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub(crate) use ::{
|
pub(crate) use ::{
|
||||||
dizzle::*,
|
dizzle::*, tengri_input::*, tengri_output::*,
|
||||||
tengri_input::*,
|
|
||||||
tengri_output::*,
|
|
||||||
atomic_float::AtomicF64,
|
|
||||||
std::{io::{stdout, Stdout}, sync::{Arc, RwLock, atomic::{AtomicBool, Ordering::*}}},
|
std::{io::{stdout, Stdout}, sync::{Arc, RwLock, atomic::{AtomicBool, Ordering::*}}},
|
||||||
better_panic::{Settings, Verbosity},
|
better_panic::{Settings, Verbosity},
|
||||||
palette::{*, convert::*, okhsl::*},
|
palette::{*, convert::*, okhsl::*},
|
||||||
|
|
@ -38,8 +31,7 @@ pub(crate) use ::{
|
||||||
#[macro_export] macro_rules! tui_main {
|
#[macro_export] macro_rules! tui_main {
|
||||||
($expr:expr) => {
|
($expr:expr) => {
|
||||||
fn main () -> Usually<()> {
|
fn main () -> Usually<()> {
|
||||||
let state = Arc::new(RwLock::new($expr));
|
tengri_tui::Tui::run(true, $expr)?;
|
||||||
tengri_tui::Tui::new().unwrap().run(&state)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -80,12 +72,14 @@ macro_rules! border {
|
||||||
)+}
|
)+}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod tui_structs; pub use self::tui_structs::*;
|
mod tui_structs; pub use self::tui_structs::*;
|
||||||
mod tui_traits; pub use self::tui_traits::*;
|
mod tui_traits; pub use self::tui_traits::*;
|
||||||
mod tui_impls; pub use self::tui_impls::*;
|
mod tui_impls;
|
||||||
|
#[cfg(test)] mod tui_test;
|
||||||
|
|
||||||
/// Run an app in the main loop.
|
/// Run an app in the main loop.
|
||||||
pub fn tui_run <T: Send + Sync + Draw<TuiOut> + Handle<TuiIn> + 'static> (
|
pub fn tui_run <T: Send + Sync + Draw<TuiOut> + Handle<TuiIn> + 'static> (
|
||||||
|
join: bool,
|
||||||
state: &Arc<RwLock<T>>
|
state: &Arc<RwLock<T>>
|
||||||
) -> Usually<Arc<RwLock<Tui>>> {
|
) -> Usually<Arc<RwLock<Tui>>> {
|
||||||
let backend = CrosstermBackend::new(stdout());
|
let backend = CrosstermBackend::new(stdout());
|
||||||
|
|
@ -100,15 +94,17 @@ pub fn tui_run <T: Send + Sync + Draw<TuiOut> + Handle<TuiIn> + 'static> (
|
||||||
let _input_thread = tui_input(tui.clone(), state, Duration::from_millis(100));
|
let _input_thread = tui_input(tui.clone(), state, Duration::from_millis(100));
|
||||||
tui.write().unwrap().setup()?;
|
tui.write().unwrap().setup()?;
|
||||||
let render_thread = tui_output(tui.clone(), state, Duration::from_millis(10))?;
|
let render_thread = tui_output(tui.clone(), state, Duration::from_millis(10))?;
|
||||||
match render_thread.join() {
|
if join {
|
||||||
Ok(result) => {
|
match render_thread.join() {
|
||||||
tui.write().unwrap().teardown()?;
|
Ok(result) => {
|
||||||
println!("\n\rRan successfully: {result:?}\n\r");
|
tui.write().unwrap().teardown()?;
|
||||||
},
|
println!("\n\rRan successfully: {result:?}\n\r");
|
||||||
Err(error) => {
|
},
|
||||||
tui.write().unwrap().teardown()?;
|
Err(error) => {
|
||||||
panic!("\n\rDraw thread failed: error={error:?}.\n\r")
|
tui.write().unwrap().teardown()?;
|
||||||
},
|
panic!("\n\rDraw thread failed: error={error:?}.\n\r")
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(tui)
|
Ok(tui)
|
||||||
}
|
}
|
||||||
|
|
@ -492,41 +488,3 @@ pub(crate) fn width_chars_max (max: u16, text: impl AsRef<str>) -> u16 {
|
||||||
}
|
}
|
||||||
return width
|
return width
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)] mod tui_test {
|
|
||||||
use crate::*;
|
|
||||||
#[test] fn test_tui_engine () -> Usually<()> {
|
|
||||||
//use std::sync::{Arc, RwLock};
|
|
||||||
struct TestComponent(String);
|
|
||||||
impl HasContent<TuiOut> for TestComponent {
|
|
||||||
fn content (&self) -> impl Content<TuiOut> {
|
|
||||||
Some(self.0.as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Handle<TuiIn> for TestComponent {
|
|
||||||
fn handle (&mut self, _from: &TuiIn) -> Perhaps<bool> {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let engine = Tui::new()?;
|
|
||||||
engine.read().unwrap().exited.store(true, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
let state = TestComponent("hello world".into());
|
|
||||||
let _state = std::sync::Arc::new(std::sync::RwLock::new(state));
|
|
||||||
//engine.run(&state)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
//#[test] fn test_parse_key () {
|
|
||||||
////use KeyModifiers as Mods;
|
|
||||||
//let _test = |x: &str, y|assert_eq!(KeyMatcher::new(x).build(), Some(Event::Key(y)));
|
|
||||||
////test(":x",
|
|
||||||
////KeyEvent::new(KeyCode::Char('x'), Mods::NONE));
|
|
||||||
////test(":ctrl-x",
|
|
||||||
////KeyEvent::new(KeyCode::Char('x'), Mods::CONTROL));
|
|
||||||
////test(":alt-x",
|
|
||||||
////KeyEvent::new(KeyCode::Char('x'), Mods::ALT));
|
|
||||||
////test(":shift-x",
|
|
||||||
////KeyEvent::new(KeyCode::Char('x'), Mods::SHIFT));
|
|
||||||
////test(":ctrl-alt-shift-x",
|
|
||||||
////KeyEvent::new(KeyCode::Char('x'), Mods::CONTROL | Mods::ALT | Mods::SHIFT ));
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@ use rand::{thread_rng, distributions::uniform::UniformSampler};
|
||||||
|
|
||||||
impl Tui {
|
impl Tui {
|
||||||
/// Create and launch a terminal user interface.
|
/// Create and launch a terminal user interface.
|
||||||
pub fn run <T: Send + Sync + Handle<TuiIn> + Draw<TuiOut> + 'static> (
|
pub fn run <T> (join: bool, state: T) -> Usually<Arc<RwLock<Self>>> where
|
||||||
state: &Arc<RwLock<T>>
|
T: Handle<TuiIn> + Draw<TuiOut> + Send + Sync + 'static
|
||||||
) -> Usually<Arc<RwLock<Self>>> {
|
{
|
||||||
tui_run(state)
|
tui_run(join, &Arc::new(RwLock::new(state)))
|
||||||
}
|
}
|
||||||
/// True if done
|
/// True if done
|
||||||
pub fn exited (&self) -> bool { self.exited.fetch_and(true, Relaxed) }
|
pub fn exited (&self) -> bool { self.exited.fetch_and(true, Relaxed) }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
#[test] fn test_tui_engine () -> Usually<()> {
|
||||||
|
//use std::sync::{Arc, RwLock};
|
||||||
|
struct TestComponent(String);
|
||||||
|
impl Draw<TuiOut> for TestComponent {
|
||||||
|
fn draw (&self, _to: &mut TuiOut) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Handle<TuiIn> for TestComponent {
|
||||||
|
fn handle (&mut self, _from: &TuiIn) -> Perhaps<bool> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let engine = Tui::run(false, TestComponent("hello world".into()))?;
|
||||||
|
engine.read().unwrap().exited.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
//engine.run(&state)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
//#[test] fn test_parse_key () {
|
||||||
|
////use KeyModifiers as Mods;
|
||||||
|
//let _test = |x: &str, y|assert_eq!(KeyMatcher::new(x).build(), Some(Event::Key(y)));
|
||||||
|
////test(":x",
|
||||||
|
////KeyEvent::new(KeyCode::Char('x'), Mods::NONE));
|
||||||
|
////test(":ctrl-x",
|
||||||
|
////KeyEvent::new(KeyCode::Char('x'), Mods::CONTROL));
|
||||||
|
////test(":alt-x",
|
||||||
|
////KeyEvent::new(KeyCode::Char('x'), Mods::ALT));
|
||||||
|
////test(":shift-x",
|
||||||
|
////KeyEvent::new(KeyCode::Char('x'), Mods::SHIFT));
|
||||||
|
////test(":ctrl-alt-shift-x",
|
||||||
|
////KeyEvent::new(KeyCode::Char('x'), Mods::CONTROL | Mods::ALT | Mods::SHIFT ));
|
||||||
|
//}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue