mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
detach all layout constructors from engine
This commit is contained in:
parent
61b447403b
commit
e0e680eb7c
19 changed files with 487 additions and 520 deletions
|
|
@ -31,7 +31,7 @@ impl<'a> ArrangerVClips<'a> {
|
|||
Tui::bg(scene.color.base.rgb,
|
||||
if playing { "▶ " } else { " " }),
|
||||
Tui::fg_bg(scene.color.lightest.rgb, scene.color.base.rgb,
|
||||
Tui::grow_x(1, Tui::bold(true, scene.name.read().unwrap().as_str()))),
|
||||
Grow::x(1, Tui::bold(true, scene.name.read().unwrap().as_str()))),
|
||||
row!((index, track, x1, x2) in ArrangerTrack::with_widths(tracks) => {
|
||||
Self::format_clip(scene, index, track, (x2 - x1) as u16, height)
|
||||
})])
|
||||
|
|
@ -53,7 +53,7 @@ impl<'a> ArrangerVClips<'a> {
|
|||
}
|
||||
};
|
||||
add(&Tui::bg(bg,
|
||||
Tui::push_x(1, Fixed::w(w, &name.as_str()[0..max_w])))
|
||||
Push::x(1, Fixed::w(w, &name.as_str()[0..max_w])))
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from!(<'a>|state: &'a ArrangerTui|ArrangerVHead<'a> = Self { // A
|
|||
scenes_w: SCENES_W_OFFSET + ArrangerScene::longest_name(&state.scenes) as u16,
|
||||
});
|
||||
|
||||
render!(<Tui>|self: ArrangerVHead<'a>|Tui::push_x(self.scenes_w, row!(
|
||||
render!(<Tui>|self: ArrangerVHead<'a>|Push::x(self.scenes_w, row!(
|
||||
(_, track, x1, x2) in ArrangerTrack::with_widths(self.tracks) => {
|
||||
let (w, h) = (ArrangerTrack::MIN_WIDTH.max(x2 - x1), HEADER_H);
|
||||
let color = track.color();
|
||||
|
|
@ -25,7 +25,7 @@ render!(<Tui>|self: ArrangerVHead<'a>|Tui::push_x(self.scenes_w, row!(
|
|||
Tui::fg(color.lightest.rgb, field)
|
||||
])
|
||||
}
|
||||
Tui::bg(color.base.rgb, Tui::min_xy(w as u16, h, Fixed::wh(w as u16, 5, col!([
|
||||
Tui::bg(color.base.rgb, Min::xy(w as u16, h, Fixed::wh(w as u16, 5, col!([
|
||||
row(color, &Self::format_name(track, w)),
|
||||
row(color, &Self::format_input(track)?),
|
||||
row(color, &Self::format_output(track)?),
|
||||
|
|
|
|||
|
|
@ -120,14 +120,14 @@ render!(<Tui>|self:Groovebox|{
|
|||
Fill::wh(lay!([
|
||||
&self.size,
|
||||
Fill::wh(Align::s(Fixed::h(2, GrooveboxStatus::from(self)))),
|
||||
Tui::shrink_y(2, col!([
|
||||
Shrink::y(2, col!([
|
||||
Fixed::h(2, row!([
|
||||
Fixed::wh(5, 2, PlayPause(self.clock().is_rolling())),
|
||||
Fixed::h(2, TransportView::from((self, self.player.play_phrase().as_ref().map(|(_,p)|
|
||||
p.as_ref().map(|p|p.read().unwrap().color)
|
||||
).flatten().clone(), true))),
|
||||
])),
|
||||
Tui::push_x(sampler_w, Fixed::h(1, row!([
|
||||
Push::x(sampler_w, Fixed::h(1, row!([
|
||||
PhraseSelector::play_phrase(&self.player),
|
||||
PhraseSelector::next_phrase(&self.player),
|
||||
]))),
|
||||
|
|
@ -153,7 +153,7 @@ render!(<Tui>|self:Groovebox|{
|
|||
]),
|
||||
]),
|
||||
Split::w(false, pool_w,
|
||||
Tui::pull_y(1, Fill::h(Align::e(PoolView(&self.pool)))),
|
||||
Pull::y(1, Fill::h(Align::e(PoolView(&self.pool)))),
|
||||
Split::e(false, sampler_w, Fill::wh(col!([
|
||||
Meters(self.sampler.input_meter.as_ref()),
|
||||
GrooveboxSamples(self),
|
||||
|
|
|
|||
|
|
@ -77,16 +77,16 @@ render!(<Tui>|self: PianoHorizontal|{
|
|||
let cursor = move||PianoHorizontalCursor(self);
|
||||
|
||||
let border = Fill::wh(Outer(Style::default().fg(self.color.dark.rgb).bg(self.color.darkest.rgb)));
|
||||
let with_border = |x|lay!([border, Tui::inset_xy(0, 0, &x)]);
|
||||
let with_border = |x|lay!([border, Inset::xy(0, 0, &x)]);
|
||||
|
||||
with_border(lay!([
|
||||
Tui::push_x(0, row!(![
|
||||
Push::x(0, row!(![
|
||||
//" ",
|
||||
field("Edit:", name.to_string()), " ",
|
||||
field("Length:", length.to_string()), " ",
|
||||
field("Loop:", looped.to_string())
|
||||
])),
|
||||
Tui::inset_xy(0, 1, Fill::wh(Bsp::s(
|
||||
Inset::xy(0, 1, Fill::wh(Bsp::s(
|
||||
Fixed::h(1, Bsp::e(
|
||||
Fixed::w(self.keys_width, ""),
|
||||
Fill::w(timeline()),
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ render!(<Tui>|self: PoolView<'a>|{
|
|||
Tui::bg(bg, lay!(move|add|{
|
||||
add(&Fill::wh(Outer(Style::default().fg(color.base.rgb).bg(bg))))?;
|
||||
//add(&Lozenge(Style::default().bg(border_bg).fg(border_color)))?;
|
||||
add(&Tui::inset_xy(0, 1, Fill::wh(col!(move|add|match mode {
|
||||
add(&Inset::xy(0, 1, Fill::wh(col!(move|add|match mode {
|
||||
Some(PoolMode::Import(_, ref file_picker)) => add(file_picker),
|
||||
Some(PoolMode::Export(_, ref file_picker)) => add(file_picker),
|
||||
_ => Ok(for (i, phrase) in phrases.iter().enumerate() {
|
||||
|
|
@ -226,7 +226,7 @@ render!(<Tui>|self: PoolView<'a>|{
|
|||
add(&Tui::bg(color.base.rgb, Fill::w(col!([
|
||||
Fill::w(lay!(|add|{
|
||||
add(&Fill::w(Align::w(format!(" {i}"))))?;
|
||||
add(&Fill::w(Align::e(Tui::pull_x(1, length.clone()))))
|
||||
add(&Fill::w(Align::e(Pull::x(1, length.clone()))))
|
||||
})),
|
||||
Tui::bold(true, {
|
||||
let mut row2 = format!(" {name}");
|
||||
|
|
@ -245,8 +245,8 @@ render!(<Tui>|self: PoolView<'a>|{
|
|||
}))?;
|
||||
})
|
||||
}))))?;
|
||||
add(&Fill::w(Align::nw(Tui::push_x(1, Tui::fg(title_color, upper_left.to_string())))))?;
|
||||
add(&Fill::w(Align::ne(Tui::pull_x(1, Tui::fg(title_color, upper_right.to_string())))))?;
|
||||
add(&Fill::w(Align::nw(Push::x(1, Tui::fg(title_color, upper_left.to_string())))))?;
|
||||
add(&Fill::w(Align::ne(Pull::x(1, Tui::fg(title_color, upper_right.to_string())))))?;
|
||||
add(&self.0.size)
|
||||
}))
|
||||
});
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ render!(<Tui>|self: SamplerTui|{
|
|||
let with_size = |x|lay!([self.size, x]);
|
||||
Tui::bg(bg, Fill::wh(with_border(Bsp::s(
|
||||
Tui::fg(self.color.light.rgb, Tui::bold(true, "Sampler")),
|
||||
with_size(Tui::shrink_y(1, Bsp::e(
|
||||
with_size(Shrink::y(1, Bsp::e(
|
||||
Fixed::w(keys_width, keys()),
|
||||
Fill::wh(render(|to: &mut TuiOutput|Ok({
|
||||
let x = to.area.x();
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ render!(<Tui>|self: SequencerTui|{
|
|||
let w = self.size.w();
|
||||
let phrase_w = if w > 60 { 20 } else if w > 40 { 15 } else { 10 };
|
||||
let pool_w = if self.phrases.visible { phrase_w } else { 0 };
|
||||
let pool = Tui::pull_y(1, Fill::h(Align::e(PoolView(&self.phrases))));
|
||||
let pool = Pull::y(1, Fill::h(Align::e(PoolView(&self.phrases))));
|
||||
let with_pool = move|x|Split::w(false, pool_w, pool, x);
|
||||
let status = SequencerStatus::from(self);
|
||||
let with_status = |x|Split::n(false, if self.status { 2 } else { 0 }, status, x);
|
||||
|
|
@ -66,7 +66,7 @@ render!(<Tui>|self: SequencerTui|{
|
|||
PhraseSelector::next_phrase(&self.player),
|
||||
]));
|
||||
|
||||
Tui::min_y(15, with_size(with_status(col!([
|
||||
Min::y(15, with_size(with_status(col!([
|
||||
toolbar,
|
||||
play_queue,
|
||||
editor,
|
||||
|
|
|
|||
412
src/space.rs
412
src/space.rs
|
|
@ -2,58 +2,58 @@ use crate::*;
|
|||
use std::ops::{Add, Sub, Mul, Div};
|
||||
use std::fmt::{Display, Debug};
|
||||
|
||||
// TODO: return impl Point and impl Size instead of [N;x]
|
||||
// to disambiguate between usage of 2-"tuple"s
|
||||
mod cond; pub use self::cond::*;
|
||||
mod coord; pub use self::coord::*;
|
||||
mod layers; pub use self::layers::*;
|
||||
mod measure; pub use self::measure::*;
|
||||
mod position; pub use self::position::*;
|
||||
mod scroll; pub use self::scroll::*;
|
||||
mod size; pub use self::size::*;
|
||||
mod split; pub use self::split::*;
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
/// Has static methods for conditional rendering,
|
||||
/// in unary and binary forms.
|
||||
pub struct Cond;
|
||||
|
||||
pub(crate) mod align;
|
||||
pub(crate) mod cond; pub(crate) use cond::*;
|
||||
pub(crate) mod layers; pub(crate) use layers::*;
|
||||
pub(crate) mod measure; pub(crate) use measure::*;
|
||||
pub(crate) mod position; pub(crate) use position::*;
|
||||
pub(crate) mod scroll;
|
||||
pub(crate) mod size; pub(crate) use size::*;
|
||||
pub(crate) mod split; pub(crate) use split::*;
|
||||
|
||||
pub use self::{
|
||||
align::*,
|
||||
cond::*,
|
||||
measure::*,
|
||||
position::*,
|
||||
size::*,
|
||||
split::*,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum Direction { North, South, West, East, }
|
||||
|
||||
impl Direction {
|
||||
pub fn is_north (&self) -> bool { matches!(self, Self::North) }
|
||||
pub fn is_south (&self) -> bool { matches!(self, Self::South) }
|
||||
pub fn is_east (&self) -> bool { matches!(self, Self::West) }
|
||||
pub fn is_west (&self) -> bool { matches!(self, Self::East) }
|
||||
/// Return next direction clockwise
|
||||
pub fn cw (&self) -> Self {
|
||||
match self {
|
||||
Self::North => Self::East,
|
||||
Self::South => Self::West,
|
||||
Self::West => Self::North,
|
||||
Self::East => Self::South,
|
||||
}
|
||||
impl Cond {
|
||||
/// Render `item` when `cond` is true.
|
||||
pub fn when <E: Engine, A: Render<E>> (cond: bool, item: A) -> When<E, A> {
|
||||
When(cond, item, Default::default())
|
||||
}
|
||||
/// Return next direction counterclockwise
|
||||
pub fn ccw (&self) -> Self {
|
||||
match self {
|
||||
Self::North => Self::West,
|
||||
Self::South => Self::East,
|
||||
Self::West => Self::South,
|
||||
Self::East => Self::North,
|
||||
}
|
||||
/// Render `item` if `cond` is true, otherwise render `other`.
|
||||
pub fn either <E: Engine, A: Render<E>, B: Render<E>> (cond: bool, item: A, other: B) -> Either<E, A, B> {
|
||||
Either(cond, item, other, Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// Standard numeric type.
|
||||
/// Renders `self.1` when `self.0` is true.
|
||||
pub struct When<E: Engine, A: Render<E>>(bool, A, PhantomData<E>);
|
||||
|
||||
/// Renders `self.1` when `self.0` is true, otherwise renders `self.2`
|
||||
pub struct Either<E: Engine, A: Render<E>, B: Render<E>>(bool, A, B, PhantomData<E>);
|
||||
|
||||
/// Renders multiple things on top of each other,
|
||||
/// in the order they are provided by the callback.
|
||||
/// Total size is largest width x largest height.
|
||||
pub struct Layers<
|
||||
E: Engine,
|
||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
||||
>(pub F, PhantomData<E>);
|
||||
|
||||
/// Shorthand for defining an instance of [Layers].
|
||||
#[macro_export] macro_rules! lay {
|
||||
([$($expr:expr),* $(,)?]) => {
|
||||
Layers::new(move|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
};
|
||||
(![$($expr:expr),* $(,)?]) => {
|
||||
Layers::new(|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
};
|
||||
($expr:expr) => {
|
||||
Layers::new($expr)
|
||||
};
|
||||
}
|
||||
|
||||
/// A linear coordinate.
|
||||
pub trait Coordinate: Send + Sync + Copy
|
||||
+ Add<Self, Output=Self>
|
||||
+ Sub<Self, Output=Self>
|
||||
|
|
@ -77,18 +77,6 @@ pub trait Coordinate: Send + Sync + Copy
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Coordinate for T where T: Send + Sync + Copy
|
||||
+ Add<Self, Output=Self>
|
||||
+ Sub<Self, Output=Self>
|
||||
+ Mul<Self, Output=Self>
|
||||
+ Div<Self, Output=Self>
|
||||
+ Ord + PartialEq + Eq
|
||||
+ Debug + Display + Default
|
||||
+ From<u16> + Into<u16>
|
||||
+ Into<usize>
|
||||
+ Into<f64>
|
||||
{}
|
||||
|
||||
pub trait Size<N: Coordinate> {
|
||||
fn x (&self) -> N;
|
||||
fn y (&self) -> N;
|
||||
|
|
@ -105,43 +93,52 @@ pub trait Size<N: Coordinate> {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl<N: Coordinate> Size<N> for (N, N) {
|
||||
fn x (&self) -> N { self.0 }
|
||||
fn y (&self) -> N { self.1 }
|
||||
}
|
||||
|
||||
impl<N: Coordinate> Size<N> for [N;2] {
|
||||
fn x (&self) -> N { self[0] }
|
||||
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 x2 (&self) -> N { self.x() + self.w() }
|
||||
fn y2 (&self) -> N { self.y() + self.h() }
|
||||
#[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 lrtb (&self) -> [N;4] { [self.x(), self.x2(), self.y(), self.y2()] }
|
||||
#[inline] fn push_x (&self, x: N) -> [N;4] { [self.x() + x, self.y(), self.w(), self.h()] }
|
||||
#[inline] fn push_y (&self, y: N) -> [N;4] { [self.x(), self.y() + y, self.w(), self.h()] }
|
||||
fn x2 (&self) -> N {
|
||||
self.x() + self.w()
|
||||
}
|
||||
fn y2 (&self) -> N {
|
||||
self.y() + self.h()
|
||||
}
|
||||
#[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 lrtb (&self) -> [N;4] {
|
||||
[self.x(), self.x2(), self.y(), self.y2()]
|
||||
}
|
||||
#[inline] fn push_x (&self, x: N) -> [N;4] {
|
||||
[self.x() + x, self.y(), self.w(), self.h()]
|
||||
}
|
||||
#[inline] fn push_y (&self, y: N) -> [N;4] {
|
||||
[self.x(), self.y() + y, self.w(), self.h()]
|
||||
}
|
||||
#[inline] fn shrink_x (&self, x: N) -> [N;4] {
|
||||
[self.x(), self.y(), self.w().minus(x), self.h()]
|
||||
}
|
||||
#[inline] fn shrink_y (&self, y: N) -> [N;4] {
|
||||
[self.x(), self.y(), self.w(), self.h().minus(y)]
|
||||
}
|
||||
#[inline] fn set_w (&self, w: N) -> [N;4] { [self.x(), self.y(), w, self.h()] }
|
||||
#[inline] fn set_h (&self, h: N) -> [N;4] { [self.x(), self.y(), self.w(), h] }
|
||||
#[inline] fn clip_h (&self, h: N) -> [N;4] {
|
||||
#[inline] fn set_w (&self, w: N) -> [N;4] {
|
||||
[self.x(), self.y(), w, self.h()]
|
||||
}
|
||||
#[inline] fn set_h (&self, h: N) -> [N;4] {
|
||||
[self.x(), self.y(), self.w(), 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] {
|
||||
#[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] {
|
||||
#[inline] fn clip (&self, wh: impl Size<N>) -> [N;4] {
|
||||
[self.x(), self.y(), wh.w(), wh.h()]
|
||||
}
|
||||
#[inline] fn expect_min (&self, w: N, h: N) -> Usually<&Self> {
|
||||
|
|
@ -173,20 +170,186 @@ pub trait Area<N: Coordinate>: Copy {
|
|||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
macro_rules! by_axis {
|
||||
(!$Enum:ident) => {
|
||||
impl<E: Engine, T: Render<E>> $Enum<E, T> {
|
||||
pub fn x (item: T) -> Self {
|
||||
Self::X(item)
|
||||
}
|
||||
pub fn y (item: T) -> Self {
|
||||
Self::Y(item)
|
||||
}
|
||||
pub fn xy (item: T) -> Self {
|
||||
Self::XY(item)
|
||||
}
|
||||
}
|
||||
};
|
||||
(+$Enum:ident) => {
|
||||
impl<E: Engine, T: Render<E>> $Enum<E, T> {
|
||||
pub fn x (x: E::Unit, item: T) -> Self {
|
||||
Self::X(x, item)
|
||||
}
|
||||
pub fn y (y: E::Unit, item: T) -> Self {
|
||||
Self::Y(y, item)
|
||||
}
|
||||
pub fn xy (x: E::Unit, y: E::Unit, item: T) -> Self {
|
||||
Self::XY(x, y, item)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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] }
|
||||
/// Shrink drawing area
|
||||
pub enum Shrink<E: Engine, T: Render<E>> {
|
||||
/// Decrease width
|
||||
X(E::Unit, T),
|
||||
/// Decrease height
|
||||
Y(E::Unit, T),
|
||||
/// Decrease width and height
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
by_axis!(+Shrink);
|
||||
|
||||
/// Expand drawing area
|
||||
pub enum Grow<E: Engine, T: Render<E>> {
|
||||
/// Increase width
|
||||
X(E::Unit, T),
|
||||
/// Increase height
|
||||
Y(E::Unit, T),
|
||||
/// Increase width and height
|
||||
XY(E::Unit, E::Unit, T)
|
||||
}
|
||||
|
||||
by_axis!(+Grow);
|
||||
|
||||
pub enum Fill<E: Engine, W: Render<E>> {
|
||||
_Unused(PhantomData<E>),
|
||||
/// Maximize width
|
||||
X(W),
|
||||
/// Maximize height
|
||||
Y(W),
|
||||
/// Maximize width and height
|
||||
XY(W),
|
||||
}
|
||||
|
||||
by_axis!(!Fill);
|
||||
|
||||
/// Enforce fixed size of drawing area
|
||||
pub enum Fixed<E: Engine, T: Render<E>> {
|
||||
/// Set width
|
||||
X(E::Unit, T),
|
||||
/// Set height
|
||||
Y(E::Unit, T),
|
||||
/// Set width and height
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
by_axis!(+Fixed);
|
||||
|
||||
/// Enforce minimum size of drawing area
|
||||
pub enum Min<E: Engine, T: Render<E>> {
|
||||
/// Enforce minimum width
|
||||
X(E::Unit, T),
|
||||
/// Enforce minimum height
|
||||
Y(E::Unit, T),
|
||||
/// Enforce minimum width and height
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
by_axis!(+Min);
|
||||
|
||||
/// Enforce maximum size of drawing area
|
||||
pub enum Max<E: Engine, T: Render<E>> {
|
||||
/// Enforce maximum width
|
||||
X(E::Unit, T),
|
||||
/// Enforce maximum height
|
||||
Y(E::Unit, T),
|
||||
/// Enforce maximum width and height
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
by_axis!(+Max);
|
||||
|
||||
/// Increment origin point of drawing area
|
||||
pub enum Push<E: Engine, T: Render<E>> {
|
||||
/// Move origin to the right
|
||||
X(E::Unit, T),
|
||||
/// Move origin downwards
|
||||
Y(E::Unit, T),
|
||||
/// Move origin to the right and downwards
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
by_axis!(+Push);
|
||||
|
||||
/// Decrement origin point of drawing area
|
||||
pub enum Pull<E: Engine, T: Render<E>> {
|
||||
/// Move origin to the right
|
||||
X(E::Unit, T),
|
||||
/// Move origin downwards
|
||||
Y(E::Unit, T),
|
||||
/// Move origin to the right and downwards
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
by_axis!(+Pull);
|
||||
|
||||
/// Shrink from each side
|
||||
pub enum Inset<E: Engine, T> {
|
||||
/// Decrease width
|
||||
X(E::Unit, T),
|
||||
/// Decrease height
|
||||
Y(E::Unit, T),
|
||||
/// Decrease width and height
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
by_axis!(+Inset);
|
||||
|
||||
/// Grow on each side
|
||||
pub enum Outset<E: Engine, T: Render<E>> {
|
||||
/// Increase width
|
||||
X(E::Unit, T),
|
||||
/// Increase height
|
||||
Y(E::Unit, T),
|
||||
/// Increase width and height
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
by_axis!(+Outset);
|
||||
|
||||
/// A cardinal direction.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum Direction { North, South, West, East, }
|
||||
|
||||
/// A binary split with fixed proportion
|
||||
pub struct Split<E: Engine, A: Render<E>, B: Render<E>>(
|
||||
pub bool, pub Direction, pub E::Unit, A, B, PhantomData<E>
|
||||
);
|
||||
|
||||
pub enum Bsp<E: Engine, X: Render<E>, Y: Render<E>> {
|
||||
/// X is north of Y
|
||||
N(Option<X>, Option<Y>),
|
||||
/// X is south of Y
|
||||
S(Option<X>, Option<Y>),
|
||||
/// X is east of Y
|
||||
E(Option<X>, Option<Y>),
|
||||
/// X is west of Y
|
||||
W(Option<X>, Option<Y>),
|
||||
/// X is above Y
|
||||
A(Option<X>, Option<Y>),
|
||||
/// X is below Y
|
||||
B(Option<X>, Option<Y>),
|
||||
/// Should be avoided.
|
||||
Null(PhantomData<E>),
|
||||
}
|
||||
|
||||
pub struct Stack<
|
||||
E: Engine,
|
||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
||||
>(pub F, pub Direction, PhantomData<E>);
|
||||
|
||||
#[macro_export] macro_rules! col {
|
||||
([$($expr:expr),* $(,)?]) => {
|
||||
Stack::down(move|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
|
|
@ -232,14 +395,65 @@ impl<N: Coordinate> Area<N> for [N;4] {
|
|||
};
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! lay {
|
||||
([$($expr:expr),* $(,)?]) => {
|
||||
Layers::new(move|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
};
|
||||
(![$($expr:expr),* $(,)?]) => {
|
||||
Layers::new(|add|{ $(add(&$expr)?;)* Ok(()) })
|
||||
};
|
||||
($expr:expr) => {
|
||||
Layers::new($expr)
|
||||
};
|
||||
pub trait HasSize<E: Engine> {
|
||||
fn size (&self) -> &Measure<E>;
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! has_size {
|
||||
(<$E:ty>|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
|
||||
impl $(<$($L),*$($T $(: $U)?),*>)? HasSize<$E> for $Struct $(<$($L),*$($T),*>)? {
|
||||
fn size (&$self) -> &Measure<$E> { $cb }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait LayoutDebug<E: Engine> {
|
||||
fn debug <W: Render<E>> (other: W) -> DebugOverlay<E, W> {
|
||||
DebugOverlay(Default::default(), other)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DebugOverlay<E: Engine, W: Render<E>>(PhantomData<E>, pub W);
|
||||
|
||||
/// A widget that tracks its render width and height
|
||||
#[derive(Default)]
|
||||
pub struct Measure<E: Engine> {
|
||||
_engine: PhantomData<E>,
|
||||
pub x: Arc<AtomicUsize>,
|
||||
pub y: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
pub struct ShowMeasure<'a>(&'a Measure<Tui>);
|
||||
|
||||
/// A scrollable area.
|
||||
pub struct Scroll<
|
||||
E: Engine,
|
||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
||||
>(pub F, pub Direction, pub u64, PhantomData<E>);
|
||||
|
||||
/// Override X and Y coordinates, aligning to corner, side, or center of area
|
||||
pub enum Align<E: Engine, T: Render<E>> {
|
||||
_Unused(PhantomData<E>),
|
||||
/// Draw at center of container
|
||||
Center(T),
|
||||
/// Draw at center of X axis
|
||||
X(T),
|
||||
/// Draw at center of Y axis
|
||||
Y(T),
|
||||
/// Draw at upper left corner of contaier
|
||||
NW(T),
|
||||
/// Draw at center of upper edge of container
|
||||
N(T),
|
||||
/// Draw at right left corner of contaier
|
||||
NE(T),
|
||||
/// Draw at center of left edge of container
|
||||
W(T),
|
||||
/// Draw at center of right edge of container
|
||||
E(T),
|
||||
/// Draw at lower left corner of container
|
||||
SW(T),
|
||||
/// Draw at center of lower edge of container
|
||||
S(T),
|
||||
/// Draw at lower right edge of container
|
||||
SE(T)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
/// Override X and Y coordinates, aligning to corner, side, or center of area
|
||||
pub enum Align<E: Engine, T: Render<E>> {
|
||||
_Unused(PhantomData<E>),
|
||||
/// Draw at center of container
|
||||
Center(T),
|
||||
/// Draw at center of X axis
|
||||
X(T),
|
||||
/// Draw at center of Y axis
|
||||
Y(T),
|
||||
/// Draw at upper left corner of contaier
|
||||
NW(T),
|
||||
/// Draw at center of upper edge of container
|
||||
N(T),
|
||||
/// Draw at right left corner of contaier
|
||||
NE(T),
|
||||
/// Draw at center of left edge of container
|
||||
W(T),
|
||||
/// Draw at center of right edge of container
|
||||
E(T),
|
||||
/// Draw at lower left corner of container
|
||||
SW(T),
|
||||
/// Draw at center of lower edge of container
|
||||
S(T),
|
||||
/// Draw at lower right edge of container
|
||||
SE(T)
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Render<E>> Align<E, T> {
|
||||
pub fn inner (&self) -> &T {
|
||||
match self {
|
||||
Self::Center(inner) => inner,
|
||||
Self::X(inner) => inner,
|
||||
Self::Y(inner) => inner,
|
||||
Self::NW(inner) => inner,
|
||||
Self::N(inner) => inner,
|
||||
Self::NE(inner) => inner,
|
||||
Self::W(inner) => inner,
|
||||
Self::E(inner) => inner,
|
||||
Self::SW(inner) => inner,
|
||||
Self::S(inner) => inner,
|
||||
Self::SE(inner) => inner,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn c (w: T) -> Self { Self::Center(w) }
|
||||
pub fn x (w: T) -> Self { Self::X(w) }
|
||||
pub fn y (w: T) -> Self { Self::Y(w) }
|
||||
pub fn n (w: T) -> Self { Self::N(w) }
|
||||
pub fn s (w: T) -> Self { Self::S(w) }
|
||||
pub fn e (w: T) -> Self { Self::E(w) }
|
||||
pub fn w (w: T) -> Self { Self::W(w) }
|
||||
pub fn nw (w: T) -> Self { Self::NW(w) }
|
||||
pub fn sw (w: T) -> Self { Self::SW(w) }
|
||||
pub fn ne (w: T) -> Self { Self::NE(w) }
|
||||
pub fn se (w: T) -> Self { Self::SE(w) }
|
||||
}
|
||||
|
||||
fn align<E: Engine, T: Render<E>, N: Coordinate, R: Area<N> + From<[N;4]>> (align: &Align<E, T>, outer: R, inner: R) -> Option<R> {
|
||||
if outer.w() < inner.w() || outer.h() < inner.h() {
|
||||
None
|
||||
} else {
|
||||
let [ox, oy, ow, oh] = outer.xywh();
|
||||
let [ix, iy, iw, ih] = inner.xywh();
|
||||
Some(match align {
|
||||
Align::Center(_) => [ox + (ow - iw) / 2.into(), oy + (oh - ih) / 2.into(), iw, ih,].into(),
|
||||
Align::X(_) => [ox + (ow - iw) / 2.into(), iy, iw, ih,].into(),
|
||||
Align::Y(_) => [ix, oy + (oh - ih) / 2.into(), iw, ih,].into(),
|
||||
Align::NW(_) => [ox, oy, iw, ih,].into(),
|
||||
Align::N(_) => [ox + (ow - iw) / 2.into(), oy, iw, ih,].into(),
|
||||
Align::NE(_) => [ox + ow - iw, oy, iw, ih,].into(),
|
||||
Align::W(_) => [ox, oy + (oh - ih) / 2.into(), iw, ih,].into(),
|
||||
Align::E(_) => [ox + ow - iw, oy + (oh - ih) / 2.into(), iw, ih,].into(),
|
||||
Align::SW(_) => [ox, oy + oh - ih, iw, ih,].into(),
|
||||
Align::S(_) => [ox + (ow - iw) / 2.into(), oy + oh - ih, iw, ih,].into(),
|
||||
Align::SE(_) => [ox + ow - iw, oy + oh - ih, iw, ih,].into(),
|
||||
_ => unreachable!()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Render<E>> Render<E> for Align<E, T> {
|
||||
fn min_size (&self, outer_area: E::Size) -> Perhaps<E::Size> {
|
||||
self.inner().min_size(outer_area)
|
||||
}
|
||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||
let outer_area = to.area();
|
||||
Ok(if let Some(inner_size) = self.min_size(outer_area.wh().into())? {
|
||||
let inner_area = outer_area.clip(inner_size);
|
||||
if let Some(aligned) = align(&self, outer_area.into(), inner_area.into()) {
|
||||
to.render_in(aligned, self.inner())?
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::*;
|
||||
use super::*;
|
||||
|
||||
pub enum Collect<'a, E: Engine, const N: usize> {
|
||||
Callback(CallbackCollection<'a, E>),
|
||||
|
|
|
|||
|
|
@ -1,24 +1,5 @@
|
|||
use crate::*;
|
||||
|
||||
/// Conditional rendering, in unary and binary forms.
|
||||
pub struct Cond;
|
||||
|
||||
impl Cond {
|
||||
/// Render `item` when `cond` is true.
|
||||
pub fn when <E: Engine, A: Render<E>> (cond: bool, item: A) -> When<E, A> {
|
||||
When(cond, item, Default::default())
|
||||
}
|
||||
/// Render `item` if `cond` is true, otherwise render `other`.
|
||||
pub fn either <E: Engine, A: Render<E>, B: Render<E>> (cond: bool, item: A, other: B) -> Either<E, A, B> {
|
||||
Either(cond, item, other, Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// Renders `self.1` when `self.0` is true.
|
||||
pub struct When<E: Engine, A: Render<E>>(bool, A, PhantomData<E>);
|
||||
|
||||
/// Renders `self.1` when `self.0` is true, otherwise renders `self.2`
|
||||
pub struct Either<E: Engine, A: Render<E>, B: Render<E>>(bool, A, B, PhantomData<E>);
|
||||
use super::*;
|
||||
|
||||
impl<E: Engine, A: Render<E>> Render<E> for When<E, A> {
|
||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||
|
|
|
|||
14
src/space/coord.rs
Normal file
14
src/space/coord.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use crate::*;
|
||||
use super::*;
|
||||
|
||||
impl<T> Coordinate for T where T: Send + Sync + Copy
|
||||
+ Add<Self, Output=Self>
|
||||
+ Sub<Self, Output=Self>
|
||||
+ Mul<Self, Output=Self>
|
||||
+ Div<Self, Output=Self>
|
||||
+ Ord + PartialEq + Eq
|
||||
+ Debug + Display + Default
|
||||
+ From<u16> + Into<u16>
|
||||
+ Into<usize>
|
||||
+ Into<f64>
|
||||
{}
|
||||
|
|
@ -1,9 +1,5 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct Layers<
|
||||
E: Engine,
|
||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
||||
>(pub F, PhantomData<E>);
|
||||
use super::*;
|
||||
|
||||
impl<
|
||||
E: Engine,
|
||||
|
|
|
|||
|
|
@ -1,35 +1,8 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait HasSize<E: Engine> {
|
||||
fn size (&self) -> &Measure<E>;
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! has_size {
|
||||
(<$E:ty>|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => {
|
||||
impl $(<$($L),*$($T $(: $U)?),*>)? HasSize<$E> for $Struct $(<$($L),*$($T),*>)? {
|
||||
fn size (&$self) -> &Measure<$E> { $cb }
|
||||
}
|
||||
}
|
||||
}
|
||||
use super::*;
|
||||
|
||||
impl<E: Engine> LayoutDebug<E> for E {}
|
||||
|
||||
pub trait LayoutDebug<E: Engine> {
|
||||
fn debug <W: Render<E>> (other: W) -> DebugOverlay<E, W> {
|
||||
DebugOverlay(Default::default(), other)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DebugOverlay<E: Engine, W: Render<E>>(PhantomData<E>, pub W);
|
||||
|
||||
/// A widget that tracks its render width and height
|
||||
#[derive(Default)]
|
||||
pub struct Measure<E: Engine> {
|
||||
_engine: PhantomData<E>,
|
||||
pub x: Arc<AtomicUsize>,
|
||||
pub y: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl<E: Engine> Clone for Measure<E> {
|
||||
fn clone (&self) -> Self {
|
||||
Self {
|
||||
|
|
@ -83,7 +56,6 @@ impl Measure<Tui> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct ShowMeasure<'a>(&'a Measure<Tui>);
|
||||
render!(<Tui>|self: ShowMeasure<'a>|render(|to|Ok({
|
||||
let w = self.0.w();
|
||||
let h = self.0.h();
|
||||
|
|
|
|||
|
|
@ -1,59 +1,18 @@
|
|||
use crate::*;
|
||||
|
||||
impl<E: Engine> LayoutPushPull<E> for E {}
|
||||
|
||||
pub trait LayoutPushPull<E: Engine> {
|
||||
fn push_x <W: Render<E>> (x: E::Unit, w: W) -> Push<E, W> {
|
||||
Push::X(x, w)
|
||||
}
|
||||
fn push_y <W: Render<E>> (y: E::Unit, w: W) -> Push<E, W> {
|
||||
Push::Y(y, w)
|
||||
}
|
||||
fn push_xy <W: Render<E>> (x: E::Unit, y: E::Unit, w: W) -> Push<E, W> {
|
||||
Push::XY(x, y, w)
|
||||
}
|
||||
fn pull_x <W: Render<E>> (x: E::Unit, w: W) -> Pull<E, W> {
|
||||
Pull::X(x, w)
|
||||
}
|
||||
fn pull_y <W: Render<E>> (y: E::Unit, w: W) -> Pull<E, W> {
|
||||
Pull::Y(y, w)
|
||||
}
|
||||
fn pull_xy <W: Render<E>> (x: E::Unit, y: E::Unit, w: W) -> Pull<E, W> {
|
||||
Pull::XY(x, y, w)
|
||||
}
|
||||
}
|
||||
|
||||
/// Increment origin point of drawing area
|
||||
pub enum Push<E: Engine, T: Render<E>> {
|
||||
/// Move origin to the right
|
||||
X(E::Unit, T),
|
||||
/// Move origin downwards
|
||||
Y(E::Unit, T),
|
||||
/// Move origin to the right and downwards
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
use super::*;
|
||||
|
||||
impl<E: Engine, T: Render<E>> Push<E, T> {
|
||||
pub fn inner (&self) -> &T {
|
||||
match self {
|
||||
Self::X(_, i) => i,
|
||||
Self::Y(_, i) => i,
|
||||
Self::XY(_, _, i) => i,
|
||||
}
|
||||
use Push::*;
|
||||
match self { X(_, i) => i, Y(_, i) => i, XY(_, _, i) => i, }
|
||||
}
|
||||
pub fn x (&self) -> E::Unit {
|
||||
match self {
|
||||
Self::X(x, _) => *x,
|
||||
Self::Y(_, _) => E::Unit::default(),
|
||||
Self::XY(x, _, _) => *x,
|
||||
}
|
||||
pub fn dx (&self) -> E::Unit {
|
||||
use Push::*;
|
||||
match self { X(x, _) => *x, Y(_, _) => E::Unit::default(), XY(x, _, _) => *x, }
|
||||
}
|
||||
pub fn y (&self) -> E::Unit {
|
||||
match self {
|
||||
Self::X(_, _) => E::Unit::default(),
|
||||
Self::Y(y, _) => *y,
|
||||
Self::XY(_, y, _) => *y,
|
||||
}
|
||||
pub fn dy (&self) -> E::Unit {
|
||||
use Push::*;
|
||||
match self { X(_, _) => E::Unit::default(), Y(y, _) => *y, XY(_, y, _) => *y, }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,17 +31,6 @@ impl<E: Engine, T: Render<E>> Render<E> for Push<E, T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Decrement origin point of drawing area
|
||||
pub enum Pull<E: Engine, T: Render<E>> {
|
||||
_Unused(PhantomData<E>),
|
||||
/// Move origin to the right
|
||||
X(E::Unit, T),
|
||||
/// Move origin downwards
|
||||
Y(E::Unit, T),
|
||||
/// Move origin to the right and downwards
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Render<E>> Pull<E, T> {
|
||||
pub fn inner (&self) -> &T {
|
||||
match self {
|
||||
|
|
@ -92,7 +40,7 @@ impl<E: Engine, T: Render<E>> Pull<E, T> {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn x (&self) -> E::Unit {
|
||||
pub fn dx (&self) -> E::Unit {
|
||||
match self {
|
||||
Self::X(x, _) => *x,
|
||||
Self::Y(_, _) => E::Unit::default(),
|
||||
|
|
@ -100,7 +48,7 @@ impl<E: Engine, T: Render<E>> Pull<E, T> {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn y (&self) -> E::Unit {
|
||||
pub fn dy (&self) -> E::Unit {
|
||||
match self {
|
||||
Self::X(_, _) => E::Unit::default(),
|
||||
Self::Y(y, _) => *y,
|
||||
|
|
@ -126,40 +74,6 @@ impl<E: Engine, T: Render<E>> Render<E> for Pull<E, T> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl<E: Engine + LayoutPushPull<E> + LayoutShrinkGrow<E>> LayoutInsetOutset<E> for E {}
|
||||
|
||||
pub trait LayoutInsetOutset<E: Engine>: LayoutPushPull<E> + LayoutShrinkGrow<E> {
|
||||
fn inset_x <W: Render<E>> (x: E::Unit, w: W) -> Inset<E, W> {
|
||||
Inset::X(x, w)
|
||||
}
|
||||
fn inset_y <W: Render<E>> (y: E::Unit, w: W) -> Inset<E, W> {
|
||||
Inset::Y(y, w)
|
||||
}
|
||||
fn inset_xy <W: Render<E>> (x: E::Unit, y: E::Unit, w: W) -> Inset<E, W> {
|
||||
Inset::XY(x, y, w)
|
||||
}
|
||||
fn outset_x <W: Render<E>> (x: E::Unit, w: W) -> Outset<E, W> {
|
||||
Outset::X(x, w)
|
||||
}
|
||||
fn outset_y <W: Render<E>> (y: E::Unit, w: W) -> Outset<E, W> {
|
||||
Outset::Y(y, w)
|
||||
}
|
||||
fn outset_xy <W: Render<E>> (x: E::Unit, y: E::Unit, w: W) -> Outset<E, W> {
|
||||
Outset::XY(x, y, w)
|
||||
}
|
||||
}
|
||||
|
||||
/// Shrink from each side
|
||||
pub enum Inset<E: Engine, T> {
|
||||
/// Decrease width
|
||||
X(E::Unit, T),
|
||||
/// Decrease height
|
||||
Y(E::Unit, T),
|
||||
/// Decrease width and height
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Render<E>> Inset<E, T> {
|
||||
pub fn inner (&self) -> &T {
|
||||
match self {
|
||||
|
|
@ -173,23 +87,13 @@ impl<E: Engine, T: Render<E>> Inset<E, T> {
|
|||
impl<E: Engine, T: Render<E>> Render<E> for Inset<E, T> {
|
||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||
match self {
|
||||
Self::X(x, inner) => E::push_x(*x, E::shrink_x(*x, inner)),
|
||||
Self::Y(y, inner) => E::push_y(*y, E::shrink_y(*y, inner)),
|
||||
Self::XY(x, y, inner) => E::push_xy(*x, *y, E::shrink_xy(*x, *y, inner)),
|
||||
Self::X(x, inner) => Push::x(*x, Shrink::x(*x, inner)),
|
||||
Self::Y(y, inner) => Push::y(*y, Shrink::y(*y, inner)),
|
||||
Self::XY(x, y, inner) => Push::xy(*x, *y, Shrink::xy(*x, *y, inner)),
|
||||
}.render(to)
|
||||
}
|
||||
}
|
||||
|
||||
/// Grow on each side
|
||||
pub enum Outset<E: Engine, T: Render<E>> {
|
||||
/// Increase width
|
||||
X(E::Unit, T),
|
||||
/// Increase height
|
||||
Y(E::Unit, T),
|
||||
/// Increase width and height
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
|
||||
impl<E: Engine, T: Render<E>> Outset<E, T> {
|
||||
pub fn inner (&self) -> &T {
|
||||
|
|
@ -204,16 +108,84 @@ impl<E: Engine, T: Render<E>> Outset<E, T> {
|
|||
impl<E: Engine, T: Render<E>> Render<E> for Outset<E, T> {
|
||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||
match *self {
|
||||
Self::X(x, ref inner) => E::grow_x(x + x, inner),
|
||||
Self::Y(y, ref inner) => E::grow_y(y + y, inner),
|
||||
Self::XY(x, y, ref inner) => E::grow_xy(x + x, y + y, inner),
|
||||
Self::X(x, ref inner) => Grow::x(x + x, inner),
|
||||
Self::Y(y, ref inner) => Grow::y(y + y, inner),
|
||||
Self::XY(x, y, ref inner) => Grow::xy(x + x, y + y, inner),
|
||||
}.min_size(to)
|
||||
}
|
||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||
match *self {
|
||||
Self::X(x, ref inner) => E::push_x(x, inner),
|
||||
Self::Y(y, ref inner) => E::push_y(y, inner),
|
||||
Self::XY(x, y, ref inner) => E::push_xy(x, y, inner),
|
||||
Self::X(x, ref inner) => Push::x(x, inner),
|
||||
Self::Y(y, ref inner) => Push::y(y, inner),
|
||||
Self::XY(x, y, ref inner) => Push::xy(x, y, inner),
|
||||
}.render(to)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Render<E>> Align<E, T> {
|
||||
pub fn c (w: T) -> Self { Self::Center(w) }
|
||||
pub fn x (w: T) -> Self { Self::X(w) }
|
||||
pub fn y (w: T) -> Self { Self::Y(w) }
|
||||
pub fn n (w: T) -> Self { Self::N(w) }
|
||||
pub fn s (w: T) -> Self { Self::S(w) }
|
||||
pub fn e (w: T) -> Self { Self::E(w) }
|
||||
pub fn w (w: T) -> Self { Self::W(w) }
|
||||
pub fn nw (w: T) -> Self { Self::NW(w) }
|
||||
pub fn sw (w: T) -> Self { Self::SW(w) }
|
||||
pub fn ne (w: T) -> Self { Self::NE(w) }
|
||||
pub fn se (w: T) -> Self { Self::SE(w) }
|
||||
pub fn inner (&self) -> &T {
|
||||
match self {
|
||||
Self::Center(inner) => inner,
|
||||
Self::X(inner) => inner,
|
||||
Self::Y(inner) => inner,
|
||||
Self::NW(inner) => inner,
|
||||
Self::N(inner) => inner,
|
||||
Self::NE(inner) => inner,
|
||||
Self::W(inner) => inner,
|
||||
Self::E(inner) => inner,
|
||||
Self::SW(inner) => inner,
|
||||
Self::S(inner) => inner,
|
||||
Self::SE(inner) => inner,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn align<E: Engine, T: Render<E>, N: Coordinate, R: Area<N> + From<[N;4]>> (align: &Align<E, T>, outer: R, inner: R) -> Option<R> {
|
||||
if outer.w() < inner.w() || outer.h() < inner.h() {
|
||||
None
|
||||
} else {
|
||||
let [ox, oy, ow, oh] = outer.xywh();
|
||||
let [ix, iy, iw, ih] = inner.xywh();
|
||||
Some(match align {
|
||||
Align::Center(_) => [ox + (ow - iw) / 2.into(), oy + (oh - ih) / 2.into(), iw, ih,].into(),
|
||||
Align::X(_) => [ox + (ow - iw) / 2.into(), iy, iw, ih,].into(),
|
||||
Align::Y(_) => [ix, oy + (oh - ih) / 2.into(), iw, ih,].into(),
|
||||
Align::NW(_) => [ox, oy, iw, ih,].into(),
|
||||
Align::N(_) => [ox + (ow - iw) / 2.into(), oy, iw, ih,].into(),
|
||||
Align::NE(_) => [ox + ow - iw, oy, iw, ih,].into(),
|
||||
Align::W(_) => [ox, oy + (oh - ih) / 2.into(), iw, ih,].into(),
|
||||
Align::E(_) => [ox + ow - iw, oy + (oh - ih) / 2.into(), iw, ih,].into(),
|
||||
Align::SW(_) => [ox, oy + oh - ih, iw, ih,].into(),
|
||||
Align::S(_) => [ox + (ow - iw) / 2.into(), oy + oh - ih, iw, ih,].into(),
|
||||
Align::SE(_) => [ox + ow - iw, oy + oh - ih, iw, ih,].into(),
|
||||
_ => unreachable!()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Render<E>> Render<E> for Align<E, T> {
|
||||
fn min_size (&self, outer_area: E::Size) -> Perhaps<E::Size> {
|
||||
self.inner().min_size(outer_area)
|
||||
}
|
||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||
let outer_area = to.area();
|
||||
Ok(if let Some(inner_size) = self.min_size(outer_area.wh().into())? {
|
||||
let inner_area = outer_area.clip(inner_size);
|
||||
if let Some(aligned) = align(&self, outer_area.into(), inner_area.into()) {
|
||||
to.render_in(aligned, self.inner())?
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1 @@
|
|||
use crate::*;
|
||||
|
||||
/// A scrollable area.
|
||||
pub struct Scroll<
|
||||
E: Engine,
|
||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
||||
>(pub F, pub Direction, pub u64, PhantomData<E>);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,46 +1,28 @@
|
|||
use crate::*;
|
||||
use super::*;
|
||||
|
||||
impl<E: Engine> LayoutShrinkGrow<E> for E {}
|
||||
|
||||
pub trait LayoutShrinkGrow<E: Engine> {
|
||||
fn shrink_x <W: Render<E>> (x: E::Unit, w: W) -> Shrink<E, W> {
|
||||
Shrink::X(x, w)
|
||||
}
|
||||
fn shrink_y <W: Render<E>> (y: E::Unit, w: W) -> Shrink<E, W> {
|
||||
Shrink::Y(y, w)
|
||||
}
|
||||
fn shrink_xy <W: Render<E>> (x: E::Unit, y: E::Unit, w: W) -> Shrink<E, W> {
|
||||
Shrink::XY(x, y, w)
|
||||
}
|
||||
fn grow_x <W: Render<E>> (x: E::Unit, w: W) -> Grow<E, W> {
|
||||
Grow::X(x, w)
|
||||
}
|
||||
fn grow_y <W: Render<E>> (y: E::Unit, w: W) -> Grow<E, W> {
|
||||
Grow::Y(y, w)
|
||||
}
|
||||
fn grow_xy <W: Render<E>> (x: E::Unit, y: E::Unit, w: W) -> Grow<E, W> {
|
||||
Grow::XY(x, y, w)
|
||||
}
|
||||
impl<N: Coordinate> Size<N> for (N, N) {
|
||||
fn x (&self) -> N { self.0 }
|
||||
fn y (&self) -> N { self.1 }
|
||||
}
|
||||
|
||||
/// Shrink drawing area
|
||||
pub enum Shrink<E: Engine, T: Render<E>> {
|
||||
/// Decrease width
|
||||
X(E::Unit, T),
|
||||
/// Decrease height
|
||||
Y(E::Unit, T),
|
||||
/// Decrease width and height
|
||||
XY(E::Unit, E::Unit, T),
|
||||
impl<N: Coordinate> Size<N> for [N;2] {
|
||||
fn x (&self) -> N { self[0] }
|
||||
fn y (&self) -> N { self[1] }
|
||||
}
|
||||
|
||||
/// Expand drawing area
|
||||
pub enum Grow<E: Engine, T: Render<E>> {
|
||||
/// Increase width
|
||||
X(E::Unit, T),
|
||||
/// Increase height
|
||||
Y(E::Unit, T),
|
||||
/// Increase width and height
|
||||
XY(E::Unit, E::Unit, T)
|
||||
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] }
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Render<E>> Shrink<E, T> {
|
||||
|
|
@ -102,13 +84,6 @@ impl<E: Engine, T: Render<E>> Render<E> for Grow<E, T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum Fill<E: Engine, W: Render<E>> {
|
||||
_Unused(PhantomData<E>),
|
||||
X(W),
|
||||
Y(W),
|
||||
XY(W),
|
||||
}
|
||||
|
||||
impl<E: Engine, W: Render<E>> Fill<E, W> {
|
||||
fn inner (&self) -> &W {
|
||||
match self {
|
||||
|
|
@ -148,17 +123,6 @@ impl<E: Engine, W: Render<E>> Render<E> for Fill<E, W> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Enforce fixed size of drawing area
|
||||
pub enum Fixed<E: Engine, T: Render<E>> {
|
||||
_Unused(PhantomData<E>),
|
||||
/// Enforce fixed width
|
||||
X(E::Unit, T),
|
||||
/// Enforce fixed height
|
||||
Y(E::Unit, T),
|
||||
/// Enforce fixed width and height
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Render<E>> Fixed<E, T> {
|
||||
pub fn inner (&self) -> &T {
|
||||
match self {
|
||||
|
|
@ -201,49 +165,6 @@ impl<E: Engine, T: Render<E>> Render<E> for Fixed<E, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> LayoutMinMax<E> for E {}
|
||||
|
||||
pub trait LayoutMinMax<E: Engine> {
|
||||
fn min_x <W: Render<E>> (x: E::Unit, w: W) -> Min<E, W> {
|
||||
Min::X(x, w)
|
||||
}
|
||||
fn min_y <W: Render<E>> (y: E::Unit, w: W) -> Min<E, W> {
|
||||
Min::Y(y, w)
|
||||
}
|
||||
fn min_xy <W: Render<E>> (x: E::Unit, y: E::Unit, w: W) -> Min<E, W> {
|
||||
Min::XY(x, y, w)
|
||||
}
|
||||
fn max_x <W: Render<E>> (x: E::Unit, w: W) -> Max<E, W> {
|
||||
Max::X(x, w)
|
||||
}
|
||||
fn max_y <W: Render<E>> (y: E::Unit, w: W) -> Max<E, W> {
|
||||
Max::Y(y, w)
|
||||
}
|
||||
fn max_xy <W: Render<E>> (x: E::Unit, y: E::Unit, w: W) -> Max<E, W> {
|
||||
Max::XY(x, y, w)
|
||||
}
|
||||
}
|
||||
|
||||
/// Enforce minimum size of drawing area
|
||||
pub enum Min<E: Engine, T: Render<E>> {
|
||||
/// Enforce minimum width
|
||||
X(E::Unit, T),
|
||||
/// Enforce minimum height
|
||||
Y(E::Unit, T),
|
||||
/// Enforce minimum width and height
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
/// Enforce maximum size of drawing area
|
||||
pub enum Max<E: Engine, T: Render<E>> {
|
||||
/// Enforce maximum width
|
||||
X(E::Unit, T),
|
||||
/// Enforce maximum height
|
||||
Y(E::Unit, T),
|
||||
/// Enforce maximum width and height
|
||||
XY(E::Unit, E::Unit, T),
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Render<E>> Min<E, T> {
|
||||
pub fn inner (&self) -> &T {
|
||||
match self {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,31 @@
|
|||
use crate::*;
|
||||
use super::*;
|
||||
use Direction::*;
|
||||
|
||||
/// A binary split with fixed proportion
|
||||
pub struct Split<E: Engine, A: Render<E>, B: Render<E>>(
|
||||
pub bool, pub Direction, pub E::Unit, A, B, PhantomData<E>
|
||||
);
|
||||
impl Direction {
|
||||
pub fn is_north (&self) -> bool { matches!(self, Self::North) }
|
||||
pub fn is_south (&self) -> bool { matches!(self, Self::South) }
|
||||
pub fn is_east (&self) -> bool { matches!(self, Self::West) }
|
||||
pub fn is_west (&self) -> bool { matches!(self, Self::East) }
|
||||
/// Return next direction clockwise
|
||||
pub fn cw (&self) -> Self {
|
||||
match self {
|
||||
Self::North => Self::East,
|
||||
Self::South => Self::West,
|
||||
Self::West => Self::North,
|
||||
Self::East => Self::South,
|
||||
}
|
||||
}
|
||||
/// Return next direction counterclockwise
|
||||
pub fn ccw (&self) -> Self {
|
||||
match self {
|
||||
Self::North => Self::West,
|
||||
Self::South => Self::East,
|
||||
Self::West => Self::South,
|
||||
Self::East => Self::North,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, A: Render<E>, B: Render<E>> Split<E, A, B> {
|
||||
pub fn new (flip: bool, direction: Direction, proportion: E::Unit, a: A, b: B) -> Self {
|
||||
|
|
@ -40,23 +61,6 @@ impl<E: Engine, A: Render<E>, B: Render<E>> Render<E> for Split<E, A, B> {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum Bsp<E: Engine, X: Render<E>, Y: Render<E>> {
|
||||
/// X is north of Y
|
||||
N(Option<X>, Option<Y>),
|
||||
/// X is south of Y
|
||||
S(Option<X>, Option<Y>),
|
||||
/// X is east of Y
|
||||
E(Option<X>, Option<Y>),
|
||||
/// X is west of Y
|
||||
W(Option<X>, Option<Y>),
|
||||
/// X is above Y
|
||||
A(Option<X>, Option<Y>),
|
||||
/// X is below Y
|
||||
B(Option<X>, Option<Y>),
|
||||
/// Should be avoided.
|
||||
Null(PhantomData<E>),
|
||||
}
|
||||
|
||||
impl<E: Engine, X: Render<E>, Y: Render<E>> Bsp<E, X, Y> {
|
||||
pub fn new (x: X) -> Self { Self::A(Some(x), None) }
|
||||
pub fn n (x: X, y: Y) -> Self { Self::N(Some(x), Some(y)) }
|
||||
|
|
@ -138,11 +142,6 @@ impl<E: Engine, X: Render<E>, Y: Render<E>> Render<E> for Bsp<E, X, Y> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Stack<
|
||||
E: Engine,
|
||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
||||
>(pub F, pub Direction, PhantomData<E>);
|
||||
|
||||
impl<
|
||||
E: Engine,
|
||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
||||
|
|
@ -174,7 +173,7 @@ where
|
|||
(self.0)(&mut |component: &dyn Render<E>| {
|
||||
let max = to.h().minus(h);
|
||||
if max > E::Unit::zero() {
|
||||
let item = E::max_y(max, E::push_y(h, component));
|
||||
let item = Max::y(max, Push::y(h, component));
|
||||
let size = item.min_size(to)?.map(|size|size.wh());
|
||||
if let Some([width, height]) = size {
|
||||
h = h + height.into();
|
||||
|
|
@ -192,7 +191,7 @@ where
|
|||
(self.0)(&mut |component: &dyn Render<E>| {
|
||||
let max = to.w().minus(w);
|
||||
if max > E::Unit::zero() {
|
||||
let item = E::max_x(max, E::push_x(h, component));
|
||||
let item = Max::x(max, Push::x(h, component));
|
||||
let size = item.min_size(to)?.map(|size|size.wh());
|
||||
if let Some([width, height]) = size {
|
||||
w = w + width.into();
|
||||
|
|
@ -210,7 +209,7 @@ where
|
|||
(self.0)(&mut |component: &dyn Render<E>| {
|
||||
let max = to.h().minus(h);
|
||||
if max > E::Unit::zero() {
|
||||
let item = E::max_y(to.h() - h, component);
|
||||
let item = Max::y(to.h() - h, component);
|
||||
let size = item.min_size(to)?.map(|size|size.wh());
|
||||
if let Some([width, height]) = size {
|
||||
h = h + height.into();
|
||||
|
|
@ -244,7 +243,7 @@ where
|
|||
South => {
|
||||
(self.0)(&mut |item| {
|
||||
if h < area.h() {
|
||||
let item = E::max_y(area.h() - h, E::push_y(h, item));
|
||||
let item = Max::y(area.h() - h, Push::y(h, item));
|
||||
let show = item.min_size(area.wh().into())?.map(|s|s.wh());
|
||||
if let Some([width, height]) = show {
|
||||
item.render(to)?;
|
||||
|
|
@ -258,7 +257,7 @@ where
|
|||
East => {
|
||||
(self.0)(&mut |item| {
|
||||
if w < area.w() {
|
||||
let item = E::max_x(area.w() - w, E::push_x(w, item));
|
||||
let item = Max::x(area.w() - w, Push::x(w, item));
|
||||
let show = item.min_size(area.wh().into())?.map(|s|s.wh());
|
||||
if let Some([width, height]) = show {
|
||||
item.render(to)?;
|
||||
|
|
@ -274,7 +273,7 @@ where
|
|||
if h < area.h() {
|
||||
let show = item.min_size([area.w(), area.h().minus(h)].into())?.map(|s|s.wh());
|
||||
if let Some([width, height]) = show {
|
||||
E::shrink_y(height, E::push_y(area.h() - height, item))
|
||||
Shrink::y(height, Push::y(area.h() - height, item))
|
||||
.render(to)?;
|
||||
h = h + height;
|
||||
if width > w { w = width }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::*;
|
|||
pub struct Bordered<S: BorderStyle, W: Render<Tui>>(pub S, pub W);
|
||||
|
||||
render!(<Tui>|self: Bordered<S: BorderStyle, W: Render<Tui>>|{
|
||||
Fill::wh(lay!([Border(self.0), Tui::inset_xy(1, 1, widget(&self.1))]))
|
||||
Fill::wh(lay!([Border(self.0), Inset::xy(1, 1, widget(&self.1))]))
|
||||
});
|
||||
|
||||
pub struct Border<S: BorderStyle>(pub S);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue