group tui_engine and tui_content; cargo update

This commit is contained in:
🪞👃🪞 2025-03-16 23:33:27 +02:00
parent 877b344765
commit 71dead5150
13 changed files with 150 additions and 72 deletions

98
Cargo.lock generated
View file

@ -102,12 +102,6 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cassowary"
version = "0.3.0"
@ -177,7 +171,7 @@ dependencies = [
"crossterm_winapi",
"mio",
"parking_lot",
"rustix",
"rustix 0.38.44",
"signal-hook",
"signal-hook-mio",
"winapi",
@ -229,9 +223,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.14.0"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "encode_unicode"
@ -275,9 +269,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "getrandom"
@ -333,9 +327,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indoc"
version = "2.0.5"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
[[package]]
name = "instability"
@ -370,9 +364,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.14"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "js-sys"
@ -419,9 +413,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.170"
version = "0.2.171"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
[[package]]
name = "linux-raw-sys"
@ -429,6 +423,12 @@ version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
[[package]]
name = "lock_api"
version = "0.4.12"
@ -501,9 +501,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.20.3"
version = "1.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
[[package]]
name = "palette"
@ -603,9 +603,9 @@ dependencies = [
[[package]]
name = "ppv-lite86"
version = "0.2.20"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
@ -673,9 +673,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.39"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
@ -742,9 +742,9 @@ dependencies = [
[[package]]
name = "raw-cpuid"
version = "11.4.0"
version = "11.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "529468c1335c1c03919960dfefdb1b3648858c20d7ec2d0663e728e4a717efbc"
checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146"
dependencies = [
"bitflags",
]
@ -779,15 +779,28 @@ dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"linux-raw-sys 0.4.15",
"windows-sys 0.59.0",
]
[[package]]
name = "rustix"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys 0.9.3",
"windows-sys 0.59.0",
]
[[package]]
name = "rustversion"
version = "1.0.19"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]]
name = "rusty-fork"
@ -803,9 +816,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.19"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "scopeguard"
@ -891,9 +904,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.99"
version = "2.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
@ -902,15 +915,14 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.17.1"
version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230"
checksum = "488960f40a3fd53d72c2a29a58722561dee8afdd175bd88e3db4677d7b2ba600"
dependencies = [
"cfg-if",
"fastrand",
"getrandom 0.3.1",
"once_cell",
"rustix",
"rustix 1.0.2",
"windows-sys 0.59.0",
]
@ -949,6 +961,7 @@ version = "0.1.0"
dependencies = [
"proptest",
"proptest-derive",
"tengri",
"tengri_dsl",
"tengri_tui",
]
@ -1014,9 +1027,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
[[package]]
name = "unicode-ident"
version = "1.0.17"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unicode-segmentation"
@ -1253,19 +1266,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.7.35"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
dependencies = [
"proc-macro2",
"quote",

36
input/src/input.rs Normal file
View file

@ -0,0 +1,36 @@
use crate::*;
use std::time::Duration;
use std::thread::JoinHandle;
/// Event source
pub trait Input: Send + Sync + Sized {
/// Type of input event
type Event;
/// Result of handling input
type Handled; // TODO: make this an Option<Box dyn Command<Self>> containing the undo
/// Currently handled event
fn event (&self) -> &Self::Event;
/// Whether component should exit
fn is_done (&self) -> bool;
/// Mark component as done
fn done (&self);
}
/// Input thread entrypoint.
pub trait InputRun<T> {
fn run_input (engine: T, state: Self, timer: Duration) -> JoinHandle<()>;
}
/// Handle input through a mutable reference.
pub trait Handle<E: Input>: Send + Sync {
fn handle (&mut self, _input: &E) -> Perhaps<E::Handled> {
Ok(None)
}
}
/// Handle input through an immutable reference (e.g. [Arc<RwLock>] or [Arc<Mutex>])
pub trait HandleRef<E: Input>: Send + Sync {
fn handle (&self, _input: &E) -> Perhaps<E::Handled> {
Ok(None)
}
}

View file

@ -1,11 +1,5 @@
mod tui_buffer; pub use self::tui_buffer::*;
mod tui_color; pub use self::tui_color::*;
mod tui_content; pub use self::tui_content::*;
mod tui_engine; pub use self::tui_engine::*;
mod tui_file; pub use self::tui_file::*;
mod tui_input; pub use self::tui_input::*;
mod tui_output; pub use self::tui_output::*;
mod tui_perf; pub use self::tui_perf::*;
mod tui_content; pub use self::tui_content::*;
pub use ::tengri_input as input;
pub(crate) use ::tengri_input::*;

View file

@ -1,6 +1,10 @@
use crate::*;
use crate::Color::*;
use ratatui::prelude::Position;
mod tui_color; pub use self::tui_color::*;
mod tui_file; pub use self::tui_file::*;
macro_rules! impl_content_layout_render {
($Output:ty: |$self:ident: $Struct:ty, $to:ident| layout = $layout:expr; render = $render:expr) => {
impl Content<$Output> for $Struct {
@ -13,19 +17,24 @@ impl_content_layout_render!(TuiOut: |self: &str, to|
layout = to.center_xy([self.chars().count() as u16, 1]);
render = {let [x, y, ..] = Content::layout(self, to.area());
to.blit(self, x, y, None)});
impl_content_layout_render!(TuiOut: |self: String, to|
layout = to.center_xy([self.chars().count() as u16, 1]);
render = {let [x, y, ..] = Content::layout(self, to.area());
to.blit(self, x, y, None)});
impl_content_layout_render!(TuiOut: |self: std::sync::RwLock<String>, to|
layout = Content::<TuiOut>::layout(&self.read().unwrap(), to);
render = Content::<TuiOut>::render(&self.read().unwrap(), to));
impl_content_layout_render!(TuiOut: |self: std::sync::RwLockReadGuard<'_, String>, to|
layout = Content::<TuiOut>::layout(&**self, to);
render = Content::<TuiOut>::render(&**self, to));
impl_content_layout_render!(TuiOut: |self: Arc<str>, to|
layout = to.center_xy([self.chars().count() as u16, 1]);
render = to.blit(self, to.area.x(), to.area.y(), None));
impl<T: Content<TuiOut>> Content<TuiOut> for std::sync::Arc<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
Content::<TuiOut>::layout(&**self, to)

View file

@ -1,5 +1,6 @@
use crate::*;
use rand::{thread_rng, distributions::uniform::UniformSampler};
impl Tui {
pub const fn null () -> Color { Color::Reset }
pub const fn g (g: u8) -> Color { Color::Rgb(g, g, g) }
@ -23,7 +24,9 @@ impl Tui {
//fn ti1 () -> Color { Color::Rgb(150, 160, 90) }
//fn ti2 () -> Color { Color::Rgb(120, 130, 100) }
}
pub trait HasColor { fn color (&self) -> ItemColor; }
#[macro_export] macro_rules! has_color {
(|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
impl $(<$($L),*$($T $(: $U)?),*>)? HasColor for $Struct $(<$($L),*$($T),*>)? {
@ -31,17 +34,22 @@ pub trait HasColor { fn color (&self) -> ItemColor; }
}
}
}
/// A color in OKHSL and RGB representations.
#[derive(Debug, Default, Copy, Clone, PartialEq)] pub struct ItemColor {
pub okhsl: Okhsl<f32>,
pub rgb: Color,
}
from!(|okhsl: Okhsl<f32>|ItemColor = Self { okhsl, rgb: okhsl_to_rgb(okhsl) });
pub fn okhsl_to_rgb (color: Okhsl<f32>) -> Color {
let Srgb { red, green, blue, .. }: Srgb<f32> = Srgb::from_color_unclamped(color);
Color::Rgb((red * 255.0) as u8, (green * 255.0) as u8, (blue * 255.0) as u8,)
}
from!(|rgb: Color|ItemColor = Self { rgb, okhsl: rgb_to_okhsl(rgb) });
pub fn rgb_to_okhsl (color: Color) -> Okhsl<f32> {
if let Color::Rgb(r, g, b) = color {
Okhsl::from_color(Srgb::new(r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0))
@ -49,6 +57,7 @@ pub fn rgb_to_okhsl (color: Color) -> Okhsl<f32> {
unreachable!("only Color::Rgb is supported")
}
}
// A single color within item theme parameters, in OKHSL and RGB representations.
impl ItemColor {
pub const fn from_rgb (rgb: Color) -> Self {
@ -77,6 +86,7 @@ impl ItemColor {
self.okhsl.mix(other.okhsl, distance).into()
}
}
/// A color in OKHSL and RGB with lighter and darker variants.
#[derive(Debug, Default, Copy, Clone, PartialEq)] pub struct ItemPalette {
pub base: ItemColor,
@ -87,6 +97,7 @@ impl ItemColor {
pub darker: ItemColor,
pub darkest: ItemColor,
}
impl ItemPalette {
pub const G: [Self;256] = {
let mut builder = konst::array::ArrayBuilder::new();
@ -159,5 +170,6 @@ impl ItemPalette {
}
}
}
from!(|base: Color| ItemPalette = Self::from_tui_color(base));
from!(|base: ItemColor|ItemPalette = Self::from_item_color(base));

View file

@ -1,5 +1,11 @@
use crate::*;
use std::time::Duration;
mod tui_buffer; pub use self::tui_buffer::*;
mod tui_input; pub use self::tui_input::*;
mod tui_output; pub use self::tui_output::*;
mod tui_perf; pub use self::tui_perf::*;
pub struct Tui {
pub exited: Arc<AtomicBool>,
pub backend: CrosstermBackend<Stdout>,
@ -7,6 +13,31 @@ pub struct Tui {
pub area: [u16;4],
pub perf: PerfModel,
}
pub trait TuiRun<R: Render<TuiOut> + Handle<TuiIn> + 'static> {
/// Run an app in the main loop.
fn run (&self, state: &Arc<RwLock<R>>) -> Usually<()>;
}
impl<T: Render<TuiOut> + Handle<TuiIn> + 'static> TuiRun<T> for Arc<RwLock<Tui>> {
fn run (&self, state: &Arc<RwLock<T>>) -> Usually<()> {
let _input_thread = TuiIn::run_input(self, state, Duration::from_millis(100));
self.write().unwrap().setup()?;
let render_thread = TuiOut::run_output(self, state, Duration::from_millis(10));
match render_thread.join() {
Ok(result) => {
self.write().unwrap().teardown()?;
println!("\n\rRan successfully: {result:?}\n\r");
},
Err(error) => {
self.write().unwrap().teardown()?;
panic!("\n\rRender thread failed: {error:?}.\n\r")
},
}
Ok(())
}
}
impl Tui {
/// Construct a new TUI engine and wrap it for shared ownership.
pub fn new () -> Usually<Arc<RwLock<Self>>> {
@ -58,25 +89,3 @@ impl Tui {
disable_raw_mode().map_err(Into::into)
}
}
pub trait TuiRun<R: Render<TuiOut> + Handle<TuiIn> + 'static> {
/// Run an app in the main loop.
fn run (&self, state: &Arc<RwLock<R>>) -> Usually<()>;
}
impl<T: Render<TuiOut> + Handle<TuiIn> + 'static> TuiRun<T> for Arc<RwLock<Tui>> {
fn run (&self, state: &Arc<RwLock<T>>) -> Usually<()> {
let _input_thread = TuiIn::run_input(self, state, Duration::from_millis(100));
self.write().unwrap().setup()?;
let render_thread = TuiOut::run_output(self, state, Duration::from_millis(10));
match render_thread.join() {
Ok(result) => {
self.write().unwrap().teardown()?;
println!("\n\rRan successfully: {result:?}\n\r");
},
Err(error) => {
self.write().unwrap().teardown()?;
panic!("\n\rRender thread failed: {error:?}.\n\r")
},
}
Ok(())
}
}

View file

@ -1,4 +1,5 @@
use crate::*;
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;
@ -12,16 +13,19 @@ pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut C
}
}
}
#[derive(Default)] pub struct BigBuffer {
pub width: usize,
pub height: usize,
pub content: Vec<Cell>
}
impl std::fmt::Debug for BigBuffer {
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
write!(f, "[BB {}x{} ({})]", self.width, self.height, self.content.len())
}
}
impl BigBuffer {
pub fn new (width: usize, height: usize) -> Self {
Self { width, height, content: vec![Cell::default(); width*height] }
@ -38,4 +42,5 @@ impl BigBuffer {
y * self.width + x
}
}
from!(|size:(usize, usize)| BigBuffer = Self::new(size.0, size.1));

View file

@ -2,6 +2,7 @@ use crate::*;
use std::time::Duration;
use std::thread::{spawn, JoinHandle};
use crossterm::event::{poll, read};
#[derive(Debug, Clone)] pub struct TuiIn(pub Arc<AtomicBool>, pub Event);
impl Input for TuiIn {
type Event = Event;