use crate::*;
use Alignment::*;
use Direction::*;
use unicode_width::{UnicodeWidthStr, UnicodeWidthChar};
use rand::{thread_rng, distributions::uniform::UniformSampler};
macro_rules! layout_op_xy (
// Variant for layout ops that take no coordinates
(0: $T: ident) => {
impl $T {
#[inline] pub const fn inner (&self) -> &A {
match self { Self::X(c) | Self::Y(c) | Self::XY(c) => c }
}
}
impl> Draw for $T {
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
}
};
// Variant for layout ops that take one coordinate
(1: $T: ident) => {
impl $T {
#[inline] pub const fn inner (&self) -> &A {
match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, }
}
}
impl> Draw for $T {
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
}
impl $T {
#[inline] pub fn dx (&self) -> U {
match self { Self::X(x, _) | Self::XY(x, ..) => *x, _ => 0.into() }
}
#[inline] pub fn dy (&self) -> U {
match self { Self::Y(y, _) | Self::XY(y, ..) => *y, _ => 0.into() }
}
}
};
(1 opt: $T: ident) => {
impl $T {
#[inline] pub const fn inner (&self) -> &A {
match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, }
}
}
impl> Draw for $T {
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
}
impl $T {
#[inline] pub const fn dx (&self) -> Option {
match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None }
}
#[inline] pub const fn dy (&self) -> Option {
match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None }
}
}
};
);
// Implement layout op that increments X and/or Y by fixed amount.
macro_rules! push_pull(($T:ident: $method: ident)=>{
layout_op_xy!(1: $T);
impl> Layout for $T {
fn layout_x (&self, area: XYWH) -> O::Unit { area.x().$method(self.dx()) }
fn layout_y (&self, area: XYWH) -> O::Unit { area.y().$method(self.dy()) }
}
});
macro_rules! impl_map_direction (($name:ident, $axis:ident, $align:ident)=>{
impl<'a, O, A, B, I, F> Map<
O, A, Push>>>, I, F, fn(A, usize)->B
> where
O: Out,
B: Draw,
I: Iterator- + Send + Sync + 'a,
F: Fn() -> I + Send + Sync + 'a
{
pub const fn $name (
size: O::Unit,
get_iter: F,
get_item: impl Fn(A, usize)->B + Send + Sync
) -> Map<
O, A,
Push>>,
I, F,
impl Fn(A, usize)->Push>> + Send + Sync
> {
Map {
__: PhantomData,
get_iter,
get_item: move |item: A, index: usize|{
// FIXME: multiply
let mut push: O::Unit = O::Unit::from(0u16);
for _ in 0..index {
push = push + size;
}
Push::$axis(push, Align::$align(Fixed::$axis(size, get_item(item, index))))
}
}
}
}
});
impl
> Command for Option {
fn execute (&self, _: &mut S) -> Perhaps {
Ok(None)
}
fn delegate (&self, _: &mut S, _: impl Fn(Self)->U) -> Perhaps
where Self: Sized
{
Ok(None)
}
}
impl Coord for u16 {
fn plus (self, other: Self) -> Self { self.saturating_add(other) }
}
impl HasXY for XY {
fn x (&self) -> N { self.0 }
fn y (&self) -> N { self.1 }
}
impl HasXY for XYWH {
fn x (&self) -> N { self.0 }
fn y (&self) -> N { self.1 }
}
impl HasXY for O {
// X coordinate of output area
#[inline] fn x (&self) -> O::Unit { self.area().x() }
// Y coordinate of output area
#[inline] fn y (&self) -> O::Unit { self.area().y() }
}
impl HasWH for WH {
fn w (&self) -> N { self.0 }
fn h (&self) -> N { self.1 }
}
impl HasWH for XYWH {
fn w (&self) -> N { self.2 }
fn h (&self) -> N { self.3 }
}
impl HasWH for O {
// Width of output area
#[inline] fn w (&self) -> O::Unit { self.area().w() }
// Height of output area
#[inline] fn h (&self) -> O::Unit { self.area().h() }
}
impl WH {
pub fn clip_w (&self, w: N) -> [N;2] { [self.w().min(w), self.h()] }
pub fn clip_h (&self, h: N) -> [N;2] { [self.w(), self.h().min(h)] }
pub fn expect_min (&self, w: N, h: N) -> Usually<&Self> {
if self.w() < w || self.h() < h { return Err(format!("min {w}x{h}").into()) }
Ok(self)
}
}
impl XYWH {
pub fn zero () -> Self {
Self(0.into(), 0.into(), 0.into(), 0.into())
}
pub fn x2 (&self) -> N {
self.x().plus(self.w())
}
pub fn y2 (&self) -> N {
self.y().plus(self.h())
}
pub fn with_w (&self, w: N) -> XYWH {
Self(self.x(), self.y(), w, self.h())
}
pub fn with_h (&self, h: N) -> XYWH {
Self(self.x(), self.y(), self.w(), h)
}
pub fn lrtb (&self) -> [N;4] {
[self.x(), self.x2(), self.y(), self.y2()]
}
pub fn clipped_w (&self, w: N) -> XYWH {
Self(self.x(), self.y(), self.w().min(w), self.h())
}
pub fn clipped_h (&self, h: N) -> XYWH {
Self(self.x(), self.y(), self.w(), self.h().min(h))
}
pub fn clipped (&self, wh: WH) -> XYWH {
Self(self.x(), self.y(), wh.w(), wh.h())
}
/// Iterate over every covered X coordinate.
pub fn iter_x (&self) -> impl Iterator- where N: std::iter::Step {
let Self(x, _, w, _) = *self;
x..(x+w)
}
/// Iterate over every covered Y coordinate.
pub fn iter_y (&self) -> impl Iterator
- where N: std::iter::Step {
let Self(_, y, _, h) = *self;
y..(y+h)
}
pub fn center (&self) -> XY {
let Self(x, y, w, h) = self;
XY(self.x().plus(self.w()/2.into()), self.y().plus(self.h()/2.into()))
}
pub fn centered (&self) -> XY {
let Self(x, y, w, h) = *self;
XY(x.minus(w/2.into()), y.minus(h/2.into()))
}
pub fn centered_x (&self, n: N) -> XYWH {
let Self(x, y, w, h) = *self;
XYWH((x.plus(w / 2.into())).minus(n / 2.into()), y.plus(h / 2.into()), n, 1.into())
}
pub fn centered_y (&self, n: N) -> XYWH {
let Self(x, y, w, h) = *self;
XYWH(x.plus(w / 2.into()), (y.plus(h / 2.into())).minus(n / 2.into()), 1.into(), n)
}
pub fn centered_xy (&self, [n, m]: [N;2]) -> XYWH {
let Self(x, y, w, h) = *self;
XYWH((x.plus(w / 2.into())).minus(n / 2.into()), (y.plus(h / 2.into())).minus(m / 2.into()), n, m)
}
}
impl + Layout> Content for T {}
impl<'a, O: Out> AsRef + 'a> for dyn Content + 'a {
fn as_ref (&self) -> &(dyn Draw + 'a) { self }
}
impl<'a, O: Out> AsRef + 'a> for dyn Content + 'a {
fn as_ref (&self) -> &(dyn Layout + 'a) { self }
}
impl Draw for () {
fn draw (&self, _: &mut O) {}
}
impl Draw for fn(&mut O) {
fn draw (&self, to: &mut O) { (*self)(to) }
}
impl Draw for Box> {
fn draw (&self, to: &mut O) { (**self).draw(to) }
}
impl> Draw for &D {
fn draw (&self, to: &mut O) { (*self).draw(to) }
}
impl> Draw for &mut D {
fn draw (&self, to: &mut O) { (**self).draw(to) }
}
impl> Draw for Arc {
fn draw (&self, to: &mut O) { (**self).draw(to) }
}
impl> Draw for RwLock {
fn draw (&self, to: &mut O) { self.read().unwrap().draw(to) }
}
impl> Draw for Option {
fn draw (&self, to: &mut O) { if let Some(draw) = self { draw.draw(to) } }
}
//impl> Draw for T {
//fn draw (&self, to: &mut O) {
//let area = to.area();
//*to.area_mut() = self.0;
//self.content().draw(to);
//*to.area_mut() = area;
//}
//}
impl, F: Fn()->T> Lazy {
pub const fn new (thunk: F) -> Self {
Self(thunk, PhantomData)
}
}
impl Thunk {
pub const fn new (draw: F) -> Self {
Self(PhantomData, draw)
}
}
impl Layout for Thunk {}
impl Draw for Thunk {
fn draw (&self, to: &mut O) {
(self.1)(to)
}
}
impl Memo {
pub fn new (value: T, view: U) -> Self { Self { value, view: Arc::new(view.into()) } }
pub fn update (&mut self, newval: T, draw: impl Fn(&mut U, &T, &T)->R) -> Option {
if newval != self.value {
let result = draw(&mut*self.view.write().unwrap(), &newval, &self.value);
self.value = newval;
return Some(result);
}
None
}
}
impl Direction {
pub fn split_fixed (self, area: XYWH, a: N) -> (XYWH, XYWH) {
let XYWH(x, y, w, h) = area;
match self {
North => (XYWH(x, y.plus(h).minus(a), w, a), XYWH(x, y, w, h.minus(a))),
South => (XYWH(x, y, w, a), XYWH(x, y.plus(a), w, h.minus(a))),
East => (XYWH(x, y, a, h), XYWH(x.plus(a), y, w.minus(a), h)),
West => (XYWH(x.plus(w).minus(a), y, a, h), XYWH(x, y, w.minus(a), h)),
Above | Below => (area, area)
}
}
}
impl>> Measured for T {
fn measure (&self) -> &Measure {
self.get()
}
}
impl Clone for Measure {
fn clone (&self) -> Self {
Self { __: Default::default(), x: self.x.clone(), y: self.y.clone(), }
}
}
impl Layout for Measure {}
impl PartialEq for Measure {
fn eq (&self, other: &Self) -> bool {
self.x.load(Relaxed) == other.x.load(Relaxed) &&
self.y.load(Relaxed) == other.y.load(Relaxed)
}
}
// TODO: 🡘 🡙 ←🡙→ indicator to expand window when too small
impl Draw for Measure {
fn draw (&self, to: &mut O) {
self.x.store(to.area().w().into(), Relaxed);
self.y.store(to.area().h().into(), Relaxed);
}
}
impl Debug for Measure {
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
f.debug_struct("Measure").field("width", &self.x).field("height", &self.y).finish()
}
}
impl Measure {
pub fn set_w (&self, w: impl Into) -> &Self { self.x.store(w.into(), Relaxed); self }
pub fn set_h (&self, h: impl Into) -> &Self { self.y.store(h.into(), Relaxed); self }
pub fn set_wh (&self, w: impl Into, h: impl Into) -> &Self { self.set_w(w); self.set_h(h); self }
pub fn format (&self) -> Arc { format!("{}x{}", self.w(), self.h()).into() }
pub fn of > (&self, item: T) -> Bsp, T> { Bsp::b(Fill::XY(self), item) }
pub fn new (x: O::Unit, y: O::Unit) -> Self {
Self { __: PhantomData::default(), x: Arc::new(x.atomic()), y: Arc::new(y.atomic()), }
}
}
/// FIXME don't convert to u16 specifically
impl HasWH for Measure {
fn w (&self) -> O::Unit { (self.x.load(Relaxed) as u16).into() }
fn h (&self) -> O::Unit { (self.y.load(Relaxed) as u16).into() }
}
impl From> for Measure {
fn from (WH(x, y): WH) -> Self { Self::new(x, y) }
}
impl Layout for () {
fn layout_x (&self, a: XYWH) -> O::Unit { a.x() }
fn layout_y (&self, a: XYWH) -> O::Unit { a.y() }
fn layout_w (&self, _: XYWH) -> O::Unit { 0.into() }
fn layout_w_min (&self, _: XYWH) -> O::Unit { 0.into() }
fn layout_w_max (&self, _: XYWH) -> O::Unit { 0.into() }
fn layout_h (&self, _: XYWH) -> O::Unit { 0.into() }
fn layout_h_min (&self, _: XYWH) -> O::Unit { 0.into() }
fn layout_h_max (&self, _: XYWH) -> O::Unit { 0.into() }
fn layout (&self, a: XYWH) -> XYWH { XYWH(a.x(), a.y(), 0.into(), 0.into()) }
}
impl> Layout for &L {
fn layout_x (&self, a: XYWH) -> O::Unit { (*self).layout_x(a) }
fn layout_y (&self, a: XYWH) -> O::Unit { (*self).layout_y(a) }
fn layout_w (&self, a: XYWH) -> O::Unit { (*self).layout_w(a) }
fn layout_w_min (&self, a: XYWH) -> O::Unit { (*self).layout_w_min(a) }
fn layout_w_max (&self, a: XYWH) -> O::Unit { (*self).layout_w_max(a) }
fn layout_h (&self, a: XYWH) -> O::Unit { (*self).layout_h(a) }
fn layout_h_min (&self, a: XYWH) -> O::Unit { (*self).layout_h_min(a) }
fn layout_h_max (&self, a: XYWH) -> O::Unit { (*self).layout_h_max(a) }
fn layout (&self, a: XYWH) -> XYWH { (*self).layout(a) }
}
impl> Layout for &mut L {
fn layout_x (&self, a: XYWH) -> O::Unit { (**self).layout_x(a) }
fn layout_y (&self, a: XYWH) -> O::Unit { (**self).layout_y(a) }
fn layout_w (&self, a: XYWH) -> O::Unit { (**self).layout_w(a) }
fn layout_w_min (&self, a: XYWH) -> O::Unit { (**self).layout_w_min(a) }
fn layout_w_max (&self, a: XYWH) -> O::Unit { (**self).layout_w_max(a) }
fn layout_h (&self, a: XYWH) -> O::Unit { (**self).layout_h(a) }
fn layout_h_min (&self, a: XYWH) -> O::Unit { (**self).layout_h_min(a) }
fn layout_h_max (&self, a: XYWH) -> O::Unit { (**self).layout_h_max(a) }
fn layout (&self, a: XYWH) -> XYWH { (**self).layout(a) }
}
impl> Layout for Arc {
fn layout_x (&self, a: XYWH) -> O::Unit { (**self).layout_x(a) }
fn layout_y (&self, a: XYWH) -> O::Unit { (**self).layout_y(a) }
fn layout_w (&self, a: XYWH) -> O::Unit { (**self).layout_w(a) }
fn layout_w_min (&self, a: XYWH) -> O::Unit { (**self).layout_w_min(a) }
fn layout_w_max (&self, a: XYWH) -> O::Unit { (**self).layout_w_max(a) }
fn layout_h (&self, a: XYWH) -> O::Unit { (**self).layout_h(a) }
fn layout_h_min (&self, a: XYWH) -> O::Unit { (**self).layout_h_min(a) }
fn layout_h_max (&self, a: XYWH) -> O::Unit { (**self).layout_h_max(a) }
fn layout (&self, a: XYWH) -> XYWH { (**self).layout(a) }
}
impl Layout for Box> {
fn layout_x (&self, a: XYWH) -> O::Unit { (**self).layout_x(a) }
fn layout_y (&self, a: XYWH) -> O::Unit { (**self).layout_y(a) }
fn layout_w (&self, a: XYWH) -> O::Unit { (**self).layout_w(a) }
fn layout_w_min (&self, a: XYWH) -> O::Unit { (**self).layout_w_min(a) }
fn layout_w_max (&self, a: XYWH) -> O::Unit { (**self).layout_w_max(a) }
fn layout_h (&self, a: XYWH) -> O::Unit { (**self).layout_h(a) }
fn layout_h_min (&self, a: XYWH) -> O::Unit { (**self).layout_h_min(a) }
fn layout_h_max (&self, a: XYWH) -> O::Unit { (**self).layout_h_max(a) }
fn layout (&self, a: XYWH) -> XYWH { (**self).layout(a) }
}
impl> Layout for RwLock {
fn layout_x (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_x(a) }
fn layout_y (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_y(a) }
fn layout_w (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_w(a) }
fn layout_w_min (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_w_min(a) }
fn layout_w_max (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_w_max(a) }
fn layout_h (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_h(a) }
fn layout_h_min (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_h_min(a) }
fn layout_h_max (&self, a: XYWH) -> O::Unit { self.read().unwrap().layout_h_max(a) }
fn layout (&self, a: XYWH) -> XYWH { self.read().unwrap().layout(a) }
}
impl> Layout for Option {
fn layout_x (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_x(to)).unwrap_or(to.x()) }
fn layout_y (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_y(to)).unwrap_or(to.y()) }
fn layout_w_min (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_w_min(to)).unwrap_or(0.into()) }
fn layout_w_max (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_w_max(to)).unwrap_or(0.into()) }
fn layout_w (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_w(to)).unwrap_or(0.into()) }
fn layout_h_min (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_h_min(to)).unwrap_or(0.into()) }
fn layout_h_max (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_h_max(to)).unwrap_or(0.into()) }
fn layout_h (&self, to: XYWH) -> O::Unit { self.as_ref().map(|c|c.layout_h(to)).unwrap_or(0.into()) }
fn layout (&self, to: XYWH) -> XYWH {
let xywh = XYWH(self.layout_x(to), self.layout_y(to), self.layout_w(to), self.layout_h(to));
self.as_ref().map(|c|c.layout(xywh)).unwrap_or(XYWH(to.x(), to.y(), 0.into(), 0.into()))
}
}
impl> HasContent for Bounded {
fn content (&self) -> impl Content {
&self.1
}
}
impl> Draw for Bounded {
fn draw (&self, to: &mut O) {
let area = to.area();
*to.area_mut() = self.0;
self.1.draw(to);
*to.area_mut() = area;
}
}
impl> When {
/// Create a binary condition.
pub const fn new (c: bool, a: T) -> Self { Self(c, a, PhantomData) }
}
impl> Layout for When {
fn layout (&self, to: XYWH) -> XYWH {
let Self(cond, item, ..) = self;
if *cond { item.layout(to) } else { XYWH::::zero().into() }
}
}
impl> Draw for When