mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-05-13 02:30:13 +02:00
refactor: extract more tui_content modules
This commit is contained in:
parent
86236b76cd
commit
ea01deb854
|
@ -1,41 +1,18 @@
|
|||
use crate::*;
|
||||
use ratatui::prelude::Position;
|
||||
|
||||
mod tui_color; pub use self::tui_color::*;
|
||||
mod tui_file; pub use self::tui_file::*;
|
||||
mod tui_scroll; pub use self::tui_scroll::*;
|
||||
mod tui_string; pub use self::tui_string::*;
|
||||
mod tui_border; pub use self::tui_border::*;
|
||||
|
||||
macro_rules! impl_content_layout_render {
|
||||
($Output:ty: |$self:ident: $Struct:ty, $to:ident| layout = $layout:expr; render = $render:expr) => {
|
||||
(
|
||||
$Output:ty: |$self:ident: $Struct:ty, $to:ident|
|
||||
layout = $layout:expr;
|
||||
render = $render:expr
|
||||
) => {
|
||||
impl Content<$Output> for $Struct {
|
||||
fn layout (&$self, $to: [u16;4]) -> [u16;4] { $layout }
|
||||
fn render (&$self, $to: &mut $Output) { $render }
|
||||
}
|
||||
}
|
||||
}
|
||||
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] {
|
||||
|
@ -46,158 +23,12 @@ impl<T: Content<TuiOut>> Content<TuiOut> for std::sync::Arc<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct FieldH<T, U>(pub ItemPalette, pub T, pub U);
|
||||
impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldH<T, U> {
|
||||
fn content (&self) -> impl Render<TuiOut> {
|
||||
let Self(ItemPalette { darkest, dark, lighter, lightest, .. }, title, value) = self;
|
||||
row!(
|
||||
Tui::fg_bg(dark.rgb, darkest.rgb, "▐"),
|
||||
Tui::fg_bg(lighter.rgb, dark.rgb, Tui::bold(true, title)),
|
||||
Tui::fg_bg(dark.rgb, darkest.rgb, "▌"),
|
||||
Tui::fg_bg(lightest.rgb, darkest.rgb, value),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldV<T, U>(pub ItemPalette, pub T, pub U);
|
||||
impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldV<T, U> {
|
||||
fn content (&self) -> impl Render<TuiOut> {
|
||||
let Self(ItemPalette { darkest, dark, lighter, lightest, .. }, title, value) = self;
|
||||
let sep1 = Tui::bg(darkest.rgb, Tui::fg(dark.rgb, "▐"));
|
||||
let sep2 = Tui::bg(darkest.rgb, Tui::fg(dark.rgb, "▌"));
|
||||
let title = Tui::bg(dark.rgb, Tui::fg(lighter.rgb, Tui::bold(true, title)));
|
||||
let value = Tui::bg(darkest.rgb, Tui::fg(lightest.rgb, value));
|
||||
Bsp::e(Bsp::s(row!(sep1, title, sep2), value), " ")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Repeat<'a>(pub &'a str);
|
||||
impl Content<TuiOut> for Repeat<'_> {
|
||||
fn layout (&self, to: [u16;4]) -> [u16;4] { to }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
let [x, y, w, h] = to.area().xywh();
|
||||
let a = self.0.len();
|
||||
for (_v, y) in (y..y+h).enumerate() {
|
||||
for (u, x) in (x..x+w).enumerate() {
|
||||
if let Some(cell) = to.buffer.cell_mut(Position::from((x, y))) {
|
||||
let u = u % a;
|
||||
cell.set_symbol(&self.0[u..u+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RepeatV<'a>(pub &'a str);
|
||||
impl Content<TuiOut> for RepeatV<'_> {
|
||||
fn layout (&self, to: [u16;4]) -> [u16;4] { to }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
let [x, y, _w, h] = to.area().xywh();
|
||||
for y in y..y+h {
|
||||
if let Some(cell) = to.buffer.cell_mut(Position::from((x, y))) {
|
||||
cell.set_symbol(&self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RepeatH<'a>(pub &'a str);
|
||||
impl Content<TuiOut> for RepeatH<'_> {
|
||||
fn layout (&self, to: [u16;4]) -> [u16;4] { to }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
let [x, y, w, _h] = to.area().xywh();
|
||||
for x in x..x+w {
|
||||
if let Some(cell) = to.buffer.cell_mut(Position::from((x, y))) {
|
||||
cell.set_symbol(&self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A cell that takes up 3 rows on its own,
|
||||
/// but stacks, giving (N+1)*2 rows per N cells.
|
||||
pub struct Phat<T> {
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub content: T,
|
||||
pub colors: [Color;4],
|
||||
}
|
||||
impl<T> Phat<T> {
|
||||
/// A phat line
|
||||
pub fn lo (fg: Color, bg: Color) -> impl Content<TuiOut> {
|
||||
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(&"▄")))
|
||||
}
|
||||
/// A phat line
|
||||
pub fn hi (fg: Color, bg: Color) -> impl Content<TuiOut> {
|
||||
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(&"▀")))
|
||||
}
|
||||
}
|
||||
impl<T: Content<TuiOut>> Content<TuiOut> for Phat<T> {
|
||||
fn content (&self) -> impl Render<TuiOut> {
|
||||
let [fg, bg, hi, lo] = self.colors;
|
||||
let top = Fixed::y(1, Self::lo(bg, hi));
|
||||
let low = Fixed::y(1, Self::hi(bg, lo));
|
||||
let content = Tui::fg_bg(fg, bg, &self.content);
|
||||
Min::xy(self.width, self.height, Bsp::s(top, Bsp::n(low, Fill::xy(content))))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TuiStyle {
|
||||
fn fg <R: Content<TuiOut>> (color: Color, w: R) -> Foreground<R> {
|
||||
Foreground(color, w)
|
||||
}
|
||||
fn bg <R: Content<TuiOut>> (color: Color, w: R) -> Background<R> {
|
||||
Background(color, w)
|
||||
}
|
||||
fn fg_bg <R: Content<TuiOut>> (fg: Color, bg: Color, w: R) -> Background<Foreground<R>> {
|
||||
Background(bg, Foreground(fg, w))
|
||||
}
|
||||
fn modify <R: Content<TuiOut>> (enable: bool, modifier: Modifier, w: R) -> Modify<R> {
|
||||
Modify(enable, modifier, w)
|
||||
}
|
||||
fn bold <R: Content<TuiOut>> (enable: bool, w: R) -> Modify<R> {
|
||||
Self::modify(enable, Modifier::BOLD, w)
|
||||
}
|
||||
fn border <R: Content<TuiOut>, S: BorderStyle> (enable: bool, style: S, w: R) -> Bordered<S, R> {
|
||||
Bordered(enable, style, w)
|
||||
}
|
||||
}
|
||||
|
||||
impl TuiStyle for Tui {}
|
||||
|
||||
pub struct Foreground<R: Content<TuiOut>>(pub Color, pub 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<TuiOut>>(pub Color, pub 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 Modify<R: Content<TuiOut>>(pub bool, pub Modifier, pub R);
|
||||
impl<R: Content<TuiOut>> Content<TuiOut> for Modify<R> {
|
||||
fn content (&self) -> impl Render<TuiOut> { &self.2 }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
to.fill_mod(to.area(), self.0, self.1);
|
||||
self.2.render(to)
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
to.place(self.content().layout(to.area()), &self.content());
|
||||
// TODO write style over area
|
||||
}
|
||||
}
|
||||
mod tui_border; pub use self::tui_border::*;
|
||||
mod tui_color; pub use self::tui_color::*;
|
||||
mod tui_field; pub use self::tui_field::*;
|
||||
mod tui_file; pub use self::tui_file::*;
|
||||
mod tui_phat; pub use self::tui_phat::*;
|
||||
mod tui_repeat; pub use self::tui_repeat::*;
|
||||
mod tui_scroll; pub use self::tui_scroll::*;
|
||||
mod tui_string; pub use self::tui_string::*;
|
||||
mod tui_style; pub use self::tui_style::*;
|
||||
|
|
26
tui/src/tui_content/tui_field.rs
Normal file
26
tui/src/tui_content/tui_field.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct FieldH<T, U>(pub ItemPalette, pub T, pub U);
|
||||
impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldH<T, U> {
|
||||
fn content (&self) -> impl Render<TuiOut> {
|
||||
let Self(ItemPalette { darkest, dark, lighter, lightest, .. }, title, value) = self;
|
||||
row!(
|
||||
Tui::fg_bg(dark.rgb, darkest.rgb, "▐"),
|
||||
Tui::fg_bg(lighter.rgb, dark.rgb, Tui::bold(true, title)),
|
||||
Tui::fg_bg(dark.rgb, darkest.rgb, "▌"),
|
||||
Tui::fg_bg(lightest.rgb, darkest.rgb, value),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldV<T, U>(pub ItemPalette, pub T, pub U);
|
||||
impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldV<T, U> {
|
||||
fn content (&self) -> impl Render<TuiOut> {
|
||||
let Self(ItemPalette { darkest, dark, lighter, lightest, .. }, title, value) = self;
|
||||
let sep1 = Tui::bg(darkest.rgb, Tui::fg(dark.rgb, "▐"));
|
||||
let sep2 = Tui::bg(darkest.rgb, Tui::fg(dark.rgb, "▌"));
|
||||
let title = Tui::bg(dark.rgb, Tui::fg(lighter.rgb, Tui::bold(true, title)));
|
||||
let value = Tui::bg(darkest.rgb, Tui::fg(lightest.rgb, value));
|
||||
Bsp::e(Bsp::s(row!(sep1, title, sep2), value), " ")
|
||||
}
|
||||
}
|
29
tui/src/tui_content/tui_phat.rs
Normal file
29
tui/src/tui_content/tui_phat.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use crate::*;
|
||||
|
||||
/// A cell that takes up 3 rows on its own,
|
||||
/// but stacks, giving (N+1)*2 rows per N cells.
|
||||
pub struct Phat<T> {
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub content: T,
|
||||
pub colors: [Color;4],
|
||||
}
|
||||
impl<T> Phat<T> {
|
||||
/// A phat line
|
||||
pub fn lo (fg: Color, bg: Color) -> impl Content<TuiOut> {
|
||||
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(&"▄")))
|
||||
}
|
||||
/// A phat line
|
||||
pub fn hi (fg: Color, bg: Color) -> impl Content<TuiOut> {
|
||||
Fixed::y(1, Tui::fg_bg(fg, bg, RepeatH(&"▀")))
|
||||
}
|
||||
}
|
||||
impl<T: Content<TuiOut>> Content<TuiOut> for Phat<T> {
|
||||
fn content (&self) -> impl Render<TuiOut> {
|
||||
let [fg, bg, hi, lo] = self.colors;
|
||||
let top = Fixed::y(1, Self::lo(bg, hi));
|
||||
let low = Fixed::y(1, Self::hi(bg, lo));
|
||||
let content = Tui::fg_bg(fg, bg, &self.content);
|
||||
Min::xy(self.width, self.height, Bsp::s(top, Bsp::n(low, Fill::xy(content))))
|
||||
}
|
||||
}
|
45
tui/src/tui_content/tui_repeat.rs
Normal file
45
tui/src/tui_content/tui_repeat.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use crate::*;
|
||||
use ratatui::prelude::Position;
|
||||
|
||||
pub struct Repeat<'a>(pub &'a str);
|
||||
impl Content<TuiOut> for Repeat<'_> {
|
||||
fn layout (&self, to: [u16;4]) -> [u16;4] { to }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
let [x, y, w, h] = to.area().xywh();
|
||||
let a = self.0.len();
|
||||
for (_v, y) in (y..y+h).enumerate() {
|
||||
for (u, x) in (x..x+w).enumerate() {
|
||||
if let Some(cell) = to.buffer.cell_mut(Position::from((x, y))) {
|
||||
let u = u % a;
|
||||
cell.set_symbol(&self.0[u..u+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RepeatV<'a>(pub &'a str);
|
||||
impl Content<TuiOut> for RepeatV<'_> {
|
||||
fn layout (&self, to: [u16;4]) -> [u16;4] { to }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
let [x, y, _w, h] = to.area().xywh();
|
||||
for y in y..y+h {
|
||||
if let Some(cell) = to.buffer.cell_mut(Position::from((x, y))) {
|
||||
cell.set_symbol(&self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RepeatH<'a>(pub &'a str);
|
||||
impl Content<TuiOut> for RepeatH<'_> {
|
||||
fn layout (&self, to: [u16;4]) -> [u16;4] { to }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
let [x, y, w, _h] = to.area().xywh();
|
||||
for x in x..x+w {
|
||||
if let Some(cell) = to.buffer.cell_mut(Position::from((x, y))) {
|
||||
cell.set_symbol(&self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,24 @@ use crate::*;
|
|||
use crate::ratatui::prelude::Position;
|
||||
use unicode_width::{UnicodeWidthStr, UnicodeWidthChar};
|
||||
|
||||
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));
|
||||
|
||||
/// Displays an owned [str]-like with fixed maximum width.
|
||||
///
|
||||
/// Width is computed using [unicode_width].
|
||||
|
|
60
tui/src/tui_content/tui_style.rs
Normal file
60
tui/src/tui_content/tui_style.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait TuiStyle {
|
||||
fn fg <R: Content<TuiOut>> (color: Color, w: R) -> Foreground<R> {
|
||||
Foreground(color, w)
|
||||
}
|
||||
fn bg <R: Content<TuiOut>> (color: Color, w: R) -> Background<R> {
|
||||
Background(color, w)
|
||||
}
|
||||
fn fg_bg <R: Content<TuiOut>> (fg: Color, bg: Color, w: R) -> Background<Foreground<R>> {
|
||||
Background(bg, Foreground(fg, w))
|
||||
}
|
||||
fn modify <R: Content<TuiOut>> (enable: bool, modifier: Modifier, w: R) -> Modify<R> {
|
||||
Modify(enable, modifier, w)
|
||||
}
|
||||
fn bold <R: Content<TuiOut>> (enable: bool, w: R) -> Modify<R> {
|
||||
Self::modify(enable, Modifier::BOLD, w)
|
||||
}
|
||||
fn border <R: Content<TuiOut>, S: BorderStyle> (enable: bool, style: S, w: R) -> Bordered<S, R> {
|
||||
Bordered(enable, style, w)
|
||||
}
|
||||
}
|
||||
|
||||
impl TuiStyle for Tui {}
|
||||
|
||||
pub struct Foreground<R: Content<TuiOut>>(pub Color, pub 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<TuiOut>>(pub Color, pub 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 Modify<R: Content<TuiOut>>(pub bool, pub Modifier, pub R);
|
||||
impl<R: Content<TuiOut>> Content<TuiOut> for Modify<R> {
|
||||
fn content (&self) -> impl Render<TuiOut> { &self.2 }
|
||||
fn render (&self, to: &mut TuiOut) {
|
||||
to.fill_mod(to.area(), self.0, self.1);
|
||||
self.2.render(to)
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
to.place(self.content().layout(to.area()), &self.content());
|
||||
// TODO write style over area
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue