mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +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
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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue