mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-02-21 10:39:03 +01:00
wip: refactor(output): pen and paper ftw
This commit is contained in:
parent
501782f8fe
commit
eaa05b7f09
26 changed files with 1701 additions and 1697 deletions
|
|
@ -1,45 +1,4 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
/// Show an item only when a condition is true.
|
|
||||||
pub struct When<O, T>(bool, T, PhantomData<O>);
|
|
||||||
impl<O: Out, T: Content<O>> When<O, T> {
|
|
||||||
/// Create a binary condition.
|
|
||||||
pub const fn new (c: bool, a: T) -> Self { Self(c, a, PhantomData) }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Layout<O>> Layout<O> for When<O, T> {
|
|
||||||
fn layout (&self, to: O::Area) -> O::Area {
|
|
||||||
let Self(cond, item, ..) = self;
|
|
||||||
if *cond { item.layout(to) } else { O::Area::zero().into() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Content<O>> Draw<O> for When<O, T> {
|
|
||||||
fn draw (&self, to: &mut O) {
|
|
||||||
let Self(cond, item, ..) = self;
|
|
||||||
if *cond { Bounded(self.layout(to.area()), item).draw(to) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Show one item if a condition is true and another if the condition is false
|
|
||||||
pub struct Either<E: Out, A, B>(pub bool, pub A, pub B, pub PhantomData<E>);
|
|
||||||
impl<E: Out, A: Content<E>, B: Content<E>> Either<E, A, B> {
|
|
||||||
/// Create a ternary view condition.
|
|
||||||
pub const fn new (c: bool, a: A, b: B) -> Self {
|
|
||||||
Self(c, a, b, PhantomData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<E: Out, A: Layout<E>, B: Layout<E>> Layout<E> for Either<E, A, B> {
|
|
||||||
fn layout (&self, to: E::Area) -> E::Area {
|
|
||||||
let Self(cond, a, b, ..) = self;
|
|
||||||
if *cond { a.layout(to) } else { b.layout(to) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<E: Out, A: Content<E>, B: Content<E>> Draw<E> for Either<E, A, B> {
|
|
||||||
fn draw (&self, to: &mut E) {
|
|
||||||
let Self(cond, a, b, ..) = self;
|
|
||||||
let area = self.layout(to.area());
|
|
||||||
if *cond { Bounded(area, a).draw(to) } else { Bounded(area, b).draw(to) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
@ -55,7 +14,7 @@ impl<E: Out, A: Content<E>, B: Content<E>> Draw<E> for Either<E, A, B> {
|
||||||
//))))
|
//))))
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
///// The syntagm `(either :condition :content1 :content2)` corresponds to an [Either] layout element.
|
///// The syntagm `(either :condition :content1 :content2)` corresponds to an [Either] layout element.
|
||||||
//impl<S, A, B> FromDsl<S> for Either<A, B> where S: Eval<Ast, bool> + Eval<Ast, A> + Eval<Ast, B> {
|
//impl<S, A, B> FromDsl<S> for Either<A, B> where S: Eval<Ast, bool> + Eval<Ast, A> + Eval<Ast, B> {
|
||||||
//fn try_provide (state: &S, source: &DslVal<impl DslStr, impl DslExpr>) -> Perhaps<Self> {
|
//fn try_provide (state: &S, source: &DslVal<impl DslStr, impl DslExpr>) -> Perhaps<Self> {
|
||||||
//source.exp_match("either", |_, tail|Ok(Some(Self(
|
//source.exp_match("either", |_, tail|Ok(Some(Self(
|
||||||
|
|
@ -209,3 +168,184 @@ impl<E: Out, A: Content<E>, B: Content<E>> Draw<E> for Either<E, A, B> {
|
||||||
//)),
|
//)),
|
||||||
//_ => None
|
//_ => None
|
||||||
//})
|
//})
|
||||||
|
//use crate::*;
|
||||||
|
//use Direction::*;
|
||||||
|
|
||||||
|
//pub struct Stack<'x, E, F1> {
|
||||||
|
//__: PhantomData<&'x (E, F1)>,
|
||||||
|
//direction: Direction,
|
||||||
|
//callback: F1
|
||||||
|
//}
|
||||||
|
|
||||||
|
//impl<'x, E, F1> Stack<'x, E, F1> {
|
||||||
|
//pub fn new (direction: Direction, callback: F1) -> Self {
|
||||||
|
//Self { direction, callback, __: Default::default(), }
|
||||||
|
//}
|
||||||
|
//pub fn above (callback: F1) -> Self {
|
||||||
|
//Self::new(Above, callback)
|
||||||
|
//}
|
||||||
|
//pub fn below (callback: F1) -> Self {
|
||||||
|
//Self::new(Below, callback)
|
||||||
|
//}
|
||||||
|
//pub fn north (callback: F1) -> Self {
|
||||||
|
//Self::new(North, callback)
|
||||||
|
//}
|
||||||
|
//pub fn south (callback: F1) -> Self {
|
||||||
|
//Self::new(South, callback)
|
||||||
|
//}
|
||||||
|
//pub fn east (callback: F1) -> Self {
|
||||||
|
//Self::new(East, callback)
|
||||||
|
//}
|
||||||
|
//pub fn west (callback: F1) -> Self {
|
||||||
|
//Self::new(West, callback)
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
|
//impl<'x, E: Out, F1: Fn(&mut dyn FnMut(&dyn Layout<E>))> Layout<E> for Stack<'x, E, F1> {
|
||||||
|
//fn layout (&self, to: E::Area) -> E::Area {
|
||||||
|
//let state = StackLayoutState::<E>::new(self.direction, to);
|
||||||
|
//(self.callback)(&mut |component: &dyn Layout<E>|{
|
||||||
|
//let StackLayoutState { x, y, w_remaining, h_remaining, .. } = *state.borrow();
|
||||||
|
//let [_, _, w, h] = component.layout([x, y, w_remaining, h_remaining].into()).xywh();
|
||||||
|
//state.borrow_mut().grow(w, h);
|
||||||
|
//});
|
||||||
|
//let StackLayoutState { w_used, h_used, .. } = *state.borrow();
|
||||||
|
//match self.direction {
|
||||||
|
//North | West => { todo!() },
|
||||||
|
//South | East => { [to.x(), to.y(), w_used, h_used].into() },
|
||||||
|
//_ => unreachable!(),
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
//impl<'x, E: Out, F1: Fn(&mut dyn FnMut(&dyn Draw<E>))> Draw<E> for Stack<'x, E, F1> {
|
||||||
|
//fn draw (&self, to: &mut E) {
|
||||||
|
//let state = StackLayoutState::<E>::new(self.direction, to.area());
|
||||||
|
//let to = Rc::new(RefCell::new(to));
|
||||||
|
//(self.callback)(&mut |component: &dyn Draw<E>|{
|
||||||
|
//let StackLayoutState { x, y, w_remaining, h_remaining, .. } = *state.borrow();
|
||||||
|
//let layout = component.layout([x, y, w_remaining, h_remaining].into());
|
||||||
|
//state.borrow_mut().grow(layout.w(), layout.h());
|
||||||
|
//to.borrow_mut().place_at(layout, component);
|
||||||
|
//});
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
|
//#[derive(Copy, Clone)]
|
||||||
|
//struct StackLayoutState<E: Out> {
|
||||||
|
//direction: Direction,
|
||||||
|
//x: E::Unit,
|
||||||
|
//y: E::Unit,
|
||||||
|
//w_used: E::Unit,
|
||||||
|
//h_used: E::Unit,
|
||||||
|
//w_remaining: E::Unit,
|
||||||
|
//h_remaining: E::Unit,
|
||||||
|
//}
|
||||||
|
//impl<E: Out> StackLayoutState<E> {
|
||||||
|
//fn new (direction: Direction, area: E::Area) -> std::rc::Rc<std::cell::RefCell<Self>> {
|
||||||
|
//let [x, y, w_remaining, h_remaining] = area.xywh();
|
||||||
|
//std::rc::Rc::new(std::cell::RefCell::new(Self {
|
||||||
|
//direction,
|
||||||
|
//x, y, w_remaining, h_remaining,
|
||||||
|
//w_used: E::Unit::zero(), h_used: E::Unit::zero()
|
||||||
|
//}))
|
||||||
|
//}
|
||||||
|
//fn grow (&mut self, w: E::Unit, h: E::Unit) -> &mut Self {
|
||||||
|
//match self.direction {
|
||||||
|
//South => { self.y = self.y.plus(h);
|
||||||
|
//self.h_used = self.h_used.plus(h);
|
||||||
|
//self.h_remaining = self.h_remaining.minus(h);
|
||||||
|
//self.w_used = self.w_used.max(w); },
|
||||||
|
//East => { self.x = self.x.plus(w);
|
||||||
|
//self.w_used = self.w_used.plus(w);
|
||||||
|
//self.w_remaining = self.w_remaining.minus(w);
|
||||||
|
//self.h_used = self.h_used.max(h); },
|
||||||
|
//North | West => { todo!() },
|
||||||
|
//Above | Below => {},
|
||||||
|
//};
|
||||||
|
//self
|
||||||
|
//}
|
||||||
|
//fn area_remaining (&self) -> E::Area {
|
||||||
|
//[self.x, self.y, self.w_remaining, self.h_remaining].into()
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
|
////pub struct Stack<'a, E, F1> {
|
||||||
|
////__: PhantomData<&'a (E, F1)>,
|
||||||
|
////direction: Direction,
|
||||||
|
////callback: F1
|
||||||
|
////}
|
||||||
|
////impl<'a, E, F1> Stack<'a, E, F1> where
|
||||||
|
////E: Out, F1: Fn(&mut dyn FnMut(&'a dyn Draw<E>)) + Send + Sync,
|
||||||
|
////{
|
||||||
|
////pub fn north (callback: F1) -> Self { Self::new(North, callback) }
|
||||||
|
////pub fn south (callback: F1) -> Self { Self::new(South, callback) }
|
||||||
|
////pub fn east (callback: F1) -> Self { Self::new(East, callback) }
|
||||||
|
////pub fn west (callback: F1) -> Self { Self::new(West, callback) }
|
||||||
|
////pub fn above (callback: F1) -> Self { Self::new(Above, callback) }
|
||||||
|
////pub fn below (callback: F1) -> Self { Self::new(Below, callback) }
|
||||||
|
////pub fn new (direction: Direction, callback: F1) -> Self {
|
||||||
|
////Self { direction, callback, __: Default::default(), }
|
||||||
|
////}
|
||||||
|
////}
|
||||||
|
////impl<'a, E, F1> Draw<E> for Stack<'a, E, F1> where
|
||||||
|
////E: Out, F1: Fn(&mut dyn FnMut(&'a dyn Draw<E>)) + Send + Sync,
|
||||||
|
////{
|
||||||
|
////fn layout (&self, to: E::Area) -> E::Area {
|
||||||
|
////let state = StackLayoutState::<E>::new(self.direction, to);
|
||||||
|
////let mut adder = {
|
||||||
|
////let state = state.clone();
|
||||||
|
////move|component: &dyn Draw<E>|{
|
||||||
|
////let [w, h] = component.layout(state.borrow().area_remaining()).wh();
|
||||||
|
////state.borrow_mut().grow(w, h);
|
||||||
|
////}
|
||||||
|
////};
|
||||||
|
////(self.callback)(&mut adder);
|
||||||
|
////let StackLayoutState { w_used, h_used, .. } = *state.borrow();
|
||||||
|
////match self.direction {
|
||||||
|
////North | West => { todo!() },
|
||||||
|
////South | East => { [to.x(), to.y(), w_used, h_used].into() },
|
||||||
|
////Above | Below => { [to.x(), to.y(), to.w(), to.h()].into() },
|
||||||
|
////}
|
||||||
|
////}
|
||||||
|
////fn draw (&self, to: &mut E) {
|
||||||
|
////let state = StackLayoutState::<E>::new(self.direction, to.area());
|
||||||
|
////let mut adder = {
|
||||||
|
////let state = state.clone();
|
||||||
|
////move|component: &dyn Draw<E>|{
|
||||||
|
////let [x, y, w, h] = component.layout(state.borrow().area_remaining()).xywh();
|
||||||
|
////state.borrow_mut().grow(w, h);
|
||||||
|
////to.place_at([x, y, w, h].into(), component);
|
||||||
|
////}
|
||||||
|
////};
|
||||||
|
////(self.callback)(&mut adder);
|
||||||
|
////}
|
||||||
|
////}
|
||||||
|
|
||||||
|
//[>Stack::down(|add|{
|
||||||
|
//let mut i = 0;
|
||||||
|
//for (_, name) in self.dirs.iter() {
|
||||||
|
//if i >= self.scroll {
|
||||||
|
//add(&Tui::bold(i == self.index, name.as_str()))?;
|
||||||
|
//}
|
||||||
|
//i += 1;
|
||||||
|
//}
|
||||||
|
//for (_, name) in self.files.iter() {
|
||||||
|
//if i >= self.scroll {
|
||||||
|
//add(&Tui::bold(i == self.index, name.as_str()))?;
|
||||||
|
//}
|
||||||
|
//i += 1;
|
||||||
|
//}
|
||||||
|
//add(&format!("{}/{i}", self.index))?;
|
||||||
|
//Ok(())
|
||||||
|
//}));*/
|
||||||
|
|
||||||
|
|
||||||
|
//#[test] fn test_iter_map () {
|
||||||
|
//struct Foo;
|
||||||
|
//impl<T: Out> Content<T> for Foo {}
|
||||||
|
//fn _make_map <T: Out, U: Content<T> + Send + Sync> (data: &Vec<U>) -> impl Draw<T> {
|
||||||
|
//Map::new(||data.iter(), |_foo, _index|{})
|
||||||
|
//}
|
||||||
|
//let _data = vec![Foo, Foo, Foo];
|
||||||
|
////let map = make_map(&data);
|
||||||
|
//}
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
pub trait Content<O: Out>: Draw<O> + Layout<O> {}
|
|
||||||
|
|
||||||
impl<O: Out, T: Draw<O> + Layout<O>> Content<O> for T {}
|
|
||||||
|
|
||||||
impl<'a, O: Out> AsRef<dyn Draw<O> + 'a> for dyn Content<O> + 'a {
|
|
||||||
fn as_ref (&self) -> &(dyn Draw<O> + 'a) { self }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, O: Out> AsRef<dyn Layout<O> + 'a> for dyn Content<O> + 'a {
|
|
||||||
fn as_ref (&self) -> &(dyn Layout<O> + 'a) { self }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait HasContent<O: Out> {
|
|
||||||
fn content (&self) -> impl Content<O>;
|
|
||||||
}
|
|
||||||
|
|
||||||
//impl<O: Out, T: HasContent<O>> Draw<O> 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;
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
/// Drawable with dynamic dispatch.
|
|
||||||
pub trait Draw<O: Out> {
|
|
||||||
fn draw (&self, to: &mut O);
|
|
||||||
}
|
|
||||||
impl<O: Out> Draw<O> for () {
|
|
||||||
fn draw (&self, _: &mut O) {}
|
|
||||||
}
|
|
||||||
impl<O: Out> Draw<O> for fn(&mut O) {
|
|
||||||
fn draw (&self, to: &mut O) { (*self)(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out> Draw<O> for Box<dyn Draw<O>> {
|
|
||||||
fn draw (&self, to: &mut O) { (**self).draw(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, D: Draw<O>> Draw<O> for &D {
|
|
||||||
fn draw (&self, to: &mut O) { (*self).draw(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, D: Draw<O>> Draw<O> for &mut D {
|
|
||||||
fn draw (&self, to: &mut O) { (**self).draw(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, D: Draw<O>> Draw<O> for Arc<D> {
|
|
||||||
fn draw (&self, to: &mut O) { (**self).draw(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, D: Draw<O>> Draw<O> for RwLock<D> {
|
|
||||||
fn draw (&self, to: &mut O) { self.read().unwrap().draw(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, D: Draw<O>> Draw<O> for Option<D> {
|
|
||||||
fn draw (&self, to: &mut O) { if let Some(draw) = self { draw.draw(to) } }
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
#[allow(unused)] use crate::*;
|
|
||||||
|
|
||||||
pub struct Group<T>(T);
|
|
||||||
|
|
||||||
impl<T> Group<T> {
|
|
||||||
pub const fn new () -> Group<()> {
|
|
||||||
Group(())
|
|
||||||
}
|
|
||||||
pub const fn add <U> (self, value: U) -> Group<(T, U)> {
|
|
||||||
Group((self.0, value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,199 +0,0 @@
|
||||||
mod layout_cond; pub use self::layout_cond::*;
|
|
||||||
mod layout_map; pub use self::layout_map::*;
|
|
||||||
mod layout_pad; pub use self::layout_pad::*;
|
|
||||||
mod layout_move; pub use self::layout_move::*;
|
|
||||||
mod layout_size; pub use self::layout_size::*;
|
|
||||||
mod layout_stack; //pub use self::layout_stack::*;
|
|
||||||
|
|
||||||
/// Stack things on top of each other,
|
|
||||||
#[macro_export] macro_rules! lay (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::b(bsp, $expr);)*; bsp }});
|
|
||||||
/// Stack southward.
|
|
||||||
#[macro_export] macro_rules! col (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::s(bsp, $expr);)*; bsp }});
|
|
||||||
/// Stack northward.
|
|
||||||
#[macro_export] macro_rules! col_up (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::n(bsp, $expr);)*; bsp }});
|
|
||||||
/// Stack eastward.
|
|
||||||
#[macro_export] macro_rules! row (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::e(bsp, $expr);)*; bsp }});
|
|
||||||
|
|
||||||
pub use self::align::*; mod align {
|
|
||||||
use crate::*;
|
|
||||||
use Alignment::*;
|
|
||||||
|
|
||||||
/// 9th of area to place.
|
|
||||||
#[derive(Debug, Copy, Clone, Default)]
|
|
||||||
pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W }
|
|
||||||
|
|
||||||
/// Align position of inner area to middle, side, or corner of outer area.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use ::tengri::{output::*, tui::*};
|
|
||||||
/// let area: [u16;4] = [10, 10, 20, 20];
|
|
||||||
/// fn test (area: [u16;4], item: &impl Draw<TuiOut>, expected: [u16;4]) {
|
|
||||||
/// assert_eq!(Content::layout(item, area), expected);
|
|
||||||
/// assert_eq!(Draw::layout(item, area), expected);
|
|
||||||
/// };
|
|
||||||
///
|
|
||||||
/// let four = ||Fixed::XY(4, 4, "");
|
|
||||||
/// test(area, &Align::nw(four()), [10, 10, 4, 4]);
|
|
||||||
/// test(area, &Align::n(four()), [18, 10, 4, 4]);
|
|
||||||
/// test(area, &Align::ne(four()), [26, 10, 4, 4]);
|
|
||||||
/// test(area, &Align::e(four()), [26, 18, 4, 4]);
|
|
||||||
/// test(area, &Align::se(four()), [26, 26, 4, 4]);
|
|
||||||
/// test(area, &Align::s(four()), [18, 26, 4, 4]);
|
|
||||||
/// test(area, &Align::sw(four()), [10, 26, 4, 4]);
|
|
||||||
/// test(area, &Align::w(four()), [10, 18, 4, 4]);
|
|
||||||
///
|
|
||||||
/// let two_by_four = ||Fixed::XY(4, 2, "");
|
|
||||||
/// test(area, &Align::nw(two_by_four()), [10, 10, 4, 2]);
|
|
||||||
/// test(area, &Align::n(two_by_four()), [18, 10, 4, 2]);
|
|
||||||
/// test(area, &Align::ne(two_by_four()), [26, 10, 4, 2]);
|
|
||||||
/// test(area, &Align::e(two_by_four()), [26, 19, 4, 2]);
|
|
||||||
/// test(area, &Align::se(two_by_four()), [26, 28, 4, 2]);
|
|
||||||
/// test(area, &Align::s(two_by_four()), [18, 28, 4, 2]);
|
|
||||||
/// test(area, &Align::sw(two_by_four()), [10, 28, 4, 2]);
|
|
||||||
/// test(area, &Align::w(two_by_four()), [10, 19, 4, 2]);
|
|
||||||
/// ```
|
|
||||||
pub struct Align<T>(Alignment, T);
|
|
||||||
impl<T> Align<T> {
|
|
||||||
#[inline] pub const fn c (a: T) -> Self { Self(Alignment::Center, a) }
|
|
||||||
#[inline] pub const fn x (a: T) -> Self { Self(Alignment::X, a) }
|
|
||||||
#[inline] pub const fn y (a: T) -> Self { Self(Alignment::Y, a) }
|
|
||||||
#[inline] pub const fn n (a: T) -> Self { Self(Alignment::N, a) }
|
|
||||||
#[inline] pub const fn s (a: T) -> Self { Self(Alignment::S, a) }
|
|
||||||
#[inline] pub const fn e (a: T) -> Self { Self(Alignment::E, a) }
|
|
||||||
#[inline] pub const fn w (a: T) -> Self { Self(Alignment::W, a) }
|
|
||||||
#[inline] pub const fn nw (a: T) -> Self { Self(Alignment::NW, a) }
|
|
||||||
#[inline] pub const fn sw (a: T) -> Self { Self(Alignment::SW, a) }
|
|
||||||
#[inline] pub const fn ne (a: T) -> Self { Self(Alignment::NE, a) }
|
|
||||||
#[inline] pub const fn se (a: T) -> Self { Self(Alignment::SE, a) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: Out, T: Content<O>> Draw<O> for Align<T> {
|
|
||||||
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), &self.1).draw(to) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: Out, T: Layout<O>> Layout<O> for Align<T> {
|
|
||||||
fn x (&self, to: O::Area) -> O::Unit {
|
|
||||||
match self.0 {
|
|
||||||
NW | W | SW => to.x(),
|
|
||||||
N | Center | S => to.x().plus(to.w() / 2.into()).minus(self.1.w(to) / 2.into()),
|
|
||||||
NE | E | SE => to.x().plus(to.w()).minus(self.1.w(to)),
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn y (&self, to: O::Area) -> O::Unit {
|
|
||||||
match self.0 {
|
|
||||||
NW | N | NE => to.y(),
|
|
||||||
W | Center | E => to.y().plus(to.h() / 2.into()).minus(self.1.h(to) / 2.into()),
|
|
||||||
SW | S | SE => to.y().plus(to.h()).minus(self.1.h(to)),
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::bsp::*; mod bsp {
|
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
/// A binary split or layer.
|
|
||||||
pub struct Bsp<Head, Tail>(
|
|
||||||
pub(crate) Direction,
|
|
||||||
/// First element.
|
|
||||||
pub(crate) Head,
|
|
||||||
/// Second element.
|
|
||||||
pub(crate) Tail,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<Head, Tail> Bsp<Head, Tail> {
|
|
||||||
#[inline] pub const fn n (a: Head, b: Tail) -> Self { Self(North, a, b) }
|
|
||||||
#[inline] pub const fn s (a: Head, b: Tail) -> Self { Self(South, a, b) }
|
|
||||||
#[inline] pub const fn e (a: Head, b: Tail) -> Self { Self(East, a, b) }
|
|
||||||
#[inline] pub const fn w (a: Head, b: Tail) -> Self { Self(West, a, b) }
|
|
||||||
#[inline] pub const fn a (a: Head, b: Tail) -> Self { Self(Above, a, b) }
|
|
||||||
#[inline] pub const fn b (a: Head, b: Tail) -> Self { Self(Below, a, b) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: Out, Head: Content<O>, Tail: Content<O>> Draw<O> for Bsp<Head, Tail> {
|
|
||||||
fn draw (&self, to: &mut O) {
|
|
||||||
match self.0 {
|
|
||||||
South => {
|
|
||||||
//panic!("{}", self.1.h(to.area()));
|
|
||||||
let area_1 = self.1.layout(to.area());
|
|
||||||
let area_2 = self.2.layout([
|
|
||||||
to.area().x(),
|
|
||||||
to.area().y().plus(area_1.h()),
|
|
||||||
to.area().w(),
|
|
||||||
to.area().h().minus(area_1.h())
|
|
||||||
].into());
|
|
||||||
//panic!("{area_1:?} {area_2:?}");
|
|
||||||
to.place_at(area_1, &self.1);
|
|
||||||
to.place_at(area_2, &self.2);
|
|
||||||
},
|
|
||||||
_ => todo!("{:?}", self.0)
|
|
||||||
}
|
|
||||||
//let [a, b, _] = bsp_areas(to.area(), self.0, &self.1, &self.2);
|
|
||||||
//panic!("{a:?} {b:?}");
|
|
||||||
//if self.0 == Below {
|
|
||||||
//to.place_at(a, &self.1);
|
|
||||||
//to.place_at(b, &self.2);
|
|
||||||
//} else {
|
|
||||||
//to.place_at(b, &self.2);
|
|
||||||
//to.place_at(a, &self.1);
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<O: Out, Head: Layout<O>, Tail: Layout<O>> Layout<O> for Bsp<Head, Tail> {
|
|
||||||
fn w (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | North | South => self.1.w(area).max(self.2.w(area)), East | West => self.1.min_w(area).plus(self.2.w(area)), } }
|
|
||||||
fn min_w (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | North | South => self.1.min_w(area).max(self.2.min_w(area)), East | West => self.1.min_w(area).plus(self.2.min_w(area)), } }
|
|
||||||
fn max_w (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | North | South => self.1.max_w(area).max(self.2.max_w(area)), East | West => self.1.max_w(area).plus(self.2.max_w(area)), } }
|
|
||||||
fn h (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | East | West => self.1.h(area).max(self.2.h(area)), North | South => self.1.h(area).plus(self.2.h(area)), } }
|
|
||||||
fn min_h (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | East | West => self.1.min_h(area).max(self.2.min_h(area)), North | South => self.1.min_h(area).plus(self.2.min_h(area)), } }
|
|
||||||
fn max_h (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | North | South => self.1.max_h(area).max(self.2.max_h(area)), East | West => self.1.max_h(area).plus(self.2.max_h(area)), } }
|
|
||||||
fn layout (&self, area: O::Area) -> O::Area { bsp_areas(area, self.0, &self.1, &self.2)[2] }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bsp_areas <O: Out, A: Layout<O>, B: Layout<O>> (area: O::Area, direction: Direction, a: &A, b: &B,) -> [O::Area;3] {
|
|
||||||
let [x, y, w, h] = area.xywh();
|
|
||||||
let [aw, ah] = a.layout(area).wh();
|
|
||||||
let [bw, bh] = b.layout(match direction {
|
|
||||||
Above | Below => area,
|
|
||||||
South => [x, y + ah, w, h.minus(ah)].into(),
|
|
||||||
North => [x, y, w, h.minus(ah)].into(),
|
|
||||||
East => [x + aw, y, w.minus(aw), h].into(),
|
|
||||||
West => [x, y, w.minus(aw), h].into(),
|
|
||||||
}).wh();
|
|
||||||
match direction {
|
|
||||||
Above | Below => {
|
|
||||||
let [x, y, w, h] = area.center_xy([aw.max(bw), ah.max(bh)]);
|
|
||||||
let a = [(x + w/2.into()).minus(aw/2.into()), (y + h/2.into()).minus(ah/2.into()), aw, ah];
|
|
||||||
let b = [(x + w/2.into()).minus(bw/2.into()), (y + h/2.into()).minus(bh/2.into()), bw, bh];
|
|
||||||
[a.into(), b.into(), [x, y, w, h].into()]
|
|
||||||
},
|
|
||||||
South => {
|
|
||||||
let [x, y, w, h] = area.center_xy([aw.max(bw), ah + bh]);
|
|
||||||
let a = [(x + w/2.into()).minus(aw/2.into()), y, aw, ah];
|
|
||||||
let b = [(x + w/2.into()).minus(bw/2.into()), y + ah, bw, bh];
|
|
||||||
[a.into(), b.into(), [x, y, w, h].into()]
|
|
||||||
},
|
|
||||||
North => {
|
|
||||||
let [x, y, w, h] = area.center_xy([aw.max(bw), ah + bh]);
|
|
||||||
let a = [(x + (w/2.into())).minus(aw/2.into()), y + bh, aw, ah];
|
|
||||||
let b = [(x + (w/2.into())).minus(bw/2.into()), y, bw, bh];
|
|
||||||
[a.into(), b.into(), [x, y, w, h].into()]
|
|
||||||
},
|
|
||||||
East => {
|
|
||||||
let [x, y, w, h] = area.center_xy([aw + bw, ah.max(bh)]);
|
|
||||||
let a = [x, (y + h/2.into()).minus(ah/2.into()), aw, ah];
|
|
||||||
let b = [x + aw, (y + h/2.into()).minus(bh/2.into()), bw, bh];
|
|
||||||
[a.into(), b.into(), [x, y, w, h].into()]
|
|
||||||
},
|
|
||||||
West => {
|
|
||||||
let [x, y, w, h] = area.center_xy([aw + bw, ah.max(bh)]);
|
|
||||||
let a = [x + bw, (y + h/2.into()).minus(ah/2.into()), aw, ah];
|
|
||||||
let b = [x, (y + h/2.into()).minus(bh/2.into()), bw, bh];
|
|
||||||
[a.into(), b.into(), [x, y, w, h].into()]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,139 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
/// Draws items from an iterator.
|
|
||||||
pub struct Map<O, A, B, I, F, G>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = A> + Send + Sync,
|
|
||||||
F: Fn() -> I + Send + Sync,
|
|
||||||
{
|
|
||||||
__: PhantomData<(O, B)>,
|
|
||||||
/// Function that returns iterator over stacked components
|
|
||||||
get_iter: F,
|
|
||||||
/// Function that returns each stacked component
|
|
||||||
get_item: G,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, O, A, B, I, F, G> Map<O, A, B, I, F, G> where
|
|
||||||
I: Iterator<Item = A> + Send + Sync + 'a,
|
|
||||||
F: Fn() -> I + Send + Sync + 'a,
|
|
||||||
{
|
|
||||||
pub const fn new (get_iter: F, get_item: G) -> Self {
|
|
||||||
Self {
|
|
||||||
__: PhantomData,
|
|
||||||
get_iter,
|
|
||||||
get_item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_map_direction (($name:ident, $axis:ident, $align:ident)=>{
|
|
||||||
impl<'a, O, A, B, I, F> Map<
|
|
||||||
O, A, Push<O::Unit, Align<Fixed<O::Unit, Fill<B>>>>, I, F, fn(A, usize)->B
|
|
||||||
> where
|
|
||||||
O: Out,
|
|
||||||
B: Draw<O>,
|
|
||||||
I: Iterator<Item = A> + 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<O::Unit, Align<Fixed<O::Unit, B>>>,
|
|
||||||
I, F,
|
|
||||||
impl Fn(A, usize)->Push<O::Unit, Align<Fixed<O::Unit, B>>> + 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_map_direction!(east, X, w);
|
|
||||||
impl_map_direction!(south, Y, n);
|
|
||||||
impl_map_direction!(west, X, e);
|
|
||||||
impl_map_direction!(north, Y, s);
|
|
||||||
|
|
||||||
impl<'a, O, A, B, I, F, G> Layout<O> for Map<O, A, B, I, F, G> where
|
|
||||||
O: Out,
|
|
||||||
B: Layout<O>,
|
|
||||||
I: Iterator<Item = A> + Send + Sync + 'a,
|
|
||||||
F: Fn() -> I + Send + Sync + 'a,
|
|
||||||
G: Fn(A, usize)->B + Send + Sync
|
|
||||||
{
|
|
||||||
fn layout (&self, area: O::Area) -> O::Area {
|
|
||||||
let Self { get_iter, get_item, .. } = self;
|
|
||||||
let mut index = 0;
|
|
||||||
let [mut min_x, mut min_y] = area.center();
|
|
||||||
let [mut max_x, mut max_y] = area.center();
|
|
||||||
for item in get_iter() {
|
|
||||||
let [x,y,w,h] = get_item(item, index).layout(area).xywh();
|
|
||||||
min_x = min_x.min(x);
|
|
||||||
min_y = min_y.min(y);
|
|
||||||
max_x = max_x.max(x + w);
|
|
||||||
max_y = max_y.max(y + h);
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
let w = max_x - min_x;
|
|
||||||
let h = max_y - min_y;
|
|
||||||
//[min_x.into(), min_y.into(), w.into(), h.into()].into()
|
|
||||||
area.center_xy([w.into(), h.into()]).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a, O, A, B, I, F, G> Draw<O> for Map<O, A, B, I, F, G> where
|
|
||||||
O: Out,
|
|
||||||
B: Content<O>,
|
|
||||||
I: Iterator<Item = A> + Send + Sync + 'a,
|
|
||||||
F: Fn() -> I + Send + Sync + 'a,
|
|
||||||
G: Fn(A, usize)->B + Send + Sync
|
|
||||||
{
|
|
||||||
fn draw (&self, to: &mut O) {
|
|
||||||
let Self { get_iter, get_item, .. } = self;
|
|
||||||
let mut index = 0;
|
|
||||||
let area = self.layout(to.area());
|
|
||||||
for item in get_iter() {
|
|
||||||
let item = get_item(item, index);
|
|
||||||
//to.place_at(area.into(), &item);
|
|
||||||
to.place_at(item.layout(area), &item);
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline] pub fn map_south<O: Out>(
|
|
||||||
item_offset: O::Unit,
|
|
||||||
item_height: O::Unit,
|
|
||||||
item: impl Content<O>
|
|
||||||
) -> impl Content<O> {
|
|
||||||
Push::Y(item_offset, Fixed::Y(item_height, Fill::X(item)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline] pub fn map_south_west<O: Out>(
|
|
||||||
item_offset: O::Unit,
|
|
||||||
item_height: O::Unit,
|
|
||||||
item: impl Content<O>
|
|
||||||
) -> impl Content<O> {
|
|
||||||
Push::Y(item_offset, Align::nw(Fixed::Y(item_height, Fill::X(item))))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline] pub fn map_east<O: Out>(
|
|
||||||
item_offset: O::Unit,
|
|
||||||
item_width: O::Unit,
|
|
||||||
item: impl Content<O>
|
|
||||||
) -> impl Content<O> {
|
|
||||||
Push::X(item_offset, Align::w(Fixed::X(item_width, Fill::Y(item))))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
/// Increment X and/or Y coordinate.
|
|
||||||
pub enum Push<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
|
||||||
impl<U, A> Push<U, A> {
|
|
||||||
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, } }
|
|
||||||
}
|
|
||||||
impl<U: Coordinate, T> Push<U, T> {
|
|
||||||
#[inline] pub fn dx (&self) -> U { match self { Self::X(x, ..) | Self::XY(x, _, _) => *x, Self::Y(_, _) => 0.into() } }
|
|
||||||
#[inline] pub fn dy (&self) -> U { match self { Self::Y(y, ..) | Self::XY(_, y, _) => *y, Self::X(_, _) => 0.into() } }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Content<O>> Draw<O> for Push<O::Unit, T> {
|
|
||||||
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Layout<O>> Layout<O> for Push<O::Unit, T> {
|
|
||||||
fn x (&self, area: O::Area) -> O::Unit { area.x().plus(self.dx()) }
|
|
||||||
fn y (&self, area: O::Area) -> O::Unit { area.y().plus(self.dy()) }
|
|
||||||
}
|
|
||||||
/// Decrement X and/or Y coordinate.
|
|
||||||
pub enum Pull<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
|
||||||
impl<U, A> Pull<U, A> {
|
|
||||||
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, } }
|
|
||||||
}
|
|
||||||
impl<U: Coordinate, T> Pull<U, T> {
|
|
||||||
#[inline] pub fn dx (&self) -> U { match self { Self::X(x, ..) | Self::XY(x, _, _) => *x, Self::Y(_, _) => 0.into() } }
|
|
||||||
#[inline] pub fn dy (&self) -> U { match self { Self::Y(y, ..) | Self::XY(_, y, _) => *y, Self::X(_, _) => 0.into() } }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Content<O>> Draw<O> for Pull<O::Unit, T> {
|
|
||||||
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Layout<O>> Layout<O> for Pull<O::Unit, T> {
|
|
||||||
fn x (&self, area: O::Area) -> O::Unit { area.x().minus(self.dx()) }
|
|
||||||
fn y (&self, area: O::Area) -> O::Unit { area.y().minus(self.dy()) }
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
use Pad::*;
|
|
||||||
pub enum Pad<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
|
||||||
impl<U, A> Pad<U, A> {
|
|
||||||
#[inline] pub const fn inner (&self) -> &A { match self { X(_, c) | Y(_, c) | XY(_, _, c) => c, } }
|
|
||||||
}
|
|
||||||
impl<U: Coordinate, T> Pad<U, T> {
|
|
||||||
#[inline] pub fn dx (&self) -> U { match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, } }
|
|
||||||
#[inline] pub fn dy (&self) -> U { match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, } }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Content<O>> Draw<O> for Pad<O::Unit, T> {
|
|
||||||
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Layout<O>> Layout<O> for Pad<O::Unit, T> {
|
|
||||||
fn x (&self, area: O::Area) -> O::Unit {
|
|
||||||
area.x().plus(self.dx())
|
|
||||||
}
|
|
||||||
fn y (&self, area: O::Area) -> O::Unit {
|
|
||||||
area.x().plus(self.dx())
|
|
||||||
}
|
|
||||||
fn w (&self, area: O::Area) -> O::Unit {
|
|
||||||
area.w().minus(self.dx() * 2.into())
|
|
||||||
}
|
|
||||||
fn h (&self, area: O::Area) -> O::Unit {
|
|
||||||
area.h().minus(self.dy() * 2.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,121 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
pub enum Fill<A> { X(A), Y(A), XY(A) }
|
|
||||||
impl<A> Fill<A> {
|
|
||||||
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(c) | Self::Y(c) | Self::XY(c) => c } }
|
|
||||||
#[inline] pub const fn dx (&self) -> bool { match self { Self::X(_) | Self::XY(_) => true, _ => false } }
|
|
||||||
#[inline] pub const fn dy (&self) -> bool { match self { Self::Y(_) | Self::XY(_) => true, _ => false } }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Content<O>> Draw<O> for Fill<T> {
|
|
||||||
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Layout<O>> Layout<O> for Fill<T> {
|
|
||||||
fn x (&self, area: O::Area) -> O::Unit { if self.dx() { area.x() } else { self.inner().x(area) } }
|
|
||||||
fn y (&self, area: O::Area) -> O::Unit { if self.dy() { area.y() } else { self.inner().y(area) } }
|
|
||||||
fn w (&self, area: O::Area) -> O::Unit { if self.dx() { area.w() } else { self.inner().w(area) } }
|
|
||||||
fn min_w (&self, area: O::Area) -> O::Unit { if self.dx() { area.w() } else { self.inner().min_w(area) } }
|
|
||||||
fn max_w (&self, area: O::Area) -> O::Unit { if self.dx() { area.w() } else { self.inner().max_w(area) } }
|
|
||||||
fn h (&self, area: O::Area) -> O::Unit { if self.dy() { area.h() } else { self.inner().h(area) } }
|
|
||||||
fn min_h (&self, area: O::Area) -> O::Unit { if self.dy() { area.h() } else { self.inner().min_h(area) } }
|
|
||||||
fn max_h (&self, area: O::Area) -> O::Unit { if self.dy() { area.h() } else { self.inner().max_h(area) } }
|
|
||||||
}
|
|
||||||
/// Set fixed size for content.
|
|
||||||
pub enum Fixed<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
|
||||||
impl<U, A> Fixed<U, A> {
|
|
||||||
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } }
|
|
||||||
}
|
|
||||||
impl<U: Copy, A> Fixed<U, A> {
|
|
||||||
#[inline] pub const fn dx (&self) -> Option<U> { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } }
|
|
||||||
#[inline] pub const fn dy (&self) -> Option<U> { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Content<O>> Draw<O> for Fixed<O::Unit, T> {
|
|
||||||
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Layout<O>> Layout<O> for Fixed<O::Unit, T> {
|
|
||||||
fn w (&self, area: O::Area) -> O::Unit { self.dx().unwrap_or(self.inner().w(area)) }
|
|
||||||
fn min_w (&self, area: O::Area) -> O::Unit { self.dx().unwrap_or(self.inner().min_w(area)) }
|
|
||||||
fn max_w (&self, area: O::Area) -> O::Unit { self.dx().unwrap_or(self.inner().max_w(area)) }
|
|
||||||
fn h (&self, area: O::Area) -> O::Unit { self.dy().unwrap_or(self.inner().h(area)) }
|
|
||||||
fn min_h (&self, area: O::Area) -> O::Unit { self.dy().unwrap_or(self.inner().min_h(area)) }
|
|
||||||
fn max_h (&self, area: O::Area) -> O::Unit { self.dy().unwrap_or(self.inner().max_h(area)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Max<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
|
||||||
impl<U, A> Max<U, A> {
|
|
||||||
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } }
|
|
||||||
}
|
|
||||||
impl<U: Copy, A> Max<U, A> {
|
|
||||||
#[inline] pub const fn dx (&self) -> Option<U> { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } }
|
|
||||||
#[inline] pub const fn dy (&self) -> Option<U> { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Content<O>> Draw<O> for Max<O::Unit, T> {
|
|
||||||
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
|
|
||||||
}
|
|
||||||
impl<E: Out, T: Layout<E>> Layout<E> for Max<E::Unit, T> {
|
|
||||||
fn layout (&self, area: E::Area) -> E::Area {
|
|
||||||
let [x, y, w, h] = self.inner().layout(area).xywh();
|
|
||||||
match self {
|
|
||||||
Self::X(mw, _) => [x, y, w.min(*mw), h],
|
|
||||||
Self::Y(mh, _) => [x, y, w, h.min(*mh)],
|
|
||||||
Self::XY(mw, mh, _) => [x, y, w.min(*mw), h.min(*mh)],
|
|
||||||
}.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Min<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
|
||||||
impl<U, A> Min<U, A> {
|
|
||||||
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } }
|
|
||||||
}
|
|
||||||
impl<U: Copy, A> Min<U, A> {
|
|
||||||
#[inline] pub const fn dx (&self) -> Option<U> { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } }
|
|
||||||
#[inline] pub const fn dy (&self) -> Option<U> { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Content<O>> Draw<O> for Min<O::Unit, T> {
|
|
||||||
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
|
|
||||||
}
|
|
||||||
impl<E: Out, T: Layout<E>> Layout<E> for Min<E::Unit, T> {
|
|
||||||
fn layout (&self, area: E::Area) -> E::Area {
|
|
||||||
let [x, y, w, h] = self.inner().layout(area).xywh();
|
|
||||||
match self {
|
|
||||||
Self::X(mw, _) => [x, y, w.max(*mw), h],
|
|
||||||
Self::Y(mh, _) => [x, y, w, h.max(*mh)],
|
|
||||||
Self::XY(mw, mh, _) => [x, y, w.max(*mw), h.max(*mh)],
|
|
||||||
}.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Expand<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
|
||||||
impl<U, A> Expand<U, A> {
|
|
||||||
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } }
|
|
||||||
}
|
|
||||||
impl<U: Copy + Default, A> Expand<U, A> {
|
|
||||||
#[inline] pub const fn dx (&self) -> Option<U> { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } }
|
|
||||||
#[inline] pub const fn dy (&self) -> Option<U> { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Content<O>> Draw<O> for Expand<O::Unit, T> {
|
|
||||||
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Layout<O>> Layout<O> for Expand<O::Unit, T> {
|
|
||||||
fn w (&self, to: O::Area) -> O::Unit { self.inner().w(to).plus(self.dx().unwrap_or_default()) }
|
|
||||||
fn h (&self, to: O::Area) -> O::Unit { self.inner().w(to).plus(self.dy().unwrap_or_default()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Shrink<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
|
||||||
impl<U, A> Shrink<U, A> {
|
|
||||||
#[inline] pub const fn inner (&self) -> &A { match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c } }
|
|
||||||
}
|
|
||||||
impl<U: Copy, A> Shrink<U, A> {
|
|
||||||
#[inline] pub const fn dx (&self) -> Option<U> { match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None } }
|
|
||||||
#[inline] pub const fn dy (&self) -> Option<U> { match self { Self::Y(y, _) | Self::XY(y, ..) => Some(*y), _ => None } }
|
|
||||||
}
|
|
||||||
impl<O: Out, T: Content<O>> Draw<O> for Shrink<O::Unit, T> {
|
|
||||||
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
|
|
||||||
}
|
|
||||||
impl<E: Out, T: Layout<E>> Layout<E> for Shrink<E::Unit, T> {
|
|
||||||
fn layout (&self, to: E::Area) -> E::Area {
|
|
||||||
let area = self.inner().layout(to);
|
|
||||||
let dx = self.dx().unwrap_or_default();
|
|
||||||
let dy = self.dy().unwrap_or_default();
|
|
||||||
[area.x(), area.y(), area.w().minus(dx), area.h().minus(dy)].into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,170 +0,0 @@
|
||||||
//use crate::*;
|
|
||||||
//use Direction::*;
|
|
||||||
|
|
||||||
//pub struct Stack<'x, E, F1> {
|
|
||||||
//__: PhantomData<&'x (E, F1)>,
|
|
||||||
//direction: Direction,
|
|
||||||
//callback: F1
|
|
||||||
//}
|
|
||||||
|
|
||||||
//impl<'x, E, F1> Stack<'x, E, F1> {
|
|
||||||
//pub fn new (direction: Direction, callback: F1) -> Self {
|
|
||||||
//Self { direction, callback, __: Default::default(), }
|
|
||||||
//}
|
|
||||||
//pub fn above (callback: F1) -> Self {
|
|
||||||
//Self::new(Above, callback)
|
|
||||||
//}
|
|
||||||
//pub fn below (callback: F1) -> Self {
|
|
||||||
//Self::new(Below, callback)
|
|
||||||
//}
|
|
||||||
//pub fn north (callback: F1) -> Self {
|
|
||||||
//Self::new(North, callback)
|
|
||||||
//}
|
|
||||||
//pub fn south (callback: F1) -> Self {
|
|
||||||
//Self::new(South, callback)
|
|
||||||
//}
|
|
||||||
//pub fn east (callback: F1) -> Self {
|
|
||||||
//Self::new(East, callback)
|
|
||||||
//}
|
|
||||||
//pub fn west (callback: F1) -> Self {
|
|
||||||
//Self::new(West, callback)
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
|
|
||||||
//impl<'x, E: Out, F1: Fn(&mut dyn FnMut(&dyn Layout<E>))> Layout<E> for Stack<'x, E, F1> {
|
|
||||||
//fn layout (&self, to: E::Area) -> E::Area {
|
|
||||||
//let state = StackLayoutState::<E>::new(self.direction, to);
|
|
||||||
//(self.callback)(&mut |component: &dyn Layout<E>|{
|
|
||||||
//let StackLayoutState { x, y, w_remaining, h_remaining, .. } = *state.borrow();
|
|
||||||
//let [_, _, w, h] = component.layout([x, y, w_remaining, h_remaining].into()).xywh();
|
|
||||||
//state.borrow_mut().grow(w, h);
|
|
||||||
//});
|
|
||||||
//let StackLayoutState { w_used, h_used, .. } = *state.borrow();
|
|
||||||
//match self.direction {
|
|
||||||
//North | West => { todo!() },
|
|
||||||
//South | East => { [to.x(), to.y(), w_used, h_used].into() },
|
|
||||||
//_ => unreachable!(),
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//impl<'x, E: Out, F1: Fn(&mut dyn FnMut(&dyn Draw<E>))> Draw<E> for Stack<'x, E, F1> {
|
|
||||||
//fn draw (&self, to: &mut E) {
|
|
||||||
//let state = StackLayoutState::<E>::new(self.direction, to.area());
|
|
||||||
//let to = Rc::new(RefCell::new(to));
|
|
||||||
//(self.callback)(&mut |component: &dyn Draw<E>|{
|
|
||||||
//let StackLayoutState { x, y, w_remaining, h_remaining, .. } = *state.borrow();
|
|
||||||
//let layout = component.layout([x, y, w_remaining, h_remaining].into());
|
|
||||||
//state.borrow_mut().grow(layout.w(), layout.h());
|
|
||||||
//to.borrow_mut().place_at(layout, component);
|
|
||||||
//});
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
|
|
||||||
//#[derive(Copy, Clone)]
|
|
||||||
//struct StackLayoutState<E: Out> {
|
|
||||||
//direction: Direction,
|
|
||||||
//x: E::Unit,
|
|
||||||
//y: E::Unit,
|
|
||||||
//w_used: E::Unit,
|
|
||||||
//h_used: E::Unit,
|
|
||||||
//w_remaining: E::Unit,
|
|
||||||
//h_remaining: E::Unit,
|
|
||||||
//}
|
|
||||||
//impl<E: Out> StackLayoutState<E> {
|
|
||||||
//fn new (direction: Direction, area: E::Area) -> std::rc::Rc<std::cell::RefCell<Self>> {
|
|
||||||
//let [x, y, w_remaining, h_remaining] = area.xywh();
|
|
||||||
//std::rc::Rc::new(std::cell::RefCell::new(Self {
|
|
||||||
//direction,
|
|
||||||
//x, y, w_remaining, h_remaining,
|
|
||||||
//w_used: E::Unit::zero(), h_used: E::Unit::zero()
|
|
||||||
//}))
|
|
||||||
//}
|
|
||||||
//fn grow (&mut self, w: E::Unit, h: E::Unit) -> &mut Self {
|
|
||||||
//match self.direction {
|
|
||||||
//South => { self.y = self.y.plus(h);
|
|
||||||
//self.h_used = self.h_used.plus(h);
|
|
||||||
//self.h_remaining = self.h_remaining.minus(h);
|
|
||||||
//self.w_used = self.w_used.max(w); },
|
|
||||||
//East => { self.x = self.x.plus(w);
|
|
||||||
//self.w_used = self.w_used.plus(w);
|
|
||||||
//self.w_remaining = self.w_remaining.minus(w);
|
|
||||||
//self.h_used = self.h_used.max(h); },
|
|
||||||
//North | West => { todo!() },
|
|
||||||
//Above | Below => {},
|
|
||||||
//};
|
|
||||||
//self
|
|
||||||
//}
|
|
||||||
//fn area_remaining (&self) -> E::Area {
|
|
||||||
//[self.x, self.y, self.w_remaining, self.h_remaining].into()
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
|
|
||||||
////pub struct Stack<'a, E, F1> {
|
|
||||||
////__: PhantomData<&'a (E, F1)>,
|
|
||||||
////direction: Direction,
|
|
||||||
////callback: F1
|
|
||||||
////}
|
|
||||||
////impl<'a, E, F1> Stack<'a, E, F1> where
|
|
||||||
////E: Out, F1: Fn(&mut dyn FnMut(&'a dyn Draw<E>)) + Send + Sync,
|
|
||||||
////{
|
|
||||||
////pub fn north (callback: F1) -> Self { Self::new(North, callback) }
|
|
||||||
////pub fn south (callback: F1) -> Self { Self::new(South, callback) }
|
|
||||||
////pub fn east (callback: F1) -> Self { Self::new(East, callback) }
|
|
||||||
////pub fn west (callback: F1) -> Self { Self::new(West, callback) }
|
|
||||||
////pub fn above (callback: F1) -> Self { Self::new(Above, callback) }
|
|
||||||
////pub fn below (callback: F1) -> Self { Self::new(Below, callback) }
|
|
||||||
////pub fn new (direction: Direction, callback: F1) -> Self {
|
|
||||||
////Self { direction, callback, __: Default::default(), }
|
|
||||||
////}
|
|
||||||
////}
|
|
||||||
////impl<'a, E, F1> Draw<E> for Stack<'a, E, F1> where
|
|
||||||
////E: Out, F1: Fn(&mut dyn FnMut(&'a dyn Draw<E>)) + Send + Sync,
|
|
||||||
////{
|
|
||||||
////fn layout (&self, to: E::Area) -> E::Area {
|
|
||||||
////let state = StackLayoutState::<E>::new(self.direction, to);
|
|
||||||
////let mut adder = {
|
|
||||||
////let state = state.clone();
|
|
||||||
////move|component: &dyn Draw<E>|{
|
|
||||||
////let [w, h] = component.layout(state.borrow().area_remaining()).wh();
|
|
||||||
////state.borrow_mut().grow(w, h);
|
|
||||||
////}
|
|
||||||
////};
|
|
||||||
////(self.callback)(&mut adder);
|
|
||||||
////let StackLayoutState { w_used, h_used, .. } = *state.borrow();
|
|
||||||
////match self.direction {
|
|
||||||
////North | West => { todo!() },
|
|
||||||
////South | East => { [to.x(), to.y(), w_used, h_used].into() },
|
|
||||||
////Above | Below => { [to.x(), to.y(), to.w(), to.h()].into() },
|
|
||||||
////}
|
|
||||||
////}
|
|
||||||
////fn draw (&self, to: &mut E) {
|
|
||||||
////let state = StackLayoutState::<E>::new(self.direction, to.area());
|
|
||||||
////let mut adder = {
|
|
||||||
////let state = state.clone();
|
|
||||||
////move|component: &dyn Draw<E>|{
|
|
||||||
////let [x, y, w, h] = component.layout(state.borrow().area_remaining()).xywh();
|
|
||||||
////state.borrow_mut().grow(w, h);
|
|
||||||
////to.place_at([x, y, w, h].into(), component);
|
|
||||||
////}
|
|
||||||
////};
|
|
||||||
////(self.callback)(&mut adder);
|
|
||||||
////}
|
|
||||||
////}
|
|
||||||
|
|
||||||
//[>Stack::down(|add|{
|
|
||||||
//let mut i = 0;
|
|
||||||
//for (_, name) in self.dirs.iter() {
|
|
||||||
//if i >= self.scroll {
|
|
||||||
//add(&Tui::bold(i == self.index, name.as_str()))?;
|
|
||||||
//}
|
|
||||||
//i += 1;
|
|
||||||
//}
|
|
||||||
//for (_, name) in self.files.iter() {
|
|
||||||
//if i >= self.scroll {
|
|
||||||
//add(&Tui::bold(i == self.index, name.as_str()))?;
|
|
||||||
//}
|
|
||||||
//i += 1;
|
|
||||||
//}
|
|
||||||
//add(&format!("{}/{i}", self.index))?;
|
|
||||||
//Ok(())
|
|
||||||
//}));*/
|
|
||||||
|
|
@ -11,88 +11,145 @@
|
||||||
//#![feature(non_lifetime_binders)]
|
//#![feature(non_lifetime_binders)]
|
||||||
pub(crate) use self::Direction::*;
|
pub(crate) use self::Direction::*;
|
||||||
pub(crate) use std::fmt::{Debug, Display};
|
pub(crate) use std::fmt::{Debug, Display};
|
||||||
pub(crate) use std::marker::PhantomData;
|
|
||||||
pub(crate) use std::ops::{Add, Sub, Mul, Div};
|
pub(crate) use std::ops::{Add, Sub, Mul, Div};
|
||||||
pub(crate) use std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::Relaxed}};
|
pub(crate) use std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::Relaxed}};
|
||||||
|
pub(crate) use std::marker::PhantomData;
|
||||||
pub(crate) use dizzle::*;
|
pub(crate) use dizzle::*;
|
||||||
mod output; pub use self::output::*;
|
|
||||||
mod content; pub use self::content::*;
|
mod out_macros; // Must be defined first
|
||||||
mod draw; pub use self::draw::*;
|
mod out_traits; pub use self::out_traits::*;
|
||||||
mod group; pub use self::group::*;
|
mod out_structs; pub use self::out_structs::*;
|
||||||
mod layout; pub use self::layout::*;
|
mod out_impls; pub use self::out_impls::*;
|
||||||
mod space; pub use self::space::*;
|
|
||||||
mod thunk; pub use self::thunk::*;
|
mod widget; pub use self::widget::*;
|
||||||
mod widget; pub use self::widget::*;
|
mod layout; pub use self::layout::*;
|
||||||
#[cfg(feature = "dsl")] mod view;
|
|
||||||
#[cfg(feature = "dsl")] pub use self::view::*;
|
#[cfg(test)] mod out_tests;
|
||||||
#[cfg(test)] pub(crate) use proptest_derive::Arbitrary;
|
|
||||||
#[cfg(test)] mod test {
|
#[cfg(feature = "dsl")]
|
||||||
use crate::{*, Direction::*};
|
pub fn evaluate_output_expression <'a, O: Out + 'a, S> (
|
||||||
//use proptest_derive::Arbitrary;
|
state: &S, output: &mut O, expr: &'a impl Expression
|
||||||
use proptest::{prelude::*, option::of};
|
) -> Usually<bool> where
|
||||||
macro_rules! test_op_transform {
|
S: View<O, ()>
|
||||||
($fn:ident, $Op:ident) => {
|
+ for<'b>Namespace<'b, bool>
|
||||||
proptest! {
|
+ for<'b>Namespace<'b, O::Unit>
|
||||||
#[test] fn $fn (
|
{
|
||||||
op_x in of(u16::MIN..u16::MAX),
|
// First element of expression is used for dispatch.
|
||||||
op_y in of(u16::MIN..u16::MAX),
|
// Dispatch is proto-namespaced using separator character
|
||||||
content in "\\PC*",
|
let head = expr.head()?;
|
||||||
x in u16::MIN..u16::MAX,
|
let mut frags = head.src()?.unwrap_or_default().split("/");
|
||||||
y in u16::MIN..u16::MAX,
|
// The rest of the tokens in the expr are arguments.
|
||||||
w in u16::MIN..u16::MAX,
|
// Their meanings depend on the dispatched operation
|
||||||
h in u16::MIN..u16::MAX,
|
let args = expr.tail();
|
||||||
) {
|
let arg0 = args.head();
|
||||||
if let Some(op) = match (op_x, op_y) {
|
let tail0 = args.tail();
|
||||||
(Some(x), Some(y)) => Some($Op::XY(x, y, content)),
|
let arg1 = tail0.head();
|
||||||
(Some(x), None) => Some($Op::X(x, content)),
|
let tail1 = tail0.tail();
|
||||||
(None, Some(y)) => Some($Op::Y(y, content)),
|
let arg2 = tail1.head();
|
||||||
_ => None
|
// And we also have to do the above binding dance
|
||||||
} {
|
// so that the Perhaps<token>s remain in scope.
|
||||||
//assert_eq!(Content::layout(&op, [x, y, w, h]),
|
match frags.next() {
|
||||||
//Draw::layout(&op, [x, y, w, h]));
|
|
||||||
}
|
Some("when") => output.place(&When::new(
|
||||||
}
|
state.resolve(arg0?)?.unwrap(),
|
||||||
|
Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap())
|
||||||
|
)),
|
||||||
|
|
||||||
|
Some("either") => output.place(&Either::new(
|
||||||
|
state.resolve(arg0?)?.unwrap(),
|
||||||
|
Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap()),
|
||||||
|
Thunk::new(move|output: &mut O|state.view(output, &arg2).unwrap())
|
||||||
|
)),
|
||||||
|
|
||||||
|
Some("bsp") => output.place(&{
|
||||||
|
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
|
||||||
|
let b = Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap());
|
||||||
|
match frags.next() {
|
||||||
|
Some("n") => Bsp::n(a, b),
|
||||||
|
Some("s") => Bsp::s(a, b),
|
||||||
|
Some("e") => Bsp::e(a, b),
|
||||||
|
Some("w") => Bsp::w(a, b),
|
||||||
|
Some("a") => Bsp::a(a, b),
|
||||||
|
Some("b") => Bsp::b(a, b),
|
||||||
|
frag => unimplemented!("bsp/{frag:?}")
|
||||||
}
|
}
|
||||||
}
|
}),
|
||||||
}
|
|
||||||
test_op_transform!(proptest_op_fixed, Fixed);
|
|
||||||
test_op_transform!(proptest_op_min, Min);
|
|
||||||
test_op_transform!(proptest_op_max, Max);
|
|
||||||
test_op_transform!(proptest_op_push, Push);
|
|
||||||
test_op_transform!(proptest_op_pull, Pull);
|
|
||||||
test_op_transform!(proptest_op_shrink, Shrink);
|
|
||||||
test_op_transform!(proptest_op_expand, Expand);
|
|
||||||
test_op_transform!(proptest_op_padding, Pad);
|
|
||||||
|
|
||||||
proptest! {
|
Some("align") => output.place(&{
|
||||||
#[test] fn proptest_op_bsp (
|
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
|
||||||
d in prop_oneof![
|
match frags.next() {
|
||||||
Just(North), Just(South),
|
Some("n") => Align::n(a),
|
||||||
Just(East), Just(West),
|
Some("s") => Align::s(a),
|
||||||
Just(Above), Just(Below)
|
Some("e") => Align::e(a),
|
||||||
],
|
Some("w") => Align::w(a),
|
||||||
a in "\\PC*",
|
Some("x") => Align::x(a),
|
||||||
b in "\\PC*",
|
Some("y") => Align::y(a),
|
||||||
x in u16::MIN..u16::MAX,
|
Some("c") => Align::c(a),
|
||||||
y in u16::MIN..u16::MAX,
|
frag => unimplemented!("align/{frag:?}")
|
||||||
w in u16::MIN..u16::MAX,
|
}
|
||||||
h in u16::MIN..u16::MAX,
|
}),
|
||||||
) {
|
|
||||||
let bsp = Bsp(d, a, b);
|
|
||||||
//assert_eq!(
|
|
||||||
//Content::layout(&bsp, [x, y, w, h]),
|
|
||||||
//Draw::layout(&bsp, [x, y, w, h]),
|
|
||||||
//);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//#[test] fn test_iter_map () {
|
Some("fill") => output.place(&{
|
||||||
//struct Foo;
|
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
|
||||||
//impl<T: Out> Content<T> for Foo {}
|
match frags.next() {
|
||||||
//fn _make_map <T: Out, U: Content<T> + Send + Sync> (data: &Vec<U>) -> impl Draw<T> {
|
Some("xy") | None => Fill::XY(a),
|
||||||
//Map::new(||data.iter(), |_foo, _index|{})
|
Some("x") => Fill::X(a),
|
||||||
//}
|
Some("y") => Fill::Y(a),
|
||||||
//let _data = vec![Foo, Foo, Foo];
|
frag => unimplemented!("fill/{frag:?}")
|
||||||
////let map = make_map(&data);
|
}
|
||||||
//}
|
}),
|
||||||
|
|
||||||
|
Some("fixed") => output.place(&{
|
||||||
|
let axis = frags.next();
|
||||||
|
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
|
||||||
|
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
|
||||||
|
match axis {
|
||||||
|
Some("xy") | None => Fixed::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb),
|
||||||
|
Some("x") => Fixed::X(state.resolve(arg0?)?.unwrap(), cb),
|
||||||
|
Some("y") => Fixed::Y(state.resolve(arg0?)?.unwrap(), cb),
|
||||||
|
frag => unimplemented!("fixed/{frag:?} ({expr:?}) ({head:?}) ({:?})",
|
||||||
|
head.src()?.unwrap_or_default().split("/").next())
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
Some("min") => output.place(&{
|
||||||
|
let axis = frags.next();
|
||||||
|
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
|
||||||
|
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
|
||||||
|
match axis {
|
||||||
|
Some("xy") | None => Min::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb),
|
||||||
|
Some("x") => Min::X(state.resolve(arg0?)?.unwrap(), cb),
|
||||||
|
Some("y") => Min::Y(state.resolve(arg0?)?.unwrap(), cb),
|
||||||
|
frag => unimplemented!("min/{frag:?}")
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
Some("max") => output.place(&{
|
||||||
|
let axis = frags.next();
|
||||||
|
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
|
||||||
|
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
|
||||||
|
match axis {
|
||||||
|
Some("xy") | None => Max::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb),
|
||||||
|
Some("x") => Max::X(state.resolve(arg0?)?.unwrap(), cb),
|
||||||
|
Some("y") => Max::Y(state.resolve(arg0?)?.unwrap(), cb),
|
||||||
|
frag => unimplemented!("max/{frag:?}")
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
Some("push") => output.place(&{
|
||||||
|
let axis = frags.next();
|
||||||
|
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
|
||||||
|
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
|
||||||
|
match axis {
|
||||||
|
Some("xy") | None => Push::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb),
|
||||||
|
Some("x") => Push::X(state.resolve(arg0?)?.unwrap(), cb),
|
||||||
|
Some("y") => Push::Y(state.resolve(arg0?)?.unwrap(), cb),
|
||||||
|
frag => unimplemented!("push/{frag:?}")
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
_ => return Ok(false)
|
||||||
|
|
||||||
|
};
|
||||||
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
790
output/src/out_impls.rs
Normal file
790
output/src/out_impls.rs
Normal file
|
|
@ -0,0 +1,790 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
impl Coord for u16 {
|
||||||
|
fn plus (self, other: Self) -> Self { self.saturating_add(other) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coord> HasXY<N> for XY<N> {
|
||||||
|
fn x (&self) -> N { self.0 }
|
||||||
|
fn y (&self) -> N { self.1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coord> HasWH<N> for WH<N> {
|
||||||
|
fn w (&self) -> N { self.0 }
|
||||||
|
fn h (&self) -> N { self.1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coord> WH<N> {
|
||||||
|
fn clip_w (&self, w: N) -> [N;2] { [self.w().min(w), self.h()] }
|
||||||
|
fn clip_h (&self, h: N) -> [N;2] { [self.w(), self.h().min(h)] }
|
||||||
|
fn to_area_pos (&self) -> [N;4] { let [x, y] = self.wh(); [x, y, 0.into(), 0.into()] }
|
||||||
|
fn to_area_size (&self) -> [N;4] { let [w, h] = self.wh(); [0.into(), 0.into(), w, h] }
|
||||||
|
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<N: Coord> XYWH<N> {
|
||||||
|
fn from_position (pos: impl Size<N>) -> Self {
|
||||||
|
let [x, y] = pos.wh();
|
||||||
|
[x, y, 0.into(), 0.into()]
|
||||||
|
}
|
||||||
|
fn from_size (size: impl Size<N>) -> Self {
|
||||||
|
let [w, h] = size.wh();
|
||||||
|
[0.into(), 0.into(), w, h]
|
||||||
|
}
|
||||||
|
fn lrtb (&self) -> [N;4] {
|
||||||
|
[self.x(), self.x2(), self.y(), self.y2()]
|
||||||
|
}
|
||||||
|
fn center (&self) -> XY<N> {
|
||||||
|
[self.x().plus(self.w()/2.into()), self.y().plus(self.h()/2.into())]
|
||||||
|
}
|
||||||
|
fn centered (&self) -> XY<N> {
|
||||||
|
[self.x().minus(self.w()/2.into()), self.y().minus(self.h()/2.into())]
|
||||||
|
}
|
||||||
|
fn centered_x (&self, n: N) -> XYWH<N> {
|
||||||
|
let [x, y, w, h] = self.xywh();
|
||||||
|
[(x.plus(w / 2.into())).minus(n / 2.into()), y.plus(h / 2.into()), n, 1.into()]
|
||||||
|
}
|
||||||
|
fn centered_y (&self, n: N) -> XYWH<N> {
|
||||||
|
let [x, y, w, h] = self.xywh();
|
||||||
|
[x.plus(w / 2.into()), (y.plus(h / 2.into())).minus(n / 2.into()), 1.into(), n]
|
||||||
|
}
|
||||||
|
fn centered_xy (&self, [n, m]: [N;2]) -> XYWH<N> {
|
||||||
|
let [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]
|
||||||
|
}
|
||||||
|
fn iter_x (&self) -> impl Iterator<Item = N> where N: std::iter::Step {
|
||||||
|
self.x()..(self.x()+self.w())
|
||||||
|
}
|
||||||
|
fn iter_y (&self) -> impl Iterator<Item = N> where N: std::iter::Step {
|
||||||
|
self.y()..(self.y()+self.h())
|
||||||
|
}
|
||||||
|
fn clipped (&self, wh: impl Size<N>) -> XYWH<N> {
|
||||||
|
[self.x(), self.y(), wh.w(), wh.h()]
|
||||||
|
}
|
||||||
|
fn clipped_h (&self, h: N) -> XYWH<N> {
|
||||||
|
[self.x(), self.y(), self.w(), self.h().min(h)]
|
||||||
|
}
|
||||||
|
fn clipped_w (&self, w: N) -> XYWH<N> {
|
||||||
|
[self.x(), self.y(), self.w().min(w), self.h()]
|
||||||
|
}
|
||||||
|
fn with_w (&self, w: N) -> XYWH<N> {
|
||||||
|
[self.x(), self.y(), w, self.h()]
|
||||||
|
}
|
||||||
|
fn with_h (&self, h: N) -> XYWH<N> {
|
||||||
|
[self.x(), self.y(), self.w(), h]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coord> HasXY<N> for XYWH<N> {
|
||||||
|
fn x (&self) -> N { self.0 }
|
||||||
|
fn y (&self) -> N { self.1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coord> HasWH<N> for XYWH<N> {
|
||||||
|
fn w (&self) -> N { self.2 }
|
||||||
|
fn h (&self) -> N { self.3 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out> super::ng::HasXY<O::Unit> 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<O: Out> super::ng::HasWH<O::Unit> 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<O: Out, T: Draw<O> + Layout<O>> Content<O> for T {}
|
||||||
|
|
||||||
|
impl<'a, O: Out> AsRef<dyn Draw<O> + 'a> for dyn Content<O> + 'a {
|
||||||
|
fn as_ref (&self) -> &(dyn Draw<O> + 'a) { self }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, O: Out> AsRef<dyn Layout<O> + 'a> for dyn Content<O> + 'a {
|
||||||
|
fn as_ref (&self) -> &(dyn Layout<O> + 'a) { self }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HasContent<O: Out> {
|
||||||
|
fn content (&self) -> impl Content<O>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out> Draw<O> for () {
|
||||||
|
fn draw (&self, _: &mut O) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out> Draw<O> for fn(&mut O) {
|
||||||
|
fn draw (&self, to: &mut O) { (*self)(to) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out> Draw<O> for Box<dyn Draw<O>> {
|
||||||
|
fn draw (&self, to: &mut O) { (**self).draw(to) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, D: Draw<O>> Draw<O> for &D {
|
||||||
|
fn draw (&self, to: &mut O) { (*self).draw(to) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, D: Draw<O>> Draw<O> for &mut D {
|
||||||
|
fn draw (&self, to: &mut O) { (**self).draw(to) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, D: Draw<O>> Draw<O> for Arc<D> {
|
||||||
|
fn draw (&self, to: &mut O) { (**self).draw(to) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, D: Draw<O>> Draw<O> for RwLock<D> {
|
||||||
|
fn draw (&self, to: &mut O) { self.read().unwrap().draw(to) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, D: Draw<O>> Draw<O> for Option<D> {
|
||||||
|
fn draw (&self, to: &mut O) { if let Some(draw) = self { draw.draw(to) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
//impl<O: Out, T: HasContent<O>> Draw<O> 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<O: Out, T: Content<O>, F: Fn()->T> Lazy<O, T, F> {
|
||||||
|
pub const fn new (thunk: F) -> Self {
|
||||||
|
Self(thunk, PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, F: Fn(&mut O)> Thunk<O, F> {
|
||||||
|
pub const fn new (draw: F) -> Self {
|
||||||
|
Self(PhantomData, draw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, F: Fn(&mut O)> Layout<O> for Thunk<O, F> {}
|
||||||
|
|
||||||
|
impl<O: Out, F: Fn(&mut O)> Draw<O> for Thunk<O, F> {
|
||||||
|
fn draw (&self, to: &mut O) {
|
||||||
|
(self.1)(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq, U> Memo<T, U> {
|
||||||
|
pub fn new (value: T, view: U) -> Self { Self { value, view: Arc::new(view.into()) } }
|
||||||
|
pub fn update <R> (&mut self, newval: T, draw: impl Fn(&mut U, &T, &T)->R) -> Option<R> {
|
||||||
|
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 <N: Coord> (self, area: impl Area<N>, a: N) -> ([N;4],[N;4]) {
|
||||||
|
let [x, y, w, h] = area.xywh();
|
||||||
|
match self {
|
||||||
|
North => ([x, y.plus(h).minus(a), w, a], [x, y, w, h.minus(a)]),
|
||||||
|
South => ([x, y, w, a], [x, y.plus(a), w, h.minus(a)]),
|
||||||
|
East => ([x, y, a, h], [x.plus(a), y, w.minus(a), h]),
|
||||||
|
West => ([x.plus(w).minus(a), y, a, h], [x, y, w.minus(a), h]),
|
||||||
|
Above | Below => (area.xywh(), area.xywh())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coord> Size<N> for (N, N) {
|
||||||
|
fn x (&self) -> N { self.0 }
|
||||||
|
fn y (&self) -> N { self.1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Coord> Size<N> for [N;2] {
|
||||||
|
fn x (&self) -> N { self[0] }
|
||||||
|
fn y (&self) -> N { self[1] }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Out, T: Has<Measure<E>>> HasSize<E> for T {
|
||||||
|
fn size (&self) -> &Measure<E> {
|
||||||
|
self.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out> Clone for Measure<O> {
|
||||||
|
fn clone (&self) -> Self {
|
||||||
|
Self { __: Default::default(), x: self.x.clone(), y: self.y.clone(), }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out> Layout<O> for Measure<O> {}
|
||||||
|
|
||||||
|
impl<O: Out> PartialEq for Measure<O> {
|
||||||
|
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<O: Out> Draw<O> for Measure<O> {
|
||||||
|
fn draw (&self, to: &mut O) {
|
||||||
|
self.x.store(to.area().w().into(), Relaxed);
|
||||||
|
self.y.store(to.area().h().into(), Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out> Debug for Measure<O> {
|
||||||
|
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<O: Out> Measure<O> {
|
||||||
|
pub fn set_w (&self, w: impl Into<usize>) -> &Self { self.x.store(w.into(), Relaxed); self }
|
||||||
|
pub fn set_h (&self, h: impl Into<usize>) -> &Self { self.y.store(h.into(), Relaxed); self }
|
||||||
|
pub fn set_wh (&self, w: impl Into<usize>, h: impl Into<usize>) -> &Self { self.set_w(w); self.set_h(h); self }
|
||||||
|
pub fn format (&self) -> Arc<str> { format!("{}x{}", self.w(), self.h()).into() }
|
||||||
|
pub fn of <T: Draw<O>> (&self, item: T) -> Bsp<Fill<&Self>, T> { Bsp::b(Fill::XY(self), item) }
|
||||||
|
pub fn new (x: O::Unit, y: O::Unit) -> Self {
|
||||||
|
Self { __: PhantomData::default(), x: Arc::new(x.into()), y: Arc::new(y.into()), }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out> From<[O::Unit; 2]> for Measure<O> {
|
||||||
|
fn from ([x, y]: [O::Unit; 2]) -> Self { Self::new(x, y) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out> Layout<O> for () {
|
||||||
|
fn x (&self, a: O::Area) -> O::Unit { a.x() }
|
||||||
|
fn y (&self, a: O::Area) -> O::Unit { a.y() }
|
||||||
|
fn w (&self, _: O::Area) -> O::Unit { 0.into() }
|
||||||
|
fn w_min (&self, _: O::Area) -> O::Unit { 0.into() }
|
||||||
|
fn w_max (&self, _: O::Area) -> O::Unit { 0.into() }
|
||||||
|
fn h (&self, _: O::Area) -> O::Unit { 0.into() }
|
||||||
|
fn h_min (&self, _: O::Area) -> O::Unit { 0.into() }
|
||||||
|
fn h_max (&self, _: O::Area) -> O::Unit { 0.into() }
|
||||||
|
fn layout (&self, a: O::Area) -> O::Area { [a.x(), a.y(), 0.into(), 0.into()].into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, L: Layout<O>> Layout<O> for &L {
|
||||||
|
fn x (&self, a: O::Area) -> O::Unit { (*self).x(a) }
|
||||||
|
fn y (&self, a: O::Area) -> O::Unit { (*self).y(a) }
|
||||||
|
fn w (&self, a: O::Area) -> O::Unit { (*self).w(a) }
|
||||||
|
fn w_min (&self, a: O::Area) -> O::Unit { (*self).w_min(a) }
|
||||||
|
fn w_max (&self, a: O::Area) -> O::Unit { (*self).w_max(a) }
|
||||||
|
fn h (&self, a: O::Area) -> O::Unit { (*self).h(a) }
|
||||||
|
fn h_min (&self, a: O::Area) -> O::Unit { (*self).h_min(a) }
|
||||||
|
fn h_max (&self, a: O::Area) -> O::Unit { (*self).h_max(a) }
|
||||||
|
fn layout (&self, a: O::Area) -> O::Area { (*self).layout(a) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, L: Layout<O>> Layout<O> for &mut L {
|
||||||
|
fn x (&self, a: O::Area) -> O::Unit { (**self).x(a) }
|
||||||
|
fn y (&self, a: O::Area) -> O::Unit { (**self).y(a) }
|
||||||
|
fn w (&self, a: O::Area) -> O::Unit { (**self).w(a) }
|
||||||
|
fn w_min (&self, a: O::Area) -> O::Unit { (**self).w_min(a) }
|
||||||
|
fn w_max (&self, a: O::Area) -> O::Unit { (**self).w_max(a) }
|
||||||
|
fn h (&self, a: O::Area) -> O::Unit { (**self).h(a) }
|
||||||
|
fn h_min (&self, a: O::Area) -> O::Unit { (**self).h_min(a) }
|
||||||
|
fn h_max (&self, a: O::Area) -> O::Unit { (**self).h_max(a) }
|
||||||
|
fn layout (&self, a: O::Area) -> O::Area { (**self).layout(a) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, L: Layout<O>> Layout<O> for Arc<L> {
|
||||||
|
fn x (&self, a: O::Area) -> O::Unit { (**self).x(a) }
|
||||||
|
fn y (&self, a: O::Area) -> O::Unit { (**self).y(a) }
|
||||||
|
fn w (&self, a: O::Area) -> O::Unit { (**self).w(a) }
|
||||||
|
fn w_min (&self, a: O::Area) -> O::Unit { (**self).w_min(a) }
|
||||||
|
fn w_max (&self, a: O::Area) -> O::Unit { (**self).w_max(a) }
|
||||||
|
fn h (&self, a: O::Area) -> O::Unit { (**self).h(a) }
|
||||||
|
fn h_min (&self, a: O::Area) -> O::Unit { (**self).h_min(a) }
|
||||||
|
fn h_max (&self, a: O::Area) -> O::Unit { (**self).h_max(a) }
|
||||||
|
fn layout (&self, a: O::Area) -> O::Area { (**self).layout(a) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out> Layout<O> for Box<dyn Layout<O>> {
|
||||||
|
fn x (&self, a: O::Area) -> O::Unit { (**self).x(a) }
|
||||||
|
fn y (&self, a: O::Area) -> O::Unit { (**self).y(a) }
|
||||||
|
fn w (&self, a: O::Area) -> O::Unit { (**self).w(a) }
|
||||||
|
fn w_min (&self, a: O::Area) -> O::Unit { (**self).w_min(a) }
|
||||||
|
fn w_max (&self, a: O::Area) -> O::Unit { (**self).w_max(a) }
|
||||||
|
fn h (&self, a: O::Area) -> O::Unit { (**self).h(a) }
|
||||||
|
fn h_min (&self, a: O::Area) -> O::Unit { (**self).h_min(a) }
|
||||||
|
fn h_max (&self, a: O::Area) -> O::Unit { (**self).h_max(a) }
|
||||||
|
fn layout (&self, a: O::Area) -> O::Area { (**self).layout(a) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, L: Layout<O>> Layout<O> for RwLock<L> {
|
||||||
|
fn x (&self, a: O::Area) -> O::Unit { self.read().unwrap().x(a) }
|
||||||
|
fn y (&self, a: O::Area) -> O::Unit { self.read().unwrap().y(a) }
|
||||||
|
fn w (&self, a: O::Area) -> O::Unit { self.read().unwrap().w(a) }
|
||||||
|
fn w_min (&self, a: O::Area) -> O::Unit { self.read().unwrap().w_min(a) }
|
||||||
|
fn w_max (&self, a: O::Area) -> O::Unit { self.read().unwrap().w_max(a) }
|
||||||
|
fn h (&self, a: O::Area) -> O::Unit { self.read().unwrap().h(a) }
|
||||||
|
fn h_min (&self, a: O::Area) -> O::Unit { self.read().unwrap().h_min(a) }
|
||||||
|
fn h_max (&self, a: O::Area) -> O::Unit { self.read().unwrap().h_max(a) }
|
||||||
|
fn layout (&self, a: O::Area) -> O::Area { self.read().unwrap().layout(a) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, L: Layout<O>> Layout<O> for Option<L> {
|
||||||
|
fn x (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.x(to)).unwrap_or(to.x()) }
|
||||||
|
fn y (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.y(to)).unwrap_or(to.y()) }
|
||||||
|
fn w_min (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.w_min(to)).unwrap_or(0.into()) }
|
||||||
|
fn w_max (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.w_max(to)).unwrap_or(0.into()) }
|
||||||
|
fn w (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.w(to)).unwrap_or(0.into()) }
|
||||||
|
fn h_min (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.h_min(to)).unwrap_or(0.into()) }
|
||||||
|
fn h_max (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.h_max(to)).unwrap_or(0.into()) }
|
||||||
|
fn h (&self, to: O::Area) -> O::Unit { self.as_ref().map(|c|c.h(to)).unwrap_or(0.into()) }
|
||||||
|
fn layout (&self, to: O::Area) -> O::Area { self.as_ref().map(|c|c.layout([self.x(to), self.y(to), self.w(to), self.h(to)].into()))
|
||||||
|
.unwrap_or([to.x(), to.y(), 0.into(), 0.into()].into()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, D: Content<O>> HasContent<O> for Bounded<O, D> {
|
||||||
|
fn content (&self) -> impl Content<O> {
|
||||||
|
&self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, T: Draw<O>> Draw<O> for Bounded<O, T> {
|
||||||
|
fn draw (&self, to: &mut O) {
|
||||||
|
let area = to.area();
|
||||||
|
*to.area_mut() = self.0;
|
||||||
|
self.1.draw(to);
|
||||||
|
*to.area_mut() = area;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, T: Content<O>> When<O, T> {
|
||||||
|
/// Create a binary condition.
|
||||||
|
pub const fn new (c: bool, a: T) -> Self { Self(c, a, PhantomData) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, T: Layout<O>> Layout<O> for When<O, T> {
|
||||||
|
fn layout (&self, to: O::Area) -> O::Area {
|
||||||
|
let Self(cond, item, ..) = self;
|
||||||
|
if *cond { item.layout(to) } else { O::Area::zero().into() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, T: Content<O>> Draw<O> for When<O, T> {
|
||||||
|
fn draw (&self, to: &mut O) {
|
||||||
|
let Self(cond, item, ..) = self;
|
||||||
|
if *cond { Bounded(self.layout(to.area()), item).draw(to) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Out, A: Content<E>, B: Content<E>> Either<E, A, B> {
|
||||||
|
/// Create a ternary view condition.
|
||||||
|
pub const fn new (c: bool, a: A, b: B) -> Self {
|
||||||
|
Self(c, a, b, PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Out, A: Layout<E>, B: Layout<E>> Layout<E> for Either<E, A, B> {
|
||||||
|
fn layout (&self, to: E::Area) -> E::Area {
|
||||||
|
let Self(cond, a, b, ..) = self;
|
||||||
|
if *cond { a.layout(to) } else { b.layout(to) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Out, A: Content<E>, B: Content<E>> Draw<E> for Either<E, A, B> {
|
||||||
|
fn draw (&self, to: &mut E) {
|
||||||
|
let Self(cond, a, b, ..) = self;
|
||||||
|
let area = self.layout(to.area());
|
||||||
|
if *cond { Bounded(area, a).draw(to) } else { Bounded(area, b).draw(to) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push_pull!(Push: plus);
|
||||||
|
|
||||||
|
push_pull!(Pull: minus);
|
||||||
|
|
||||||
|
layout_op_xy!(0: Fill);
|
||||||
|
impl<O: Out, T: Layout<O>> Layout<O> for Fill<T> {
|
||||||
|
fn x (&self, area: O::Area) -> O::Unit { if self.dx() { area.x() } else { self.inner().x(area) } }
|
||||||
|
fn y (&self, area: O::Area) -> O::Unit { if self.dy() { area.y() } else { self.inner().y(area) } }
|
||||||
|
fn w (&self, area: O::Area) -> O::Unit { if self.dx() { area.w() } else { self.inner().w(area) } }
|
||||||
|
fn w_min (&self, area: O::Area) -> O::Unit { if self.dx() { area.w() } else { self.inner().w_min(area) } }
|
||||||
|
fn w_max (&self, area: O::Area) -> O::Unit { if self.dx() { area.w() } else { self.inner().w_max(area) } }
|
||||||
|
fn h (&self, area: O::Area) -> O::Unit { if self.dy() { area.h() } else { self.inner().h(area) } }
|
||||||
|
fn h_min (&self, area: O::Area) -> O::Unit { if self.dy() { area.h() } else { self.inner().h_min(area) } }
|
||||||
|
fn h_max (&self, area: O::Area) -> O::Unit { if self.dy() { area.h() } else { self.inner().h_max(area) } }
|
||||||
|
}
|
||||||
|
impl<A> Fill<A> {
|
||||||
|
#[inline] pub const fn dx (&self) -> bool { matches!(self, Self::X(_) | Self::XY(_)) }
|
||||||
|
#[inline] pub const fn dy (&self) -> bool { matches!(self, Self::Y(_) | Self::XY(_)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
layout_op_xy!(1 opt: Fixed);
|
||||||
|
impl<O: Out, T: Layout<O>> Layout<O> for Fixed<O::Unit, T> {
|
||||||
|
fn w (&self, area: O::Area) -> O::Unit { self.dx().unwrap_or(self.inner().w(area)) }
|
||||||
|
fn w_min (&self, area: O::Area) -> O::Unit { self.dx().unwrap_or(self.inner().w_min(area)) }
|
||||||
|
fn w_max (&self, area: O::Area) -> O::Unit { self.dx().unwrap_or(self.inner().w_max(area)) }
|
||||||
|
fn h (&self, area: O::Area) -> O::Unit { self.dy().unwrap_or(self.inner().h(area)) }
|
||||||
|
fn h_min (&self, area: O::Area) -> O::Unit { self.dy().unwrap_or(self.inner().h_min(area)) }
|
||||||
|
fn h_max (&self, area: O::Area) -> O::Unit { self.dy().unwrap_or(self.inner().h_max(area)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
layout_op_xy!(1 opt: Max);
|
||||||
|
impl<E: Out, T: Layout<E>> Layout<E> for Max<E::Unit, T> {
|
||||||
|
fn layout (&self, area: E::Area) -> E::Area {
|
||||||
|
let [x, y, w, h] = self.inner().layout(area).xywh();
|
||||||
|
match self {
|
||||||
|
Self::X(mw, _) => [x, y, w.min(*mw), h ],
|
||||||
|
Self::Y(mh, _) => [x, y, w, h.min(*mh)],
|
||||||
|
Self::XY(mw, mh, _) => [x, y, w.min(*mw), h.min(*mh)],
|
||||||
|
}.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout_op_xy!(1 opt: Min);
|
||||||
|
impl<E: Out, T: Layout<E>> Layout<E> for Min<E::Unit, T> {
|
||||||
|
fn layout (&self, area: E::Area) -> E::Area {
|
||||||
|
let [x, y, w, h] = self.inner().layout(area).xywh();
|
||||||
|
match self {
|
||||||
|
Self::X(mw, _) => [x, y, w.max(*mw), h],
|
||||||
|
Self::Y(mh, _) => [x, y, w, h.max(*mh)],
|
||||||
|
Self::XY(mw, mh, _) => [x, y, w.max(*mw), h.max(*mh)],
|
||||||
|
}.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout_op_xy!(1 opt: Expand);
|
||||||
|
impl<O: Out, T: Layout<O>> Layout<O> for Expand<O::Unit, T> {
|
||||||
|
fn w (&self, to: O::Area) -> O::Unit { self.inner().w(to).plus(self.dx().unwrap_or_default()) }
|
||||||
|
fn h (&self, to: O::Area) -> O::Unit { self.inner().w(to).plus(self.dy().unwrap_or_default()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: why they differ?
|
||||||
|
|
||||||
|
layout_op_xy!(1 opt: Shrink);
|
||||||
|
impl<E: Out, T: Layout<E>> Layout<E> for Shrink<E::Unit, T> {
|
||||||
|
fn layout (&self, to: E::Area) -> E::Area {
|
||||||
|
let area = self.inner().layout(to);
|
||||||
|
let dx = self.dx().unwrap_or_default();
|
||||||
|
let dy = self.dy().unwrap_or_default();
|
||||||
|
[area.x(), area.y(), area.w().minus(dx), area.h().minus(dy)].into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Align<T> {
|
||||||
|
#[inline] pub const fn c (a: T) -> Self { Self(Alignment::Center, a) }
|
||||||
|
#[inline] pub const fn x (a: T) -> Self { Self(Alignment::X, a) }
|
||||||
|
#[inline] pub const fn y (a: T) -> Self { Self(Alignment::Y, a) }
|
||||||
|
#[inline] pub const fn n (a: T) -> Self { Self(Alignment::N, a) }
|
||||||
|
#[inline] pub const fn s (a: T) -> Self { Self(Alignment::S, a) }
|
||||||
|
#[inline] pub const fn e (a: T) -> Self { Self(Alignment::E, a) }
|
||||||
|
#[inline] pub const fn w (a: T) -> Self { Self(Alignment::W, a) }
|
||||||
|
#[inline] pub const fn nw (a: T) -> Self { Self(Alignment::NW, a) }
|
||||||
|
#[inline] pub const fn sw (a: T) -> Self { Self(Alignment::SW, a) }
|
||||||
|
#[inline] pub const fn ne (a: T) -> Self { Self(Alignment::NE, a) }
|
||||||
|
#[inline] pub const fn se (a: T) -> Self { Self(Alignment::SE, a) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, T: Content<O>> Draw<O> for Align<T> {
|
||||||
|
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), &self.1).draw(to) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, T: Layout<O>> Layout<O> for Align<T> {
|
||||||
|
fn x (&self, to: O::Area) -> O::Unit {
|
||||||
|
match self.0 {
|
||||||
|
NW | W | SW => to.x(),
|
||||||
|
N | Center | S => to.x().plus(to.w() / 2.into()).minus(self.1.w(to) / 2.into()),
|
||||||
|
NE | E | SE => to.x().plus(to.w()).minus(self.1.w(to)),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn y (&self, to: O::Area) -> O::Unit {
|
||||||
|
match self.0 {
|
||||||
|
NW | N | NE => to.y(),
|
||||||
|
W | Center | E => to.y().plus(to.h() / 2.into()).minus(self.1.h(to) / 2.into()),
|
||||||
|
SW | S | SE => to.y().plus(to.h()).minus(self.1.h(to)),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U, A> Pad<U, A> {
|
||||||
|
#[inline] pub const fn inner (&self) -> &A { match self { X(_, c) | Y(_, c) | XY(_, _, c) => c, } }
|
||||||
|
}
|
||||||
|
impl<U: Coord, T> Pad<U, T> {
|
||||||
|
#[inline] pub fn dx (&self) -> U { match self { X(x, _) => *x, Y(_, _) => 0.into(), XY(x, _, _) => *x, } }
|
||||||
|
#[inline] pub fn dy (&self) -> U { match self { X(_, _) => 0.into(), Y(y, _) => *y, XY(_, y, _) => *y, } }
|
||||||
|
}
|
||||||
|
impl<O: Out, T: Content<O>> Draw<O> for Pad<O::Unit, T> {
|
||||||
|
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
|
||||||
|
}
|
||||||
|
impl<O: Out, T: Layout<O>> Layout<O> for Pad<O::Unit, T> {
|
||||||
|
fn x (&self, area: O::Area) -> O::Unit { area.x().plus(self.dx()) }
|
||||||
|
fn y (&self, area: O::Area) -> O::Unit { area.x().plus(self.dx()) }
|
||||||
|
fn w (&self, area: O::Area) -> O::Unit { area.w().minus(self.dx() * 2.into()) }
|
||||||
|
fn h (&self, area: O::Area) -> O::Unit { area.h().minus(self.dy() * 2.into()) }
|
||||||
|
}
|
||||||
|
impl<Head, Tail> Bsp<Head, Tail> {
|
||||||
|
#[inline] pub const fn n (a: Head, b: Tail) -> Self { Self(North, a, b) }
|
||||||
|
#[inline] pub const fn s (a: Head, b: Tail) -> Self { Self(South, a, b) }
|
||||||
|
#[inline] pub const fn e (a: Head, b: Tail) -> Self { Self(East, a, b) }
|
||||||
|
#[inline] pub const fn w (a: Head, b: Tail) -> Self { Self(West, a, b) }
|
||||||
|
#[inline] pub const fn a (a: Head, b: Tail) -> Self { Self(Above, a, b) }
|
||||||
|
#[inline] pub const fn b (a: Head, b: Tail) -> Self { Self(Below, a, b) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, Head: Content<O>, Tail: Content<O>> Draw<O> for Bsp<Head, Tail> {
|
||||||
|
fn draw (&self, to: &mut O) {
|
||||||
|
match self.0 {
|
||||||
|
South => {
|
||||||
|
//panic!("{}", self.1.h(to.area()));
|
||||||
|
let area_1 = self.1.layout(to.area());
|
||||||
|
let area_2 = self.2.layout([
|
||||||
|
to.area().x(),
|
||||||
|
to.area().y().plus(area_1.h()),
|
||||||
|
to.area().w(),
|
||||||
|
to.area().h().minus(area_1.h())
|
||||||
|
].into());
|
||||||
|
//panic!("{area_1:?} {area_2:?}");
|
||||||
|
to.place_at(area_1, &self.1);
|
||||||
|
to.place_at(area_2, &self.2);
|
||||||
|
},
|
||||||
|
_ => todo!("{:?}", self.0)
|
||||||
|
}
|
||||||
|
//let [a, b, _] = bsp_areas(to.area(), self.0, &self.1, &self.2);
|
||||||
|
//panic!("{a:?} {b:?}");
|
||||||
|
//if self.0 == Below {
|
||||||
|
//to.place_at(a, &self.1);
|
||||||
|
//to.place_at(b, &self.2);
|
||||||
|
//} else {
|
||||||
|
//to.place_at(b, &self.2);
|
||||||
|
//to.place_at(a, &self.1);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<O: Out, Head: Layout<O>, Tail: Layout<O>> Layout<O> for Bsp<Head, Tail> {
|
||||||
|
fn w (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | North | South => self.1.w(area).max(self.2.w(area)), East | West => self.1.w_min(area).plus(self.2.w(area)), } }
|
||||||
|
fn w_min (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | North | South => self.1.w_min(area).max(self.2.w_min(area)), East | West => self.1.w_min(area).plus(self.2.w_min(area)), } }
|
||||||
|
fn w_max (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | North | South => self.1.w_max(area).max(self.2.w_max(area)), East | West => self.1.w_max(area).plus(self.2.w_max(area)), } }
|
||||||
|
fn h (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | East | West => self.1.h(area).max(self.2.h(area)), North | South => self.1.h(area).plus(self.2.h(area)), } }
|
||||||
|
fn h_min (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | East | West => self.1.h_min(area).max(self.2.h_min(area)), North | South => self.1.h_min(area).plus(self.2.h_min(area)), } }
|
||||||
|
fn h_max (&self, area: O::Area) -> O::Unit { match self.0 { Above | Below | North | South => self.1.h_max(area).max(self.2.h_max(area)), East | West => self.1.h_max(area).plus(self.2.h_max(area)), } }
|
||||||
|
fn layout (&self, area: O::Area) -> O::Area { bsp_areas(area, self.0, &self.1, &self.2)[2] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bsp_areas <O: Out, A: Layout<O>, B: Layout<O>> (area: O::Area, direction: Direction, a: &A, b: &B,) -> [O::Area;3] {
|
||||||
|
let [x, y, w, h] = area.xywh();
|
||||||
|
let [aw, ah] = a.layout(area).wh();
|
||||||
|
let [bw, bh] = b.layout(match direction {
|
||||||
|
Above | Below => area,
|
||||||
|
South => [x, y + ah, w, h.minus(ah)].into(),
|
||||||
|
North => [x, y, w, h.minus(ah)].into(),
|
||||||
|
East => [x + aw, y, w.minus(aw), h].into(),
|
||||||
|
West => [x, y, w.minus(aw), h].into(),
|
||||||
|
}).wh();
|
||||||
|
match direction {
|
||||||
|
Above | Below => {
|
||||||
|
let [x, y, w, h] = area.center_xy([aw.max(bw), ah.max(bh)]);
|
||||||
|
let a = [(x + w/2.into()).minus(aw/2.into()), (y + h/2.into()).minus(ah/2.into()), aw, ah];
|
||||||
|
let b = [(x + w/2.into()).minus(bw/2.into()), (y + h/2.into()).minus(bh/2.into()), bw, bh];
|
||||||
|
[a.into(), b.into(), [x, y, w, h].into()]
|
||||||
|
},
|
||||||
|
South => {
|
||||||
|
let [x, y, w, h] = area.center_xy([aw.max(bw), ah + bh]);
|
||||||
|
let a = [(x + w/2.into()).minus(aw/2.into()), y, aw, ah];
|
||||||
|
let b = [(x + w/2.into()).minus(bw/2.into()), y + ah, bw, bh];
|
||||||
|
[a.into(), b.into(), [x, y, w, h].into()]
|
||||||
|
},
|
||||||
|
North => {
|
||||||
|
let [x, y, w, h] = area.center_xy([aw.max(bw), ah + bh]);
|
||||||
|
let a = [(x + (w/2.into())).minus(aw/2.into()), y + bh, aw, ah];
|
||||||
|
let b = [(x + (w/2.into())).minus(bw/2.into()), y, bw, bh];
|
||||||
|
[a.into(), b.into(), [x, y, w, h].into()]
|
||||||
|
},
|
||||||
|
East => {
|
||||||
|
let [x, y, w, h] = area.center_xy([aw + bw, ah.max(bh)]);
|
||||||
|
let a = [x, (y + h/2.into()).minus(ah/2.into()), aw, ah];
|
||||||
|
let b = [x + aw, (y + h/2.into()).minus(bh/2.into()), bw, bh];
|
||||||
|
[a.into(), b.into(), [x, y, w, h].into()]
|
||||||
|
},
|
||||||
|
West => {
|
||||||
|
let [x, y, w, h] = area.center_xy([aw + bw, ah.max(bh)]);
|
||||||
|
let a = [x + bw, (y + h/2.into()).minus(ah/2.into()), aw, ah];
|
||||||
|
let b = [x, (y + h/2.into()).minus(bh/2.into()), bw, bh];
|
||||||
|
[a.into(), b.into(), [x, y, w, h].into()]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, O, A, B, I, F, G> Map<O, A, B, I, F, G> where
|
||||||
|
I: Iterator<Item = A> + Send + Sync + 'a,
|
||||||
|
F: Fn() -> I + Send + Sync + 'a,
|
||||||
|
{
|
||||||
|
pub const fn new (get_iter: F, get_item: G) -> Self {
|
||||||
|
Self {
|
||||||
|
__: PhantomData,
|
||||||
|
get_iter,
|
||||||
|
get_item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_map_direction!(east, X, w);
|
||||||
|
impl_map_direction!(south, Y, n);
|
||||||
|
impl_map_direction!(west, X, e);
|
||||||
|
impl_map_direction!(north, Y, s);
|
||||||
|
|
||||||
|
impl<'a, O, A, B, I, F, G> Layout<O> for Map<O, A, B, I, F, G> where
|
||||||
|
O: Out,
|
||||||
|
B: Layout<O>,
|
||||||
|
I: Iterator<Item = A> + Send + Sync + 'a,
|
||||||
|
F: Fn() -> I + Send + Sync + 'a,
|
||||||
|
G: Fn(A, usize)->B + Send + Sync
|
||||||
|
{
|
||||||
|
fn layout (&self, area: O::Area) -> O::Area {
|
||||||
|
let Self { get_iter, get_item, .. } = self;
|
||||||
|
let mut index = 0;
|
||||||
|
let [mut min_x, mut min_y] = area.center();
|
||||||
|
let [mut max_x, mut max_y] = area.center();
|
||||||
|
for item in get_iter() {
|
||||||
|
let [x,y,w,h] = get_item(item, index).layout(area).xywh();
|
||||||
|
min_x = min_x.min(x);
|
||||||
|
min_y = min_y.min(y);
|
||||||
|
max_x = max_x.max(x + w);
|
||||||
|
max_y = max_y.max(y + h);
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
let w = max_x - min_x;
|
||||||
|
let h = max_y - min_y;
|
||||||
|
//[min_x.into(), min_y.into(), w.into(), h.into()].into()
|
||||||
|
area.center_xy([w.into(), h.into()]).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, O, A, B, I, F, G> Draw<O> for Map<O, A, B, I, F, G> where
|
||||||
|
O: Out,
|
||||||
|
B: Content<O>,
|
||||||
|
I: Iterator<Item = A> + Send + Sync + 'a,
|
||||||
|
F: Fn() -> I + Send + Sync + 'a,
|
||||||
|
G: Fn(A, usize)->B + Send + Sync
|
||||||
|
{
|
||||||
|
fn draw (&self, to: &mut O) {
|
||||||
|
let Self { get_iter, get_item, .. } = self;
|
||||||
|
let mut index = 0;
|
||||||
|
let area = self.layout(to.area());
|
||||||
|
for item in get_iter() {
|
||||||
|
let item = get_item(item, index);
|
||||||
|
//to.place_at(area.into(), &item);
|
||||||
|
to.place_at(item.layout(area), &item);
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline] pub fn map_south<O: Out>(
|
||||||
|
item_offset: O::Unit,
|
||||||
|
item_height: O::Unit,
|
||||||
|
item: impl Content<O>
|
||||||
|
) -> impl Content<O> {
|
||||||
|
Push::Y(item_offset, Fixed::Y(item_height, Fill::X(item)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline] pub fn map_south_west<O: Out>(
|
||||||
|
item_offset: O::Unit,
|
||||||
|
item_height: O::Unit,
|
||||||
|
item: impl Content<O>
|
||||||
|
) -> impl Content<O> {
|
||||||
|
Push::Y(item_offset, Align::nw(Fixed::Y(item_height, Fill::X(item))))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline] pub fn map_east<O: Out>(
|
||||||
|
item_offset: O::Unit,
|
||||||
|
item_width: O::Unit,
|
||||||
|
item: impl Content<O>
|
||||||
|
) -> impl Content<O> {
|
||||||
|
Push::X(item_offset, Align::w(Fixed::X(item_width, Fill::Y(item))))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tryptich<(), (), ()> {
|
||||||
|
pub fn center (h: u16) -> Self {
|
||||||
|
Self { h, top: false, left: (0, ()), middle: (0, ()), right: (0, ()) }
|
||||||
|
}
|
||||||
|
pub fn top (h: u16) -> Self {
|
||||||
|
Self { h, top: true, left: (0, ()), middle: (0, ()), right: (0, ()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B, C> Tryptich<A, B, C> {
|
||||||
|
pub fn left <D> (self, w: u16, content: D) -> Tryptich<D, B, C> {
|
||||||
|
Tryptich { left: (w, content), ..self }
|
||||||
|
}
|
||||||
|
pub fn middle <D> (self, w: u16, content: D) -> Tryptich<A, D, C> {
|
||||||
|
Tryptich { middle: (w, content), ..self }
|
||||||
|
}
|
||||||
|
pub fn right <D> (self, w: u16, content: D) -> Tryptich<A, B, D> {
|
||||||
|
Tryptich { right: (w, content), ..self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, Color, Item: Layout<O>> Layout<O> for Foreground<Color, Item> {
|
||||||
|
fn layout (&self, to: O::Area) -> O::Area {
|
||||||
|
self.1.layout(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, Color, Item: Layout<O>> Layout<O> for Background<Color, Item> {
|
||||||
|
fn layout (&self, to: O::Area) -> O::Area {
|
||||||
|
self.1.layout(to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, T, L: Content<O>, V: Content<O>> HasContent<O> for FieldH<T, L, V> {
|
||||||
|
fn content (&self) -> impl Content<O> { Bsp::e(&self.1, &self.2) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, T, L: Content<O>, V: Content<O>> Layout<O> for FieldH<T, L, V> {
|
||||||
|
fn layout (&self, to: O::Area) -> O::Area { self.content().layout(to) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, T, L: Content<O>, V: Content<O>> Draw<O> for FieldH<T, L, V> {
|
||||||
|
fn draw (&self, to: &mut O) { self.content().draw(to) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, T, L: Content<O>, V: Content<O>> HasContent<O> for FieldV<T, L, V> {
|
||||||
|
fn content (&self) -> impl Content<O> { Bsp::s(&self.1, &self.2) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, T, L: Content<O>, V: Content<O>> Layout<O> for FieldV<T, L, V> {
|
||||||
|
fn layout (&self, to: O::Area) -> O::Area { self.content().layout(to) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<O: Out, T, L: Content<O>, V: Content<O>> Draw<O> for FieldV<T, L, V> {
|
||||||
|
fn draw (&self, to: &mut O) { self.content().draw(to) }
|
||||||
|
}
|
||||||
|
impl<O: Out, S: Layout<O>> Layout<O> for Border<S> {
|
||||||
|
fn layout (&self, area: O::Area) -> O::Area {
|
||||||
|
self.1.layout(area)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<C, T, U> Field<C, T, U> {
|
||||||
|
pub fn new (direction: Direction) -> Field<C, (), ()> {
|
||||||
|
Field::<C, (), ()> {
|
||||||
|
direction,
|
||||||
|
label: None, label_fg: None, label_bg: None, label_align: None,
|
||||||
|
value: None, value_fg: None, value_bg: None, value_align: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn label <L> (
|
||||||
|
self, label: Option<L>, align: Option<Direction>, fg: Option<C>, bg: Option<C>
|
||||||
|
) -> Field<C, L, U> {
|
||||||
|
Field::<C, L, U> { label, label_fg: fg, label_bg: bg, label_align: align, ..self }
|
||||||
|
}
|
||||||
|
pub fn value <V> (
|
||||||
|
self, value: Option<V>, align: Option<Direction>, fg: Option<C>, bg: Option<C>
|
||||||
|
) -> Field<C, T, V> {
|
||||||
|
Field::<C, T, V> { value, value_fg: fg, value_bg: bg, value_align: align, ..self }
|
||||||
|
}
|
||||||
|
}
|
||||||
138
output/src/out_macros.rs
Normal file
138
output/src/out_macros.rs
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
/// Clear a pre-allocated buffer, then write into it.
|
||||||
|
#[macro_export] macro_rules! rewrite {
|
||||||
|
($buf:ident, $($rest:tt)*) => { |$buf,_,_|{ $buf.clear(); write!($buf, $($rest)*) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// FIXME: This macro should be some variant of `eval`, too.
|
||||||
|
/// But taking into account the different signatures (resolving them into 1?)
|
||||||
|
#[cfg(feature = "dsl")] #[macro_export] macro_rules! draw {
|
||||||
|
($State:ident: $Output:ident: $layers:expr) => {
|
||||||
|
impl Draw<$Output> for $State {
|
||||||
|
fn draw (&self, to: &mut $Output) {
|
||||||
|
for layer in $layers { layer(self, to) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// FIXME: This is generic: should be called `eval` and be part of [dizzle].
|
||||||
|
#[cfg(feature = "dsl")] #[macro_export] macro_rules! view {
|
||||||
|
($State:ident: $Output:ident: $namespaces:expr) => {
|
||||||
|
impl View<$Output, ()> for $State {
|
||||||
|
fn view_expr <'a> (&'a self, to: &mut $Output, expr: &'a impl Expression) -> Usually<()> {
|
||||||
|
for namespace in $namespaces { if namespace(self, to, expr)? { return Ok(()) } }
|
||||||
|
Err(format!("{}::<{}, ()>::view_expr: unexpected: {expr:?}",
|
||||||
|
stringify! { $State },
|
||||||
|
stringify! { $Output }).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stack things on top of each other,
|
||||||
|
#[macro_export] macro_rules! lay (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::b(bsp, $expr);)*; bsp }});
|
||||||
|
|
||||||
|
/// Stack southward.
|
||||||
|
#[macro_export] macro_rules! col (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::s(bsp, $expr);)*; bsp }});
|
||||||
|
|
||||||
|
/// Stack northward.
|
||||||
|
#[macro_export] macro_rules! col_up (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::n(bsp, $expr);)*; bsp }});
|
||||||
|
|
||||||
|
/// Stack eastward.
|
||||||
|
#[macro_export] macro_rules! row (($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::e(bsp, $expr);)*; bsp }});
|
||||||
|
|
||||||
|
/// Define layout operation.
|
||||||
|
macro_rules! layout_op_xy (
|
||||||
|
// Variant for layout ops that take no coordinates
|
||||||
|
(0: $T: ident) => {
|
||||||
|
impl<A> $T<A> {
|
||||||
|
#[inline] pub const fn inner (&self) -> &A {
|
||||||
|
match self { Self::X(c) | Self::Y(c) | Self::XY(c) => c }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<O: Out, T: Content<O>> Draw<O> for $T<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<U, A> $T<U, A> {
|
||||||
|
#[inline] pub const fn inner (&self) -> &A {
|
||||||
|
match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<O: Out, T: Content<O>> Draw<O> for $T<O::Unit, T> {
|
||||||
|
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
|
||||||
|
}
|
||||||
|
impl<U: Coord, A> $T<U, A> {
|
||||||
|
#[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<U, A> $T<U, A> {
|
||||||
|
#[inline] pub const fn inner (&self) -> &A {
|
||||||
|
match self { Self::X(_, c) | Self::Y(_, c) | Self::XY(_, _, c) => c, }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<O: Out, T: Content<O>> Draw<O> for $T<O::Unit, T> {
|
||||||
|
fn draw (&self, to: &mut O) { Bounded(self.layout(to.area()), self.inner()).draw(to) }
|
||||||
|
}
|
||||||
|
impl<U: Coord, A> $T<U, A> {
|
||||||
|
#[inline] pub const fn dx (&self) -> Option<U> {
|
||||||
|
match self { Self::X(x, _) | Self::XY(x, ..) => Some(*x), _ => None }
|
||||||
|
}
|
||||||
|
#[inline] pub const fn dy (&self) -> Option<U> {
|
||||||
|
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<O: Out, T: Layout<O>> Layout<O> for $T<O::Unit, T> {
|
||||||
|
fn x (&self, area: O::Area) -> O::Unit { area.x().$method(self.dx()) }
|
||||||
|
fn y (&self, area: O::Area) -> 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<O::Unit, Align<Fixed<O::Unit, Fill<B>>>>, I, F, fn(A, usize)->B
|
||||||
|
> where
|
||||||
|
O: Out,
|
||||||
|
B: Draw<O>,
|
||||||
|
I: Iterator<Item = A> + 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<O::Unit, Align<Fixed<O::Unit, B>>>,
|
||||||
|
I, F,
|
||||||
|
impl Fn(A, usize)->Push<O::Unit, Align<Fixed<O::Unit, B>>> + 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))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
176
output/src/out_structs.rs
Normal file
176
output/src/out_structs.rs
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
/// A point (X, Y).
|
||||||
|
pub struct XY<N: Coord>(N, N);
|
||||||
|
|
||||||
|
/// A size (Width, Height).
|
||||||
|
pub struct WH<N: Coord>(N, N);
|
||||||
|
|
||||||
|
/// Point with size.
|
||||||
|
///
|
||||||
|
/// TODO: anchor field (determines at which corner/side is X0 Y0)
|
||||||
|
pub struct XYWH<N: Coord>(N, N, N, N);
|
||||||
|
|
||||||
|
/// A cardinal direction.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Debug)] #[cfg_attr(test, derive(Arbitrary))]
|
||||||
|
pub enum Direction { North, South, East, West, Above, Below }
|
||||||
|
|
||||||
|
/// 9th of area to place.
|
||||||
|
#[derive(Debug, Copy, Clone, Default)]
|
||||||
|
pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W }
|
||||||
|
|
||||||
|
/// A widget that tracks its rendered width and height
|
||||||
|
#[derive(Default)] pub struct Measure<O: Out> {
|
||||||
|
__: PhantomData<O>,
|
||||||
|
pub x: Arc<AtomicUsize>,
|
||||||
|
pub y: Arc<AtomicUsize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
pub struct Bounded<O: Out, D>(pub O::Area, pub D);
|
||||||
|
|
||||||
|
/// Draws items from an iterator.
|
||||||
|
pub struct Map<O, A, B, I, F, G>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = A> + Send + Sync,
|
||||||
|
F: Fn() -> I + Send + Sync,
|
||||||
|
{
|
||||||
|
__: PhantomData<(O, B)>,
|
||||||
|
/// Function that returns iterator over stacked components
|
||||||
|
get_iter: F,
|
||||||
|
/// Function that returns each stacked component
|
||||||
|
get_item: G,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
pub struct Lazy<O, T, F>(
|
||||||
|
F,
|
||||||
|
PhantomData<(O, T)>
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
pub struct Thunk<O: Out, F: Fn(&mut O)>(
|
||||||
|
PhantomData<O>,
|
||||||
|
F
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
#[derive(Debug, Default)] pub struct Memo<T, U> {
|
||||||
|
pub value: T,
|
||||||
|
pub view: Arc<RwLock<U>>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show an item only when a condition is true.
|
||||||
|
pub struct When<O, T>(bool, T, PhantomData<O>);
|
||||||
|
|
||||||
|
/// Show one item if a condition is true and another if the condition is false
|
||||||
|
pub struct Either<E: Out, A, B>(pub bool, pub A, pub B, pub PhantomData<E>);
|
||||||
|
|
||||||
|
/// Increment X and/or Y coordinate.
|
||||||
|
pub enum Push<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
|
/// Decrement X and/or Y coordinate.
|
||||||
|
pub enum Pull<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
|
/// Set the content to fill the container.
|
||||||
|
pub enum Fill<A> { X(A), Y(A), XY(A) }
|
||||||
|
|
||||||
|
/// Set fixed size for content.
|
||||||
|
pub enum Fixed<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
|
/// Set the maximum width and/or height of the content.
|
||||||
|
pub enum Max<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
|
/// Set the minimum width and/or height of the content.
|
||||||
|
pub enum Min<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
|
/// Decrease the width and/or height of the content.
|
||||||
|
pub enum Shrink<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
|
/// Increaase the width and/or height of the content.
|
||||||
|
pub enum Expand<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
|
/// Align position of inner area to middle, side, or corner of outer area.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use ::tengri::{output::*, tui::*};
|
||||||
|
/// let area: [u16;4] = [10, 10, 20, 20];
|
||||||
|
/// fn test (area: [u16;4], item: &impl Draw<TuiOut>, expected: [u16;4]) {
|
||||||
|
/// assert_eq!(Content::layout(item, area), expected);
|
||||||
|
/// assert_eq!(Draw::layout(item, area), expected);
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let four = ||Fixed::XY(4, 4, "");
|
||||||
|
/// test(area, &Align::nw(four()), [10, 10, 4, 4]);
|
||||||
|
/// test(area, &Align::n(four()), [18, 10, 4, 4]);
|
||||||
|
/// test(area, &Align::ne(four()), [26, 10, 4, 4]);
|
||||||
|
/// test(area, &Align::e(four()), [26, 18, 4, 4]);
|
||||||
|
/// test(area, &Align::se(four()), [26, 26, 4, 4]);
|
||||||
|
/// test(area, &Align::s(four()), [18, 26, 4, 4]);
|
||||||
|
/// test(area, &Align::sw(four()), [10, 26, 4, 4]);
|
||||||
|
/// test(area, &Align::w(four()), [10, 18, 4, 4]);
|
||||||
|
///
|
||||||
|
/// let two_by_four = ||Fixed::XY(4, 2, "");
|
||||||
|
/// test(area, &Align::nw(two_by_four()), [10, 10, 4, 2]);
|
||||||
|
/// test(area, &Align::n(two_by_four()), [18, 10, 4, 2]);
|
||||||
|
/// test(area, &Align::ne(two_by_four()), [26, 10, 4, 2]);
|
||||||
|
/// test(area, &Align::e(two_by_four()), [26, 19, 4, 2]);
|
||||||
|
/// test(area, &Align::se(two_by_four()), [26, 28, 4, 2]);
|
||||||
|
/// test(area, &Align::s(two_by_four()), [18, 28, 4, 2]);
|
||||||
|
/// test(area, &Align::sw(two_by_four()), [10, 28, 4, 2]);
|
||||||
|
/// test(area, &Align::w(two_by_four()), [10, 19, 4, 2]);
|
||||||
|
/// ```
|
||||||
|
pub struct Align<T>(Alignment, T);
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
pub enum Pad<U, A> { X(U, A), Y(U, A), XY(U, U, A), }
|
||||||
|
|
||||||
|
/// A binary split or layer.
|
||||||
|
pub struct Bsp<Head, Tail>(
|
||||||
|
pub(crate) Direction,
|
||||||
|
/// First element.
|
||||||
|
pub(crate) Head,
|
||||||
|
/// Second element.
|
||||||
|
pub(crate) Tail,
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
pub struct Bordered<S, W>(pub bool, pub S, pub W);
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
pub struct Border<S>(pub bool, pub S);
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
pub struct Foreground<Color, Item>(pub Color, pub Item);
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
pub struct Background<Color, Item>(pub Color, pub Item);
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
pub struct FieldH<Theme, Label, Value>(pub Theme, pub Label, pub Value);
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
pub struct FieldV<Theme, Label, Value>(pub Theme, pub Label, pub Value);
|
||||||
|
|
||||||
|
/// A three-column layout.
|
||||||
|
pub struct Tryptich<A, B, C> {
|
||||||
|
pub top: bool,
|
||||||
|
pub h: u16,
|
||||||
|
pub left: (u16, A),
|
||||||
|
pub middle: (u16, B),
|
||||||
|
pub right: (u16, C),
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
pub struct Field<C, T, U> {
|
||||||
|
pub direction: Direction,
|
||||||
|
pub label: Option<T>,
|
||||||
|
pub label_fg: Option<C>,
|
||||||
|
pub label_bg: Option<C>,
|
||||||
|
pub label_align: Option<Direction>,
|
||||||
|
pub value: Option<U>,
|
||||||
|
pub value_fg: Option<C>,
|
||||||
|
pub value_bg: Option<C>,
|
||||||
|
pub value_align: Option<Direction>,
|
||||||
|
}
|
||||||
132
output/src/out_tests.rs
Normal file
132
output/src/out_tests.rs
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
use proptest::{prelude::*, option::of};
|
||||||
|
use proptest_derive::Arbitrary;
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
#[test] fn test_area () {
|
||||||
|
assert_eq!(Area::center(&[10u16, 10, 20, 20]), [20, 20]);
|
||||||
|
}
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test] fn proptest_direction (
|
||||||
|
d in prop_oneof![
|
||||||
|
Just(North), Just(South),
|
||||||
|
Just(East), Just(West),
|
||||||
|
Just(Above), Just(Below)
|
||||||
|
],
|
||||||
|
x in u16::MIN..u16::MAX,
|
||||||
|
y in u16::MIN..u16::MAX,
|
||||||
|
w in u16::MIN..u16::MAX,
|
||||||
|
h in u16::MIN..u16::MAX,
|
||||||
|
a in u16::MIN..u16::MAX,
|
||||||
|
) {
|
||||||
|
let _ = d.split_fixed([x, y, w, h], a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test] fn proptest_area (
|
||||||
|
x in u16::MIN..u16::MAX,
|
||||||
|
y in u16::MIN..u16::MAX,
|
||||||
|
w in u16::MIN..u16::MAX,
|
||||||
|
h in u16::MIN..u16::MAX,
|
||||||
|
a in u16::MIN..u16::MAX,
|
||||||
|
b in u16::MIN..u16::MAX,
|
||||||
|
) {
|
||||||
|
let _: [u16;4] = <[u16;4] as Area<u16>>::zero();
|
||||||
|
let _: [u16;4] = <[u16;4] as Area<u16>>::from_position([a, b]);
|
||||||
|
let _: [u16;4] = <[u16;4] as Area<u16>>::from_size([a, b]);
|
||||||
|
let area: [u16;4] = [x, y, w, h];
|
||||||
|
let _ = area.expect_min(a, b);
|
||||||
|
let _ = area.xy();
|
||||||
|
let _ = area.wh();
|
||||||
|
let _ = area.xywh();
|
||||||
|
let _ = area.clip_h(a);
|
||||||
|
let _ = area.clip_w(b);
|
||||||
|
let _ = area.clip([a, b]);
|
||||||
|
let _ = area.set_w(a);
|
||||||
|
let _ = area.set_h(b);
|
||||||
|
let _ = area.x2();
|
||||||
|
let _ = area.y2();
|
||||||
|
let _ = area.lrtb();
|
||||||
|
let _ = area.center();
|
||||||
|
let _ = area.center_x(a);
|
||||||
|
let _ = area.center_y(b);
|
||||||
|
let _ = area.center_xy([a, b]);
|
||||||
|
let _ = area.centered();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test] fn proptest_size (
|
||||||
|
x in u16::MIN..u16::MAX,
|
||||||
|
y in u16::MIN..u16::MAX,
|
||||||
|
a in u16::MIN..u16::MAX,
|
||||||
|
b in u16::MIN..u16::MAX,
|
||||||
|
) {
|
||||||
|
let size = [x, y];
|
||||||
|
let _ = size.w();
|
||||||
|
let _ = size.h();
|
||||||
|
let _ = size.wh();
|
||||||
|
let _ = size.clip_w(a);
|
||||||
|
let _ = size.clip_h(b);
|
||||||
|
let _ = size.expect_min(a, b);
|
||||||
|
let _ = size.to_area_pos();
|
||||||
|
let _ = size.to_area_size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! test_op_transform {
|
||||||
|
($fn:ident, $Op:ident) => {
|
||||||
|
proptest! {
|
||||||
|
#[test] fn $fn (
|
||||||
|
op_x in of(u16::MIN..u16::MAX),
|
||||||
|
op_y in of(u16::MIN..u16::MAX),
|
||||||
|
content in "\\PC*",
|
||||||
|
x in u16::MIN..u16::MAX,
|
||||||
|
y in u16::MIN..u16::MAX,
|
||||||
|
w in u16::MIN..u16::MAX,
|
||||||
|
h in u16::MIN..u16::MAX,
|
||||||
|
) {
|
||||||
|
if let Some(op) = match (op_x, op_y) {
|
||||||
|
(Some(x), Some(y)) => Some($Op::XY(x, y, content)),
|
||||||
|
(Some(x), None) => Some($Op::X(x, content)),
|
||||||
|
(None, Some(y)) => Some($Op::Y(y, content)),
|
||||||
|
_ => None
|
||||||
|
} {
|
||||||
|
//assert_eq!(Content::layout(&op, [x, y, w, h]),
|
||||||
|
//Draw::layout(&op, [x, y, w, h]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_op_transform!(proptest_op_fixed, Fixed);
|
||||||
|
test_op_transform!(proptest_op_min, Min);
|
||||||
|
test_op_transform!(proptest_op_max, Max);
|
||||||
|
test_op_transform!(proptest_op_push, Push);
|
||||||
|
test_op_transform!(proptest_op_pull, Pull);
|
||||||
|
test_op_transform!(proptest_op_shrink, Shrink);
|
||||||
|
test_op_transform!(proptest_op_expand, Expand);
|
||||||
|
test_op_transform!(proptest_op_padding, Pad);
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test] fn proptest_op_bsp (
|
||||||
|
d in prop_oneof![
|
||||||
|
Just(North), Just(South),
|
||||||
|
Just(East), Just(West),
|
||||||
|
Just(Above), Just(Below)
|
||||||
|
],
|
||||||
|
a in "\\PC*",
|
||||||
|
b in "\\PC*",
|
||||||
|
x in u16::MIN..u16::MAX,
|
||||||
|
y in u16::MIN..u16::MAX,
|
||||||
|
w in u16::MIN..u16::MAX,
|
||||||
|
h in u16::MIN..u16::MAX,
|
||||||
|
) {
|
||||||
|
let bsp = Bsp(d, a, b);
|
||||||
|
//assert_eq!(
|
||||||
|
//Content::layout(&bsp, [x, y, w, h]),
|
||||||
|
//Draw::layout(&bsp, [x, y, w, h]),
|
||||||
|
//);
|
||||||
|
}
|
||||||
|
}
|
||||||
148
output/src/out_traits.rs
Normal file
148
output/src/out_traits.rs
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
/// Drawing target.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use crate::*;
|
||||||
|
/// struct TestOut([u16;4]);
|
||||||
|
/// impl Out for TestOut {
|
||||||
|
/// type Unit = u16;
|
||||||
|
/// type Size = [u16;2];
|
||||||
|
/// type Area = [u16;4];
|
||||||
|
/// fn area (&self) -> [u16;4] {
|
||||||
|
/// self.0
|
||||||
|
/// }
|
||||||
|
/// fn area_mut (&mut self) -> &mut [u16;4] {
|
||||||
|
/// &mut self.0
|
||||||
|
/// }
|
||||||
|
/// fn place_at <T: Draw<Self> + ?Sized> (&mut self, area: [u16;4], _: &T) {
|
||||||
|
/// println!("place_at: {area:?}");
|
||||||
|
/// ()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// impl Draw<TestOut> for String {
|
||||||
|
/// fn draw (&self, to: &mut TestOut) {
|
||||||
|
/// to.area_mut().set_w(self.len() as u16);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub trait Out: Send + Sync + Sized {
|
||||||
|
/// Unit of length
|
||||||
|
type Unit: Coord;
|
||||||
|
/// Rectangle without offset
|
||||||
|
type Size: Size<Self::Unit>;
|
||||||
|
/// Rectangle with offset
|
||||||
|
type Area: Area<Self::Unit>;
|
||||||
|
/// Current output area
|
||||||
|
fn area (&self) -> Self::Area;
|
||||||
|
/// Mutable pointer to area.
|
||||||
|
fn area_mut (&mut self) -> &mut Self::Area;
|
||||||
|
/// Render drawable in area specified by `area`
|
||||||
|
fn place_at <'t, T: Draw<Self> + ?Sized> (&mut self, area: Self::Area, content: &'t T);
|
||||||
|
/// Render drawable in area specified by `T::layout(self.area())`
|
||||||
|
#[inline] fn place <'t, T: Content<Self> + ?Sized> (
|
||||||
|
&mut self, content: &'t T
|
||||||
|
) {
|
||||||
|
self.place_at(content.layout(self.area()), content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Drawable with dynamic dispatch.
|
||||||
|
pub trait Draw<O: Out> {
|
||||||
|
fn draw (&self, to: &mut O);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// FIXME: This is a general implementation: should be called `Eval` and be part of [dizzle].
|
||||||
|
/// Matches [Language] expressions to renderings for a given [Output] target.
|
||||||
|
pub trait View<O, U> {
|
||||||
|
fn view_expr <'a> (&'a self, _output: &mut O, expr: &'a impl Expression) -> Usually<U> {
|
||||||
|
Err(format!("View::view_expr: no exprs defined: {expr:?}").into())
|
||||||
|
}
|
||||||
|
fn view_word <'a> (&'a self, _output: &mut O, word: &'a impl Symbol) -> Usually<U> {
|
||||||
|
Err(format!("View::view_word: no words defined: {word:?}").into())
|
||||||
|
}
|
||||||
|
fn view <'a> (&'a self, output: &mut O, dsl: &'a impl Language) -> Usually<U> {
|
||||||
|
let is_expr = dsl.expr();
|
||||||
|
let is_word = dsl.word();
|
||||||
|
match (dsl.expr(), dsl.word()) {
|
||||||
|
(Ok(Some(e)), _ ) => self.view_expr(output, &e),
|
||||||
|
(_, Ok(Some(w))) => self.view_word(output, &w),
|
||||||
|
(Err(e), _ ) => Err(format!("invalid view expr:\n{dsl:?}\n{e}").into()),
|
||||||
|
(_, Err(w) ) => Err(format!("invalid view word:\n{dsl:?}\n{w}").into()),
|
||||||
|
(Ok(None), Ok(None) ) => Err(format!("empty view:\n{dsl:?}").into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Outputs combinator.
|
||||||
|
pub trait Lay<O: Out>: Sized {}
|
||||||
|
|
||||||
|
/// Drawable area of display.
|
||||||
|
pub trait Layout<O: Out> {
|
||||||
|
fn x (&self, to: O::Area) -> O::Unit { to.x() }
|
||||||
|
fn y (&self, to: O::Area) -> O::Unit { to.y() }
|
||||||
|
fn w_min (&self, _t: O::Area) -> O::Unit { 0.into() }
|
||||||
|
fn w_max (&self, to: O::Area) -> O::Unit { to.w() }
|
||||||
|
fn w (&self, to: O::Area) -> O::Unit { to.w().max(self.w_min(to)).min(self.w_max(to)) }
|
||||||
|
fn h_min (&self, _t: O::Area) -> O::Unit { 0.into() }
|
||||||
|
fn h_max (&self, to: O::Area) -> O::Unit { to.h() }
|
||||||
|
fn h (&self, to: O::Area) -> O::Unit { to.h().max(self.h_min(to)).min(self.h_max(to)) }
|
||||||
|
fn layout (&self, to: O::Area) -> O::Area { [self.x(to), self.y(to), self.w(to), self.h(to)].into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
pub trait Content<O: Out>: Draw<O> + Layout<O> {}
|
||||||
|
|
||||||
|
/// A numeric type that can be used as coordinate.
|
||||||
|
///
|
||||||
|
/// FIXME: Replace this ad-hoc trait with `num` crate.
|
||||||
|
pub trait Coord: 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>
|
||||||
|
{
|
||||||
|
fn zero () -> Self { 0.into() }
|
||||||
|
fn plus (self, other: Self) -> Self;
|
||||||
|
fn minus (self, other: Self) -> Self { if self >= other { self - other } else { 0.into() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something that has an origin point (X, Y).
|
||||||
|
pub trait HasXY<N: Coord> {
|
||||||
|
fn x (&self) -> N;
|
||||||
|
fn y (&self) -> N;
|
||||||
|
fn xy (&self) -> XY<N> { XY(self.x(), self.y()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something that has a size (W, H).
|
||||||
|
pub trait HasWH<N: Coord> {
|
||||||
|
fn w (&self) -> N;
|
||||||
|
fn h (&self) -> N;
|
||||||
|
fn wh (&self) -> WH<N> { WH(self.w(), self.h()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something that has a 2D bounding box (X, Y, W, H).
|
||||||
|
pub trait HasXYWH<N: Coord>: HasXY<N> + HasWH<N> {
|
||||||
|
fn x2 (&self) -> N { self.x().plus(self.w()) }
|
||||||
|
fn y2 (&self) -> N { self.y().plus(self.h()) }
|
||||||
|
fn xywh (&self) -> XYWH<N> { XYWH(self.x(), self.y(), self.w(), self.h()) }
|
||||||
|
fn expect_min (&self, w: N, h: N) -> Usually<&Self> {
|
||||||
|
if self.w() < w || self.h() < h {
|
||||||
|
Err(format!("min {w}x{h}").into())
|
||||||
|
} else {
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO DOCUMENTME
|
||||||
|
pub trait HasSize<O: Out> {
|
||||||
|
fn size (&self) -> &Measure<O>;
|
||||||
|
fn width (&self) -> usize { self.size().w() }
|
||||||
|
fn height (&self) -> usize { self.size().h() }
|
||||||
|
}
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
/// Drawing target.
|
|
||||||
pub trait Out: Send + Sync + Sized {
|
|
||||||
/// Unit of length
|
|
||||||
type Unit: Coordinate;
|
|
||||||
|
|
||||||
/// Rectangle without offset
|
|
||||||
type Size: Size<Self::Unit>;
|
|
||||||
|
|
||||||
/// Rectangle with offset
|
|
||||||
type Area: Area<Self::Unit>;
|
|
||||||
|
|
||||||
/// Render drawable in area specified by `T::layout(self.area())`
|
|
||||||
#[inline] fn place <'t, T: Content<Self> + ?Sized> (
|
|
||||||
&mut self, content: &'t T
|
|
||||||
) {
|
|
||||||
self.place_at(content.layout(self.area()), content)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Render drawable in area specified by `area`
|
|
||||||
fn place_at <'t, T: Draw<Self> + ?Sized> (&mut self, area: Self::Area, content: &'t T);
|
|
||||||
|
|
||||||
/// Current output area
|
|
||||||
fn area (&self) -> Self::Area;
|
|
||||||
#[inline] fn x (&self) -> Self::Unit { self.area().x() }
|
|
||||||
#[inline] fn y (&self) -> Self::Unit { self.area().y() }
|
|
||||||
#[inline] fn w (&self) -> Self::Unit { self.area().w() }
|
|
||||||
#[inline] fn h (&self) -> Self::Unit { self.area().h() }
|
|
||||||
#[inline] fn wh (&self) -> Self::Size { self.area().wh().into() }
|
|
||||||
|
|
||||||
/// Mutable pointer to area.
|
|
||||||
fn area_mut (&mut self) -> &mut Self::Area;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)] #[test] fn test_stub_output () -> Usually<()> {
|
|
||||||
use crate::*;
|
|
||||||
struct TestOut([u16;4]);
|
|
||||||
impl Out for TestOut {
|
|
||||||
type Unit = u16;
|
|
||||||
type Size = [u16;2];
|
|
||||||
type Area = [u16;4];
|
|
||||||
fn area (&self) -> [u16;4] {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
fn area_mut (&mut self) -> &mut [u16;4] {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
fn place_at <T: Draw<Self> + ?Sized> (&mut self, area: [u16;4], _: &T) {
|
|
||||||
println!("place_at: {area:?}");
|
|
||||||
()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Draw<TestOut> for String {
|
|
||||||
fn draw (&self, to: &mut TestOut) {
|
|
||||||
to.area_mut().set_w(self.len() as u16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
@ -1,441 +0,0 @@
|
||||||
pub(self) use crate::*;
|
|
||||||
#[cfg(test)] use proptest::{prelude::*, option::of};
|
|
||||||
|
|
||||||
pub use self::direction::*; mod direction {
|
|
||||||
use super::*;
|
|
||||||
/// A cardinal direction.
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
||||||
#[cfg_attr(test, derive(Arbitrary))]
|
|
||||||
pub enum Direction { North, South, East, West, Above, Below }
|
|
||||||
impl Direction {
|
|
||||||
pub fn split_fixed <N: Coordinate> (self, area: impl Area<N>, a: N) -> ([N;4],[N;4]) {
|
|
||||||
let [x, y, w, h] = area.xywh();
|
|
||||||
match self {
|
|
||||||
North => ([x, y.plus(h).minus(a), w, a], [x, y, w, h.minus(a)]),
|
|
||||||
South => ([x, y, w, a], [x, y.plus(a), w, h.minus(a)]),
|
|
||||||
East => ([x, y, a, h], [x.plus(a), y, w.minus(a), h]),
|
|
||||||
West => ([x.plus(w).minus(a), y, a, h], [x, y, w.minus(a), h]),
|
|
||||||
Above | Below => (area.xywh(), area.xywh())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(test)] proptest! {
|
|
||||||
#[test] fn proptest_direction (
|
|
||||||
d in prop_oneof![
|
|
||||||
Just(North), Just(South),
|
|
||||||
Just(East), Just(West),
|
|
||||||
Just(Above), Just(Below)
|
|
||||||
],
|
|
||||||
x in u16::MIN..u16::MAX,
|
|
||||||
y in u16::MIN..u16::MAX,
|
|
||||||
w in u16::MIN..u16::MAX,
|
|
||||||
h in u16::MIN..u16::MAX,
|
|
||||||
a in u16::MIN..u16::MAX,
|
|
||||||
) {
|
|
||||||
let _ = d.split_fixed([x, y, w, h], a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::coordinate::*; mod coordinate {
|
|
||||||
use super::*;
|
|
||||||
/// A linear coordinate.
|
|
||||||
pub trait Coordinate: 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>
|
|
||||||
{
|
|
||||||
fn zero () -> Self { 0.into() }
|
|
||||||
fn plus (self, other: Self) -> Self;
|
|
||||||
fn minus (self, other: Self) -> Self {
|
|
||||||
if self >= other {
|
|
||||||
self - other
|
|
||||||
} else {
|
|
||||||
0.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Coordinate for u16 { fn plus (self, other: Self) -> Self { self.saturating_add(other) } }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::area::*; mod area {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub trait Area<N: Coordinate>: From<[N;4]> + Debug + Copy {
|
|
||||||
fn x (&self) -> N;
|
|
||||||
fn y (&self) -> N;
|
|
||||||
fn w (&self) -> N;
|
|
||||||
fn h (&self) -> N;
|
|
||||||
fn zero () -> [N;4] {
|
|
||||||
[N::zero(), N::zero(), N::zero(), N::zero()]
|
|
||||||
}
|
|
||||||
fn from_position (pos: impl Size<N>) -> [N;4] {
|
|
||||||
let [x, y] = pos.wh();
|
|
||||||
[x, y, 0.into(), 0.into()]
|
|
||||||
}
|
|
||||||
fn from_size (size: impl Size<N>) -> [N;4] {
|
|
||||||
let [w, h] = size.wh();
|
|
||||||
[0.into(), 0.into(), w, h]
|
|
||||||
}
|
|
||||||
fn expect_min (&self, w: N, h: N) -> Usually<&Self> {
|
|
||||||
if self.w() < w || self.h() < h {
|
|
||||||
Err(format!("min {w}x{h}").into())
|
|
||||||
} else {
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn xy (&self) -> [N;2] {
|
|
||||||
[self.x(), self.y()]
|
|
||||||
}
|
|
||||||
fn wh (&self) -> [N;2] {
|
|
||||||
[self.w(), self.h()]
|
|
||||||
}
|
|
||||||
fn xywh (&self) -> [N;4] {
|
|
||||||
[self.x(), self.y(), self.w(), self.h()]
|
|
||||||
}
|
|
||||||
fn clip_h (&self, h: N) -> [N;4] {
|
|
||||||
[self.x(), self.y(), self.w(), self.h().min(h)]
|
|
||||||
}
|
|
||||||
fn clip_w (&self, w: N) -> [N;4] {
|
|
||||||
[self.x(), self.y(), self.w().min(w), self.h()]
|
|
||||||
}
|
|
||||||
fn clip (&self, wh: impl Size<N>) -> [N;4] {
|
|
||||||
[self.x(), self.y(), wh.w(), wh.h()]
|
|
||||||
}
|
|
||||||
fn set_w (&self, w: N) -> [N;4] {
|
|
||||||
[self.x(), self.y(), w, self.h()]
|
|
||||||
}
|
|
||||||
fn set_h (&self, h: N) -> [N;4] {
|
|
||||||
[self.x(), self.y(), self.w(), h]
|
|
||||||
}
|
|
||||||
fn x2 (&self) -> N {
|
|
||||||
self.x().plus(self.w())
|
|
||||||
}
|
|
||||||
fn y2 (&self) -> N {
|
|
||||||
self.y().plus(self.h())
|
|
||||||
}
|
|
||||||
fn lrtb (&self) -> [N;4] {
|
|
||||||
[self.x(), self.x2(), self.y(), self.y2()]
|
|
||||||
}
|
|
||||||
fn center (&self) -> [N;2] {
|
|
||||||
[self.x().plus(self.w()/2.into()), self.y().plus(self.h()/2.into())]
|
|
||||||
}
|
|
||||||
fn center_x (&self, n: N) -> [N;4] {
|
|
||||||
let [x, y, w, h] = self.xywh();
|
|
||||||
[(x.plus(w / 2.into())).minus(n / 2.into()), y.plus(h / 2.into()), n, 1.into()]
|
|
||||||
}
|
|
||||||
fn center_y (&self, n: N) -> [N;4] {
|
|
||||||
let [x, y, w, h] = self.xywh();
|
|
||||||
[x.plus(w / 2.into()), (y.plus(h / 2.into())).minus(n / 2.into()), 1.into(), n]
|
|
||||||
}
|
|
||||||
fn center_xy (&self, [n, m]: [N;2]) -> [N;4] {
|
|
||||||
let [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]
|
|
||||||
}
|
|
||||||
fn centered (&self) -> [N;2] {
|
|
||||||
[self.x().minus(self.w()/2.into()), self.y().minus(self.h()/2.into())]
|
|
||||||
}
|
|
||||||
fn iter_x (&self) -> impl Iterator<Item = N> where N: std::iter::Step {
|
|
||||||
self.x()..(self.x()+self.w())
|
|
||||||
}
|
|
||||||
fn iter_y (&self) -> impl Iterator<Item = N> where N: std::iter::Step {
|
|
||||||
self.y()..(self.y()+self.h())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: Coordinate> Area<N> for (N, N, N, N) {
|
|
||||||
fn x (&self) -> N { self.0 }
|
|
||||||
fn y (&self) -> N { self.1 }
|
|
||||||
fn w (&self) -> N { self.2 }
|
|
||||||
fn h (&self) -> N { self.3 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: Coordinate> Area<N> for [N;4] {
|
|
||||||
fn x (&self) -> N { self[0] }
|
|
||||||
fn y (&self) -> N { self[1] }
|
|
||||||
fn w (&self) -> N { self[2] }
|
|
||||||
fn h (&self) -> N { self[3] }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)] #[test] fn test_area () { assert_eq!(Area::center(&[10u16, 10, 20, 20]), [20, 20]); }
|
|
||||||
#[cfg(test)] proptest! {
|
|
||||||
#[test] fn proptest_area (
|
|
||||||
x in u16::MIN..u16::MAX,
|
|
||||||
y in u16::MIN..u16::MAX,
|
|
||||||
w in u16::MIN..u16::MAX,
|
|
||||||
h in u16::MIN..u16::MAX,
|
|
||||||
a in u16::MIN..u16::MAX,
|
|
||||||
b in u16::MIN..u16::MAX,
|
|
||||||
) {
|
|
||||||
let _: [u16;4] = <[u16;4] as Area<u16>>::zero();
|
|
||||||
let _: [u16;4] = <[u16;4] as Area<u16>>::from_position([a, b]);
|
|
||||||
let _: [u16;4] = <[u16;4] as Area<u16>>::from_size([a, b]);
|
|
||||||
let area: [u16;4] = [x, y, w, h];
|
|
||||||
let _ = area.expect_min(a, b);
|
|
||||||
let _ = area.xy();
|
|
||||||
let _ = area.wh();
|
|
||||||
let _ = area.xywh();
|
|
||||||
let _ = area.clip_h(a);
|
|
||||||
let _ = area.clip_w(b);
|
|
||||||
let _ = area.clip([a, b]);
|
|
||||||
let _ = area.set_w(a);
|
|
||||||
let _ = area.set_h(b);
|
|
||||||
let _ = area.x2();
|
|
||||||
let _ = area.y2();
|
|
||||||
let _ = area.lrtb();
|
|
||||||
let _ = area.center();
|
|
||||||
let _ = area.center_x(a);
|
|
||||||
let _ = area.center_y(b);
|
|
||||||
let _ = area.center_xy([a, b]);
|
|
||||||
let _ = area.centered();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::size::*; mod size {
|
|
||||||
use super::*;
|
|
||||||
/// The size of something.
|
|
||||||
pub trait Size<N: Coordinate>: From<[N;2]> + Debug/* + Copy*/ {
|
|
||||||
fn zero () -> [N;2] { [N::zero(), N::zero()] }
|
|
||||||
fn x (&self) -> N;
|
|
||||||
fn y (&self) -> N;
|
|
||||||
fn w (&self) -> N { self.x() }
|
|
||||||
fn h (&self) -> N { self.y() }
|
|
||||||
fn wh (&self) -> [N;2] { [self.x(), self.y()] }
|
|
||||||
fn clip_w (&self, w: N) -> [N;2] { [self.w().min(w), self.h()] }
|
|
||||||
fn clip_h (&self, h: N) -> [N;2] { [self.w(), self.h().min(h)] }
|
|
||||||
fn to_area_pos (&self) -> [N;4] { let [x, y] = self.wh(); [x, y, 0.into(), 0.into()] }
|
|
||||||
fn to_area_size (&self) -> [N;4] { let [w, h] = self.wh(); [0.into(), 0.into(), w, h] }
|
|
||||||
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<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] } }
|
|
||||||
#[cfg(test)] proptest! {
|
|
||||||
#[test] fn proptest_size (
|
|
||||||
x in u16::MIN..u16::MAX,
|
|
||||||
y in u16::MIN..u16::MAX,
|
|
||||||
a in u16::MIN..u16::MAX,
|
|
||||||
b in u16::MIN..u16::MAX,
|
|
||||||
) {
|
|
||||||
let size = [x, y];
|
|
||||||
let _ = size.w();
|
|
||||||
let _ = size.h();
|
|
||||||
let _ = size.wh();
|
|
||||||
let _ = size.clip_w(a);
|
|
||||||
let _ = size.clip_h(b);
|
|
||||||
let _ = size.expect_min(a, b);
|
|
||||||
let _ = size.to_area_pos();
|
|
||||||
let _ = size.to_area_size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub trait HasSize<E: Out> {
|
|
||||||
fn size (&self) -> &Measure<E>;
|
|
||||||
fn width (&self) -> usize { self.size().w() }
|
|
||||||
fn height (&self) -> usize { self.size().h() }
|
|
||||||
}
|
|
||||||
impl<E: Out, T: Has<Measure<E>>> HasSize<E> for T { fn size (&self) -> &Measure<E> { self.get() } }
|
|
||||||
|
|
||||||
/// A widget that tracks its rendered width and height
|
|
||||||
#[derive(Default)] pub struct Measure<O: Out> { __: PhantomData<O>, pub x: Arc<AtomicUsize>, pub y: Arc<AtomicUsize>, }
|
|
||||||
impl<O: Out> Clone for Measure<O> { fn clone (&self) -> Self { Self { __: Default::default(), x: self.x.clone(), y: self.y.clone(), } } }
|
|
||||||
impl<O: Out> Layout<O> for Measure<O> {}
|
|
||||||
impl<O: Out> PartialEq for Measure<O> {
|
|
||||||
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<O: Out> Draw<O> for Measure<O> {
|
|
||||||
fn draw (&self, to: &mut O) {
|
|
||||||
self.x.store(to.area().w().into(), Relaxed);
|
|
||||||
self.y.store(to.area().h().into(), Relaxed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<O: Out> Debug for Measure<O> {
|
|
||||||
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<O: Out> Measure<O> {
|
|
||||||
pub fn set_w (&self, w: impl Into<usize>) -> &Self { self.x.store(w.into(), Relaxed); self }
|
|
||||||
pub fn set_h (&self, h: impl Into<usize>) -> &Self { self.y.store(h.into(), Relaxed); self }
|
|
||||||
pub fn set_wh (&self, w: impl Into<usize>, h: impl Into<usize>) -> &Self { self.set_w(w); self.set_h(h); self }
|
|
||||||
pub fn format (&self) -> Arc<str> { format!("{}x{}", self.w(), self.h()).into() }
|
|
||||||
pub fn of <T: Draw<O>> (&self, item: T) -> Bsp<Fill<&Self>, T> { Bsp::b(Fill::XY(self), item) }
|
|
||||||
pub fn new (x: O::Unit, y: O::Unit) -> Self {
|
|
||||||
Self { __: PhantomData::default(), x: Arc::new(x.into()), y: Arc::new(y.into()), }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<O: Out> From<[O::Unit; 2]> for Measure<O> {
|
|
||||||
fn from ([x, y]: [O::Unit; 2]) -> Self { Self::new(x, y) }
|
|
||||||
}
|
|
||||||
//impl<O: Out> Size<O::Unit> for Measure<O> {
|
|
||||||
//fn x (&self) -> O::Unit { self.x.load(Relaxed).into() }
|
|
||||||
//fn y (&self) -> O::Unit { self.y.load(Relaxed).into() }
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::layout::*; mod layout {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
/// Drawable area of display.
|
|
||||||
pub trait Layout<O: Out> {
|
|
||||||
fn x (&self, to: O::Area) -> O::Unit {
|
|
||||||
to.x()
|
|
||||||
}
|
|
||||||
fn y (&self, to: O::Area) -> O::Unit {
|
|
||||||
to.y()
|
|
||||||
}
|
|
||||||
fn min_w (&self, _to: O::Area) -> O::Unit {
|
|
||||||
0.into()
|
|
||||||
}
|
|
||||||
fn max_w (&self, to: O::Area) -> O::Unit {
|
|
||||||
to.w()
|
|
||||||
}
|
|
||||||
fn w (&self, to: O::Area) -> O::Unit {
|
|
||||||
to.w().max(self.min_w(to)).min(self.max_w(to))
|
|
||||||
}
|
|
||||||
fn min_h (&self, _to: O::Area) -> O::Unit {
|
|
||||||
0.into()
|
|
||||||
}
|
|
||||||
fn max_h (&self, to: O::Area) -> O::Unit {
|
|
||||||
to.h()
|
|
||||||
}
|
|
||||||
fn h (&self, to: O::Area) -> O::Unit {
|
|
||||||
to.h().max(self.min_h(to)).min(self.max_h(to))
|
|
||||||
}
|
|
||||||
fn layout (&self, to: O::Area) -> O::Area {
|
|
||||||
[self.x(to), self.y(to), self.w(to), self.h(to)].into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: Out> Layout<O> for () {
|
|
||||||
fn x (&self, a: O::Area) -> O::Unit { a.x() }
|
|
||||||
fn y (&self, a: O::Area) -> O::Unit { a.y() }
|
|
||||||
fn w (&self, _: O::Area) -> O::Unit { 0.into() }
|
|
||||||
fn min_w (&self, _: O::Area) -> O::Unit { 0.into() }
|
|
||||||
fn max_w (&self, _: O::Area) -> O::Unit { 0.into() }
|
|
||||||
fn h (&self, _: O::Area) -> O::Unit { 0.into() }
|
|
||||||
fn min_h (&self, _: O::Area) -> O::Unit { 0.into() }
|
|
||||||
fn max_h (&self, _: O::Area) -> O::Unit { 0.into() }
|
|
||||||
fn layout (&self, a: O::Area) -> O::Area { [a.x(), a.y(), 0.into(), 0.into()].into() }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: Out, L: Layout<O>> Layout<O> for &L {
|
|
||||||
fn x (&self, a: O::Area) -> O::Unit { (*self).x(a) }
|
|
||||||
fn y (&self, a: O::Area) -> O::Unit { (*self).y(a) }
|
|
||||||
fn w (&self, a: O::Area) -> O::Unit { (*self).w(a) }
|
|
||||||
fn min_w (&self, a: O::Area) -> O::Unit { (*self).min_w(a) }
|
|
||||||
fn max_w (&self, a: O::Area) -> O::Unit { (*self).max_w(a) }
|
|
||||||
fn h (&self, a: O::Area) -> O::Unit { (*self).h(a) }
|
|
||||||
fn min_h (&self, a: O::Area) -> O::Unit { (*self).min_h(a) }
|
|
||||||
fn max_h (&self, a: O::Area) -> O::Unit { (*self).max_h(a) }
|
|
||||||
fn layout (&self, a: O::Area) -> O::Area { (*self).layout(a) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: Out, L: Layout<O>> Layout<O> for &mut L {
|
|
||||||
fn x (&self, a: O::Area) -> O::Unit { (**self).x(a) }
|
|
||||||
fn y (&self, a: O::Area) -> O::Unit { (**self).y(a) }
|
|
||||||
fn w (&self, a: O::Area) -> O::Unit { (**self).w(a) }
|
|
||||||
fn min_w (&self, a: O::Area) -> O::Unit { (**self).min_w(a) }
|
|
||||||
fn max_w (&self, a: O::Area) -> O::Unit { (**self).max_w(a) }
|
|
||||||
fn h (&self, a: O::Area) -> O::Unit { (**self).h(a) }
|
|
||||||
fn min_h (&self, a: O::Area) -> O::Unit { (**self).min_h(a) }
|
|
||||||
fn max_h (&self, a: O::Area) -> O::Unit { (**self).max_h(a) }
|
|
||||||
fn layout (&self, a: O::Area) -> O::Area { (**self).layout(a) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: Out, L: Layout<O>> Layout<O> for Arc<L> {
|
|
||||||
fn x (&self, a: O::Area) -> O::Unit { (**self).x(a) }
|
|
||||||
fn y (&self, a: O::Area) -> O::Unit { (**self).y(a) }
|
|
||||||
fn w (&self, a: O::Area) -> O::Unit { (**self).w(a) }
|
|
||||||
fn min_w (&self, a: O::Area) -> O::Unit { (**self).min_w(a) }
|
|
||||||
fn max_w (&self, a: O::Area) -> O::Unit { (**self).max_w(a) }
|
|
||||||
fn h (&self, a: O::Area) -> O::Unit { (**self).h(a) }
|
|
||||||
fn min_h (&self, a: O::Area) -> O::Unit { (**self).min_h(a) }
|
|
||||||
fn max_h (&self, a: O::Area) -> O::Unit { (**self).max_h(a) }
|
|
||||||
fn layout (&self, a: O::Area) -> O::Area { (**self).layout(a) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: Out> Layout<O> for Box<dyn Layout<O>> {
|
|
||||||
fn x (&self, a: O::Area) -> O::Unit { (**self).x(a) }
|
|
||||||
fn y (&self, a: O::Area) -> O::Unit { (**self).y(a) }
|
|
||||||
fn w (&self, a: O::Area) -> O::Unit { (**self).w(a) }
|
|
||||||
fn min_w (&self, a: O::Area) -> O::Unit { (**self).min_w(a) }
|
|
||||||
fn max_w (&self, a: O::Area) -> O::Unit { (**self).max_w(a) }
|
|
||||||
fn h (&self, a: O::Area) -> O::Unit { (**self).h(a) }
|
|
||||||
fn min_h (&self, a: O::Area) -> O::Unit { (**self).min_h(a) }
|
|
||||||
fn max_h (&self, a: O::Area) -> O::Unit { (**self).max_h(a) }
|
|
||||||
fn layout (&self, a: O::Area) -> O::Area { (**self).layout(a) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: Out, L: Layout<O>> Layout<O> for RwLock<L> {
|
|
||||||
fn x (&self, a: O::Area) -> O::Unit { self.read().unwrap().x(a) }
|
|
||||||
fn y (&self, a: O::Area) -> O::Unit { self.read().unwrap().y(a) }
|
|
||||||
fn w (&self, a: O::Area) -> O::Unit { self.read().unwrap().w(a) }
|
|
||||||
fn min_w (&self, a: O::Area) -> O::Unit { self.read().unwrap().min_w(a) }
|
|
||||||
fn max_w (&self, a: O::Area) -> O::Unit { self.read().unwrap().max_w(a) }
|
|
||||||
fn h (&self, a: O::Area) -> O::Unit { self.read().unwrap().h(a) }
|
|
||||||
fn min_h (&self, a: O::Area) -> O::Unit { self.read().unwrap().min_h(a) }
|
|
||||||
fn max_h (&self, a: O::Area) -> O::Unit { self.read().unwrap().max_h(a) }
|
|
||||||
fn layout (&self, a: O::Area) -> O::Area { self.read().unwrap().layout(a) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: Out, L: Layout<O>> Layout<O> for Option<L> {
|
|
||||||
fn x (&self, to: O::Area) -> O::Unit {
|
|
||||||
self.as_ref().map(|c|c.x(to)).unwrap_or(to.x())
|
|
||||||
}
|
|
||||||
fn y (&self, to: O::Area) -> O::Unit {
|
|
||||||
self.as_ref().map(|c|c.y(to)).unwrap_or(to.y())
|
|
||||||
}
|
|
||||||
fn min_w (&self, to: O::Area) -> O::Unit {
|
|
||||||
self.as_ref().map(|c|c.min_w(to)).unwrap_or(0.into())
|
|
||||||
}
|
|
||||||
fn max_w (&self, to: O::Area) -> O::Unit {
|
|
||||||
self.as_ref().map(|c|c.max_w(to)).unwrap_or(0.into())
|
|
||||||
}
|
|
||||||
fn w (&self, to: O::Area) -> O::Unit {
|
|
||||||
self.as_ref().map(|c|c.w(to)).unwrap_or(0.into())
|
|
||||||
}
|
|
||||||
fn min_h (&self, to: O::Area) -> O::Unit {
|
|
||||||
self.as_ref().map(|c|c.min_h(to)).unwrap_or(0.into())
|
|
||||||
}
|
|
||||||
fn max_h (&self, to: O::Area) -> O::Unit {
|
|
||||||
self.as_ref().map(|c|c.max_h(to)).unwrap_or(0.into())
|
|
||||||
}
|
|
||||||
fn h (&self, to: O::Area) -> O::Unit {
|
|
||||||
self.as_ref().map(|c|c.h(to)).unwrap_or(0.into())
|
|
||||||
}
|
|
||||||
fn layout (&self, to: O::Area) -> O::Area {
|
|
||||||
self.as_ref().map(|c|c.layout([self.x(to), self.y(to), self.w(to), self.h(to)].into()))
|
|
||||||
.unwrap_or([to.x(), to.y(), 0.into(), 0.into()].into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Bounded<O: Out, D>(pub O::Area, pub D);
|
|
||||||
|
|
||||||
impl<O: Out, D: Content<O>> HasContent<O> for Bounded<O, D> {
|
|
||||||
fn content (&self) -> impl Content<O> {
|
|
||||||
&self.1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: Out, T: Draw<O>> Draw<O> for Bounded<O, T> {
|
|
||||||
fn draw (&self, to: &mut O) {
|
|
||||||
let area = to.area();
|
|
||||||
*to.area_mut() = self.0;
|
|
||||||
self.1.draw(to);
|
|
||||||
*to.area_mut() = area;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
pub struct Lazy<O, T, F>(F, PhantomData<(O, T)>);
|
|
||||||
impl<O: Out, T: Content<O>, F: Fn()->T> Lazy<O, T, F> { pub const fn new (thunk: F) -> Self { Self(thunk, PhantomData) } }
|
|
||||||
|
|
||||||
pub struct Thunk<O: Out, F: Fn(&mut O)>(PhantomData<O>, F);
|
|
||||||
impl<O: Out, F: Fn(&mut O)> Thunk<O, F> { pub const fn new (draw: F) -> Self { Self(PhantomData, draw) } }
|
|
||||||
impl<O: Out, F: Fn(&mut O)> Layout<O> for Thunk<O, F> {}
|
|
||||||
impl<O: Out, F: Fn(&mut O)> Draw<O> for Thunk<O, F> {
|
|
||||||
fn draw (&self, to: &mut O) { (self.1)(to) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)] pub struct Memo<T, U> { pub value: T, pub view: Arc<RwLock<U>> }
|
|
||||||
impl<T: PartialEq, U> Memo<T, U> {
|
|
||||||
pub fn new (value: T, view: U) -> Self { Self { value, view: Arc::new(view.into()) } }
|
|
||||||
pub fn update <R> (&mut self, newval: T, draw: impl Fn(&mut U, &T, &T)->R) -> Option<R> {
|
|
||||||
if newval != self.value {
|
|
||||||
let result = draw(&mut*self.view.write().unwrap(), &newval, &self.value);
|
|
||||||
self.value = newval;
|
|
||||||
return Some(result);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear a pre-allocated buffer, then write into it.
|
|
||||||
#[macro_export] macro_rules! rewrite { ($buf:ident, $($rest:tt)*) => { |$buf,_,_|{ $buf.clear(); write!($buf, $($rest)*) } } }
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
use ::dizzle::{Language, Expression, Symbol, Namespace};
|
|
||||||
|
|
||||||
/// FIXME: This macro should be some variant of `eval`, too.
|
|
||||||
/// But taking into account the different signatures (resolving them into 1?)
|
|
||||||
#[macro_export] macro_rules! draw {
|
|
||||||
($State:ident: $Output:ident: $layers:expr) => {
|
|
||||||
impl Draw<$Output> for $State {
|
|
||||||
fn draw (&self, to: &mut $Output) {
|
|
||||||
for layer in $layers { layer(self, to) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// FIXME: This is generic: should be called `eval` and be part of [dizzle].
|
|
||||||
#[macro_export] macro_rules! view {
|
|
||||||
($State:ident: $Output:ident: $namespaces:expr) => {
|
|
||||||
impl View<$Output, ()> for $State {
|
|
||||||
fn view_expr <'a> (&'a self, to: &mut $Output, expr: &'a impl Expression) -> Usually<()> {
|
|
||||||
for namespace in $namespaces { if namespace(self, to, expr)? { return Ok(()) } }
|
|
||||||
Err(format!("{}::<{}, ()>::view_expr: unexpected: {expr:?}",
|
|
||||||
stringify! { $State },
|
|
||||||
stringify! { $Output }).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// FIXME: This is generic: should be called `Eval` and be part of [dizzle].
|
|
||||||
/// Matches [Language] expressions to renderings for a given [Output] target.
|
|
||||||
pub trait View<O, U> {
|
|
||||||
fn view_expr <'a> (&'a self, _output: &mut O, expr: &'a impl Expression) -> Usually<U> {
|
|
||||||
Err(format!("View::view_expr: no exprs defined: {expr:?}").into())
|
|
||||||
}
|
|
||||||
fn view_word <'a> (&'a self, _output: &mut O, word: &'a impl Symbol) -> Usually<U> {
|
|
||||||
Err(format!("View::view_word: no words defined: {word:?}").into())
|
|
||||||
}
|
|
||||||
fn view <'a> (&'a self, output: &mut O, dsl: &'a impl Language) -> Usually<U> {
|
|
||||||
let is_expr = dsl.expr();
|
|
||||||
let is_word = dsl.word();
|
|
||||||
match (dsl.expr(), dsl.word()) {
|
|
||||||
(Ok(Some(e)), _ ) => self.view_expr(output, &e),
|
|
||||||
(_, Ok(Some(w))) => self.view_word(output, &w),
|
|
||||||
(Err(e), _ ) => Err(format!("invalid view expr:\n{dsl:?}\n{e}").into()),
|
|
||||||
(_, Err(w) ) => Err(format!("invalid view word:\n{dsl:?}\n{w}").into()),
|
|
||||||
(Ok(None), Ok(None) ) => Err(format!("empty view:\n{dsl:?}").into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn evaluate_output_expression <'a, O: Out + 'a, S> (
|
|
||||||
state: &S, output: &mut O, expr: &'a impl Expression
|
|
||||||
) -> Usually<bool> where
|
|
||||||
S: View<O, ()>
|
|
||||||
+ for<'b>Namespace<'b, bool>
|
|
||||||
+ for<'b>Namespace<'b, O::Unit>
|
|
||||||
{
|
|
||||||
// First element of expression is used for dispatch.
|
|
||||||
// Dispatch is proto-namespaced using separator character
|
|
||||||
let head = expr.head()?;
|
|
||||||
let mut frags = head.src()?.unwrap_or_default().split("/");
|
|
||||||
// The rest of the tokens in the expr are arguments.
|
|
||||||
// Their meanings depend on the dispatched operation
|
|
||||||
let args = expr.tail();
|
|
||||||
let arg0 = args.head();
|
|
||||||
let tail0 = args.tail();
|
|
||||||
let arg1 = tail0.head();
|
|
||||||
let tail1 = tail0.tail();
|
|
||||||
let arg2 = tail1.head();
|
|
||||||
// And we also have to do the above binding dance
|
|
||||||
// so that the Perhaps<token>s remain in scope.
|
|
||||||
match frags.next() {
|
|
||||||
|
|
||||||
Some("when") => output.place(&When::new(
|
|
||||||
state.resolve(arg0?)?.unwrap(),
|
|
||||||
Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap())
|
|
||||||
)),
|
|
||||||
|
|
||||||
Some("either") => output.place(&Either::new(
|
|
||||||
state.resolve(arg0?)?.unwrap(),
|
|
||||||
Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap()),
|
|
||||||
Thunk::new(move|output: &mut O|state.view(output, &arg2).unwrap())
|
|
||||||
)),
|
|
||||||
|
|
||||||
Some("bsp") => output.place(&{
|
|
||||||
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
|
|
||||||
let b = Thunk::new(move|output: &mut O|state.view(output, &arg1).unwrap());
|
|
||||||
match frags.next() {
|
|
||||||
Some("n") => Bsp::n(a, b),
|
|
||||||
Some("s") => Bsp::s(a, b),
|
|
||||||
Some("e") => Bsp::e(a, b),
|
|
||||||
Some("w") => Bsp::w(a, b),
|
|
||||||
Some("a") => Bsp::a(a, b),
|
|
||||||
Some("b") => Bsp::b(a, b),
|
|
||||||
frag => unimplemented!("bsp/{frag:?}")
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
Some("align") => output.place(&{
|
|
||||||
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
|
|
||||||
match frags.next() {
|
|
||||||
Some("n") => Align::n(a),
|
|
||||||
Some("s") => Align::s(a),
|
|
||||||
Some("e") => Align::e(a),
|
|
||||||
Some("w") => Align::w(a),
|
|
||||||
Some("x") => Align::x(a),
|
|
||||||
Some("y") => Align::y(a),
|
|
||||||
Some("c") => Align::c(a),
|
|
||||||
frag => unimplemented!("align/{frag:?}")
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
Some("fill") => output.place(&{
|
|
||||||
let a = Thunk::new(move|output: &mut O|state.view(output, &arg0).unwrap());
|
|
||||||
match frags.next() {
|
|
||||||
Some("xy") | None => Fill::XY(a),
|
|
||||||
Some("x") => Fill::X(a),
|
|
||||||
Some("y") => Fill::Y(a),
|
|
||||||
frag => unimplemented!("fill/{frag:?}")
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
Some("fixed") => output.place(&{
|
|
||||||
let axis = frags.next();
|
|
||||||
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
|
|
||||||
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
|
|
||||||
match axis {
|
|
||||||
Some("xy") | None => Fixed::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb),
|
|
||||||
Some("x") => Fixed::X(state.resolve(arg0?)?.unwrap(), cb),
|
|
||||||
Some("y") => Fixed::Y(state.resolve(arg0?)?.unwrap(), cb),
|
|
||||||
frag => unimplemented!("fixed/{frag:?} ({expr:?}) ({head:?}) ({:?})",
|
|
||||||
head.src()?.unwrap_or_default().split("/").next())
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
Some("min") => output.place(&{
|
|
||||||
let axis = frags.next();
|
|
||||||
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
|
|
||||||
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
|
|
||||||
match axis {
|
|
||||||
Some("xy") | None => Min::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb),
|
|
||||||
Some("x") => Min::X(state.resolve(arg0?)?.unwrap(), cb),
|
|
||||||
Some("y") => Min::Y(state.resolve(arg0?)?.unwrap(), cb),
|
|
||||||
frag => unimplemented!("min/{frag:?}")
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
Some("max") => output.place(&{
|
|
||||||
let axis = frags.next();
|
|
||||||
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
|
|
||||||
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
|
|
||||||
match axis {
|
|
||||||
Some("xy") | None => Max::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb),
|
|
||||||
Some("x") => Max::X(state.resolve(arg0?)?.unwrap(), cb),
|
|
||||||
Some("y") => Max::Y(state.resolve(arg0?)?.unwrap(), cb),
|
|
||||||
frag => unimplemented!("max/{frag:?}")
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
Some("push") => output.place(&{
|
|
||||||
let axis = frags.next();
|
|
||||||
let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("fixed: unsupported axis {axis:?}") };
|
|
||||||
let cb = Thunk::new(move|output: &mut O|state.view(output, &arg).unwrap());
|
|
||||||
match axis {
|
|
||||||
Some("xy") | None => Push::XY(state.resolve(arg0?)?.unwrap(), state.resolve(arg1?)?.unwrap(), cb),
|
|
||||||
Some("x") => Push::X(state.resolve(arg0?)?.unwrap(), cb),
|
|
||||||
Some("y") => Push::Y(state.resolve(arg0?)?.unwrap(), cb),
|
|
||||||
frag => unimplemented!("push/{frag:?}")
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
_ => return Ok(false)
|
|
||||||
|
|
||||||
};
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
mod widget_border; pub use self::widget_border::*;
|
|
||||||
mod widget_form; pub use self::widget_form::*;
|
|
||||||
mod widget_style; pub use self::widget_style::*;
|
|
||||||
mod widget_tryptich; pub use self::widget_tryptich::*;
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
pub struct Border<S>(pub bool, pub S);
|
|
||||||
impl<O: Out, S: Layout<O>> Layout<O> for Border<S> {
|
|
||||||
fn layout (&self, area: O::Area) -> O::Area {
|
|
||||||
self.1.layout(area)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Bordered<S, W>(pub bool, pub S, pub W);
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
pub struct FieldH<Theme, Label, Value>(pub Theme, pub Label, pub Value);
|
|
||||||
impl<O: Out, T, L: Content<O>, V: Content<O>> HasContent<O> for FieldH<T, L, V> {
|
|
||||||
fn content (&self) -> impl Content<O> { Bsp::e(&self.1, &self.2) }
|
|
||||||
}
|
|
||||||
impl<O: Out, T, L: Content<O>, V: Content<O>> Layout<O> for FieldH<T, L, V> {
|
|
||||||
fn layout (&self, to: O::Area) -> O::Area { self.content().layout(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, T, L: Content<O>, V: Content<O>> Draw<O> for FieldH<T, L, V> {
|
|
||||||
fn draw (&self, to: &mut O) { self.content().draw(to) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FieldV<Theme, Label, Value>(pub Theme, pub Label, pub Value);
|
|
||||||
impl<O: Out, T, L: Content<O>, V: Content<O>> HasContent<O> for FieldV<T, L, V> {
|
|
||||||
fn content (&self) -> impl Content<O> { Bsp::s(&self.1, &self.2) }
|
|
||||||
}
|
|
||||||
impl<O: Out, T, L: Content<O>, V: Content<O>> Layout<O> for FieldV<T, L, V> {
|
|
||||||
fn layout (&self, to: O::Area) -> O::Area { self.content().layout(to) }
|
|
||||||
}
|
|
||||||
impl<O: Out, T, L: Content<O>, V: Content<O>> Draw<O> for FieldV<T, L, V> {
|
|
||||||
fn draw (&self, to: &mut O) { self.content().draw(to) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
pub struct Field<C, T, U> {
|
|
||||||
pub direction: Direction,
|
|
||||||
pub label: Option<T>,
|
|
||||||
pub label_fg: Option<C>,
|
|
||||||
pub label_bg: Option<C>,
|
|
||||||
pub label_align: Option<Direction>,
|
|
||||||
pub value: Option<U>,
|
|
||||||
pub value_fg: Option<C>,
|
|
||||||
pub value_bg: Option<C>,
|
|
||||||
pub value_align: Option<Direction>,
|
|
||||||
}
|
|
||||||
impl<C, T, U> Field<C, T, U> {
|
|
||||||
pub fn new (direction: Direction) -> Field<C, (), ()> {
|
|
||||||
Field::<C, (), ()> {
|
|
||||||
direction,
|
|
||||||
label: None, label_fg: None, label_bg: None, label_align: None,
|
|
||||||
value: None, value_fg: None, value_bg: None, value_align: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn label <L> (
|
|
||||||
self, label: Option<L>, align: Option<Direction>, fg: Option<C>, bg: Option<C>
|
|
||||||
) -> Field<C, L, U> {
|
|
||||||
Field::<C, L, U> { label, label_fg: fg, label_bg: bg, label_align: align, ..self }
|
|
||||||
}
|
|
||||||
pub fn value <V> (
|
|
||||||
self, value: Option<V>, align: Option<Direction>, fg: Option<C>, bg: Option<C>
|
|
||||||
) -> Field<C, T, V> {
|
|
||||||
Field::<C, T, V> { value, value_fg: fg, value_bg: bg, value_align: align, ..self }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
#[allow(unused)] use crate::*;
|
|
||||||
|
|
||||||
pub struct Foreground<Color, Item>(pub Color, pub Item);
|
|
||||||
impl<O: Out, Color, Item: Layout<O>> Layout<O> for Foreground<Color, Item> {
|
|
||||||
fn layout (&self, to: O::Area) -> O::Area {
|
|
||||||
self.1.layout(to)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Background<Color, Item>(pub Color, pub Item);
|
|
||||||
impl<O: Out, Color, Item: Layout<O>> Layout<O> for Background<Color, Item> {
|
|
||||||
fn layout (&self, to: O::Area) -> O::Area {
|
|
||||||
self.1.layout(to)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
#[allow(unused)] use crate::*;
|
|
||||||
|
|
||||||
/// A three-column layout.
|
|
||||||
pub struct Tryptich<A, B, C> {
|
|
||||||
pub top: bool,
|
|
||||||
pub h: u16,
|
|
||||||
pub left: (u16, A),
|
|
||||||
pub middle: (u16, B),
|
|
||||||
pub right: (u16, C),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Tryptich<(), (), ()> {
|
|
||||||
pub fn center (h: u16) -> Self {
|
|
||||||
Self { h, top: false, left: (0, ()), middle: (0, ()), right: (0, ()) }
|
|
||||||
}
|
|
||||||
pub fn top (h: u16) -> Self {
|
|
||||||
Self { h, top: true, left: (0, ()), middle: (0, ()), right: (0, ()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B, C> Tryptich<A, B, C> {
|
|
||||||
pub fn left <D> (self, w: u16, content: D) -> Tryptich<D, B, C> {
|
|
||||||
Tryptich { left: (w, content), ..self }
|
|
||||||
}
|
|
||||||
pub fn middle <D> (self, w: u16, content: D) -> Tryptich<A, D, C> {
|
|
||||||
Tryptich { middle: (w, content), ..self }
|
|
||||||
}
|
|
||||||
pub fn right <D> (self, w: u16, content: D) -> Tryptich<A, B, D> {
|
|
||||||
Tryptich { right: (w, content), ..self }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue