mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
reduce number of space modules
This commit is contained in:
parent
35a88cb70f
commit
61b447403b
14 changed files with 599 additions and 623 deletions
|
|
@ -70,20 +70,23 @@ pub(crate) use crossterm::{ExecutableCommand};
|
||||||
pub(crate) use crossterm::terminal::{EnterAlternateScreen, LeaveAlternateScreen, enable_raw_mode, disable_raw_mode};
|
pub(crate) use crossterm::terminal::{EnterAlternateScreen, LeaveAlternateScreen, enable_raw_mode, disable_raw_mode};
|
||||||
pub(crate) use crossterm::event::{KeyCode, KeyModifiers, KeyEvent, KeyEventKind, KeyEventState};
|
pub(crate) use crossterm::event::{KeyCode, KeyModifiers, KeyEvent, KeyEventKind, KeyEventState};
|
||||||
|
|
||||||
pub use ::ratatui; pub(crate) use ratatui::{
|
pub use ::ratatui;
|
||||||
|
pub(crate) use ratatui::{
|
||||||
prelude::{Style, Buffer},
|
prelude::{Style, Buffer},
|
||||||
style::{Stylize, Modifier},
|
style::{Stylize, Modifier},
|
||||||
backend::{Backend, CrosstermBackend, ClearType}
|
backend::{Backend, CrosstermBackend, ClearType}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use ::midly::{self, num::u7}; pub(crate) use ::midly::{
|
pub use ::midly::{self, num::u7};
|
||||||
|
pub(crate) use ::midly::{
|
||||||
Smf,
|
Smf,
|
||||||
MidiMessage,
|
MidiMessage,
|
||||||
TrackEventKind,
|
TrackEventKind,
|
||||||
live::LiveEvent,
|
live::LiveEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use ::palette; pub(crate) use ::palette::{
|
pub use ::palette;
|
||||||
|
pub(crate) use ::palette::{
|
||||||
*,
|
*,
|
||||||
convert::*,
|
convert::*,
|
||||||
okhsl::*
|
okhsl::*
|
||||||
|
|
|
||||||
|
|
@ -51,17 +51,21 @@ render!(<Tui>|self: SequencerTui|{
|
||||||
let with_editbar = |x|Split::n(false, 1, MidiEditStatus(&self.editor), x);
|
let with_editbar = |x|Split::n(false, 1, MidiEditStatus(&self.editor), x);
|
||||||
let with_size = |x|lay!([self.size, x]);
|
let with_size = |x|lay!([self.size, x]);
|
||||||
let editor = with_editbar(with_pool(Fill::wh(&self.editor)));
|
let editor = with_editbar(with_pool(Fill::wh(&self.editor)));
|
||||||
let color = self.player.play_phrase().as_ref().map(|(_,p)|
|
|
||||||
p.as_ref().map(|p|p.read().unwrap().color)
|
let color = self.player.play_phrase().as_ref().map(|(_,p)|
|
||||||
).flatten().clone();
|
p.as_ref().map(|p|p.read().unwrap().color)
|
||||||
let toolbar = row!([
|
).flatten().clone();
|
||||||
|
|
||||||
|
let toolbar = Cond::when(self.transport, row!([
|
||||||
Fixed::wh(5, 2, PlayPause(self.clock.is_rolling())),
|
Fixed::wh(5, 2, PlayPause(self.clock.is_rolling())),
|
||||||
Fixed::h(2, TransportView::from((self, color, true))),
|
Fixed::h(2, TransportView::from((self, color, true))),
|
||||||
]).when(self.transport);
|
]));
|
||||||
let play_queue = row!([
|
|
||||||
|
let play_queue = Cond::when(self.selectors, row!([
|
||||||
PhraseSelector::play_phrase(&self.player),
|
PhraseSelector::play_phrase(&self.player),
|
||||||
PhraseSelector::next_phrase(&self.player),
|
PhraseSelector::next_phrase(&self.player),
|
||||||
]).when(self.selectors);;
|
]));
|
||||||
|
|
||||||
Tui::min_y(15, with_size(with_status(col!([
|
Tui::min_y(15, with_size(with_status(col!([
|
||||||
toolbar,
|
toolbar,
|
||||||
play_queue,
|
play_queue,
|
||||||
|
|
|
||||||
35
src/space.rs
35
src/space.rs
|
|
@ -8,23 +8,20 @@ use std::fmt::{Display, Debug};
|
||||||
//////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////
|
||||||
|
|
||||||
pub(crate) mod align;
|
pub(crate) mod align;
|
||||||
pub(crate) mod cond; pub(crate) use cond::*;
|
pub(crate) mod cond; pub(crate) use cond::*;
|
||||||
pub(crate) mod fill;
|
pub(crate) mod layers; pub(crate) use layers::*;
|
||||||
pub(crate) mod fixed; pub(crate) use fixed::*;
|
pub(crate) mod measure; pub(crate) use measure::*;
|
||||||
pub(crate) mod inset_outset; pub(crate) use inset_outset::*;
|
pub(crate) mod position; pub(crate) use position::*;
|
||||||
pub(crate) mod layers; pub(crate) use layers::*;
|
|
||||||
pub(crate) mod measure; pub(crate) use measure::*;
|
|
||||||
pub use self::measure::Measure;
|
|
||||||
pub(crate) mod min_max; pub(crate) use min_max::*;
|
|
||||||
pub(crate) mod push_pull; pub(crate) use push_pull::*;
|
|
||||||
pub(crate) mod scroll;
|
pub(crate) mod scroll;
|
||||||
pub(crate) mod shrink_grow; pub(crate) use shrink_grow::*;
|
pub(crate) mod size; pub(crate) use size::*;
|
||||||
pub(crate) mod split; pub(crate) use split::*;
|
pub(crate) mod split; pub(crate) use split::*;
|
||||||
pub(crate) mod stack; pub(crate) use stack::*;
|
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
align::*,
|
align::*,
|
||||||
fill::*,
|
cond::*,
|
||||||
|
measure::*,
|
||||||
|
position::*,
|
||||||
|
size::*,
|
||||||
split::*,
|
split::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -234,3 +231,15 @@ impl<N: Coordinate> Area<N> for [N;4] {
|
||||||
Stack::right(move|add|{ for $pat in $collection { add(&$item)?; } Ok(()) })
|
Stack::right(move|add|{ for $pat in $collection { add(&$item)?; } Ok(()) })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,43 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub enum Cond<E: Engine, A: Render<E>, B: Render<E>> {
|
/// Conditional rendering, in unary and binary forms.
|
||||||
_Unused(E),
|
pub struct Cond;
|
||||||
When(bool, A),
|
|
||||||
Either(bool, A, B)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine, R: Render<E>> LayoutCond<E> for R {}
|
impl Cond {
|
||||||
|
/// Render `item` when `cond` is true.
|
||||||
pub trait LayoutCond<E: Engine>: Render<E> + Sized {
|
pub fn when <E: Engine, A: Render<E>> (cond: bool, item: A) -> When<E, A> {
|
||||||
fn when (self, cond: bool) -> If<E, Self> {
|
When(cond, item, Default::default())
|
||||||
If(Default::default(), cond, self)
|
|
||||||
}
|
}
|
||||||
fn or <B: Render<E>> (self, cond: bool, other: B) -> Either<E, Self, B> {
|
/// Render `item` if `cond` is true, otherwise render `other`.
|
||||||
Either(Default::default(), cond, self, 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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine> LayoutCondStatic<E> for E {}
|
/// Renders `self.1` when `self.0` is true.
|
||||||
|
pub struct When<E: Engine, A: Render<E>>(bool, A, PhantomData<E>);
|
||||||
|
|
||||||
pub trait LayoutCondStatic<E: Engine> {
|
/// Renders `self.1` when `self.0` is true, otherwise renders `self.2`
|
||||||
fn either <A: Render<E>, B: Render<E>> (
|
pub struct Either<E: Engine, A: Render<E>, B: Render<E>>(bool, A, B, PhantomData<E>);
|
||||||
condition: bool,
|
|
||||||
a: A,
|
|
||||||
b: B,
|
|
||||||
) -> Either<E, A, B> {
|
|
||||||
Either(Default::default(), condition, a, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Render widget if predicate is true
|
impl<E: Engine, A: Render<E>> Render<E> for When<E, A> {
|
||||||
pub struct If<E: Engine, A: Render<E>>(PhantomData<E>, bool, A);
|
|
||||||
|
|
||||||
impl<E: Engine, A: Render<E>> Render<E> for If<E, A> {
|
|
||||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||||
if self.1 {
|
let Self(cond, item, ..) = self;
|
||||||
return self.2.min_size(to)
|
if *cond { item.min_size(to) } else { Ok(Some([0.into(), 0.into()].into())) }
|
||||||
}
|
|
||||||
Ok(None)
|
|
||||||
}
|
}
|
||||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||||
if self.1 {
|
let Self(cond, item, ..) = self;
|
||||||
return self.2.render(to)
|
if *cond { item.render(to) } else { Ok(()) }
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render widget A if predicate is true, otherwise widget B
|
|
||||||
pub struct Either<E: Engine, A: Render<E>, B: Render<E>>(
|
|
||||||
PhantomData<E>,
|
|
||||||
bool,
|
|
||||||
A,
|
|
||||||
B,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<E: Engine, A: Render<E>, B: Render<E>> Render<E> for Either<E, A, B> {
|
impl<E: Engine, A: Render<E>, B: Render<E>> Render<E> for Either<E, A, B> {
|
||||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||||
if self.1 { self.2.min_size(to) } else { self.3.min_size(to) }
|
let Self(cond, item, other, ..) = self;
|
||||||
|
if *cond { item.min_size(to) } else { other.min_size(to) }
|
||||||
}
|
}
|
||||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||||
if self.1 { self.2.render(to) } else { self.3.render(to) }
|
let Self(cond, item, other, ..) = self;
|
||||||
|
if *cond { item.render(to) } else { other.render(to) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
pub enum Fill<E: Engine, W: Render<E>> {
|
|
||||||
X(W),
|
|
||||||
Y(W),
|
|
||||||
XY(W),
|
|
||||||
_Unused(PhantomData<E>)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine, W: Render<E>> Fill<E, W> {
|
|
||||||
fn inner (&self) -> &W {
|
|
||||||
match self {
|
|
||||||
Self::X(inner) => &inner,
|
|
||||||
Self::Y(inner) => &inner,
|
|
||||||
Self::XY(inner) => &inner,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn w (fill: W) -> Self {
|
|
||||||
Self::X(fill)
|
|
||||||
}
|
|
||||||
pub fn h (fill: W) -> Self {
|
|
||||||
Self::Y(fill)
|
|
||||||
}
|
|
||||||
pub fn wh (fill: W) -> Self {
|
|
||||||
Self::XY(fill)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine, W: Render<E>> Render<E> for Fill<E, W> {
|
|
||||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
|
||||||
let area = self.inner().min_size(to.into())?;
|
|
||||||
if let Some(area) = area {
|
|
||||||
Ok(Some(match self {
|
|
||||||
Self::X(_) => [to.w().into(), area.h()],
|
|
||||||
Self::Y(_) => [area.w(), to.h().into()],
|
|
||||||
Self::XY(_) => [to.w().into(), to.h().into()],
|
|
||||||
_ => unreachable!(),
|
|
||||||
}.into()))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
|
||||||
self.inner().render(to)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
/// 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 {
|
|
||||||
Self::X(_, i) => i,
|
|
||||||
Self::Y(_, i) => i,
|
|
||||||
Self::XY(_, _, i) => i,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn w (x: E::Unit, w: T) -> Self {
|
|
||||||
Self::X(x, w)
|
|
||||||
}
|
|
||||||
pub fn h (y: E::Unit, w: T) -> Self {
|
|
||||||
Self::Y(y, w)
|
|
||||||
}
|
|
||||||
pub fn wh (x: E::Unit, y: E::Unit, w: T) -> Self {
|
|
||||||
Self::XY(x, y, w)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine, T: Render<E>> Render<E> for Fixed<E, T> {
|
|
||||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
|
||||||
Ok(match self {
|
|
||||||
Self::X(w, _) =>
|
|
||||||
if to.w() >= *w { Some([*w, to.h()].into()) } else { None },
|
|
||||||
Self::Y(h, _) =>
|
|
||||||
if to.h() >= *h { Some([to.w(), *h].into()) } else { None },
|
|
||||||
Self::XY(w, h, _)
|
|
||||||
=> if to.w() >= *w && to.h() >= *h { Some([*w, *h].into()) } else { None },
|
|
||||||
_ => unreachable!(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
|
||||||
// 🡘 🡙 ←🡙→
|
|
||||||
if let Some(size) = self.min_size(to.area().wh().into())? {
|
|
||||||
to.render_in(to.area().clip(size).into(), self.inner())
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
Self::X(_, i) => i,
|
|
||||||
Self::Y(_, i) => i,
|
|
||||||
Self::XY(_, _, i) => i,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)),
|
|
||||||
}.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 {
|
|
||||||
match self {
|
|
||||||
Self::X(_, i) => i,
|
|
||||||
Self::Y(_, i) => i,
|
|
||||||
Self::XY(_, _, i) => i,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
|
||||||
}.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),
|
|
||||||
}.render(to)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +1,5 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
#[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 struct Layers<
|
pub struct Layers<
|
||||||
E: Engine,
|
E: Engine,
|
||||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
||||||
|
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
Self::X(_, i) => i,
|
|
||||||
Self::Y(_, i) => i,
|
|
||||||
Self::XY(_, _, i) => i,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine, T: Render<E>> Render<E> for Min<E, T> {
|
|
||||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
|
||||||
Ok(self.inner().min_size(to)?.map(|to|match *self {
|
|
||||||
Self::X(w, _) => [to.w().max(w), to.h()],
|
|
||||||
Self::Y(h, _) => [to.w(), to.h().max(h)],
|
|
||||||
Self::XY(w, h, _) => [to.w().max(w), to.h().max(h)],
|
|
||||||
}.into()))
|
|
||||||
}
|
|
||||||
// TODO: 🡘 🡙 ←🡙→
|
|
||||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
|
||||||
Ok(self.min_size(to.area().wh().into())?
|
|
||||||
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
|
|
||||||
.transpose()?.unwrap_or(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine, T: Render<E>> Max<E, T> {
|
|
||||||
fn inner (&self) -> &T {
|
|
||||||
match self {
|
|
||||||
Self::X(_, i) => i,
|
|
||||||
Self::Y(_, i) => i,
|
|
||||||
Self::XY(_, _, i) => i,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine, T: Render<E>> Render<E> for Max<E, T> {
|
|
||||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
|
||||||
Ok(self.inner().min_size(to)?.map(|to|match *self {
|
|
||||||
Self::X(w, _) => [to.w().min(w), to.h()],
|
|
||||||
Self::Y(h, _) => [to.w(), to.h().min(h)],
|
|
||||||
Self::XY(w, h, _) => [to.w().min(w), to.h().min(h)],
|
|
||||||
}.into()))
|
|
||||||
}
|
|
||||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
|
||||||
Ok(self.min_size(to.area().wh().into())?
|
|
||||||
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
|
|
||||||
.transpose()?.unwrap_or(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -126,3 +126,94 @@ 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 {
|
||||||
|
Self::X(_, i) => i,
|
||||||
|
Self::Y(_, i) => i,
|
||||||
|
Self::XY(_, _, i) => i,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)),
|
||||||
|
}.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 {
|
||||||
|
match self {
|
||||||
|
Self::X(_, i) => i,
|
||||||
|
Self::Y(_, i) => i,
|
||||||
|
Self::XY(_, _, i) => i,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
}.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),
|
||||||
|
}.render(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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<E: Engine, T: Render<E>> Shrink<E, T> {
|
|
||||||
fn inner (&self) -> &T {
|
|
||||||
match self {
|
|
||||||
Self::X(_, i) => i,
|
|
||||||
Self::Y(_, i) => i,
|
|
||||||
Self::XY(_, _, i) => i,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine, T: Render<E>> Grow<E, T> {
|
|
||||||
fn inner (&self) -> &T {
|
|
||||||
match self {
|
|
||||||
Self::X(_, i) => i,
|
|
||||||
Self::Y(_, i) => i,
|
|
||||||
Self::XY(_, _, i) => i,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine, T: Render<E>> Render<E> for Shrink<E, T> {
|
|
||||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
|
||||||
Ok(self.inner().min_size(to)?.map(|to|match *self {
|
|
||||||
Self::X(w, _) => [
|
|
||||||
if to.w() > w { to.w() - w } else { 0.into() },
|
|
||||||
to.h()
|
|
||||||
],
|
|
||||||
Self::Y(h, _) => [
|
|
||||||
to.w(),
|
|
||||||
if to.h() > h { to.h() - h } else { 0.into() }
|
|
||||||
],
|
|
||||||
Self::XY(w, h, _) => [
|
|
||||||
if to.w() > w { to.w() - w } else { 0.into() },
|
|
||||||
if to.h() > h { to.h() - h } else { 0.into() }
|
|
||||||
],
|
|
||||||
}.into()))
|
|
||||||
}
|
|
||||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
|
||||||
Ok(self.min_size(to.area().wh().into())?
|
|
||||||
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
|
|
||||||
.transpose()?.unwrap_or(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine, T: Render<E>> Render<E> for Grow<E, T> {
|
|
||||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
|
||||||
Ok(self.inner().min_size(to)?.map(|to|match *self {
|
|
||||||
Self::X(w, _) => [to.w() + w, to.h()],
|
|
||||||
Self::Y(h, _) => [to.w(), to.h() + h],
|
|
||||||
Self::XY(w, h, _) => [to.w() + w, to.h() + h],
|
|
||||||
}.into()))
|
|
||||||
}
|
|
||||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
|
||||||
Ok(self.min_size(to.area().wh().into())?
|
|
||||||
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
|
|
||||||
.transpose()?.unwrap_or(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
296
src/space/size.rs
Normal file
296
src/space/size.rs
Normal file
|
|
@ -0,0 +1,296 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<E: Engine, T: Render<E>> Shrink<E, T> {
|
||||||
|
fn inner (&self) -> &T {
|
||||||
|
match self {
|
||||||
|
Self::X(_, i) => i,
|
||||||
|
Self::Y(_, i) => i,
|
||||||
|
Self::XY(_, _, i) => i,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine, T: Render<E>> Grow<E, T> {
|
||||||
|
fn inner (&self) -> &T {
|
||||||
|
match self {
|
||||||
|
Self::X(_, i) => i,
|
||||||
|
Self::Y(_, i) => i,
|
||||||
|
Self::XY(_, _, i) => i,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine, T: Render<E>> Render<E> for Shrink<E, T> {
|
||||||
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||||
|
Ok(self.inner().min_size(to)?.map(|to|match *self {
|
||||||
|
Self::X(w, _) => [
|
||||||
|
if to.w() > w { to.w() - w } else { 0.into() },
|
||||||
|
to.h()
|
||||||
|
],
|
||||||
|
Self::Y(h, _) => [
|
||||||
|
to.w(),
|
||||||
|
if to.h() > h { to.h() - h } else { 0.into() }
|
||||||
|
],
|
||||||
|
Self::XY(w, h, _) => [
|
||||||
|
if to.w() > w { to.w() - w } else { 0.into() },
|
||||||
|
if to.h() > h { to.h() - h } else { 0.into() }
|
||||||
|
],
|
||||||
|
}.into()))
|
||||||
|
}
|
||||||
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||||
|
Ok(self.min_size(to.area().wh().into())?
|
||||||
|
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
|
||||||
|
.transpose()?.unwrap_or(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine, T: Render<E>> Render<E> for Grow<E, T> {
|
||||||
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||||
|
Ok(self.inner().min_size(to)?.map(|to|match *self {
|
||||||
|
Self::X(w, _) => [to.w() + w, to.h()],
|
||||||
|
Self::Y(h, _) => [to.w(), to.h() + h],
|
||||||
|
Self::XY(w, h, _) => [to.w() + w, to.h() + h],
|
||||||
|
}.into()))
|
||||||
|
}
|
||||||
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||||
|
Ok(self.min_size(to.area().wh().into())?
|
||||||
|
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
|
||||||
|
.transpose()?.unwrap_or(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
Self::X(inner) => &inner,
|
||||||
|
Self::Y(inner) => &inner,
|
||||||
|
Self::XY(inner) => &inner,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn w (fill: W) -> Self {
|
||||||
|
Self::X(fill)
|
||||||
|
}
|
||||||
|
pub fn h (fill: W) -> Self {
|
||||||
|
Self::Y(fill)
|
||||||
|
}
|
||||||
|
pub fn wh (fill: W) -> Self {
|
||||||
|
Self::XY(fill)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine, W: Render<E>> Render<E> for Fill<E, W> {
|
||||||
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||||
|
let area = self.inner().min_size(to.into())?;
|
||||||
|
if let Some(area) = area {
|
||||||
|
Ok(Some(match self {
|
||||||
|
Self::X(_) => [to.w().into(), area.h()],
|
||||||
|
Self::Y(_) => [area.w(), to.h().into()],
|
||||||
|
Self::XY(_) => [to.w().into(), to.h().into()],
|
||||||
|
_ => unreachable!(),
|
||||||
|
}.into()))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||||
|
self.inner().render(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
Self::X(_, i) => i,
|
||||||
|
Self::Y(_, i) => i,
|
||||||
|
Self::XY(_, _, i) => i,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn w (x: E::Unit, w: T) -> Self {
|
||||||
|
Self::X(x, w)
|
||||||
|
}
|
||||||
|
pub fn h (y: E::Unit, w: T) -> Self {
|
||||||
|
Self::Y(y, w)
|
||||||
|
}
|
||||||
|
pub fn wh (x: E::Unit, y: E::Unit, w: T) -> Self {
|
||||||
|
Self::XY(x, y, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine, T: Render<E>> Render<E> for Fixed<E, T> {
|
||||||
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||||
|
Ok(match self {
|
||||||
|
Self::X(w, _) =>
|
||||||
|
if to.w() >= *w { Some([*w, to.h()].into()) } else { None },
|
||||||
|
Self::Y(h, _) =>
|
||||||
|
if to.h() >= *h { Some([to.w(), *h].into()) } else { None },
|
||||||
|
Self::XY(w, h, _)
|
||||||
|
=> if to.w() >= *w && to.h() >= *h { Some([*w, *h].into()) } else { None },
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||||
|
// 🡘 🡙 ←🡙→
|
||||||
|
if let Some(size) = self.min_size(to.area().wh().into())? {
|
||||||
|
to.render_in(to.area().clip(size).into(), self.inner())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
Self::X(_, i) => i,
|
||||||
|
Self::Y(_, i) => i,
|
||||||
|
Self::XY(_, _, i) => i,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine, T: Render<E>> Render<E> for Min<E, T> {
|
||||||
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||||
|
Ok(self.inner().min_size(to)?.map(|to|match *self {
|
||||||
|
Self::X(w, _) => [to.w().max(w), to.h()],
|
||||||
|
Self::Y(h, _) => [to.w(), to.h().max(h)],
|
||||||
|
Self::XY(w, h, _) => [to.w().max(w), to.h().max(h)],
|
||||||
|
}.into()))
|
||||||
|
}
|
||||||
|
// TODO: 🡘 🡙 ←🡙→
|
||||||
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||||
|
Ok(self.min_size(to.area().wh().into())?
|
||||||
|
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
|
||||||
|
.transpose()?.unwrap_or(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine, T: Render<E>> Max<E, T> {
|
||||||
|
fn inner (&self) -> &T {
|
||||||
|
match self {
|
||||||
|
Self::X(_, i) => i,
|
||||||
|
Self::Y(_, i) => i,
|
||||||
|
Self::XY(_, _, i) => i,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine, T: Render<E>> Render<E> for Max<E, T> {
|
||||||
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||||
|
Ok(self.inner().min_size(to)?.map(|to|match *self {
|
||||||
|
Self::X(w, _) => [to.w().min(w), to.h()],
|
||||||
|
Self::Y(h, _) => [to.w(), to.h().min(h)],
|
||||||
|
Self::XY(w, h, _) => [to.w().min(w), to.h().min(h)],
|
||||||
|
}.into()))
|
||||||
|
}
|
||||||
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||||
|
Ok(self.min_size(to.area().wh().into())?
|
||||||
|
.map(|size|to.render_in(to.area().clip(size).into(), self.inner()))
|
||||||
|
.transpose()?.unwrap_or(()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -138,6 +138,157 @@ 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<()>
|
||||||
|
> Stack<E, F> {
|
||||||
|
#[inline] pub fn new (direction: Direction, build: F) -> Self {
|
||||||
|
Self(build, direction, Default::default())
|
||||||
|
}
|
||||||
|
#[inline] pub fn right (build: F) -> Self {
|
||||||
|
Self::new(East, build)
|
||||||
|
}
|
||||||
|
#[inline] pub fn down (build: F) -> Self {
|
||||||
|
Self::new(South, build)
|
||||||
|
}
|
||||||
|
#[inline] pub fn up (build: F) -> Self {
|
||||||
|
Self::new(North, build)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine, F> Render<E> for Stack<E, F>
|
||||||
|
where
|
||||||
|
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
||||||
|
{
|
||||||
|
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
||||||
|
match self.1 {
|
||||||
|
|
||||||
|
South => {
|
||||||
|
let mut w: E::Unit = 0.into();
|
||||||
|
let mut h: E::Unit = 0.into();
|
||||||
|
(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 size = item.min_size(to)?.map(|size|size.wh());
|
||||||
|
if let Some([width, height]) = size {
|
||||||
|
h = h + height.into();
|
||||||
|
w = w.max(width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
Ok(Some([w, h].into()))
|
||||||
|
},
|
||||||
|
|
||||||
|
East => {
|
||||||
|
let mut w: E::Unit = 0.into();
|
||||||
|
let mut h: E::Unit = 0.into();
|
||||||
|
(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 size = item.min_size(to)?.map(|size|size.wh());
|
||||||
|
if let Some([width, height]) = size {
|
||||||
|
w = w + width.into();
|
||||||
|
h = h.max(height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
Ok(Some([w, h].into()))
|
||||||
|
},
|
||||||
|
|
||||||
|
North => {
|
||||||
|
let mut w: E::Unit = 0.into();
|
||||||
|
let mut h: E::Unit = 0.into();
|
||||||
|
(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 size = item.min_size(to)?.map(|size|size.wh());
|
||||||
|
if let Some([width, height]) = size {
|
||||||
|
h = h + height.into();
|
||||||
|
w = w.max(width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
Ok(Some([w, h].into()))
|
||||||
|
},
|
||||||
|
|
||||||
|
West => {
|
||||||
|
let w: E::Unit = 0.into();
|
||||||
|
let h: E::Unit = 0.into();
|
||||||
|
(self.0)(&mut |component: &dyn Render<E>| {
|
||||||
|
if w < to.w() {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
Ok(Some([w, h].into()))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
||||||
|
let area = to.area();
|
||||||
|
let mut w = 0.into();
|
||||||
|
let mut h = 0.into();
|
||||||
|
match self.1 {
|
||||||
|
South => {
|
||||||
|
(self.0)(&mut |item| {
|
||||||
|
if h < area.h() {
|
||||||
|
let item = E::max_y(area.h() - h, E::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)?;
|
||||||
|
h = h + height;
|
||||||
|
if width > w { w = width }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
},
|
||||||
|
East => {
|
||||||
|
(self.0)(&mut |item| {
|
||||||
|
if w < area.w() {
|
||||||
|
let item = E::max_x(area.w() - w, E::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)?;
|
||||||
|
w = width + w;
|
||||||
|
if height > h { h = height }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
},
|
||||||
|
North => {
|
||||||
|
(self.0)(&mut |item| {
|
||||||
|
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))
|
||||||
|
.render(to)?;
|
||||||
|
h = h + height;
|
||||||
|
if width > w { w = width }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
},
|
||||||
|
_ => todo!()
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)] #[test] fn test_bsp () {
|
#[cfg(test)] #[test] fn test_bsp () {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,153 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
use Direction::*;
|
|
||||||
|
|
||||||
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<()>
|
|
||||||
> Stack<E, F> {
|
|
||||||
#[inline] pub fn new (direction: Direction, build: F) -> Self {
|
|
||||||
Self(build, direction, Default::default())
|
|
||||||
}
|
|
||||||
#[inline] pub fn right (build: F) -> Self {
|
|
||||||
Self::new(East, build)
|
|
||||||
}
|
|
||||||
#[inline] pub fn down (build: F) -> Self {
|
|
||||||
Self::new(South, build)
|
|
||||||
}
|
|
||||||
#[inline] pub fn up (build: F) -> Self {
|
|
||||||
Self::new(North, build)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine, F> Render<E> for Stack<E, F>
|
|
||||||
where
|
|
||||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)->Usually<()>)->Usually<()>
|
|
||||||
{
|
|
||||||
fn min_size (&self, to: E::Size) -> Perhaps<E::Size> {
|
|
||||||
match self.1 {
|
|
||||||
|
|
||||||
South => {
|
|
||||||
let mut w: E::Unit = 0.into();
|
|
||||||
let mut h: E::Unit = 0.into();
|
|
||||||
(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 size = item.min_size(to)?.map(|size|size.wh());
|
|
||||||
if let Some([width, height]) = size {
|
|
||||||
h = h + height.into();
|
|
||||||
w = w.max(width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
Ok(Some([w, h].into()))
|
|
||||||
},
|
|
||||||
|
|
||||||
East => {
|
|
||||||
let mut w: E::Unit = 0.into();
|
|
||||||
let mut h: E::Unit = 0.into();
|
|
||||||
(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 size = item.min_size(to)?.map(|size|size.wh());
|
|
||||||
if let Some([width, height]) = size {
|
|
||||||
w = w + width.into();
|
|
||||||
h = h.max(height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
Ok(Some([w, h].into()))
|
|
||||||
},
|
|
||||||
|
|
||||||
North => {
|
|
||||||
let mut w: E::Unit = 0.into();
|
|
||||||
let mut h: E::Unit = 0.into();
|
|
||||||
(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 size = item.min_size(to)?.map(|size|size.wh());
|
|
||||||
if let Some([width, height]) = size {
|
|
||||||
h = h + height.into();
|
|
||||||
w = w.max(width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
Ok(Some([w, h].into()))
|
|
||||||
},
|
|
||||||
|
|
||||||
West => {
|
|
||||||
let w: E::Unit = 0.into();
|
|
||||||
let h: E::Unit = 0.into();
|
|
||||||
(self.0)(&mut |component: &dyn Render<E>| {
|
|
||||||
if w < to.w() {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
Ok(Some([w, h].into()))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render (&self, to: &mut E::Output) -> Usually<()> {
|
|
||||||
let area = to.area();
|
|
||||||
let mut w = 0.into();
|
|
||||||
let mut h = 0.into();
|
|
||||||
match self.1 {
|
|
||||||
South => {
|
|
||||||
(self.0)(&mut |item| {
|
|
||||||
if h < area.h() {
|
|
||||||
let item = E::max_y(area.h() - h, E::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)?;
|
|
||||||
h = h + height;
|
|
||||||
if width > w { w = width }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
},
|
|
||||||
East => {
|
|
||||||
(self.0)(&mut |item| {
|
|
||||||
if w < area.w() {
|
|
||||||
let item = E::max_x(area.w() - w, E::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)?;
|
|
||||||
w = width + w;
|
|
||||||
if height > h { h = height }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
},
|
|
||||||
North => {
|
|
||||||
(self.0)(&mut |item| {
|
|
||||||
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))
|
|
||||||
.render(to)?;
|
|
||||||
h = h + height;
|
|
||||||
if width > w { w = width }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
},
|
|
||||||
_ => todo!()
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue