From cdc513060dd1919fec39910b256371dd35b58a0f Mon Sep 17 00:00:00 2001 From: same mf who else Date: Sat, 21 Mar 2026 20:12:51 +0200 Subject: [PATCH] compiles, once again. now 616 errors downstream... --- src/draw.rs | 29 ++------ src/keys.rs | 110 +++++++++++++++++++++++++++ src/lib.rs | 1 + src/play.rs | 16 ++-- src/space.rs | 12 +-- src/term.rs | 206 +++++++++++---------------------------------------- src/text.rs | 21 +++++- src/time.rs | 2 +- 8 files changed, 196 insertions(+), 201 deletions(-) create mode 100644 src/keys.rs diff --git a/src/draw.rs b/src/draw.rs index 3eadbf1..dd252db 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -1,7 +1,7 @@ use crate::{*, lang::*, color::*, space::*}; /// Drawable that supports dynamic dispatch. -/// +/// /// ``` /// use tengri::draw::*; /// struct TestScreen(bool); @@ -18,31 +18,16 @@ use crate::{*, lang::*, color::*, space::*}; /// TestWidget(false).draw(&mut screen); /// ``` pub trait Draw { - fn draw (&self, to: &mut T) -> Usually>; + fn draw (self, to: &mut T) -> Usually>; } impl Draw for () { - fn draw (&self, __: &mut T) -> Usually> { + fn draw (self, __: &mut T) -> Usually> { Ok(Default::default()) } } -impl> Draw for &D { - fn draw (&self, to: &mut T) -> Usually> { - (*self).draw(to) - } -} -impl> Draw for Arc { - fn draw (&self, to: &mut T) -> Usually> { - (**self).draw(to) - } -} -impl> Draw for RwLock { - fn draw (&self, to: &mut T) -> Usually> { - self.read().unwrap().draw(to) - } -} impl> Draw for Option { - fn draw (&self, to: &mut T) -> Usually> { - Ok(self.as_ref().map(|draw|draw.draw(to)).transpose()?.unwrap_or_default()) + fn draw (self, to: &mut T) -> Usually> { + Ok(self.map(|draw|draw.draw(to)).transpose()?.unwrap_or_default()) } } @@ -55,8 +40,8 @@ pub const fn thunk Usually>> (draw: Thunk(draw, std::marker::PhantomData) } implUsually>> Draw for Thunk { - fn draw (&self, to: &mut T) -> Usually> { - (&self.0)(to) + fn draw (self, to: &mut T) -> Usually> { + (self.0)(to) } } diff --git a/src/keys.rs b/src/keys.rs new file mode 100644 index 0000000..54217c4 --- /dev/null +++ b/src/keys.rs @@ -0,0 +1,110 @@ +use crate::play::Thread; + +use ::std::sync::{Arc, RwLock, atomic::{AtomicBool, Ordering::*}}; +use ::std::time::Duration; +use ::dizzle::{Usually, Do, impl_from}; +use ::crossterm::event::{ + read, Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState +}; + +/// Spawn the TUI input thread which reads keys from the terminal. +pub fn tui_input > + Send + Sync + 'static> ( + exited: &Arc, state: &Arc>, poll: Duration +) -> Result { + let exited = exited.clone(); + let state = state.clone(); + Thread::new_poll(exited.clone(), poll, move |_| { + let event = read().unwrap(); + match event { + + // Hardcoded exit. + Event::Key(KeyEvent { + modifiers: KeyModifiers::CONTROL, + code: KeyCode::Char('c'), + kind: KeyEventKind::Press, + state: KeyEventState::NONE + }) => { exited.store(true, Relaxed); }, + + // Handle all other events by the state: + event => { + if let Err(e) = state.write().unwrap().apply(&TuiEvent(event)) { + panic!("{e}") + } + }, + + } + }) +} + +/// TUI input loop event. +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)] +pub struct TuiEvent(pub Event); +impl_from!(TuiEvent: |e: Event| TuiEvent(e)); +impl_from!(TuiEvent: |c: char| TuiEvent(Event::Key(KeyEvent::new(KeyCode::Char(c), KeyModifiers::NONE)))); +impl Ord for TuiEvent { + fn cmp (&self, other: &Self) -> std::cmp::Ordering { + self.partial_cmp(other) + .unwrap_or_else(||format!("{:?}", self).cmp(&format!("{other:?}"))) // FIXME perf + } +} + +/// TUI key spec. +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)] +pub struct TuiKey(pub Option, pub KeyModifiers); +impl TuiKey { + const SPLIT: char = '/'; + pub fn from_crossterm (event: KeyEvent) -> Self { + Self(Some(event.code), event.modifiers) + } + pub fn to_crossterm (&self) -> Option { + self.0.map(|code|Event::Key(KeyEvent { + code, + modifiers: self.1, + kind: KeyEventKind::Press, + state: KeyEventState::NONE, + })) + } + pub fn named (token: &str) -> Option { + use KeyCode::*; + Some(match token { + "up" => Up, + "down" => Down, + "left" => Left, + "right" => Right, + "esc" | "escape" => Esc, + "enter" | "return" => Enter, + "delete" | "del" => Delete, + "backspace" => Backspace, + "tab" => Tab, + "space" => Char(' '), + "comma" => Char(','), + "period" => Char('.'), + "plus" => Char('+'), + "minus" | "dash" => Char('-'), + "equal" | "equals" => Char('='), + "underscore" => Char('_'), + "backtick" => Char('`'), + "lt" => Char('<'), + "gt" => Char('>'), + "cbopen" | "openbrace" => Char('{'), + "cbclose" | "closebrace" => Char('}'), + "bropen" | "openbracket" => Char('['), + "brclose" | "closebracket" => Char(']'), + "pgup" | "pageup" => PageUp, + "pgdn" | "pagedown" => PageDown, + "f1" => F(1), + "f2" => F(2), + "f3" => F(3), + "f4" => F(4), + "f5" => F(5), + "f6" => F(6), + "f7" => F(7), + "f8" => F(8), + "f9" => F(9), + "f10" => F(10), + "f11" => F(11), + "f12" => F(12), + _ => return None, + }) + } +} diff --git a/src/lib.rs b/src/lib.rs index 76e268b..7897606 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ pub(crate) use ::{ #[cfg(feature = "draw")] pub mod color; #[cfg(feature = "text")] pub mod text; #[cfg(feature = "term")] pub mod term; +#[cfg(feature = "term")] pub mod keys; #[cfg(feature = "term")] pub extern crate ratatui; #[cfg(feature = "term")] pub extern crate crossterm; diff --git a/src/play.rs b/src/play.rs index 80115d6..28c4795 100644 --- a/src/play.rs +++ b/src/play.rs @@ -21,8 +21,8 @@ impl Exit { impl Thread { /// Spawn a TUI thread that runs `callt least one, then repeats until `exit`. - pub fn new (exit: Arc, call: F) -> Result - where F: Fn(&PerfModel)->() + Send + Sync + 'static + pub fn new (exit: Arc, mut call: F) -> Result + where F: FnMut(&PerfModel)->() + Send + Sync + 'static { let perf = Arc::new(PerfModel::default()); Ok(Self { @@ -30,7 +30,7 @@ impl Thread { perf: perf.clone(), join: std::thread::Builder::new().name("tengri tui output".into()).spawn(move || { while !exit.fetch_and(true, Relaxed) { - let _ = perf.cycle(&call); + let _ = perf.cycle(&mut call); } })?.into() }) @@ -39,19 +39,19 @@ impl Thread { /// Spawn a thread that runs `call` least one, then repeats /// until `exit`, sleeping for `time` msec after every iteration. pub fn new_sleep ( - exit: Arc, time: Duration, call: F + exit: Arc, time: Duration, mut call: F ) -> Result - where F: Fn(&PerfModel)->() + Send + Sync + 'static + 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 ( - exit: Arc, time: Duration, call: F + #[cfg(feature = "term")] pub fn new_poll ( + exit: Arc, time: Duration, mut call: F ) -> Result - where F: Fn(&PerfModel)->() + Send + Sync + 'static + where F: FnMut(&PerfModel)->() + Send + Sync + 'static { Self::new(exit, move |perf| { if poll(time).is_ok() { let _ = call(perf); } }) } diff --git a/src/space.rs b/src/space.rs index e3a2058..bb8532b 100644 --- a/src/space.rs +++ b/src/space.rs @@ -158,17 +158,19 @@ impl Split { /// let _ = West.bsp((), ()); /// ``` pub const fn half (&self, a: impl Draw, b: impl Draw) -> impl Draw { - thunk(move|to: &mut T|{ + thunk(move|to: &mut T|{ let (area_a, area_b) = to.xywh().split_half(self); let (origin_a, origin_b) = self.origins(); + let a = origin_a.align(a); + let b = origin_b.align(b); match self { Self::Below => { - to.place(&origin_b.align(b), Some(area_b)); - to.place(&origin_a.align(a), Some(area_b)); + to.place(&b, Some(area_b)); + to.place(&a, Some(area_b)); }, _ => { - to.place(&origin_a.align(a), Some(area_a)); - to.place(&origin_b.align(b), Some(area_a)); + to.place(&a, Some(area_a)); + to.place(&b, Some(area_a)); } } Ok(to.xywh()) // FIXME: compute and return actually used area diff --git a/src/term.rs b/src/term.rs index d0a92e6..b06c0b3 100644 --- a/src/term.rs +++ b/src/term.rs @@ -131,26 +131,10 @@ impl Coord for u16 { } impl Draw for u64 { - fn draw (&self, _to: &mut Tui) -> Usually> { todo!() } + fn draw (self, _to: &mut Tui) -> Usually> { todo!() } } impl Draw for f64 { - fn draw (&self, _to: &mut Tui) -> Usually> { todo!() } -} -impl Draw for &str { - fn draw (&self, to: &mut Tui) -> Usually> { - let XYWH(x, y, w, ..) = to.1.centered_xy([width_chars_max(to.w(), self), 1]); - to.text(&self, x, y, w) - } -} -impl Draw for String { - fn draw (&self, to: &mut Tui) -> Usually> { - self.as_str().draw(to) - } -} -impl Draw for Arc { - fn draw (&self, to: &mut Tui) -> Usually> { - self.as_ref().draw(to) - } + fn draw (self, _to: &mut Tui) -> Usually> { todo!() } } mod phat { @@ -223,7 +207,7 @@ pub const fn button_2 <'a> (key: impl Draw, label: impl Draw, hide: bo let c2 = tui_g(0); let c3 = tui_g(96); let c4 = tui_g(255); - bold(true, fg_bg(c1, c2, east(fg(c2, east(key, fg(c3, &"▐"))), when(!hide, fg_bg(c4, c3, label))))) + bold(true, fg_bg(c1, c2, east(fg(c2, east(key, fg(c3, "▐"))), when(!hide, fg_bg(c4, c3, label))))) } /// ``` @@ -235,10 +219,10 @@ pub const fn button_3 <'a> ( ) -> impl Draw { bold(true, east( fg_bg(tui_orange(), tui_g(0), - east(fg(tui_g(0), &"▐"), east(key, fg(if editing { tui_g(128) } else { tui_g(96) }, "▐")))), + east(fg(tui_g(0), "▐"), east(key, fg(if editing { tui_g(128) } else { tui_g(96) }, "▐")))), east( - when(!editing, east(fg_bg(tui_g(255), tui_g(96), label), fg_bg(tui_g(128), tui_g(96), &"▐"),)), - east(fg_bg(tui_g(224), tui_g(128), value), fg_bg(tui_g(128), Reset, &"▌"), )))) + when(!editing, east(fg_bg(tui_g(255), tui_g(96), label), fg_bg(tui_g(128), tui_g(96), "▐"),)), + east(fg_bg(tui_g(224), tui_g(128), value), fg_bg(tui_g(128), Reset, "▌"), )))) } macro_rules! border { @@ -261,7 +245,7 @@ macro_rules! border { #[derive(Copy, Clone)] pub struct $T(pub bool, pub Style); //impl Layout for $T {} impl Draw for $T { - fn draw (&self, to: &mut Tui) -> Usually> { + fn draw (self, to: &mut Tui) -> Usually> { when(self.enabled(), thunk(|to: &mut Tui|BorderStyle::draw(self, to))).draw(to) } } @@ -385,7 +369,7 @@ pub trait BorderStyle: Draw + Copy { fn border_sw (&self) -> &str { Self::SW } fn border_se (&self) -> &str { Self::SE } - #[inline] fn draw <'a> (&self, to: &mut Tui) -> Usually> { + #[inline] fn draw <'a> (self, to: &mut Tui) -> Usually> { if self.enabled() { self.draw_h(to, None)?; self.draw_v(to, None)?; @@ -393,7 +377,7 @@ pub trait BorderStyle: Draw + Copy { } Ok(to.1) } - #[inline] fn draw_h (&self, to: &mut Tui, style: Option