mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
separate Input and Output impls
This commit is contained in:
parent
a6efde40f8
commit
0e821e098f
77 changed files with 465 additions and 454 deletions
|
|
@ -4,10 +4,11 @@ pub use ::tek_edn;
|
|||
pub(crate) use tek_layout::*;
|
||||
pub(crate) use tek_engine::*;
|
||||
|
||||
mod tui_engine; pub use self::tui_engine::*;
|
||||
mod tui_input; pub use self::tui_input::*;
|
||||
mod tui_output; pub use self::tui_output::*;
|
||||
mod tui_run; pub use self::tui_run::*;
|
||||
mod tui_engine; pub use self::tui_engine::*;
|
||||
mod tui_content; pub use self::tui_content::*;
|
||||
mod tui_input; pub use self::tui_input::*;
|
||||
mod tui_output; pub use self::tui_output::*;
|
||||
mod tui_run; pub use self::tui_run::*;
|
||||
|
||||
mod tui_color; pub use self::tui_color::*;
|
||||
mod tui_style; pub use self::tui_style::*;
|
||||
|
|
@ -41,12 +42,12 @@ pub(crate) use ratatui::{
|
|||
use crate::tui::*;
|
||||
use std::sync::{Arc, RwLock};
|
||||
struct TestComponent(String);
|
||||
impl Content<Tui> for TestComponent {
|
||||
fn content (&self) -> Option<impl Content<Tui>> {
|
||||
impl Content<TuiOut> for TestComponent {
|
||||
fn content (&self) -> Option<impl Content<TuiOut>> {
|
||||
Some(self.0.as_str())
|
||||
}
|
||||
}
|
||||
impl Handle<Tui> for TestComponent {
|
||||
impl Handle<TuiIn> for TestComponent {
|
||||
fn handle (&mut self, from: &TuiIn) -> Perhaps<bool> {
|
||||
Ok(None)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct Bordered<S: BorderStyle, W: Content<Tui>>(pub S, pub W);
|
||||
pub struct Bordered<S: BorderStyle, W: Content<TuiOut>>(pub S, pub W);
|
||||
|
||||
render!(Tui: (self: Bordered<S: BorderStyle, W: Content<Tui>>) => {
|
||||
render!(TuiOut: (self: Bordered<S: BorderStyle, W: Content<TuiOut>>) => {
|
||||
Fill::xy(lay!(Border(self.0), Padding::xy(1, 1, &self.1)))
|
||||
});
|
||||
|
||||
pub struct Border<S: BorderStyle>(pub S);
|
||||
|
||||
render!(Tui: |self: Border<S: BorderStyle>, to| {
|
||||
render!(TuiOut: |self: Border<S: BorderStyle>, to| {
|
||||
let area = to.area();
|
||||
if area.w() > 0 && area.y() > 0 {
|
||||
to.blit(&self.0.nw(), area.x(), area.y(), self.0.style());
|
||||
|
|
@ -27,13 +27,13 @@ render!(Tui: |self: Border<S: BorderStyle>, to| {
|
|||
});
|
||||
|
||||
pub trait BorderStyle: Send + Sync + Copy {
|
||||
fn wrap <W: Content<Tui>> (self, w: W) -> Bordered<Self, W> {
|
||||
fn wrap <W: Content<TuiOut>> (self, w: W) -> Bordered<Self, W> {
|
||||
Bordered(self, w)
|
||||
}
|
||||
fn enclose <W: Content<Tui>> (self, w: W) -> impl Content<Tui> {
|
||||
fn enclose <W: Content<TuiOut>> (self, w: W) -> impl Content<TuiOut> {
|
||||
lay!(Fill::xy(Border(self)), w)
|
||||
}
|
||||
fn enclose_bg <W: Content<Tui>> (self, w: W) -> impl Content<Tui> {
|
||||
fn enclose_bg <W: Content<TuiOut>> (self, w: W) -> impl Content<TuiOut> {
|
||||
Tui::bg(self.style().unwrap().bg.unwrap_or(Color::Reset), lay!(
|
||||
Fill::xy(Border(self)),
|
||||
w
|
||||
|
|
@ -137,7 +137,7 @@ macro_rules! border {
|
|||
}
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct $T(pub Style);
|
||||
impl Content<Tui> for $T {
|
||||
impl Content<TuiOut> for $T {
|
||||
fn render (&self, to: &mut TuiOut) { self.draw(to); }
|
||||
}
|
||||
)+}
|
||||
|
|
|
|||
19
tui/src/tui_content.rs
Normal file
19
tui/src/tui_content.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use crate::*;
|
||||
|
||||
impl Content<TuiOut> for &str {
|
||||
fn layout (&self, to: [u16;4]) -> [u16;4] {
|
||||
to.center_xy([self.chars().count() as u16, 1])
|
||||
}
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
to.blit(self, to.area.x(), to.area.y(), None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Content<TuiOut> for String {
|
||||
fn layout (&self, to: [u16;4]) -> [u16;4] {
|
||||
to.center_xy([self.chars().count() as u16, 1])
|
||||
}
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
to.blit(self, to.area.x(), to.area.y(), None)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,12 +8,8 @@ pub struct Tui {
|
|||
}
|
||||
|
||||
impl Engine for Tui {
|
||||
type Unit = u16;
|
||||
type Size = [Self::Unit;2];
|
||||
type Area = [Self::Unit;4];
|
||||
type Input = TuiIn;
|
||||
type Handled = bool;
|
||||
type Output = TuiOut;
|
||||
type Input = TuiIn;
|
||||
type Output = TuiOut;
|
||||
fn exited (&self) -> bool {
|
||||
self.exited.fetch_and(true, Relaxed)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ use Event as CrosstermEvent;
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct TuiIn(pub Arc<AtomicBool>, pub CrosstermEvent);
|
||||
|
||||
impl Input<Tui> for TuiIn {
|
||||
impl Input for TuiIn {
|
||||
type Event = Event;
|
||||
type Handled = bool;
|
||||
fn event (&self) -> &CrosstermEvent { &self.1 }
|
||||
fn is_done (&self) -> bool { self.0.fetch_and(true, Relaxed) }
|
||||
fn done (&self) { self.0.store(true, Relaxed); }
|
||||
|
|
|
|||
|
|
@ -5,10 +5,13 @@ pub struct TuiOut {
|
|||
pub area: [u16;4]
|
||||
}
|
||||
|
||||
impl Output<Tui> for TuiOut {
|
||||
impl Output for TuiOut {
|
||||
type Unit = u16;
|
||||
type Size = [Self::Unit;2];
|
||||
type Area = [Self::Unit;4];
|
||||
#[inline] fn area (&self) -> [u16;4] { self.area }
|
||||
#[inline] fn area_mut (&mut self) -> &mut [u16;4] { &mut self.area }
|
||||
#[inline] fn place (&mut self, area: [u16;4], content: &impl Render<Tui>) {
|
||||
#[inline] fn place (&mut self, area: [u16;4], content: &impl Render<TuiOut>) {
|
||||
let last = self.area();
|
||||
*self.area_mut() = area;
|
||||
content.render(self);
|
||||
|
|
@ -65,24 +68,6 @@ impl TuiOut {
|
|||
}
|
||||
}
|
||||
|
||||
impl Content<Tui> for &str {
|
||||
fn layout (&self, to: [u16;4]) -> [u16;4] {
|
||||
to.center_xy([self.chars().count() as u16, 1])
|
||||
}
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
to.blit(self, to.area.x(), to.area.y(), None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Content<Tui> for String {
|
||||
fn layout (&self, to: [u16;4]) -> [u16;4] {
|
||||
to.center_xy([self.chars().count() as u16, 1])
|
||||
}
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
to.blit(self, to.area.x(), to.area.y(), None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut Cell, u16, u16)) {
|
||||
for row in 0..area.h() {
|
||||
let y = area.y() + row;
|
||||
|
|
@ -113,4 +98,4 @@ pub fn half_block (lower: bool, upper: bool) -> Option<char> {
|
|||
}
|
||||
}
|
||||
|
||||
//impl<T: Content<Tui>> Render<Tui> for T {}
|
||||
//impl<T: Content<TuiOut>> Render<TuiOut> for T {}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use ratatui::prelude::Size;
|
|||
use std::time::Duration;
|
||||
use std::thread::{spawn, JoinHandle};
|
||||
|
||||
pub trait TuiRun<R: Render<Tui> + Handle<Tui> + Sized + 'static> {
|
||||
pub trait TuiRun<R: Render<TuiOut> + Handle<TuiIn> + Sized + 'static> {
|
||||
/// Run an app in the main loop.
|
||||
fn run (&self, state: &Arc<RwLock<R>>) -> Usually<()>;
|
||||
/// Spawn the input thread.
|
||||
|
|
@ -12,13 +12,21 @@ pub trait TuiRun<R: Render<Tui> + Handle<Tui> + Sized + 'static> {
|
|||
fn run_output (&self, state: &Arc<RwLock<R>>, sleep: Duration) -> JoinHandle<()>;
|
||||
}
|
||||
|
||||
impl<T: Render<Tui> + Handle<Tui> + Sized + 'static> TuiRun<T> for Arc<RwLock<Tui>> {
|
||||
impl<T: Render<TuiOut> + Handle<TuiIn> + Sized + 'static> TuiRun<T> for Arc<RwLock<Tui>> {
|
||||
fn run (&self, state: &Arc<RwLock<T>>) -> Usually<()> {
|
||||
let _input_thread = self.run_input(state, Duration::from_millis(100));
|
||||
self.write().unwrap().setup()?;
|
||||
let render_thread = self.run_output(state, Duration::from_millis(10));
|
||||
render_thread.join().expect("main thread failed");
|
||||
self.write().unwrap().teardown()?;
|
||||
match render_thread.join() {
|
||||
Ok(result) => {
|
||||
self.write().unwrap().teardown()?;
|
||||
println!("\n\rRan successfully: {result:?}\n\r");
|
||||
},
|
||||
Err(e) => {
|
||||
self.write().unwrap().teardown()?;
|
||||
panic!("\n\rRender thread failed.\n\r")
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn run_input (&self, state: &Arc<RwLock<T>>, poll: Duration) -> JoinHandle<()> {
|
||||
|
|
|
|||
|
|
@ -1,86 +1,84 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait TuiStyle {
|
||||
fn fg <R: Content<Tui>> (color: Color, w: R) -> Foreground<R> {
|
||||
fn fg <R: Content<TuiOut>> (color: Color, w: R) -> Foreground<R> {
|
||||
Foreground(color, w)
|
||||
}
|
||||
fn bg <R: Content<Tui>> (color: Color, w: R) -> Background<R> {
|
||||
fn bg <R: Content<TuiOut>> (color: Color, w: R) -> Background<R> {
|
||||
Background(color, w)
|
||||
}
|
||||
fn fg_bg <R: Content<Tui>> (fg: Color, bg: Color, w: R) -> Background<Foreground<R>> {
|
||||
fn fg_bg <R: Content<TuiOut>> (fg: Color, bg: Color, w: R) -> Background<Foreground<R>> {
|
||||
Background(bg, Foreground(fg, w))
|
||||
}
|
||||
fn bold <R: Content<Tui>> (on: bool, w: R) -> Bold<R> {
|
||||
fn bold <R: Content<TuiOut>> (on: bool, w: R) -> Bold<R> {
|
||||
Bold(on, w)
|
||||
}
|
||||
fn border <R: Content<Tui>, S: BorderStyle> (style: S, w: R) -> Bordered<S, R> {
|
||||
fn border <R: Content<TuiOut>, S: BorderStyle> (style: S, w: R) -> Bordered<S, R> {
|
||||
Bordered(style, w)
|
||||
}
|
||||
}
|
||||
|
||||
impl TuiStyle for Tui {}
|
||||
|
||||
pub struct Bold<R: Content<Tui>>(pub bool, R);
|
||||
impl<R: Content<Tui>> Content<Tui> for Bold<R> {
|
||||
fn content (&self) -> impl Render<Tui> { &self.1 }
|
||||
pub struct Bold<R: Content<TuiOut>>(pub bool, R);
|
||||
impl<R: Content<TuiOut>> Content<TuiOut> for Bold<R> {
|
||||
fn content (&self) -> impl Render<TuiOut> { &self.1 }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
to.fill_bold(to.area(), self.0);
|
||||
self.1.render(to)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Foreground<R: Content<Tui>>(pub Color, R);
|
||||
impl<R: Content<Tui>> Content<Tui> for Foreground<R> {
|
||||
fn content (&self) -> impl Render<Tui> { &self.1 }
|
||||
pub struct Foreground<R: Content<TuiOut>>(pub Color, R);
|
||||
impl<R: Content<TuiOut>> Content<TuiOut> for Foreground<R> {
|
||||
fn content (&self) -> impl Render<TuiOut> { &self.1 }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
to.fill_fg(to.area(), self.0);
|
||||
self.1.render(to)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Background<R: Content<Tui>>(pub Color, R);
|
||||
impl<R: Content<Tui>> Content<Tui> for Background<R> {
|
||||
fn content (&self) -> impl Render<Tui> { &self.1 }
|
||||
pub struct Background<R: Content<TuiOut>>(pub Color, R);
|
||||
impl<R: Content<TuiOut>> Content<TuiOut> for Background<R> {
|
||||
fn content (&self) -> impl Render<TuiOut> { &self.1 }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
to.fill_bg(to.area(), self.0);
|
||||
self.1.render(to)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Styled<R: Content<Tui>>(pub Option<Style>, pub R);
|
||||
impl Content<Tui> for Styled<&str> {
|
||||
fn content (&self) -> impl Render<Tui> { &self.1 }
|
||||
pub struct Styled<R: Content<TuiOut>>(pub Option<Style>, pub R);
|
||||
impl<R: Content<TuiOut>> Content<TuiOut> for Styled<R> {
|
||||
fn content (&self) -> impl Render<TuiOut> { &self.1 }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
// FIXME
|
||||
let [x, y, ..] = to.area();
|
||||
//let [w, h] = self.min_size(to.area().wh())?.unwrap();
|
||||
to.blit(&self.1, x, y, None)
|
||||
to.place(self.content().layout(to.area()), &self.content());
|
||||
// TODO write style over area
|
||||
}
|
||||
}
|
||||
|
||||
//pub trait TuiStyle: Render<Tui> + Sized {
|
||||
//fn fg (self, color: Color) -> impl Render<Tui> {
|
||||
//pub trait TuiStyle: Render<TuiOut> + Sized {
|
||||
//fn fg (self, color: Color) -> impl Render<TuiOut> {
|
||||
//Layers::new(move |add|{ add(&Foreground(color))?; add(&self) })
|
||||
//}
|
||||
//fn bg (self, color: Color) -> impl Render<Tui> {
|
||||
//fn bg (self, color: Color) -> impl Render<TuiOut> {
|
||||
//Layers::new(move |add|{ add(&Background(color))?; add(&self) })
|
||||
//}
|
||||
//fn bold (self, on: bool) -> impl Render<Tui> {
|
||||
//fn bold (self, on: bool) -> impl Render<TuiOut> {
|
||||
//Layers::new(move |add|{ add(&Bold(on))?; add(&self) })
|
||||
//}
|
||||
//fn border <S: BorderStyle> (self, style: S) -> impl Render<Tui> {
|
||||
//fn border <S: BorderStyle> (self, style: S) -> impl Render<TuiOut> {
|
||||
//Bordered(style, self)
|
||||
//}
|
||||
//}
|
||||
|
||||
//impl<R: Content<Tui>> TuiStyle for R {}
|
||||
//impl<R: Content<TuiOut>> TuiStyle for R {}
|
||||
|
||||
//impl<S: BorderStyle> Content<Tui> for Border<S> {
|
||||
//impl<S: BorderStyle> Content<TuiOut> for Border<S> {
|
||||
//}
|
||||
|
||||
//impl<S: BorderStyle, R: Content<Tui>> Content<Tui> for Bordered<S, R> {
|
||||
//fn content (&self) -> impl Render<Tui> {
|
||||
//let content: &dyn Content<Tui> = &self.1;
|
||||
//impl<S: BorderStyle, R: Content<TuiOut>> Content<TuiOut> for Bordered<S, R> {
|
||||
//fn content (&self) -> impl Render<TuiOut> {
|
||||
//let content: &dyn Content<TuiOut> = &self.1;
|
||||
//lay! { content.padding_xy(1, 1), Border(self.0) }.fill_xy()
|
||||
//}
|
||||
//}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue