wip: big flat pt.4: extract layout crate

This commit is contained in:
🪞👃🪞 2024-12-30 19:07:43 +01:00
parent cb680ab096
commit 34e731f111
21 changed files with 2125 additions and 83 deletions

View file

@ -36,14 +36,14 @@ pub trait Coordinate: Send + Sync + Copy
+ Into<usize>
+ Into<f64>
{
fn minus (self, other: Self) -> Self {
#[inline] fn minus (self, other: Self) -> Self {
if self >= other {
self - other
} else {
0.into()
}
}
fn zero () -> Self {
#[inline] fn zero () -> Self {
0.into()
}
}
@ -65,11 +65,21 @@ pub trait Size<N: Coordinate> {
}
}
impl<N: Coordinate> Size<N> for (N, N) {
#[inline] fn x (&self) -> N { self.0 }
#[inline] fn y (&self) -> N { self.1 }
}
impl<N: Coordinate> Size<N> for [N;2] {
#[inline] fn x (&self) -> N { self[0] }
#[inline] fn y (&self) -> N { self[1] }
}
pub trait Area<N: Coordinate>: Copy {
fn x (&self) -> N;
fn y (&self) -> N;
fn w (&self) -> N;
fn h (&self) -> N;
fn x (&self) -> N;
fn y (&self) -> N;
fn w (&self) -> N;
fn h (&self) -> N;
#[inline] fn expect_min (&self, w: N, h: N) -> Usually<&Self> {
if self.w() < w || self.h() < h {
Err(format!("min {w}x{h}").into())
@ -77,4 +87,33 @@ pub trait Area<N: Coordinate>: Copy {
Ok(self)
}
}
#[inline] fn wh (&self) -> [N;2] {
[self.w(), self.h()]
}
#[inline] fn xywh (&self) -> [N;4] {
[self.x(), self.y(), self.w(), self.h()]
}
#[inline] fn clip_h (&self, h: N) -> [N;4] {
[self.x(), self.y(), self.w(), self.h().min(h)]
}
#[inline] fn clip_w (&self, w: N) -> [N;4] {
[self.x(), self.y(), self.w().min(w), self.h()]
}
#[inline] fn clip (&self, wh: impl Size<N>) -> [N;4] {
[self.x(), self.y(), wh.w(), wh.h()]
}
}
impl<N: Coordinate> Area<N> for (N, N, N, N) {
#[inline] fn x (&self) -> N { self.0 }
#[inline] fn y (&self) -> N { self.1 }
#[inline] fn w (&self) -> N { self.2 }
#[inline] fn h (&self) -> N { self.3 }
}
impl<N: Coordinate> Area<N> for [N;4] {
#[inline] fn x (&self) -> N { self[0] }
#[inline] fn y (&self) -> N { self[1] }
#[inline] fn w (&self) -> N { self[2] }
#[inline] fn h (&self) -> N { self[3] }
}

View file

@ -1,6 +1,38 @@
use crate::*;
use std::sync::{Arc, Mutex, RwLock};
/// Define custom content for a struct.
#[macro_export] macro_rules! render {
// Implement for all engines
(|$self:ident:$Struct:ident$(<$($L:lifetime),*E$(,$T:ident$(:$U:path)?)*$(,)?>)?|$cb:expr) => {
impl<E: Engine, $($($L),*$($T $(: $U)?),*)?> Content<E> for $Struct $(<$($L,)* E, $($T),*>)? {
fn content (&$self) -> Option<impl Render<$E>> {
Some($cb)
}
}
};
// Implement for a specific engine
(<$E:ty>|$self:ident:$Struct:ident$(<
$($($L:lifetime),+)?
$($($T:ident$(:$U:path)?),+)?
>)?|$cb:expr) => {
impl $(<
$($($L),+)?
$($($T$(:$U)?),+)?
>)? Content<$E> for $Struct $(<
$($($L),+)?
$($($T),+)?
>)? {
fn content (&$self) -> Option<impl Render<$E>> {
Some($cb)
}
}
}
}
/// Write content to output buffer.
pub trait Render<E: Engine>: Send + Sync {
/// Minimum size to use
@ -18,18 +50,18 @@ pub trait Content<E: Engine>: Send + Sync {
fn content (&self) -> Option<impl Render<E>>;
}
impl<E: Engine, C: Content<E>> Render<E> for C {
/// Minimum size to use
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
self.content().map(|content|content.min_size(to))
.unwrap_or(Ok(None))
}
/// Draw to output render target
fn render (&self, to: &mut E::Output) -> Usually<()> {
self.content().map(|content|content.render(to))
.unwrap_or(Ok(()))
}
}
//impl<E: Engine, C: Content<E>> Render<E> for C {
///// Minimum size to use
//fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
//self.content().map(|content|content.min_size(to))
//.unwrap_or(Ok(None))
//}
///// Draw to output render target
//fn render (&self, to: &mut E::Output) -> Usually<()> {
//self.content().map(|content|content.render(to))
//.unwrap_or(Ok(()))
//}
//}
/// Rendering target
pub trait Output<E: Engine> {
@ -44,9 +76,9 @@ pub trait Output<E: Engine> {
//impl<E: Engine> Render<E> for &dyn Render<E> {}
//impl<E: Engine> Render<E> for &mut dyn Render<E> {}
//impl<E: Engine> Render<E> for Box<dyn Render<E>> {}
//impl<E: Engine, R: Render<E>> Render<E> for &R {}
impl<E: Engine, R: Render<E>> Render<E> for &R {}
//impl<E: Engine, R: Render<E>> Render<E> for &mut R {}
//impl<E: Engine, R: Render<E>> Render<E> for Option<R> {}
impl<E: Engine, R: Render<E>> Render<E> for Option<R> {}
//impl<E: Engine, R: Render<E>> Render<E> for Arc<R> {}
//impl<E: Engine, R: Render<E>> Render<E> for Mutex<R> {}
//impl<E: Engine, R: Render<E>> Render<E> for RwLock<R> {}
@ -101,38 +133,6 @@ impl<E: Engine, C: Content<E>> Render<E> for C {
//}
/// Define custom content for a struct.
#[macro_export] macro_rules! render {
// Implement for all engines
(|$self:ident:$Struct:ident$(<$($L:lifetime),*E$(,$T:ident$(:$U:path)?)*$(,)?>)?|$cb:expr) => {
impl<E: Engine, $($($L),*$($T $(: $U)?),*)?> Content<E> for $Struct $(<$($L,)* E, $($T),*>)? {
fn content (&$self) -> Option<impl Render<$E>> {
Some($cb)
}
}
};
// Implement for a specific engine
(<$E:ty>|$self:ident:$Struct:ident$(<
$($($L:lifetime),+)?
$($($T:ident$(:$U:path)?),+)?
>)?|$cb:expr) => {
impl $(<
$($($L),+)?
$($($T$(:$U)?),+)?
>)? Content<$E> for $Struct $(<
$($($L),+)?
$($($T),+)?
>)? {
fn content (&$self) -> Option<impl Render<$E>> {
Some($cb)
}
}
}
}
impl<E: Engine, R: Render<E>> Render<E> for &R {
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
(*self).min_size(to)

View file

@ -25,18 +25,6 @@ pub(crate) use ratatui::{
impl Coordinate for u16 {}
impl Size<u16> for [u16;2] {
fn x (&self) -> u16 { self[0] }
fn y (&self) -> u16 { self[1] }
}
impl Area<u16> for [u16;4] {
fn x (&self) -> u16 { self[0] }
fn y (&self) -> u16 { self[1] }
fn w (&self) -> u16 { self[2] }
fn h (&self) -> u16 { self[3] }
}
pub struct Tui {
pub exited: Arc<AtomicBool>,
pub buffer: Buffer,
@ -349,19 +337,7 @@ pub fn half_block (lower: bool, upper: bool) -> Option<char> {
//impl<T: Content<Tui>> Render<Tui> for T {}
impl Render<Tui> for &str {
fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
// TODO: line breaks
Ok(Some([self.chars().count() as u16, 1]))
}
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
let [x, y, ..] = to.area();
//let [w, h] = self.min_size(to.area().wh())?.unwrap();
Ok(to.blit(&self, x, y, None))
}
}
impl Render<Tui> for &String {
impl Render<Tui> for str {
fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
// TODO: line breaks
Ok(Some([self.chars().count() as u16, 1]))