mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
start implementing edn loader; remove PhantomData from some tek_layout constructs
This commit is contained in:
parent
f359768ba2
commit
2b07e7963e
20 changed files with 239 additions and 222 deletions
|
|
@ -3,23 +3,23 @@ use crate::*;
|
|||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W }
|
||||
|
||||
pub struct Align<E: Engine, T: Content<E>>(Alignment, T, PhantomData<E>);
|
||||
pub struct Align<T>(Alignment, T);
|
||||
|
||||
impl<E: Engine, T: Content<E>> Align<E, T> {
|
||||
pub fn c (a: T) -> Self { Self(Alignment::Center, a, Default::default()) }
|
||||
pub fn x (a: T) -> Self { Self(Alignment::X, a, Default::default()) }
|
||||
pub fn y (a: T) -> Self { Self(Alignment::Y, a, Default::default()) }
|
||||
pub fn n (a: T) -> Self { Self(Alignment::N, a, Default::default()) }
|
||||
pub fn s (a: T) -> Self { Self(Alignment::S, a, Default::default()) }
|
||||
pub fn e (a: T) -> Self { Self(Alignment::E, a, Default::default()) }
|
||||
pub fn w (a: T) -> Self { Self(Alignment::W, a, Default::default()) }
|
||||
pub fn nw (a: T) -> Self { Self(Alignment::NW, a, Default::default()) }
|
||||
pub fn sw (a: T) -> Self { Self(Alignment::SW, a, Default::default()) }
|
||||
pub fn ne (a: T) -> Self { Self(Alignment::NE, a, Default::default()) }
|
||||
pub fn se (a: T) -> Self { Self(Alignment::SE, a, Default::default()) }
|
||||
impl<T> Align<T> {
|
||||
pub fn c (a: T) -> Self { Self(Alignment::Center, a) }
|
||||
pub fn x (a: T) -> Self { Self(Alignment::X, a) }
|
||||
pub fn y (a: T) -> Self { Self(Alignment::Y, a) }
|
||||
pub fn n (a: T) -> Self { Self(Alignment::N, a) }
|
||||
pub fn s (a: T) -> Self { Self(Alignment::S, a) }
|
||||
pub fn e (a: T) -> Self { Self(Alignment::E, a) }
|
||||
pub fn w (a: T) -> Self { Self(Alignment::W, a) }
|
||||
pub fn nw (a: T) -> Self { Self(Alignment::NW, a) }
|
||||
pub fn sw (a: T) -> Self { Self(Alignment::SW, a) }
|
||||
pub fn ne (a: T) -> Self { Self(Alignment::NE, a) }
|
||||
pub fn se (a: T) -> Self { Self(Alignment::SE, a) }
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Content<E>> Content<E> for Align<E, T> {
|
||||
impl<E: Engine, T: Content<E>> Content<E> for Align<T> {
|
||||
fn content (&self) -> impl Content<E> {
|
||||
&self.1
|
||||
}
|
||||
|
|
@ -45,52 +45,8 @@ impl<E: Engine, T: Content<E>> Content<E> for Align<E, T> {
|
|||
Y => [it.x(), centered.y()],
|
||||
};
|
||||
[x, y, centered.w(), centered.h()].into()
|
||||
//let [cfx, cfy, ..] = on.center();
|
||||
//let [cmx, cmy, ..] = it.center();
|
||||
////let center = |cf, cm, m|if cf >= cm { m + (cf - cm) } else { m.minus(cm - cf) };
|
||||
//let center_x = center(cfx, cmx, it.x());
|
||||
//let center_y = center(cfy, cmy, it.y());
|
||||
//let east_x = on.x() + on.w().minus(it.w());
|
||||
//let south_y = on.y() + on.h().minus(it.h());
|
||||
//let [x, y] = match self.0 {
|
||||
//Alignment::X => [center_x, it.y(), ],
|
||||
//Alignment::Y => [it.x(), center_y,],
|
||||
|
||||
//Alignment::NW => [on.x(), on.y(), ],
|
||||
//Alignment::N => [center_x, on.y(), ],
|
||||
//Alignment::NE => [east_x, on.y(), ],
|
||||
//Alignment::E => [east_x, center_y,],
|
||||
//Alignment::SE => [east_x, south_y, ],
|
||||
//Alignment::S => [center_x, south_y, ],
|
||||
//Alignment::SW => [on.x(), south_y, ],
|
||||
//Alignment::W => [on.x(), center_y,],
|
||||
//};
|
||||
//[x, y, it.w(), it.h()].into()
|
||||
}
|
||||
fn render (&self, render: &mut E::Output) {
|
||||
render.place(self.layout(render.area()), &self.content())
|
||||
}
|
||||
}
|
||||
|
||||
//fn align<E: Engine, T: Content<E>, N: Coordinate, R: Area<N> + From<[N;4]>> (align: &Align<E, T>, outer: R, content: R) -> Option<R> {
|
||||
//if outer.w() < content.w() || outer.h() < content.h() {
|
||||
//None
|
||||
//} else {
|
||||
//let [ox, oy, ow, oh] = outer.xywh();
|
||||
//let [ix, iy, iw, ih] = content.xywh();
|
||||
//Some(match align {
|
||||
//Align::Center(_) => [ox + (ow - iw) / 2.into(), oy + (oh - ih) / 2.into(), iw, ih,].into(),
|
||||
//Align::X(_) => [ox + (ow - iw) / 2.into(), iy, iw, ih,].into(),
|
||||
//Align::Y(_) => [ix, oy + (oh - ih) / 2.into(), iw, ih,].into(),
|
||||
//Align::NW(_) => [ox, oy, iw, ih,].into(),
|
||||
//Align::N(_) => [ox + (ow - iw) / 2.into(), oy, iw, ih,].into(),
|
||||
//Align::NE(_) => [ox + ow - iw, oy, iw, ih,].into(),
|
||||
//Align::W(_) => [ox, oy + (oh - ih) / 2.into(), iw, ih,].into(),
|
||||
//Align::E(_) => [ox + ow - iw, oy + (oh - ih) / 2.into(), iw, ih,].into(),
|
||||
//Align::SW(_) => [ox, oy + oh - ih, iw, ih,].into(),
|
||||
//Align::S(_) => [ox + (ow - iw) / 2.into(), oy + oh - ih, iw, ih,].into(),
|
||||
//Align::SE(_) => [ox + ow - iw, oy + oh - ih, iw, ih,].into(),
|
||||
//_ => unreachable!()
|
||||
//})
|
||||
//}
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ impl Direction {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Bsp<E: Engine, X: Content<E>, Y: Content<E>>(Direction, X, Y, PhantomData<E>);
|
||||
pub struct Bsp<X, Y>(Direction, X, Y);
|
||||
|
||||
impl<E: Engine, A: Content<E>, B: Content<E>> Content<E> for Bsp<E, A, B> {
|
||||
impl<E: Engine, A: Content<E>, B: Content<E>> Content<E> for Bsp<A, B> {
|
||||
fn layout (&self, outer: E::Area) -> E::Area {
|
||||
let [_, _, c] = self.areas(outer);
|
||||
c
|
||||
|
|
@ -35,26 +35,31 @@ impl<E: Engine, A: Content<E>, B: Content<E>> Content<E> for Bsp<E, A, B> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, A: Content<E>, B: Content<E>> Bsp<E, A, B> {
|
||||
pub fn n (a: A, b: B) -> Self { Self(North, a, b, Default::default()) }
|
||||
pub fn s (a: A, b: B) -> Self { Self(South, a, b, Default::default()) }
|
||||
pub fn e (a: A, b: B) -> Self { Self(East, a, b, Default::default()) }
|
||||
pub fn w (a: A, b: B) -> Self { Self(West, a, b, Default::default()) }
|
||||
pub fn a (a: A, b: B) -> Self { Self(Above, a, b, Default::default()) }
|
||||
pub fn b (a: A, b: B) -> Self { Self(Below, a, b, Default::default()) }
|
||||
pub fn contents (&self) -> (&A, &B) { (&self.1, &self.2) }
|
||||
pub fn areas (&self, outer: E::Area) -> [E::Area;3] {
|
||||
impl<A, B> Bsp<A, B> {
|
||||
pub fn n (a: A, b: B) -> Self { Self(North, a, b) }
|
||||
pub fn s (a: A, b: B) -> Self { Self(South, a, b) }
|
||||
pub fn e (a: A, b: B) -> Self { Self(East, a, b) }
|
||||
pub fn w (a: A, b: B) -> Self { Self(West, a, b) }
|
||||
pub fn a (a: A, b: B) -> Self { Self(Above, a, b) }
|
||||
pub fn b (a: A, b: B) -> Self { Self(Below, a, b) }
|
||||
}
|
||||
|
||||
pub trait BspAreas<E: Engine, A: Content<E>, B: Content<E>> {
|
||||
fn direction (&self) -> Direction;
|
||||
fn contents (&self) -> (&A, &B);
|
||||
fn areas (&self, outer: E::Area) -> [E::Area;3] {
|
||||
let direction = self.direction();
|
||||
let [x, y, w, h] = outer.xywh();
|
||||
let (a, b) = self.contents();
|
||||
let [ax, ay, aw, ah] = a.layout(outer).xywh();
|
||||
let [bx, by, bw, bh] = b.layout(match self.0 {
|
||||
let [bx, by, bw, bh] = b.layout(match direction {
|
||||
Above | Below => outer,
|
||||
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(),
|
||||
}).xywh();
|
||||
match self.0 {
|
||||
match direction {
|
||||
Above | Below => {
|
||||
let x = ax.min(bx);
|
||||
let w = (ax+aw).max(bx+bw).minus(x);
|
||||
|
|
@ -90,6 +95,11 @@ impl<E: Engine, A: Content<E>, B: Content<E>> Bsp<E, A, B> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, A: Content<E>, B: Content<E>> BspAreas<E, A, B> for Bsp<A, B> {
|
||||
fn direction (&self) -> Direction { self. 0 }
|
||||
fn contents (&self) -> (&A, &B) { (&self.1, &self.2) }
|
||||
}
|
||||
|
||||
/// Renders multiple things on top of each other,
|
||||
#[macro_export] macro_rules! lay {
|
||||
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::b(bsp, $expr);)*; bsp }}
|
||||
|
|
|
|||
47
layout/src/layout_edn.rs
Normal file
47
layout/src/layout_edn.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
use crate::*;
|
||||
use ::tek_engine::edn::*;
|
||||
|
||||
macro_rules! edn_module {
|
||||
($name:literal = $Host:ident<$E:ident: $Engine:path> { $(
|
||||
(defn $fn:ident
|
||||
$(<$($G:ident: $Generic:ty),+>)?
|
||||
$Struct:ident($($arg:ident : $Arg:ty),*))
|
||||
)* }) => {
|
||||
pub trait $Host<$E: Engine> {
|
||||
pub fn read_one <'e> (edn: &[Edn<'e>]) -> impl Content<$E> {
|
||||
if let Some(Edn::Symbol(name)) = edn.get(0) {
|
||||
match name {
|
||||
$(
|
||||
stringify!($fn) =>
|
||||
),*
|
||||
}
|
||||
} else {
|
||||
panic!("invalid edn")
|
||||
}
|
||||
}
|
||||
$(
|
||||
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//edn_module! {
|
||||
//(host LayoutEdn<E>)
|
||||
//(name "layout")
|
||||
|
||||
//(defn when <A: Content<E>>
|
||||
//When(cond: bool, item: A))
|
||||
|
||||
//(defn either <A: Content<E>, B: Content<E>>
|
||||
//Either(cond: bool, a: A, b: B))
|
||||
|
||||
//(defn map <
|
||||
//A: Content<E>,
|
||||
//B: Content<E>,
|
||||
//I: Iterator<Item = A> + Send + Sync,
|
||||
//F: Fn() -> I + Send + Sync,
|
||||
//G: Fn(A, usize)->B + Send + Sync
|
||||
//>
|
||||
//Map(get_iterator: I, callback: G))
|
||||
//}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
mod align; pub use self::align::*;
|
||||
mod direction; pub use self::direction::*;
|
||||
mod layout_edn; pub use self::edn::*;
|
||||
mod measure; pub use self::measure::*;
|
||||
mod ops; pub use self::ops::*;
|
||||
mod transform_xy; pub use self::transform_xy::*;
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ impl<E: Engine> Measure<E> {
|
|||
y: Arc::new(0.into()),
|
||||
}
|
||||
}
|
||||
pub fn of <T: Content<E>> (&self, item: T) -> Bsp<E, Fill<E, &Self>, T> {
|
||||
pub fn of <T: Content<E>> (&self, item: T) -> Bsp<Fill<E, &Self>, T> {
|
||||
Bsp::b(Fill::xy(&self), item)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,55 +1,11 @@
|
|||
use crate::*;
|
||||
|
||||
impl<E: Engine> Layout<E> for E {}
|
||||
/// Show an item only when a condition is true.
|
||||
pub struct When<A>(pub bool, pub A);
|
||||
|
||||
pub trait Layout<E: Engine> {
|
||||
/// Content `item` when `cond` is true.
|
||||
fn when <A> (cond: bool, item: A) -> When<E, A> where
|
||||
A: Content<E>
|
||||
{
|
||||
When(cond, item, Default::default())
|
||||
}
|
||||
/// Content `item` if `cond` is true, otherwise render `other`.
|
||||
fn either <A, B> (cond: bool, a: A, b: B) -> Either<E, A, B> where
|
||||
A: Content<E>,
|
||||
B: Content<E>,
|
||||
{
|
||||
Either(cond, a, b, Default::default())
|
||||
}
|
||||
/// Maps an [Option<T>] through a callback `F`
|
||||
fn opt <A, F, R> (option: Option<A>, cb: F) -> Opt<E, A, F, R> where
|
||||
F: Fn(A) -> R,
|
||||
R: Content<E>
|
||||
{
|
||||
Opt(option, cb, Default::default())
|
||||
}
|
||||
fn map <T, I, J, R, F>(iterator: J, callback: F) -> Map<E, T, I, J, R, F> where
|
||||
E: Engine,
|
||||
I: Iterator<Item = T> + Send + Sync,
|
||||
J: Fn() -> I + Send + Sync,
|
||||
R: Content<E>,
|
||||
F: Fn(T, usize)->R + Send + Sync
|
||||
{
|
||||
Map(Default::default(), iterator, callback)
|
||||
}
|
||||
//pub fn reduce <E, T, I, R, F>(iterator: I, callback: F) -> Reduce<E, T, I, R, F> where
|
||||
//E: Engine,
|
||||
//I: Iterator<Item = T> + Send + Sync,
|
||||
//R: Content<E>,
|
||||
//F: Fn(R, T, usize) -> R + Send + Sync
|
||||
//{
|
||||
//Reduce(Default::default(), iterator, callback)
|
||||
//}
|
||||
}
|
||||
|
||||
pub struct Opt<E: Engine, A, F: Fn(A)->R, R: Content<E>>(Option<A>, F, PhantomData<E>);
|
||||
|
||||
/// Contents `self.1` when `self.0` is true.
|
||||
pub struct When<E: Engine, A>(bool, A, PhantomData<E>);
|
||||
|
||||
impl<E: Engine, A: Content<E>> Content<E> for When<E, A> {
|
||||
impl<E: Engine, A: Content<E>> Content<E> for When<A> {
|
||||
fn layout (&self, to: E::Area) -> E::Area {
|
||||
let Self(cond, item, ..) = self;
|
||||
let Self(cond, item) = self;
|
||||
let mut area = E::Area::zero();
|
||||
if *cond {
|
||||
let item_area = item.layout(to);
|
||||
|
|
@ -61,45 +17,44 @@ impl<E: Engine, A: Content<E>> Content<E> for When<E, A> {
|
|||
area.into()
|
||||
}
|
||||
fn render (&self, to: &mut E::Output) {
|
||||
let Self(cond, item, ..) = self;
|
||||
let Self(cond, item) = self;
|
||||
if *cond { item.render(to) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Contents `self.1` when `self.0` is true, otherwise renders `self.2`
|
||||
pub struct Either<E: Engine, A, B>(bool, A, B, PhantomData<E>);
|
||||
/// Show one item if a condition is true and another if the condition is false
|
||||
pub struct Either<A, B>(pub bool, pub A, pub B);
|
||||
|
||||
impl<E: Engine, A: Content<E>, B: Content<E>> Content<E> for Either<E, A, B> {
|
||||
impl<E: Engine, A: Content<E>, B: Content<E>> Content<E> for Either<A, B> {
|
||||
fn layout (&self, to: E::Area) -> E::Area {
|
||||
let Self(cond, a, b, ..) = self;
|
||||
let Self(cond, a, b) = self;
|
||||
if *cond { a.layout(to) } else { b.layout(to) }
|
||||
}
|
||||
fn render (&self, to: &mut E::Output) {
|
||||
let Self(cond, a, b, ..) = self;
|
||||
let Self(cond, a, b) = self;
|
||||
if *cond { a.render(to) } else { b.render(to) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Map<E, T, I, J, R, F>(PhantomData<E>, J, F) where
|
||||
E: Engine,
|
||||
I: Iterator<Item = T> + Send + Sync,
|
||||
J: Fn()->I + Send + Sync,
|
||||
R: Content<E>,
|
||||
F: Fn(T, usize)->R + Send + Sync;
|
||||
pub struct Map<A, B, I, F, G>(pub F, pub G) where
|
||||
I: Iterator<Item = A> + Send + Sync,
|
||||
F: Fn() -> I + Send + Sync,
|
||||
G: Fn(A, usize)->B + Send + Sync;
|
||||
|
||||
impl<E, T, I, J, R, F> Content<E> for Map<E, T, I, J, R, F> where
|
||||
impl<E, A, B, I, F, G> Content<E> for Map<A, B, I, F, G> where
|
||||
E: Engine,
|
||||
I: Iterator<Item = T> + Send + Sync,
|
||||
J: Fn()->I + Send + Sync,
|
||||
R: Content<E>,
|
||||
F: Fn(T, usize)->R + Send + Sync
|
||||
B: Content<E>,
|
||||
I: Iterator<Item = A> + Send + Sync,
|
||||
F: Fn() -> I + Send + Sync,
|
||||
G: Fn(A, usize)->B + Send + Sync
|
||||
{
|
||||
fn layout (&self, area: E::Area) -> E::Area {
|
||||
let Self(get_iterator, callback) = 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 (self.1)() {
|
||||
let area = (self.2)(item, index).layout(area).xywh();
|
||||
for item in get_iterator() {
|
||||
let area = callback(item, index).layout(area).xywh();
|
||||
let [x,y,w,h] = area.xywh();
|
||||
min_x = min_x.min(x.into());
|
||||
min_y = min_y.min(y.into());
|
||||
|
|
@ -113,10 +68,11 @@ impl<E, T, I, J, R, F> Content<E> for Map<E, T, I, J, R, F> where
|
|||
area.center_xy([w.into(), h.into()].into()).into()
|
||||
}
|
||||
fn render (&self, to: &mut E::Output) {
|
||||
let Self(get_iterator, callback) = self;
|
||||
let mut index = 0;
|
||||
//let area = self.layout(to.area());
|
||||
for item in (self.1)() {
|
||||
let item = (self.2)(item, index);
|
||||
for item in get_iterator() {
|
||||
let item = callback(item, index);
|
||||
//to.place(area.into(), &item);
|
||||
to.place(to.area().into(), &item);
|
||||
index += 1;
|
||||
|
|
@ -125,6 +81,15 @@ impl<E, T, I, J, R, F> Content<E> for Map<E, T, I, J, R, F> where
|
|||
}
|
||||
|
||||
/*
|
||||
|
||||
//pub fn reduce <E, T, I, R, F>(iterator: I, callback: F) -> Reduce<E, T, I, R, F> where
|
||||
//E: Engine,
|
||||
//I: Iterator<Item = T> + Send + Sync,
|
||||
//R: Content<E>,
|
||||
//F: Fn(R, T, usize) -> R + Send + Sync
|
||||
//{
|
||||
//Reduce(Default::default(), iterator, callback)
|
||||
//}
|
||||
pub struct Reduce<E, T, I, R, F>(PhantomData<(E, R)>, I, F) where
|
||||
E: Engine,
|
||||
I: Iterator<Item = T> + Send + Sync,
|
||||
|
|
@ -141,3 +106,42 @@ impl<E, T, I, R, F> Content<E> for Reduce<E, T, I, R, F> where
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//macro_rules! define_ops {
|
||||
//($Trait:ident<$E:ident:$Engine:path> { $(
|
||||
//$(#[$attr:meta $($attr_args:tt)*])*
|
||||
//(
|
||||
//$fn:ident
|
||||
//$(<$($G:ident$(:$Gen:path)?, )+>)?
|
||||
//$Op:ident
|
||||
//($($arg:ident:$Arg:ty),*)
|
||||
//)
|
||||
//)* }) => {
|
||||
//impl<$E: $Engine> $Trait<E> for E {}
|
||||
//pub trait $Trait<$E: $Engine> {
|
||||
//$(
|
||||
//$(#[$attr $($attr_args)*])*
|
||||
//fn $fn $(<$($G),+>)?
|
||||
//($($arg:$Arg),*)-> $Op<$($(, $G)+)?>
|
||||
//$(where $($G: $($Gen + Send + Sync)?),+)?
|
||||
//{ $Op($($arg),*) }
|
||||
//)*
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
||||
//define_ops! {
|
||||
//Layout<E: Engine> {
|
||||
//(when <A: Content<E>,>
|
||||
//When(cond: bool, item: A))
|
||||
///// When `cond` is `true`, render `a`, otherwise render `b`.
|
||||
//(either <A: Content<E>, B: Content<E>,>
|
||||
//Either(cond: bool, a: A, b: B))
|
||||
///// If `opt` is `Some(T)` renders `cb(t)`, otherwise nothing.
|
||||
//(opt <A, F: Fn(A) -> B, B: Content<E>,>
|
||||
//Opt(option: Option<A>, cb: F))
|
||||
///// Maps items of iterator through callback.
|
||||
//(map <A, B: Content<E>, I: Iterator<Item = A>, F: Fn() -> I, G: Fn(A, usize)->B,>
|
||||
//Map(get_iterator: F, callback: G))
|
||||
//}
|
||||
//}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue