mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-07-17 15:56:57 +02:00
reorganize, add Azimuth
This commit is contained in:
parent
bf16288884
commit
1f60b43f61
26 changed files with 677 additions and 594 deletions
540
src/term.rs
540
src/term.rs
|
|
@ -1,10 +1,15 @@
|
|||
mod border;
|
||||
pub use self::border::*;
|
||||
use crate::{*, lang::*};
|
||||
|
||||
mod border; pub use self::border::*;
|
||||
mod event; pub use self::event::*;
|
||||
mod keys; pub use self::keys::*;
|
||||
mod buffer; pub use self::buffer::*;
|
||||
mod input; pub use self::input::*;
|
||||
mod output; pub use self::output::*;
|
||||
|
||||
use crate::{*, lang::*, draw::*, task::*, exit::*};
|
||||
//use unicode_width::{UnicodeWidthStr, UnicodeWidthChar};
|
||||
//use rand::distributions::uniform::UniformSampler;
|
||||
use ::{
|
||||
pub(crate) use ::{
|
||||
std::{
|
||||
io::{stdout, Write},
|
||||
time::Duration,
|
||||
|
|
@ -27,6 +32,74 @@ use ::{
|
|||
},
|
||||
};
|
||||
|
||||
/// Terminal output.
|
||||
pub struct Tui(
|
||||
/// Ratatui buffer; area is screen size
|
||||
pub Buffer,
|
||||
/// Current draw area
|
||||
pub XYWH<u16>
|
||||
);
|
||||
|
||||
impl Deref for Tui { type Target = Buffer; fn deref (&self) -> &Buffer { &self.0 } }
|
||||
impl DerefMut for Tui { fn deref_mut (&mut self) -> &mut Buffer { &mut self.0 } }
|
||||
impl AsMut<Buffer> for Tui { fn as_mut (&mut self) -> &mut Buffer { &mut self.0 } }
|
||||
impl Wide<u16> for Tui { fn w (&self) -> u16 { self.1.2 } }
|
||||
impl Tall<u16> for Tui { fn h (&self) -> u16 { self.1.3 } }
|
||||
impl HasOrigin for Tui { fn origin (&self) -> Azimuth { Azimuth::NW } }
|
||||
impl Xy<u16> for Tui { fn x (&self) -> u16 { self.1.0 } fn y (&self) -> u16 { self.1.1 } }
|
||||
|
||||
impl Tui {
|
||||
pub fn new (width: u16, height: u16) -> Self {
|
||||
Self(Buffer::empty(Rect { x: 0, y: 0, width, height }), XYWH(0, 0, width, height))
|
||||
}
|
||||
pub fn resize <W: Write> (&mut self, back: &mut CrosstermBackend<W>, width: u16, height: u16) {
|
||||
let size = Rect { x: 0, y: 0, width, height };
|
||||
if self.0.area != size {
|
||||
back.clear_region(ClearType::All).unwrap();
|
||||
self.0.resize(size);
|
||||
self.0.reset();
|
||||
}
|
||||
}
|
||||
pub fn redraw <'b, W: Write> (&'b mut self, back: &mut CrosstermBackend<W>, mut next: &'b mut Self) {
|
||||
let updates = self.0.diff(&next.0);
|
||||
back.draw(updates.into_iter()).expect("failed to render");
|
||||
Backend::flush(back).expect("failed to flush output new");
|
||||
std::mem::swap(self, &mut next);
|
||||
next.0.reset();
|
||||
}
|
||||
}
|
||||
|
||||
impl Tui {
|
||||
pub fn update (&mut self, callback: &impl Fn(&mut Cell, u16, u16)) -> XYWH<u16> {
|
||||
for row in 0..self.h() {
|
||||
let y = self.y() + row;
|
||||
for col in 0..self.w() {
|
||||
let x = self.x() + col;
|
||||
if x < self.0.area.width && y < self.0.area.height {
|
||||
if let Some(cell) = self.0.cell_mut(Position { x, y }) {
|
||||
callback(cell, col, row);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.xywh()
|
||||
}
|
||||
pub fn tint_all (&mut self, fg: Color, bg: Color, modifier: Modifier) {
|
||||
for cell in self.0.content.iter_mut() {
|
||||
cell.fg = fg;
|
||||
cell.bg = bg;
|
||||
cell.modifier = modifier;
|
||||
}
|
||||
}
|
||||
pub fn blit (&mut self, text: &impl AsRef<str>, x: u16, y: u16, style: Option<Style>) {
|
||||
let text = text.as_ref();
|
||||
let style = style.unwrap_or(Style::default());
|
||||
if x < self.0.area.width && y < self.0.area.height {
|
||||
self.0.set_string(x, y, text, style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement standard [main] entrypoint for TUI apps.
|
||||
#[macro_export] macro_rules! tui_main {
|
||||
($state:expr) => {
|
||||
|
|
@ -34,24 +107,6 @@ use ::{
|
|||
}
|
||||
}
|
||||
|
||||
/// Enable TUI keyboard input for main state struct.
|
||||
#[macro_export] macro_rules! tui_keys {
|
||||
(|$self:ident:$State:ty,$input:ident|$body:block) => {
|
||||
impl Apply<TuiEvent, Usually<()>> for $State {
|
||||
fn apply (&mut $self, $input: &TuiEvent) -> Usually<()> $body
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Enable TUI output for state struct.
|
||||
#[macro_export] macro_rules! tui_view {
|
||||
(|$self:ident: $State:ty|$body:block) => {
|
||||
impl View<Tui> for $State {
|
||||
fn view (&$self) -> impl Draw<Tui> $body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tui_run_main <T> (state: Arc<RwLock<T>>) -> Usually<()> where
|
||||
T: View<Tui> + Apply<TuiEvent, Usually<()>> + Send + Sync + 'static
|
||||
{
|
||||
|
|
@ -98,444 +153,3 @@ pub fn tui_io <
|
|||
let terminal = tui_output(exited, state, sleep, output)?;
|
||||
Ok((keyboard, terminal))
|
||||
}
|
||||
|
||||
/// Spawn the TUI input thread which reads keys from the terminal.
|
||||
pub fn tui_input <T: Apply<TuiEvent, Usually<()>> + Send + Sync + 'static> (
|
||||
exited: &Arc<AtomicBool>, state: &Arc<RwLock<T>>, poll: Duration
|
||||
) -> Result<Task, std::io::Error> {
|
||||
let exited = exited.clone();
|
||||
let state = state.clone();
|
||||
Task::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}")
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Spawn the TUI output thread which writes colored characters to the terminal.
|
||||
///
|
||||
/// ```
|
||||
/// let state = Arc::new(RwLock::new(()));
|
||||
/// Exit::run(|exit|tui_output(exit, state, sleep, stdout()))
|
||||
/// ```
|
||||
pub fn tui_output <
|
||||
W: Write + Send + Sync + 'static, T: View<Tui> + Send + Sync + 'static
|
||||
> (
|
||||
exited: &Arc<AtomicBool>,
|
||||
state: &Arc<RwLock<T>>,
|
||||
sleep: Duration,
|
||||
output: W,
|
||||
) -> Usually<Task> {
|
||||
let state = state.clone();
|
||||
stdout().execute(EnterAlternateScreen)?;
|
||||
CrosstermBackend::new(stdout()).hide_cursor()?;
|
||||
enable_raw_mode()?;
|
||||
let mut backend = CrosstermBackend::new(output);
|
||||
let Size { width, height } = backend.size().expect("get size failed");
|
||||
let mut prev = Tui::new(width, height);
|
||||
let mut next = Tui::new(width, height);
|
||||
Ok(Task::new_sleep(exited.clone(), sleep, move |perf| {
|
||||
let Size { width, height } = backend.size().expect("get size failed");
|
||||
if let Ok(state) = state.try_read() {
|
||||
prev.resize(&mut backend, width, height);
|
||||
state.view().draw(&mut next).expect("draw failed"); // TODO draw error
|
||||
prev.redraw(&mut backend, &mut next);
|
||||
}
|
||||
let timer = format!("{:>3.3}ms", perf.used.load(Relaxed));
|
||||
prev.set_string(0, 0, &timer, Style::default());
|
||||
})?)
|
||||
}
|
||||
|
||||
/// Terminal output.
|
||||
pub struct Tui(
|
||||
/// Ratatui buffer; area is screen size
|
||||
pub Buffer,
|
||||
/// Current draw area
|
||||
pub XYWH<u16>
|
||||
);
|
||||
|
||||
impl Tui {
|
||||
pub fn new (width: u16, height: u16) -> Self {
|
||||
Self(Buffer::empty(Rect { x: 0, y: 0, width, height }), XYWH(0, 0, width, height))
|
||||
}
|
||||
pub fn resize <W: Write> (&mut self, back: &mut CrosstermBackend<W>, width: u16, height: u16) {
|
||||
let size = Rect { x: 0, y: 0, width, height };
|
||||
if self.0.area != size {
|
||||
back.clear_region(ClearType::All).unwrap();
|
||||
self.0.resize(size);
|
||||
self.0.reset();
|
||||
}
|
||||
}
|
||||
pub fn redraw <'b, W: Write> (&'b mut self, back: &mut CrosstermBackend<W>, mut next: &'b mut Self) {
|
||||
let updates = self.0.diff(&next.0);
|
||||
back.draw(updates.into_iter()).expect("failed to render");
|
||||
Backend::flush(back).expect("failed to flush output new");
|
||||
std::mem::swap(self, &mut next);
|
||||
next.0.reset();
|
||||
}
|
||||
}
|
||||
|
||||
impl Screen for Tui {
|
||||
type Unit = u16;
|
||||
/// Render drawable in subarea specified by `area`
|
||||
fn show <'t, T: Draw<Self>> (&mut self, content: T) -> Perhaps<XYWH<u16>> {
|
||||
let previous_area = self.1;
|
||||
if let Some(area) = content.layout(self.1)? {
|
||||
self.1 = area;
|
||||
if let Some(result_area) = content.draw(self)? {
|
||||
self.1 = previous_area;
|
||||
result_area
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Tui { type Target = Buffer; fn deref (&self) -> &Buffer { &self.0 } }
|
||||
impl DerefMut for Tui { fn deref_mut (&mut self) -> &mut Buffer { &mut self.0 } }
|
||||
impl AsMut<Buffer> for Tui { fn as_mut (&mut self) -> &mut Buffer { &mut self.0 } }
|
||||
impl Wide<u16> for Tui { fn w (&self) -> u16 { self.1.2 } }
|
||||
impl Tall<u16> for Tui { fn h (&self) -> u16 { self.1.3 } }
|
||||
impl HasOrigin for Tui { fn origin (&self) -> Origin { Origin::NW } }
|
||||
impl Xy<u16> for Tui {
|
||||
fn x (&self) -> u16 { self.1.0 }
|
||||
fn y (&self) -> u16 { self.1.1 }
|
||||
}
|
||||
|
||||
impl Tui {
|
||||
pub fn update (&mut self, callback: &impl Fn(&mut Cell, u16, u16)) -> XYWH<u16> {
|
||||
for row in 0..self.h() {
|
||||
let y = self.y() + row;
|
||||
for col in 0..self.w() {
|
||||
let x = self.x() + col;
|
||||
if x < self.0.area.width && y < self.0.area.height {
|
||||
if let Some(cell) = self.0.cell_mut(Position { x, y }) {
|
||||
callback(cell, col, row);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.xywh()
|
||||
}
|
||||
pub fn tint_all (&mut self, fg: Color, bg: Color, modifier: Modifier) {
|
||||
for cell in self.0.content.iter_mut() {
|
||||
cell.fg = fg;
|
||||
cell.bg = bg;
|
||||
cell.modifier = modifier;
|
||||
}
|
||||
}
|
||||
pub fn blit (&mut self, text: &impl AsRef<str>, x: u16, y: u16, style: Option<Style>) {
|
||||
let text = text.as_ref();
|
||||
let style = style.unwrap_or(Style::default());
|
||||
if x < self.0.area.width && y < self.0.area.height {
|
||||
self.0.set_string(x, y, text, style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply foreground color.
|
||||
pub const fn fg (fg: Color, draw: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||
thunk(move|to: &mut Tui|{
|
||||
to.update(&|cell,_,_|{ cell.set_fg(fg); });
|
||||
draw.draw(to)
|
||||
})
|
||||
}
|
||||
|
||||
/// Apply background color.
|
||||
pub const fn bg (bg: Color, draw: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||
thunk(move|to: &mut Tui|{
|
||||
to.update(&|cell,_,_|{ cell.set_bg(bg); });
|
||||
draw.draw(to)
|
||||
})
|
||||
}
|
||||
|
||||
pub const fn fg_bg (fg: Color, bg: Color, draw: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||
thunk(move|to: &mut Tui|{
|
||||
to.update(&|cell,_,_|{ cell.set_fg(fg); cell.set_bg(bg); });
|
||||
draw.draw(to)
|
||||
})
|
||||
}
|
||||
|
||||
pub const fn fill_char (c: char) -> impl Draw<Tui> {
|
||||
thunk(move|to: &mut Tui|Ok(to.update(&|cell,_,_|{
|
||||
cell.set_char(c);
|
||||
})))
|
||||
}
|
||||
|
||||
/// Draw contents with modifier applied.
|
||||
pub const fn modify (on: bool, modifier: Modifier, draw: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||
thunk(move|to: &mut Tui|{
|
||||
fill_mod(on, modifier).draw(to)?;
|
||||
draw.draw(to)
|
||||
})
|
||||
}
|
||||
|
||||
pub const fn fill_mod (on: bool, modifier: Modifier) -> impl Draw<Tui> {
|
||||
thunk(move|to: &mut Tui|Ok({
|
||||
if on {
|
||||
to.update(&|cell,_,_|cell.modifier.insert(modifier))
|
||||
} else {
|
||||
to.update(&|cell,_,_|cell.modifier.remove(modifier))
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
/// Draw contents with bold modifier applied.
|
||||
pub const fn bold (on: bool, draw: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||
modify(on, Modifier::BOLD, draw)
|
||||
}
|
||||
|
||||
pub const fn fill_ul (color: Option<Color>) -> impl Draw<Tui> {
|
||||
thunk(move|to: &mut Tui|Ok(if let Some(color) = color {
|
||||
to.update(&|cell,_,_|{
|
||||
cell.modifier.insert(Modifier::UNDERLINED);
|
||||
cell.underline_color = color;
|
||||
})
|
||||
} else {
|
||||
to.update(&|cell,_,_|{
|
||||
cell.modifier.remove(Modifier::UNDERLINED);
|
||||
cell.underline_color = Reset;
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
/// TUI works in u16 coordinates.
|
||||
impl Coord for u16 {
|
||||
fn plus (self, other: Self) -> Self {
|
||||
self.saturating_add(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl_draw!(|self: u64, _to: Tui|{ todo!() });
|
||||
impl_draw!(|self: f64, _to: Tui|{ todo!() });
|
||||
|
||||
mod phat {
|
||||
use super::*;
|
||||
pub const LO: &'static str = "▄";
|
||||
pub const HI: &'static str = "▀";
|
||||
/// A phat line
|
||||
pub fn lo (fg: Color, bg: Color) -> impl Draw<Tui> {
|
||||
h_exact(1, fg_bg(fg, bg, x_repeat(self::phat::LO)))
|
||||
}
|
||||
/// A phat line
|
||||
pub fn hi (fg: Color, bg: Color) -> impl Draw<Tui> {
|
||||
h_exact(1, fg_bg(fg, bg, x_repeat(self::phat::HI)))
|
||||
}
|
||||
}
|
||||
|
||||
mod scroll {
|
||||
pub const ICON_DEC_V: &[char] = &['▲'];
|
||||
pub const ICON_INC_V: &[char] = &['▼'];
|
||||
pub const ICON_DEC_H: &[char] = &[' ', '🞀', ' '];
|
||||
pub const ICON_INC_H: &[char] = &[' ', '🞂', ' '];
|
||||
}
|
||||
|
||||
pub const fn x_repeat (c: &str) -> impl Draw<Tui> {
|
||||
thunk(move|to: &mut Tui|{
|
||||
let XYWH(x, y, w, h) = to.xywh();
|
||||
for x in x..x+w {
|
||||
if let Some(cell) = to.0.cell_mut(Position::from((x, y))) {
|
||||
cell.set_symbol(&c);
|
||||
}
|
||||
}
|
||||
Ok(XYWH(x, y, w, 1))
|
||||
})
|
||||
}
|
||||
|
||||
pub const fn y_repeat (c: &str) -> impl Draw<Tui> {
|
||||
thunk(move|to: &mut Tui|{
|
||||
let XYWH(x, y, w, h) = to.xywh();
|
||||
for y in y..y+h {
|
||||
if let Some(cell) = to.0.cell_mut(Position::from((x, y))) {
|
||||
cell.set_symbol(&c);
|
||||
}
|
||||
}
|
||||
Ok(XYWH(x, y, 1, h))
|
||||
})
|
||||
}
|
||||
|
||||
pub const fn xy_repeat (c: &str) -> impl Draw<Tui> {
|
||||
thunk(move|to: &mut Tui|{
|
||||
let XYWH(x, y, w, h) = to.xywh();
|
||||
let a = c.len();
|
||||
for (_v, y) in (y..y+h).enumerate() {
|
||||
for (u, x) in (x..x+w).enumerate() {
|
||||
if let Some(cell) = to.0.cell_mut(Position::from((x, y))) {
|
||||
let u = u % a;
|
||||
cell.set_symbol(&c[u..u+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(XYWH(x, y, w, h))
|
||||
})
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// let _ = tengri::button_2("", "", true);
|
||||
/// let _ = tengri::button_2("", "", false);
|
||||
/// ```
|
||||
pub const fn button_2 <'a> (key: impl Draw<Tui>, label: impl Draw<Tui>, hide: bool) -> impl Draw<Tui> {
|
||||
let c1 = tui_orange();
|
||||
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)))))
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// let _ = tengri::button_3("", "", "", true);
|
||||
/// let _ = tengri::button_3("", "", "", false);
|
||||
/// ```
|
||||
pub const fn button_3 <'a> (
|
||||
key: impl Draw<Tui>, label: impl Draw<Tui>, value: impl Draw<Tui>, editing: bool,
|
||||
) -> impl Draw<Tui> {
|
||||
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(
|
||||
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, "▌"), ))))
|
||||
}
|
||||
|
||||
/// Stackably padded.
|
||||
///
|
||||
/// ```
|
||||
/// /// TODO
|
||||
/// ```
|
||||
pub fn phat (w: u16, h: u16, [fg, bg, hi, lo]: [Color;4], draw: impl Draw<Tui>) -> impl Draw<Tui> {
|
||||
let top = w_exact(1, self::phat::lo(bg, hi));
|
||||
let low = w_exact(1, self::phat::hi(bg, lo));
|
||||
let draw = fg_bg(fg, bg, draw);
|
||||
wh_min(Some(w), Some(h), south(top, north(low, draw)))
|
||||
}
|
||||
|
||||
fn x_scroll () -> impl Draw<Tui> {
|
||||
thunk(|Tui(buf, XYWH(x1, y1, w, h)): &mut Tui|{
|
||||
let x2 = *x1 + *w;
|
||||
for (i, x) in (*x1..=x2).enumerate() {
|
||||
if let Some(cell) = buf.cell_mut(Position::from((x, *y1))) {
|
||||
if i < (self::scroll::ICON_DEC_H.len()) {
|
||||
cell.set_fg(Rgb(255, 255, 255));
|
||||
cell.set_bg(Rgb(0, 0, 0));
|
||||
cell.set_char(self::scroll::ICON_DEC_H[i as usize]);
|
||||
} else if i > (*w as usize - self::scroll::ICON_INC_H.len()) {
|
||||
cell.set_fg(Rgb(255, 255, 255));
|
||||
cell.set_bg(Rgb(0, 0, 0));
|
||||
cell.set_char(self::scroll::ICON_INC_H[*w as usize - i]);
|
||||
} else if false {
|
||||
cell.set_fg(Rgb(255, 255, 255));
|
||||
cell.set_bg(Reset);
|
||||
cell.set_char('━');
|
||||
} else {
|
||||
cell.set_fg(Rgb(0, 0, 0));
|
||||
cell.set_bg(Reset);
|
||||
cell.set_char('╌');
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(XYWH(*x1, *y1, *w, 1))
|
||||
})
|
||||
}
|
||||
|
||||
fn y_scroll () -> impl Draw<Tui> {
|
||||
thunk(|Tui(buf, XYWH(x1, y1, w, h)): &mut Tui|{
|
||||
let y2 = *y1 + *h;
|
||||
for (i, y) in (*y1..=y2).enumerate() {
|
||||
if let Some(cell) = buf.cell_mut(Position::from((*x1, y))) {
|
||||
if (i as usize) < (self::scroll::ICON_DEC_V.len()) {
|
||||
cell.set_fg(Rgb(255, 255, 255));
|
||||
cell.set_bg(Rgb(0, 0, 0));
|
||||
cell.set_char(self::scroll::ICON_DEC_V[i as usize]);
|
||||
} else if (i as usize) > (*h as usize - self::scroll::ICON_INC_V.len()) {
|
||||
cell.set_fg(Rgb(255, 255, 255));
|
||||
cell.set_bg(Rgb(0, 0, 0));
|
||||
cell.set_char(self::scroll::ICON_INC_V[*h as usize - i]);
|
||||
} else if false {
|
||||
cell.set_fg(Rgb(255, 255, 255));
|
||||
cell.set_bg(Reset);
|
||||
cell.set_char('‖'); // ━
|
||||
} else {
|
||||
cell.set_fg(Rgb(0, 0, 0));
|
||||
cell.set_bg(Reset);
|
||||
cell.set_char('╎'); // ━
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(XYWH(*x1, *y1, 1, *h))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn tui_update (
|
||||
Tui(buf, ..): &mut Tui,
|
||||
area: XYWH<u16>,
|
||||
callback: &impl Fn(&mut Cell, u16, u16)
|
||||
) {
|
||||
}
|
||||
|
||||
/// Draw TUI content or its error message.
|
||||
///
|
||||
/// ```
|
||||
/// let _ = tengri::term::catcher(Ok(Some("hello")));
|
||||
/// let _ = tengri::term::catcher(Ok(None));
|
||||
/// let _ = tengri::term::catcher(Err("draw fail".into()));
|
||||
/// ```
|
||||
pub fn catcher <T: Draw<Tui>> (result: Usually<T>) -> impl Draw<Tui> {
|
||||
thunk(move|to: &mut Tui|match result {
|
||||
Ok(content) => content.draw(to),
|
||||
Err(e) => {
|
||||
let err_fg = Color::Rgb(255,224,244);
|
||||
let err_bg = Color::Rgb(96, 24, 24);
|
||||
let title = east(bold(true, "upsi daisy. "), "rendering failed.");
|
||||
let error = east("\"why?\" ", bold(true, format!("{e}")));
|
||||
fg(err_fg, bg(err_bg, south(title, error))).draw(to)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
mod event; pub use self::event::*;
|
||||
mod keys; pub use self::keys::*;
|
||||
mod buffer; pub use self::buffer::*;
|
||||
|
||||
use self::colors::*; mod colors {
|
||||
use ratatui::prelude::Color;
|
||||
pub const fn tui_color_bg () -> Color { Color::Rgb(28, 35, 25) }
|
||||
pub const fn tui_bg0 () -> Color { Color::Rgb(20, 20, 20) }
|
||||
pub const fn tui_bo1 () -> Color { Color::Rgb(100, 110, 40) }
|
||||
pub const fn tui_bo2 () -> Color { Color::Rgb(70, 80, 50) }
|
||||
pub const fn tui_border_bg () -> Color { Color::Rgb(40, 50, 30) }
|
||||
pub const fn tui_border_fg (f: bool) -> Color { if f { tui_bo1() } else { tui_bo2() } }
|
||||
pub const fn tui_brown () -> Color { Color::Rgb(128,255,0) }
|
||||
pub const fn tui_electric () -> Color { Color::Rgb(0,255,128) }
|
||||
pub const fn tui_g (g: u8) -> Color { Color::Rgb(g, g, g) }
|
||||
pub const fn tui_green () -> Color { Color::Rgb(0,255,0) }
|
||||
pub const fn tui_mode_bg () -> Color { Color::Rgb(150, 160, 90) }
|
||||
pub const fn tui_mode_fg () -> Color { Color::Rgb(255, 255, 255) }
|
||||
pub const fn tui_null () -> Color { Color::Reset }
|
||||
pub const fn tui_orange () -> Color { Color::Rgb(255,128,0) }
|
||||
pub const fn tui_red () -> Color { Color::Rgb(255,0, 0) }
|
||||
pub const fn tui_separator_fg (_: bool) -> Color { Color::Rgb(0, 0, 0) }
|
||||
pub const fn tui_status_bar_bg () -> Color { Color::Rgb(28, 35, 25) }
|
||||
pub const fn tui_ti1 () -> Color { Color::Rgb(150, 160, 90) }
|
||||
pub const fn tui_ti2 () -> Color { Color::Rgb(120, 130, 100) }
|
||||
pub const fn tui_title_fg (f: bool) -> Color { if f { tui_ti1() } else { tui_ti2() } }
|
||||
pub const fn tui_yellow () -> Color { Color::Rgb(255,255,0) }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue