mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-07-17 07:56:56 +02:00
wip: final simplify
This commit is contained in:
parent
90ebae0f26
commit
0b9e9c0696
21 changed files with 607 additions and 544 deletions
0
PAPER.qmd
Normal file
0
PAPER.qmd
Normal file
2
dizzle
2
dizzle
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0292cea24f5bfe71e0f8c6f4afe3cad105aa8ab8
|
Subproject commit f8e310b477afc1aab4701fdc52da474143d78a28
|
||||||
23
shell.nix
23
shell.nix
|
|
@ -1,13 +1,28 @@
|
||||||
#!/usr/bin/env nix-shell
|
#!/usr/bin/env nix-shell
|
||||||
{pkgs?import<nixpkgs>{}}:let
|
{pkgs?import<nixpkgs>{}}:let
|
||||||
stdenv = pkgs.clang19Stdenv;
|
|
||||||
name = "tengri";
|
name = "tengri";
|
||||||
nativeBuildInputs = [ pkgs.pkg-config pkgs.clang pkgs.libclang pkgs.mold pkgs.bacon ];
|
stdenv = pkgs.clang19Stdenv;
|
||||||
buildInputs = [ pkgs.libclang pkgs.jack2 ];
|
|
||||||
LIBCLANG_PATH = "${pkgs.libclang.lib.outPath}/lib";
|
LIBCLANG_PATH = "${pkgs.libclang.lib.outPath}/lib";
|
||||||
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [];
|
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [];
|
||||||
in pkgs.mkShell.override {
|
in pkgs.mkShell.override {
|
||||||
inherit stdenv;
|
inherit stdenv;
|
||||||
} {
|
} {
|
||||||
inherit name nativeBuildInputs buildInputs LIBCLANG_PATH LD_LIBRARY_PATH;
|
inherit name LIBCLANG_PATH LD_LIBRARY_PATH;
|
||||||
|
buildInputs = [
|
||||||
|
pkgs.libclang
|
||||||
|
pkgs.jack2
|
||||||
|
];
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkgs.pkg-config
|
||||||
|
pkgs.clang
|
||||||
|
pkgs.libclang
|
||||||
|
pkgs.mold
|
||||||
|
pkgs.bacon
|
||||||
|
(pkgs.quarto.overrideAttrs (oldAttrs: { # https://github.com/NixOS/nixpkgs/issues/519484
|
||||||
|
postPatch = (oldAttrs.postPatch or "") + ''
|
||||||
|
substituteInPlace bin/quarto.js \
|
||||||
|
--replace-fail "syntax-highlighting" "highlight-style"
|
||||||
|
'';
|
||||||
|
}))
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
123
src/draw.rs
123
src/draw.rs
|
|
@ -1,14 +1,30 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
pub use crate::space::*;
|
pub use crate::space::*;
|
||||||
|
|
||||||
mod view;
|
/// Output target.
|
||||||
pub use self::view::*;
|
///
|
||||||
|
/// ```
|
||||||
mod thunk;
|
/// use tengri::{*, draw::*};
|
||||||
pub use self::thunk::*;
|
///
|
||||||
|
/// struct TestOut<T: Screen<Unit = u16>>(T);
|
||||||
mod screen;
|
///
|
||||||
pub use self::screen::*;
|
/// impl<T: Screen<Unit = u16>> Screen for TestOut {
|
||||||
|
/// type Unit = u16;
|
||||||
|
/// fn show <D: Draw<Self> + ?Sized> (&mut self, _: D) {
|
||||||
|
/// println!("placed");
|
||||||
|
/// ()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl_draw!(|self: String, to: TestOut<u16>|{
|
||||||
|
/// to.area_mut().set_w(self.len() as u16);
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
pub trait Screen: Xy<Self::Unit> + Wh<Self::Unit> + Send + Sync + Sized {
|
||||||
|
type Unit: Coord;
|
||||||
|
/// Render drawable in subarea specified by `area`
|
||||||
|
fn show <'t, T: Draw<Self>> (&mut self, content: T) -> Perhaps<XYWH<Self::Unit>>;
|
||||||
|
}
|
||||||
|
|
||||||
/// Implement the [Draw] trait for a particular drawable and [Screen].
|
/// Implement the [Draw] trait for a particular drawable and [Screen].
|
||||||
///
|
///
|
||||||
|
|
@ -22,7 +38,7 @@ pub use self::screen::*;
|
||||||
#[macro_export] macro_rules! impl_draw ((|
|
#[macro_export] macro_rules! impl_draw ((|
|
||||||
$self:ident:$Self:ty, $to:ident:$To:ty
|
$self:ident:$Self:ty, $to:ident:$To:ty
|
||||||
|$draw:block)=>{ impl Draw<$To> for $Self {
|
|$draw:block)=>{ impl Draw<$To> for $Self {
|
||||||
fn draw ($self, $to: &mut $To) -> Usually<XYWH<u16>> $draw
|
fn draw ($self, $to: &mut $To) -> Usually<XYWH<<$To as Screen>::Unit>> $draw
|
||||||
} });
|
} });
|
||||||
|
|
||||||
/// Drawable that supports dynamic dispatch.
|
/// Drawable that supports dynamic dispatch.
|
||||||
|
|
@ -48,29 +64,94 @@ pub use self::screen::*;
|
||||||
/// ```
|
/// ```
|
||||||
pub trait Draw<S: Screen> {
|
pub trait Draw<S: Screen> {
|
||||||
fn draw (self, to: &mut S) -> Usually<XYWH<S::Unit>>;
|
fn draw (self, to: &mut S) -> Usually<XYWH<S::Unit>>;
|
||||||
|
fn layout (&self, area: XYWH<S::Unit>) -> Perhaps<XYWH<S::Unit>> {
|
||||||
|
Ok(Some(area))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S: Screen> Draw<S> for () {
|
impl<S: Screen> Draw<S> for () {
|
||||||
fn draw (self, __: &mut S) -> Usually<XYWH<S::Unit>> {
|
fn draw (self, __: &mut S) -> Usually<XYWH<S::Unit>> {
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<S: Screen, D: Draw<S>> Draw<S> for &D {
|
|
||||||
fn draw (self, __: &mut S) -> Usually<XYWH<S::Unit>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<S: Screen, D: Draw<S>> Draw<S> for Option<D> {
|
impl<S: Screen, D: Draw<S>> Draw<S> for Option<D> {
|
||||||
fn draw (self, __: &mut S) -> Usually<XYWH<S::Unit>> {
|
fn draw (self, to: &mut S) -> Usually<XYWH<S::Unit>> {
|
||||||
todo!()
|
self.map(|it|it.draw(to)).transpose().map(Option::unwrap_or_default)
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<S: Screen, D: Draw<S>> Draw<S> for RwLock<D> {
|
|
||||||
fn draw (self, __: &mut S) -> Usually<XYWH<S::Unit>> {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//impl<S: Screen, D: Draw<S>> Draw<S> for RwLock<D> {
|
||||||
|
//fn draw (self, __: &mut S) -> Usually<XYWH<S::Unit>> {
|
||||||
|
//todo!()
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
//impl<T: Screen, D: Draw<T>> Draw<T> for Arc<D> {
|
//impl<T: Screen, D: Draw<T>> Draw<T> for Arc<D> {
|
||||||
//fn draw (self, __: &mut T) -> Usually<XYWH<T::Unit>> {
|
//fn draw (self, __: &mut T) -> Usually<XYWH<T::Unit>> {
|
||||||
//todo!()
|
//todo!()
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
/// Emit a [Draw]able.
|
||||||
|
///
|
||||||
|
/// Speculative. How to avoid conflicts with [Draw] proper?
|
||||||
|
pub trait View<T: Screen> {
|
||||||
|
fn view (&self) -> impl Draw<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Screen, V: View<T>> Draw<T> for &V {
|
||||||
|
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>> {
|
||||||
|
self.view().draw(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
|
||||||
|
pub struct Thunk<T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>>(
|
||||||
|
pub F,
|
||||||
|
std::marker::PhantomData<T>
|
||||||
|
);
|
||||||
|
|
||||||
|
impl<T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>> Draw<T> for Thunk<T, F> {
|
||||||
|
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>> {
|
||||||
|
(self.0)(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Basic [Draw]able closure.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use tengri::{draw::*, term::*};
|
||||||
|
/// # fn test () -> impl tengri::draw::Draw<tengri::term::Tui> {
|
||||||
|
/// thunk(|to: &mut Tui|Ok(to.1))
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub const fn thunk <T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>> (
|
||||||
|
draw: F
|
||||||
|
) -> Thunk<T, F> {
|
||||||
|
Thunk(draw, std::marker::PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Only render when condition is true.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use tengri::{draw::*, term::*};
|
||||||
|
/// # fn test () -> impl tengri::draw::Draw<tengri::term::Tui> {
|
||||||
|
/// when(true, "Yes")
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub const fn when <T: Screen> (condition: bool, draw: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
thunk(move|to: &mut T|if condition { draw.draw(to) } else { Ok(Default::default()) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render one thing if a condition is true and another false.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use tengri::{draw::*, term::*};
|
||||||
|
/// # fn test () -> impl tengri::draw::Draw<tengri::term::Tui> {
|
||||||
|
/// either(true, "Yes", "No")
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub const fn either <T: Screen> (condition: bool, a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
thunk(move|to: &mut T|if condition { a.draw(to) } else { b.draw(to) })
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// Output target.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use tengri::{*, draw::*};
|
|
||||||
///
|
|
||||||
/// struct TestOut<T: Screen<Unit = u16>>(T);
|
|
||||||
///
|
|
||||||
/// impl<T: Screen<Unit = u16>> Screen for TestOut {
|
|
||||||
/// type Unit = u16;
|
|
||||||
/// fn show <D: Draw<Self> + ?Sized> (&mut self, area: T, _: D) {
|
|
||||||
/// println!("placed: {area:?}");
|
|
||||||
/// ()
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// impl_draw!(|self: String, to: TestOut<u16>|{
|
|
||||||
/// to.area_mut().set_w(self.len() as u16);
|
|
||||||
/// });
|
|
||||||
/// ```
|
|
||||||
pub trait Screen: Space<Self::Unit> + Send + Sync + Sized {
|
|
||||||
type Unit: Coord;
|
|
||||||
/// Render drawable in subarea specified by `area`
|
|
||||||
fn show <'t, T: Draw<Self>> (&mut self, area: XYWH<Self::Unit>, content: T) ->
|
|
||||||
Usually<XYWH<Self::Unit>>;
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
|
|
||||||
pub struct Thunk<T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>>(
|
|
||||||
pub F,
|
|
||||||
std::marker::PhantomData<T>
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>> Draw<T> for Thunk<T, F> {
|
|
||||||
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>> {
|
|
||||||
(self.0)(to)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Basic [Draw]able closure.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use tengri::{draw::*, term::*};
|
|
||||||
/// # fn test () -> impl tengri::draw::Draw<tengri::term::Tui> {
|
|
||||||
/// thunk(|to: &mut Tui|Ok(to.1))
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub const fn thunk <T: Screen, F: FnOnce(&mut T)->Usually<XYWH<T::Unit>>> (
|
|
||||||
draw: F
|
|
||||||
) -> Thunk<T, F> {
|
|
||||||
Thunk(draw, std::marker::PhantomData)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Only render when condition is true.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use tengri::{draw::*, term::*};
|
|
||||||
/// # fn test () -> impl tengri::draw::Draw<tengri::term::Tui> {
|
|
||||||
/// when(true, "Yes")
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub const fn when <T: Screen> (condition: bool, draw: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
thunk(move|to: &mut T|if condition { draw.draw(to) } else { Ok(Default::default()) })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Render one thing if a condition is true and another false.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use tengri::{draw::*, term::*};
|
|
||||||
/// # fn test () -> impl tengri::draw::Draw<tengri::term::Tui> {
|
|
||||||
/// either(true, "Yes", "No")
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub const fn either <T: Screen> (condition: bool, a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
thunk(move|to: &mut T|if condition { a.draw(to) } else { b.draw(to) })
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// Emit a [Draw]able.
|
|
||||||
///
|
|
||||||
/// Speculative. How to avoid conflicts with [Draw] proper?
|
|
||||||
pub trait View<T: Screen> {
|
|
||||||
fn view (&self) -> impl Draw<T>;
|
|
||||||
}
|
|
||||||
|
|
@ -195,7 +195,7 @@ pub fn eval_view_tui <'a, S> (
|
||||||
|
|
||||||
Some("text") => {
|
Some("text") => {
|
||||||
if let Some(src) = args?.src()? {
|
if let Some(src) = args?.src()? {
|
||||||
output.show(output.xywh(), &src)?
|
output.show(src)?
|
||||||
} else {
|
} else {
|
||||||
return Ok(None)
|
return Ok(None)
|
||||||
}
|
}
|
||||||
|
|
@ -204,7 +204,7 @@ pub fn eval_view_tui <'a, S> (
|
||||||
Some("fg") => {
|
Some("fg") => {
|
||||||
let arg0 = arg0?.expect("fg: expected arg 0 (color)");
|
let arg0 = arg0?.expect("fg: expected arg 0 (color)");
|
||||||
let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("fg: {arg0:?}: not a color"));
|
let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("fg: {arg0:?}: not a color"));
|
||||||
output.show(output.xywh(), &fg(color, thunk(move|output: &mut Tui|{
|
output.show(fg(color, thunk(move|output: &mut Tui|{
|
||||||
state.interpret(output, &arg1)?;
|
state.interpret(output, &arg1)?;
|
||||||
// FIXME?: don't max out the used area?
|
// FIXME?: don't max out the used area?
|
||||||
Ok(output.area().into())
|
Ok(output.area().into())
|
||||||
|
|
@ -214,7 +214,7 @@ pub fn eval_view_tui <'a, S> (
|
||||||
Some("bg") => {
|
Some("bg") => {
|
||||||
let arg0 = arg0?.expect("bg: expected arg 0 (color)");
|
let arg0 = arg0?.expect("bg: expected arg 0 (color)");
|
||||||
let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("bg: {arg0:?}: not a color"));
|
let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("bg: {arg0:?}: not a color"));
|
||||||
output.show(output.xywh(), &bg(color, thunk(move|output: &mut Tui|{
|
output.show(bg(color, thunk(move|output: &mut Tui|{
|
||||||
state.interpret(output, &arg1)?;
|
state.interpret(output, &arg1)?;
|
||||||
// FIXME?: don't max out the used area?
|
// FIXME?: don't max out the used area?
|
||||||
Ok(output.area().into())
|
Ok(output.area().into())
|
||||||
|
|
|
||||||
87
src/layout.rs
Normal file
87
src/layout.rs
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
mod align; pub use self::align::*;
|
||||||
|
mod area; pub use self::area::*;
|
||||||
|
mod origin; pub use self::origin::*;
|
||||||
|
mod split; pub use self::split::*;
|
||||||
|
|
||||||
|
pub enum Layout<T: Screen, X: Into<Option<T::Unit>>, I: Draw<T>> {
|
||||||
|
__(PhantomData<T>),
|
||||||
|
MinW(X, I),
|
||||||
|
MinH(X, I),
|
||||||
|
MinWH(X, X, I),
|
||||||
|
MaxW(X, I),
|
||||||
|
MaxH(X, I),
|
||||||
|
MaxWH(X, X, I),
|
||||||
|
ExactW(X, I),
|
||||||
|
ExactH(X, I),
|
||||||
|
ExactWH(X, X, I),
|
||||||
|
ClipW(X, I),
|
||||||
|
ClipH(X, I),
|
||||||
|
ClipWH(X, X, I),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
T: Screen,
|
||||||
|
X: Into<Option<T::Unit>>,
|
||||||
|
I: Draw<T>
|
||||||
|
> Draw<T> for Layout<T, X, I> {
|
||||||
|
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>> {
|
||||||
|
use Layout::*;
|
||||||
|
match self {
|
||||||
|
__(_) => unreachable!(),
|
||||||
|
MinW(x, it) => {
|
||||||
|
let x = x.into();
|
||||||
|
it.draw(to)
|
||||||
|
},
|
||||||
|
MinH(y, it) => {
|
||||||
|
let y = y.into();
|
||||||
|
it.draw(to)
|
||||||
|
},
|
||||||
|
MinWH(x, y, it) => {
|
||||||
|
let x = x.into();
|
||||||
|
let y = y.into();
|
||||||
|
it.draw(to)
|
||||||
|
},
|
||||||
|
MaxW(x, it) => {
|
||||||
|
let x = x.into();
|
||||||
|
it.draw(to)
|
||||||
|
},
|
||||||
|
MaxH(y, it) => {
|
||||||
|
let y = y.into();
|
||||||
|
it.draw(to)
|
||||||
|
},
|
||||||
|
MaxWH(x, y, it) => {
|
||||||
|
let x = x.into();
|
||||||
|
let y = y.into();
|
||||||
|
it.draw(to)
|
||||||
|
},
|
||||||
|
ExactW(x, it) => {
|
||||||
|
let x = x.into();
|
||||||
|
it.draw(to)
|
||||||
|
},
|
||||||
|
ExactH(y, it) => {
|
||||||
|
let y = y.into();
|
||||||
|
it.draw(to)
|
||||||
|
},
|
||||||
|
ExactWH(x, y, it) => {
|
||||||
|
let x = x.into();
|
||||||
|
let y = y.into();
|
||||||
|
it.draw(to)
|
||||||
|
},
|
||||||
|
ClipW(x, it) => {
|
||||||
|
let x = x.into();
|
||||||
|
it.draw(to)
|
||||||
|
},
|
||||||
|
ClipH(y, it) => {
|
||||||
|
let y = y.into();
|
||||||
|
it.draw(to)
|
||||||
|
},
|
||||||
|
ClipWH(x, y, it) => {
|
||||||
|
let x = x.into();
|
||||||
|
let y = y.into();
|
||||||
|
it.draw(to)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/layout/align.rs
Normal file
13
src/layout/align.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
pub struct Align<T>(Option<Origin>, T);
|
||||||
|
|
||||||
|
/// ```
|
||||||
|
/// use tengri::*;
|
||||||
|
/// let _ = align(None, "unaligned");
|
||||||
|
/// let _ = align(Origin::SE, "southeast");
|
||||||
|
/// let _ = align(Some(Origin::SE), "southeast");
|
||||||
|
/// ```
|
||||||
|
pub fn align <S: Screen, T: Draw<S>, U: Into<Option<Origin>>> (origin: U, it: T) -> Align<T> {
|
||||||
|
Align(origin.into(), it)
|
||||||
|
}
|
||||||
15
src/layout/area.rs
Normal file
15
src/layout/area.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
pub struct Area<S: Screen, T: Draw<S>>(Option<XYWH<S::Unit>>, T);
|
||||||
|
|
||||||
|
/// ```
|
||||||
|
/// use tengri::*;
|
||||||
|
/// let _ = area(None, "unareaed");
|
||||||
|
/// let _ = area([1, 2, 3, 4], "southeast");
|
||||||
|
/// let _ = area(Some([1, 2, 3, 4]), "southeast");
|
||||||
|
/// ```
|
||||||
|
pub fn area <S: Screen, T: Draw<S>, U: Into<Option<XYWH<S::Unit>>>> (
|
||||||
|
origin: U, it: T
|
||||||
|
) -> Area<S, T> {
|
||||||
|
Area(origin.into(), it)
|
||||||
|
}
|
||||||
23
src/layout/origin.rs
Normal file
23
src/layout/origin.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Where is [0, 0] located?
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use tengri::draw::Origin;
|
||||||
|
/// let _ = Origin::NW.align(());
|
||||||
|
/// ```
|
||||||
|
#[cfg_attr(test, derive(Arbitrary))]
|
||||||
|
#[derive(Debug, Copy, Clone, Default)] pub enum Origin {
|
||||||
|
#[default] C, X, Y, NW, N, NE, E, SE, S, SW, W
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Something that has `[0, 0]` at a particular point.
|
||||||
|
pub trait HasOrigin {
|
||||||
|
fn origin (&self) -> Origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<Origin>> HasOrigin for T {
|
||||||
|
fn origin (&self) -> Origin {
|
||||||
|
*self.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -50,16 +50,16 @@ impl Split {
|
||||||
thunk(move|to: &mut T|{
|
thunk(move|to: &mut T|{
|
||||||
let (area_a, area_b) = to.xywh().split_half(self);
|
let (area_a, area_b) = to.xywh().split_half(self);
|
||||||
let (origin_a, origin_b) = self.origins();
|
let (origin_a, origin_b) = self.origins();
|
||||||
let a = origin_a.align(a);
|
let a = align(origin_a, a);
|
||||||
let b = origin_b.align(b);
|
let b = align(origin_b, b);
|
||||||
match self {
|
match self {
|
||||||
Self::Below => {
|
Self::Below => {
|
||||||
to.show(area_b, &b);
|
to.show(area(area_b, b))?;
|
||||||
to.show(area_b, &a);
|
to.show(area(area_b, a))?;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
to.show(area_a, &a);
|
to.show(area(area_a, a))?;
|
||||||
to.show(area_a, &b);
|
to.show(area(area_b, b))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(to.xywh()) // FIXME: compute and return actually used area
|
Ok(to.xywh()) // FIXME: compute and return actually used area
|
||||||
46
src/lib.rs
46
src/lib.rs
|
|
@ -25,30 +25,32 @@ pub(crate) use ::{
|
||||||
std::ops::{Add, Sub, Mul, Div},
|
std::ops::{Add, Sub, Mul, Div},
|
||||||
std::sync::{Arc, RwLock},
|
std::sync::{Arc, RwLock},
|
||||||
std::sync::atomic::{AtomicBool, AtomicUsize, Ordering::*},
|
std::sync::atomic::{AtomicBool, AtomicUsize, Ordering::*},
|
||||||
|
std::error::Error,
|
||||||
|
std::marker::PhantomData
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "lang")]
|
macro_rules! features {
|
||||||
pub use ::dizzle::{Usually, Perhaps, impl_default};
|
($($feature:literal: [ $($module:ident),* ]),*) => {
|
||||||
/// DSL builtins.
|
$(
|
||||||
#[cfg(feature = "lang")] pub mod eval;
|
$(
|
||||||
/// Temporal dimension.
|
#[cfg(feature = $feature)] mod $module;
|
||||||
#[cfg(feature = "time")] pub mod time;
|
#[cfg(feature = $feature)] pub use $module::*;
|
||||||
/// Circuit breaker for main loop.
|
)*
|
||||||
#[cfg(feature = "play")] pub mod exit;
|
)*
|
||||||
/// Thread management.
|
}
|
||||||
#[cfg(feature = "play")] pub mod task;
|
}
|
||||||
/// Integration with JACK audio backend.
|
|
||||||
#[cfg(feature = "sing")] pub mod sing;
|
#[cfg(feature = "lang")] pub use ::dizzle::{Usually, Perhaps, impl_default};
|
||||||
/// Generic drawing utilities.
|
|
||||||
#[cfg(feature = "draw")] pub mod draw;
|
features! {
|
||||||
/// Spatial dimension.
|
"lang": [ eval ],
|
||||||
#[cfg(feature = "draw")] pub mod space;
|
"time": [ time ],
|
||||||
/// Color handling.
|
"play": [ exit, task ],
|
||||||
#[cfg(feature = "draw")] pub mod color;
|
"sing": [ sing ],
|
||||||
/// Text handling.
|
"draw": [ draw, space, layout, color ],
|
||||||
#[cfg(feature = "text")] pub mod text;
|
"text": [ text ],
|
||||||
/// Terminal output.
|
"term": [ term ]
|
||||||
#[cfg(feature = "term")] pub mod term;
|
}
|
||||||
|
|
||||||
/// Define a trait an implement it for various mutation-enabled wrapper types. */
|
/// Define a trait an implement it for various mutation-enabled wrapper types. */
|
||||||
#[macro_export] macro_rules! flex_trait_mut (
|
#[macro_export] macro_rules! flex_trait_mut (
|
||||||
|
|
|
||||||
198
src/space.rs
198
src/space.rs
|
|
@ -1,195 +1,7 @@
|
||||||
use crate::{*, draw::*};
|
use crate::*;
|
||||||
#[cfg(test)] use proptest_derive::Arbitrary;
|
#[cfg(test)] use proptest_derive::Arbitrary;
|
||||||
|
|
||||||
mod coord;
|
mod coord; pub use self::coord::*;
|
||||||
pub use self::coord::*;
|
mod iter; pub use self::iter::*;
|
||||||
|
mod sizer; pub use self::sizer::*;
|
||||||
mod xywh;
|
mod xywh; pub use self::xywh::*;
|
||||||
pub use self::xywh::*;
|
|
||||||
|
|
||||||
mod origin;
|
|
||||||
pub use self::origin::*;
|
|
||||||
|
|
||||||
mod split;
|
|
||||||
pub use self::split::*;
|
|
||||||
|
|
||||||
mod iter;
|
|
||||||
pub use self::iter::*;
|
|
||||||
|
|
||||||
mod size;
|
|
||||||
pub use self::size::*;
|
|
||||||
|
|
||||||
/// Horizontal axis.
|
|
||||||
pub trait X<N: Coord> {
|
|
||||||
fn x (&self) -> N;
|
|
||||||
fn w (&self) -> N { N::zero() }
|
|
||||||
fn w_min (&self) -> N { self.w() }
|
|
||||||
fn w_max (&self) -> N { self.w() }
|
|
||||||
fn iter_x (&self) -> impl Iterator<Item = N> where Self: HasOrigin {
|
|
||||||
self.x_west()..self.x_east()
|
|
||||||
}
|
|
||||||
fn x_west (&self) -> N where Self: HasOrigin {
|
|
||||||
use Origin::*;
|
|
||||||
let w = self.w();
|
|
||||||
let a = self.origin();
|
|
||||||
let d = match a { NW|W|SW => 0.into(), N|X|C|Y|S => w/2.into(), NE|E|SE => w };
|
|
||||||
self.x().minus(d)
|
|
||||||
}
|
|
||||||
fn x_east (&self) -> N where Self: HasOrigin {
|
|
||||||
use Origin::*;
|
|
||||||
let w = self.w();
|
|
||||||
let a = self.origin();
|
|
||||||
let d = match a { NW|W|SW => w, N|X|C|Y|S => w/2.into(), NE|E|SE => 0.into() };
|
|
||||||
self.x().plus(d)
|
|
||||||
}
|
|
||||||
fn x_center (&self) -> N where Self: HasOrigin {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const fn x_push <T: Screen> (x: T::Unit, a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
a
|
|
||||||
}
|
|
||||||
pub const fn x_pull <T: Screen> (x: T::Unit, a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
a
|
|
||||||
}
|
|
||||||
pub const fn w_max <T: Screen> (w: Option<T::Unit>, a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
wh_max(w, None, a)
|
|
||||||
}
|
|
||||||
pub const fn w_min <T: Screen> (w: Option<T::Unit>, a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
wh_min(w, None, a)
|
|
||||||
}
|
|
||||||
pub const fn w_exact <T: Screen> (w: T::Unit, c: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
wh_exact(Some(w), None, c)
|
|
||||||
}
|
|
||||||
/// Shrink drawing area symmetrically.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let padded = tengri::space::w_pad(3, "Hello");
|
|
||||||
/// ```
|
|
||||||
pub const fn w_pad <T: Screen> (x: T::Unit, draw: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
thunk(move|to: &mut T|draw.draw(todo!()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Y<N: Coord> {
|
|
||||||
fn y (&self) -> N;
|
|
||||||
fn h (&self) -> N { N::zero() }
|
|
||||||
fn h_min (&self) -> N { self.h() }
|
|
||||||
fn h_max (&self) -> N { self.h() }
|
|
||||||
fn iter_y (&self) -> impl Iterator<Item = N> where Self: HasOrigin {
|
|
||||||
self.y_north()..self.y_south()
|
|
||||||
}
|
|
||||||
fn y_north (&self) -> N where Self: HasOrigin {
|
|
||||||
let a = self.origin();
|
|
||||||
let h = self.h();
|
|
||||||
use Origin::*;
|
|
||||||
let d = match a { NW|N|NE => 0.into(), W|X|C|Y|E => h/2.into(), SW|S|SE => h };
|
|
||||||
self.y().minus(d)
|
|
||||||
}
|
|
||||||
fn y_south (&self) -> N where Self: HasOrigin {
|
|
||||||
let a = self.origin();
|
|
||||||
let h = self.h();
|
|
||||||
use Origin::*;
|
|
||||||
let d = match a { NW|N|NE => h, W|X|C|Y|E => h/2.into(), SW|S|SE => 0.into() };
|
|
||||||
self.y().plus(d)
|
|
||||||
}
|
|
||||||
fn y_center (&self) -> N where Self: HasOrigin {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const fn y_push <T: Screen> (x: T::Unit, a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
a
|
|
||||||
}
|
|
||||||
pub const fn y_pull <T: Screen> (x: T::Unit, a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
a
|
|
||||||
}
|
|
||||||
pub const fn h_max <T: Screen> (h: Option<T::Unit>, a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
wh_max(None, h, a)
|
|
||||||
}
|
|
||||||
pub const fn h_min <T: Screen> (h: Option<T::Unit>, a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
wh_min(None, h, a)
|
|
||||||
}
|
|
||||||
pub const fn h_exact <T: Screen> (h: T::Unit, c: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
wh_exact(None, Some(h), c)
|
|
||||||
}
|
|
||||||
/// Shrink drawing area symmetrically.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let padded = tengri::space::w_pad(3, "Hello");
|
|
||||||
/// ```
|
|
||||||
pub const fn h_pad <T: Screen> (x: T::Unit, draw: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
thunk(move|to: &mut T|draw.draw(todo!()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Space<N: Coord>: X<N> + Y<N> {
|
|
||||||
fn xywh (&self) -> XYWH<N> { XYWH(self.x(), self.y(), self.w(), self.h()) }
|
|
||||||
// FIXME: factor origin
|
|
||||||
fn lrtb (&self) -> [N;4] { [self.x(), self.y(), self.x()+self.w(), self.y()+self.h()] }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: Coord, T: X<N> + Y<N>> Space<N> for T {}
|
|
||||||
|
|
||||||
pub const fn xy_push <T: Screen> (x: T::Unit, y: T::Unit, a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
a
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn xy_pull <T: Screen> (x: T::Unit, y: T::Unit, a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
a
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shrink drawing area symmetrically.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let padded = tengri::WH(3, 5).pad("Hello");
|
|
||||||
/// ```
|
|
||||||
pub const fn wh_pad <T: Screen> (w: T::Unit, h: T::Unit, draw: impl Draw<T>)
|
|
||||||
-> impl Draw<T>
|
|
||||||
{
|
|
||||||
thunk(move|to: &mut T|draw.draw(todo!()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Only draw content if area is above a certain size.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let min = tengri::space::wh_min(3, 5, "Hello"); // 5x5
|
|
||||||
/// ```
|
|
||||||
pub const fn wh_min <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, draw: impl Draw<T>)
|
|
||||||
-> impl Draw<T>
|
|
||||||
{
|
|
||||||
thunk(move|to: &mut T|draw.draw(todo!()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the maximum width and/or height of the content.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let max = tengri::space::wh_max(Some(3), Some(5), "Hello");
|
|
||||||
/// ```
|
|
||||||
pub const fn wh_max <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, draw: impl Draw<T>)
|
|
||||||
-> impl Draw<T>
|
|
||||||
{
|
|
||||||
thunk(move|_to: &mut T|draw.draw(todo!()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the maximum width and/or height of the content.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let exact = tengri::space::wh_exact(Some(3), Some(5), "Hello");
|
|
||||||
/// ```
|
|
||||||
pub const fn wh_exact <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, draw: impl Draw<T>)
|
|
||||||
-> impl Draw<T>
|
|
||||||
{
|
|
||||||
thunk(move|_to: &mut T|draw.draw(todo!()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Limit size of drawing area
|
|
||||||
/// ```
|
|
||||||
/// let clipped = tengri::space::wh_clip(Some(3), Some(5), "Hello");
|
|
||||||
/// ```
|
|
||||||
pub const fn wh_clip <T: Screen> (
|
|
||||||
w: Option<T::Unit>, h: Option<T::Unit>, draw: impl Draw<T>
|
|
||||||
) -> impl Draw<T> {
|
|
||||||
thunk(move|_to: &mut T|draw.draw(todo!()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn wh_full <T: Screen> (a: impl Draw<T>) -> impl Draw<T> { a }
|
|
||||||
pub const fn w_full <T: Screen> (a: impl Draw<T>) -> impl Draw<T> { a }
|
|
||||||
pub const fn h_full <T: Screen> (a: impl Draw<T>) -> impl Draw<T> { a }
|
|
||||||
|
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub const fn origin_c <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
Anchor(Origin::C, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn origin_x <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
Anchor(Origin::X, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn origin_y <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
Anchor(Origin::Y, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn origin_nw <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
Anchor(Origin::NW, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn origin_n <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
Anchor(Origin::N, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn origin_ne <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
Anchor(Origin::NE, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn origin_w <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
Anchor(Origin::W, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn origin_e <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
Anchor(Origin::E, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn origin_sw <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
Anchor(Origin::SW, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn origin_s <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
Anchor(Origin::S, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn origin_se <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
Anchor(Origin::SE, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Something that has `[0, 0]` at a particular point.
|
|
||||||
pub trait HasOrigin {
|
|
||||||
fn origin (&self) -> Origin;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: AsRef<Origin>> HasOrigin for T {
|
|
||||||
fn origin (&self) -> Origin {
|
|
||||||
*self.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Anchor<T>(Origin, T);
|
|
||||||
|
|
||||||
impl<T> AsRef<Origin> for Anchor<T> {
|
|
||||||
fn as_ref (&self) -> &Origin {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Screen, U: Draw<T>> Draw<T> for Anchor<U> {
|
|
||||||
fn draw (self, to: &mut T) -> Usually<XYWH<T::Unit>> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Where is [0, 0] located?
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use tengri::draw::Origin;
|
|
||||||
/// let _ = Origin::NW.align(());
|
|
||||||
/// ```
|
|
||||||
#[cfg_attr(test, derive(Arbitrary))]
|
|
||||||
#[derive(Debug, Copy, Clone, Default)] pub enum Origin {
|
|
||||||
#[default] C, X, Y, NW, N, NE, E, SE, S, SW, W
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Origin {
|
|
||||||
pub fn align <T: Screen> (&self, a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
align(*self, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ```
|
|
||||||
/// use tengri::draw::{align, Origin::*};
|
|
||||||
/// let _ = align(NW, "test");
|
|
||||||
/// let _ = align(SE, "test");
|
|
||||||
/// ```
|
|
||||||
pub fn align <T: Screen> (origin: Origin, a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
thunk(move|to: &mut T| { todo!() })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn align_n <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
|
||||||
align(Origin::N, a)
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +1,25 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
/// Uses [AtomicUsize] to measure size during\
|
/// Uses [AtomicUsize] to measure size during\
|
||||||
/// rendering (which is normally read-only).
|
/// rendering (which is normally read-only).
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct Size(
|
pub struct Sizer(
|
||||||
/// Width
|
/// Width
|
||||||
pub Arc<AtomicUsize>,
|
pub Arc<AtomicUsize>,
|
||||||
/// Height
|
/// Height
|
||||||
pub Arc<AtomicUsize>,
|
pub Arc<AtomicUsize>,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl PartialEq for Size {
|
impl Xy<u16> for Sizer {
|
||||||
fn eq (&self, _: &Self) -> bool {
|
fn x (&self) -> u16 { self.0.load(Ordering::Relaxed) as u16 }
|
||||||
todo!()
|
fn y (&self) -> u16 { self.1.load(Ordering::Relaxed) as u16 }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
impl Wide<u16> for Sizer { fn w (&self) -> u16 { self.0.load(Relaxed) as u16 } }
|
||||||
|
impl Tall<u16> for Sizer { fn h (&self) -> u16 { self.1.load(Relaxed) as u16 } }
|
||||||
|
impl PartialEq for Sizer { fn eq (&self, _: &Self) -> bool { todo!() } }
|
||||||
|
|
||||||
impl X<u16> for Size {
|
impl Sizer {
|
||||||
fn x (&self) -> u16 { 0 }
|
|
||||||
fn w (&self) -> u16 { self.0.load(Relaxed) as u16 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Y<u16> for Size {
|
|
||||||
fn y (&self) -> u16 { 0 }
|
|
||||||
fn h (&self) -> u16 { self.1.load(Relaxed) as u16 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Size {
|
|
||||||
pub const fn of <T: Screen> (&self, of: impl Draw<T>) -> impl Draw<T> {
|
pub const fn of <T: Screen> (&self, of: impl Draw<T>) -> impl Draw<T> {
|
||||||
thunk(move|to: &mut T|{
|
thunk(move|to: &mut T|{
|
||||||
let area = of.draw(to)?;
|
let area = of.draw(to)?;
|
||||||
|
|
@ -1,4 +1,76 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use Origin::*;
|
||||||
|
use Split::*;
|
||||||
|
|
||||||
|
pub trait Xy<N: Coord> {
|
||||||
|
fn x (&self) -> N;
|
||||||
|
fn y (&self) -> N;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Wh<N: Coord>: Wide<N> + Tall<N> {
|
||||||
|
fn wh (&self) -> [N;2];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Xywh<N: Coord>: Xy<N> + Wh<N> {
|
||||||
|
fn xywh (&self) -> XYWH<N> {
|
||||||
|
XYWH(self.x(), self.y(), self.w(), self.h())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Lrtb<N: Coord> {
|
||||||
|
// FIXME: factor origin
|
||||||
|
fn lrtb (&self) -> [N;4] {
|
||||||
|
[self.x(), self.y(), self.x()+self.w(), self.y()+self.h()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Wide<N: Coord> {
|
||||||
|
fn w (&self) -> N { N::zero() }
|
||||||
|
fn w_min (&self) -> N { self.w() }
|
||||||
|
fn w_max (&self) -> N { self.w() }
|
||||||
|
fn iter_x (&self) -> impl Iterator<Item = N> where Self: HasOrigin {
|
||||||
|
self.x_west()..self.x_east()
|
||||||
|
}
|
||||||
|
fn x_west (&self) -> N where Self: HasOrigin {
|
||||||
|
let w = self.w();
|
||||||
|
let a = self.origin();
|
||||||
|
let d = match a { NW|W|SW => 0.into(), N|X|C|Y|S => w/2.into(), NE|E|SE => w };
|
||||||
|
self.x().minus(d)
|
||||||
|
}
|
||||||
|
fn x_east (&self) -> N where Self: HasOrigin {
|
||||||
|
let w = self.w();
|
||||||
|
let a = self.origin();
|
||||||
|
let d = match a { NW|W|SW => w, N|X|C|Y|S => w/2.into(), NE|E|SE => 0.into() };
|
||||||
|
self.x().plus(d)
|
||||||
|
}
|
||||||
|
fn x_center (&self) -> N where Self: HasOrigin {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Tall<N: Coord> {
|
||||||
|
fn h (&self) -> N { N::zero() }
|
||||||
|
fn h_min (&self) -> N { self.h() }
|
||||||
|
fn h_max (&self) -> N { self.h() }
|
||||||
|
fn iter_y (&self) -> impl Iterator<Item = N> where Self: HasOrigin {
|
||||||
|
self.y_north()..self.y_south()
|
||||||
|
}
|
||||||
|
fn y_north (&self) -> N where Self: HasOrigin {
|
||||||
|
let a = self.origin();
|
||||||
|
let h = self.h();
|
||||||
|
let d = match a { NW|N|NE => 0.into(), W|X|C|Y|E => h/2.into(), SW|S|SE => h };
|
||||||
|
self.y().minus(d)
|
||||||
|
}
|
||||||
|
fn y_south (&self) -> N where Self: HasOrigin {
|
||||||
|
let a = self.origin();
|
||||||
|
let h = self.h();
|
||||||
|
let d = match a { NW|N|NE => h, W|X|C|Y|E => h/2.into(), SW|S|SE => 0.into() };
|
||||||
|
self.y().plus(d)
|
||||||
|
}
|
||||||
|
fn y_center (&self) -> N where Self: HasOrigin {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Point with size.
|
/// Point with size.
|
||||||
///
|
///
|
||||||
|
|
@ -13,21 +85,14 @@ use super::*;
|
||||||
#[cfg_attr(test, derive(Arbitrary))] #[derive(Copy, Clone, Debug, Default, PartialEq)]
|
#[cfg_attr(test, derive(Arbitrary))] #[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||||
pub struct XYWH<N: Coord>(pub N, pub N, pub N, pub N);
|
pub struct XYWH<N: Coord>(pub N, pub N, pub N, pub N);
|
||||||
|
|
||||||
impl From<&ratatui::prelude::Rect> for XYWH<u16> {
|
impl<N: Coord> Xy<N> for XYWH<N> {
|
||||||
fn from (rect: &ratatui::prelude::Rect) -> Self {
|
|
||||||
Self(rect.x, rect.y, rect.width, rect.height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: Coord> X<N> for XYWH<N> {
|
|
||||||
fn x (&self) -> N { self.0 }
|
fn x (&self) -> N { self.0 }
|
||||||
fn w (&self) -> N { self.2 }
|
fn y (&self) -> N { self.1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Coord> Y<N> for XYWH<N> {
|
impl<N: Coord> Wide<N> for XYWH<N> { fn w (&self) -> N { self.2 } }
|
||||||
fn y (&self) -> N { self.0 }
|
|
||||||
fn h (&self) -> N { self.2 }
|
impl<N: Coord> Tall<N> for XYWH<N> { fn h (&self) -> N { self.3 } }
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: Coord> XYWH<N> {
|
impl<N: Coord> XYWH<N> {
|
||||||
|
|
||||||
|
|
@ -67,7 +132,6 @@ impl<N: Coord> XYWH<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_half (&self, direction: &Split) -> (Self, Self) {
|
pub fn split_half (&self, direction: &Split) -> (Self, Self) {
|
||||||
use Split::*;
|
|
||||||
let XYWH(x, y, w, h) = self.xywh();
|
let XYWH(x, y, w, h) = self.xywh();
|
||||||
match direction {
|
match direction {
|
||||||
South => (XYWH(x, y, w, h - h / 2.into()), XYWH(x, y + h / 2.into(), w, h / 2.into())),
|
South => (XYWH(x, y, w, h - h / 2.into()), XYWH(x, y + h / 2.into(), w, h / 2.into())),
|
||||||
|
|
@ -79,3 +143,144 @@ impl<N: Coord> XYWH<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&ratatui::prelude::Rect> for XYWH<u16> {
|
||||||
|
fn from (rect: &ratatui::prelude::Rect) -> Self {
|
||||||
|
Self(rect.x, rect.y, rect.width, rect.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coord, T: Wide<N> + Tall<N>> Wh<N> for T {
|
||||||
|
fn wh (&self) -> [N;2] {
|
||||||
|
[self.w(), self.h()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coord, T: Xy<N> + Wh<N>> Xywh<N> for T {}
|
||||||
|
|
||||||
|
/// Shrink drawing area symmetrically.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let padded = tengri::wh_pad("Hello");
|
||||||
|
/// ```
|
||||||
|
pub const fn wh_pad <T: Screen> (w: T::Unit, h: T::Unit, it: impl Draw<T>)
|
||||||
|
-> impl Draw<T>
|
||||||
|
{
|
||||||
|
thunk(move|to: &mut T|it.draw(todo!()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Only draw content if area is above a certain size.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let min = tengri::wh_min(3, 5, "Hello"); // 5x5
|
||||||
|
/// ```
|
||||||
|
pub const fn wh_min <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, it: impl Draw<T>)
|
||||||
|
-> impl Draw<T>
|
||||||
|
{
|
||||||
|
thunk(move|to: &mut T|it.draw(todo!()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the maximum width and/or height of the content.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let max = tengri::wh_max(Some(3), Some(5), "Hello");
|
||||||
|
/// ```
|
||||||
|
pub const fn wh_max <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, it: impl Draw<T>)
|
||||||
|
-> impl Draw<T>
|
||||||
|
{
|
||||||
|
thunk(move|_to: &mut T|it.draw(todo!()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the maximum width and/or height of the content.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let exact = tengri::wh_exact(Some(3), Some(5), "Hello");
|
||||||
|
/// ```
|
||||||
|
pub const fn wh_exact <T: Screen> (w: Option<T::Unit>, h: Option<T::Unit>, it: impl Draw<T>)
|
||||||
|
-> impl Draw<T>
|
||||||
|
{
|
||||||
|
thunk(move|_to: &mut T|it.draw(todo!()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Limit size of drawing area
|
||||||
|
/// ```
|
||||||
|
/// let clipped = tengri::wh_clip(Some(3), Some(5), "Hello");
|
||||||
|
/// ```
|
||||||
|
pub const fn wh_clip <T: Screen> (
|
||||||
|
w: Option<T::Unit>, h: Option<T::Unit>, it: impl Draw<T>
|
||||||
|
) -> impl Draw<T> {
|
||||||
|
thunk(move|_to: &mut T|it.draw(todo!()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn wh_full <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
todo!();
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn w_full <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
todo!();
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn h_full <T: Screen> (a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
todo!();
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn h_max <T: Screen> (h: Option<T::Unit>, a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
wh_max(None, h, a)
|
||||||
|
}
|
||||||
|
pub const fn h_min <T: Screen> (h: Option<T::Unit>, a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
wh_min(None, h, a)
|
||||||
|
}
|
||||||
|
pub const fn h_exact <T: Screen> (h: T::Unit, c: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
wh_exact(None, Some(h), c)
|
||||||
|
}
|
||||||
|
pub const fn w_max <T: Screen> (w: Option<T::Unit>, a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
wh_max(w, None, a)
|
||||||
|
}
|
||||||
|
pub const fn w_min <T: Screen> (w: Option<T::Unit>, a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
wh_min(w, None, a)
|
||||||
|
}
|
||||||
|
pub const fn w_exact <T: Screen> (w: T::Unit, c: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
wh_exact(Some(w), None, c)
|
||||||
|
}
|
||||||
|
/// Shrink drawing area symmetrically.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let padded = tengri::space::w_pad(3, "Hello");
|
||||||
|
/// ```
|
||||||
|
pub const fn w_pad <T: Screen> (x: T::Unit, draw: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
thunk(move|to: &mut T|draw.draw(todo!()))
|
||||||
|
}
|
||||||
|
/// Shrink drawing area symmetrically.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let padded = tengri::space::w_pad(3, "Hello");
|
||||||
|
/// ```
|
||||||
|
pub const fn h_pad <T: Screen> (x: T::Unit, draw: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
thunk(move|to: &mut T|draw.draw(todo!()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn xy_push <T: Screen> (x: T::Unit, y: T::Unit, a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn xy_pull <T: Screen> (x: T::Unit, y: T::Unit, a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn x_push <T: Screen> (x: T::Unit, a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
a
|
||||||
|
}
|
||||||
|
pub const fn x_pull <T: Screen> (x: T::Unit, a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn y_push <T: Screen> (x: T::Unit, a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
a
|
||||||
|
}
|
||||||
|
pub const fn y_pull <T: Screen> (x: T::Unit, a: impl Draw<T>) -> impl Draw<T> {
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
108
src/term.rs
108
src/term.rs
|
|
@ -29,7 +29,27 @@ use ::{
|
||||||
|
|
||||||
/// Implement standard [main] entrypoint for TUI apps.
|
/// Implement standard [main] entrypoint for TUI apps.
|
||||||
#[macro_export] macro_rules! tui_main {
|
#[macro_export] macro_rules! tui_main {
|
||||||
($state:expr) => { pub fn main () -> Usually<()> { tui_run_main($state) } }
|
($state:expr) => {
|
||||||
|
pub fn main () -> Usually<()> { tui_run_main($state) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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
|
pub fn tui_run_main <T> (state: Arc<RwLock<T>>) -> Usually<()> where
|
||||||
|
|
@ -63,15 +83,6 @@ pub fn tui_setup_panic () {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Spawn the TUI input and output threadsl.
|
/// Spawn the TUI input and output threadsl.
|
||||||
pub fn tui_io <
|
pub fn tui_io <
|
||||||
T: View<Tui> + Apply<TuiEvent, Usually<()>> + Send + Sync + 'static,
|
T: View<Tui> + Apply<TuiEvent, Usually<()>> + Send + Sync + 'static,
|
||||||
|
|
@ -117,15 +128,6 @@ pub fn tui_input <T: Apply<TuiEvent, Usually<()>> + Send + Sync + 'static> (
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Spawn the TUI output thread which writes colored characters to the terminal.
|
/// Spawn the TUI output thread which writes colored characters to the terminal.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|
@ -192,37 +194,31 @@ impl Tui {
|
||||||
impl Screen for Tui {
|
impl Screen for Tui {
|
||||||
type Unit = u16;
|
type Unit = u16;
|
||||||
/// Render drawable in subarea specified by `area`
|
/// Render drawable in subarea specified by `area`
|
||||||
fn show <'t, T: Draw<Self>> (
|
fn show <'t, T: Draw<Self>> (&mut self, content: T) -> Perhaps<XYWH<u16>> {
|
||||||
&mut self, area: XYWH<u16>, content: T
|
|
||||||
) -> Usually<XYWH<u16>> {
|
|
||||||
let previous_area = self.1;
|
let previous_area = self.1;
|
||||||
|
if let Some(area) = content.layout(self.1)? {
|
||||||
self.1 = area;
|
self.1 = area;
|
||||||
let result_area = content.draw(self);
|
if let Some(result_area) = content.draw(self)? {
|
||||||
self.1 = previous_area;
|
self.1 = previous_area;
|
||||||
result_area
|
result_area
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Tui { type Target = Buffer; fn deref (&self) -> &Buffer { &self.0 } }
|
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 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 AsMut<Buffer> for Tui {
|
impl Wide<u16> for Tui { fn w (&self) -> u16 { self.1.2 } }
|
||||||
fn as_mut (&mut self) -> &mut Buffer {
|
impl Tall<u16> for Tui { fn h (&self) -> u16 { self.1.3 } }
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasOrigin for Tui { fn origin (&self) -> Origin { Origin::NW } }
|
impl HasOrigin for Tui { fn origin (&self) -> Origin { Origin::NW } }
|
||||||
|
impl Xy<u16> for Tui {
|
||||||
impl X<u16> for Tui {
|
|
||||||
fn x (&self) -> u16 { self.1.0 }
|
fn x (&self) -> u16 { self.1.0 }
|
||||||
fn w (&self) -> u16 { self.1.2 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Y<u16> for Tui {
|
|
||||||
fn y (&self) -> u16 { self.1.1 }
|
fn y (&self) -> u16 { self.1.1 }
|
||||||
fn h (&self) -> u16 { self.1.3 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tui {
|
impl Tui {
|
||||||
|
|
@ -520,33 +516,9 @@ pub fn catcher <T: Draw<Tui>> (result: Usually<T>) -> impl Draw<Tui> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TUI buffer sized by `usize` instead of `u16`.
|
mod event; pub use self::event::*;
|
||||||
#[derive(Default)] pub struct BigBuffer {
|
mod keys; pub use self::keys::*;
|
||||||
pub width: usize,
|
mod buffer; pub use self::buffer::*;
|
||||||
pub height: usize,
|
|
||||||
pub content: Vec<Cell>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_from!(BigBuffer: |size:(usize, usize)| Self::new(size.0, size.1));
|
|
||||||
|
|
||||||
impl_debug!(BigBuffer |self, f| { 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] }
|
|
||||||
}
|
|
||||||
pub fn get (&self, x: usize, y: usize) -> Option<&Cell> {
|
|
||||||
let i = self.index_of(x, y);
|
|
||||||
self.content.get(i)
|
|
||||||
}
|
|
||||||
pub fn get_mut (&mut self, x: usize, y: usize) -> Option<&mut Cell> {
|
|
||||||
let i = self.index_of(x, y);
|
|
||||||
self.content.get_mut(i)
|
|
||||||
}
|
|
||||||
pub fn index_of (&self, x: usize, y: usize) -> usize {
|
|
||||||
y * self.width + x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use self::colors::*; mod colors {
|
use self::colors::*; mod colors {
|
||||||
use ratatui::prelude::Color;
|
use ratatui::prelude::Color;
|
||||||
|
|
@ -572,9 +544,3 @@ use self::colors::*; mod colors {
|
||||||
pub const fn tui_title_fg (f: bool) -> Color { if f { tui_ti1() } else { tui_ti2() } }
|
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) }
|
pub const fn tui_yellow () -> Color { Color::Rgb(255,255,0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "term")] pub mod event;
|
|
||||||
#[cfg(feature = "term")] pub use self::event::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "term")] pub mod keys;
|
|
||||||
#[cfg(feature = "term")] pub use self::keys::*;
|
|
||||||
|
|
|
||||||
31
src/term/buffer.rs
Normal file
31
src/term/buffer.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
use crate::*;
|
||||||
|
use crate::{*, lang::*, draw::*, task::*, exit::*};
|
||||||
|
use ::ratatui::buffer::Cell;
|
||||||
|
|
||||||
|
/// TUI buffer sized by `usize` instead of `u16`.
|
||||||
|
#[derive(Default)] pub struct BigBuffer {
|
||||||
|
pub width: usize,
|
||||||
|
pub height: usize,
|
||||||
|
pub content: Vec<Cell>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from!(BigBuffer: |size:(usize, usize)| Self::new(size.0, size.1));
|
||||||
|
|
||||||
|
impl_debug!(BigBuffer |self, f| { 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] }
|
||||||
|
}
|
||||||
|
pub fn get (&self, x: usize, y: usize) -> Option<&Cell> {
|
||||||
|
let i = self.index_of(x, y);
|
||||||
|
self.content.get(i)
|
||||||
|
}
|
||||||
|
pub fn get_mut (&mut self, x: usize, y: usize) -> Option<&mut Cell> {
|
||||||
|
let i = self.index_of(x, y);
|
||||||
|
self.content.get_mut(i)
|
||||||
|
}
|
||||||
|
pub fn index_of (&self, x: usize, y: usize) -> usize {
|
||||||
|
y * self.width + x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,12 @@ pub(crate) use ::unicode_width::*;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Draw<Tui> for &std::sync::Arc<str> {
|
||||||
|
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> {
|
||||||
|
self.as_ref().draw(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: AsRef<str>> Draw<Tui> for TrimString<T> {
|
impl<T: AsRef<str>> Draw<Tui> for TrimString<T> {
|
||||||
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> { self.as_ref().draw(to) }
|
fn draw (self, to: &mut Tui) -> Usually<XYWH<u16>> { self.as_ref().draw(to) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue