mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 03:36:42 +01:00
This commit is contained in:
parent
34982a12ba
commit
b98fccd98b
1 changed files with 297 additions and 298 deletions
|
|
@ -507,6 +507,303 @@ transform_xy_unit!("padding/x" "padding/y" "padding/xy"|self: Padding, area|{
|
||||||
"y" => Self::y(tail(0)?, tail(1)?),
|
"y" => Self::y(tail(0)?, tail(1)?),
|
||||||
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
|
"xy" => Self::xy(tail(0)?, tail(1)?, tail(2)?),
|
||||||
_ => return Err("invalid max variant".into()) });
|
_ => return Err("invalid max variant".into()) });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lazily-evaluated [Render]able.
|
||||||
|
pub struct Thunk<E: Output, T: Render<E>, F: Fn()->T>(
|
||||||
|
PhantomData<E>,
|
||||||
|
F
|
||||||
|
);
|
||||||
|
impl<E: Output, T: Render<E>, F: Fn()->T> Thunk<E, T, F> {
|
||||||
|
pub const fn new (thunk: F) -> Self {
|
||||||
|
Self(PhantomData, thunk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<E: Output, T: Render<E>, F: Fn()->T> Content<E> for Thunk<E, T, F> {
|
||||||
|
fn content (&self) -> impl Render<E> { (self.1)() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ThunkBox<E: Output>(
|
||||||
|
PhantomData<E>,
|
||||||
|
Box<dyn Fn()->Box<dyn Render<E>>>,
|
||||||
|
);
|
||||||
|
impl<E: Output> ThunkBox<E> {
|
||||||
|
pub const fn new (thunk: Box<dyn Fn()->Box<dyn Render<E>>>) -> Self {
|
||||||
|
Self(PhantomData, thunk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<E: Output> Content<E> for ThunkBox<E> {
|
||||||
|
fn content (&self) -> impl Render<E> { (&self.1)() }
|
||||||
|
}
|
||||||
|
impl<E: Output> From<Box<dyn Fn()->Box<dyn Render<E>>>> for ThunkBox<E> {
|
||||||
|
fn from (f: Box<dyn Fn()->Box<dyn Render<E>>>) -> Self {
|
||||||
|
Self(PhantomData, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//impl<'a, E: Output, F: Fn()->Box<dyn Render<E> + 'a> + 'a> From<F> for ThunkBox<'a, E> {
|
||||||
|
//fn from (f: F) -> Self {
|
||||||
|
//Self(Default::default(), Box::new(f))
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
|
pub struct ThunkRender<E: Output, F: Fn(&mut E)>(PhantomData<E>, F);
|
||||||
|
impl<E: Output, F: Fn(&mut E)> ThunkRender<E, F> {
|
||||||
|
pub fn new (render: F) -> Self { Self(PhantomData, render) }
|
||||||
|
}
|
||||||
|
impl<E: Output, F: Fn(&mut E)> Content<E> for ThunkRender<E, F> {
|
||||||
|
fn render (&self, to: &mut E) { (self.1)(to) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ThunkLayout<
|
||||||
|
E: Output,
|
||||||
|
F1: Fn(E::Area)->E::Area,
|
||||||
|
F2: Fn(&mut E)
|
||||||
|
>(
|
||||||
|
PhantomData<E>,
|
||||||
|
F1,
|
||||||
|
F2
|
||||||
|
);
|
||||||
|
impl<E: Output, F1: Fn(E::Area)->E::Area, F2: Fn(&mut E)> ThunkLayout<E, F1, F2> {
|
||||||
|
pub fn new (layout: F1, render: F2) -> Self { Self(PhantomData, layout, render) }
|
||||||
|
}
|
||||||
|
impl<E, F1, F2> Content<E> for ThunkLayout<E, F1, F2>
|
||||||
|
where
|
||||||
|
E: Output,
|
||||||
|
F1: Fn(E::Area)->E::Area,
|
||||||
|
F2: Fn(&mut E)
|
||||||
|
{
|
||||||
|
fn layout (&self, to: E::Area) -> E::Area { (self.1)(to) }
|
||||||
|
fn render (&self, to: &mut E) { (self.2)(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,
|
||||||
|
render: impl Fn(&mut U, &T, &T)->R
|
||||||
|
) -> Option<R> {
|
||||||
|
if newval != self.value {
|
||||||
|
let result = render(&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)*) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Stack<'t, E, F1> {
|
||||||
|
__: PhantomData<&'t (E, F1)>,
|
||||||
|
direction: Direction,
|
||||||
|
callback: F1
|
||||||
|
}
|
||||||
|
impl<'t, 'u: 't, E, F1> Stack<'t, E, F1> where
|
||||||
|
Self: 't, E: Output, F1: Fn(&mut dyn FnMut(&dyn Render<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<'t, 'u, E, F1> Content<E> for Stack<'t, E, F1> where
|
||||||
|
Self: 't, E: Output, F1: Fn(&mut dyn FnMut(&dyn Render<E>)) + Send + Sync,
|
||||||
|
{
|
||||||
|
fn layout (&self, to: E::Area) -> E::Area {
|
||||||
|
let Self { direction, callback, .. } = self;
|
||||||
|
let (mut x, mut y) = (to.x(), to.y());
|
||||||
|
let (mut w_used, mut w_remaining) = (E::Unit::zero(), to.w());
|
||||||
|
let (mut h_used, mut h_remaining) = (E::Unit::zero(), to.h());
|
||||||
|
callback(&mut move|component: &dyn Render<E>|{
|
||||||
|
let [_, _, w, h] = component.layout([x, y, w_remaining, h_remaining].into()).xywh();
|
||||||
|
match direction {
|
||||||
|
South => { y = y.plus(h);
|
||||||
|
h_used = h_used.plus(h);
|
||||||
|
h_remaining = h_remaining.minus(h);
|
||||||
|
w_used = w_used.max(w); },
|
||||||
|
East => { x = x.plus(w);
|
||||||
|
w_used = w_used.plus(w);
|
||||||
|
w_remaining = w_remaining.minus(w);
|
||||||
|
h_used = h_used.max(h); },
|
||||||
|
North | West => { todo!() },
|
||||||
|
Above | Below => {},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
match direction {
|
||||||
|
North | West => { todo!() },
|
||||||
|
South | East => { [to.x(), to.y(), w_used.into(), h_used.into()].into() },
|
||||||
|
Above | Below => { [to.x(), to.y(), to.w(), to.h()].into() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn render (&self, to: &mut E) {
|
||||||
|
let Self { direction, callback, .. } = self;
|
||||||
|
let (mut x, mut y) = (to.x(), to.y());
|
||||||
|
let (mut w_used, mut w_remaining) = (E::Unit::zero(), to.w());
|
||||||
|
let (mut h_used, mut h_remaining) = (E::Unit::zero(), to.h());
|
||||||
|
callback(&mut move|component: &dyn Render<E>|{
|
||||||
|
let layout = component.layout([x, y, w_remaining, h_remaining].into());
|
||||||
|
match direction {
|
||||||
|
South => {
|
||||||
|
y = y.plus(layout.h());
|
||||||
|
h_remaining = h_remaining.minus(layout.h());
|
||||||
|
h_used = h_used.plus(layout.h()) },
|
||||||
|
East => {
|
||||||
|
x = x.plus(layout.w());
|
||||||
|
w_remaining = w_remaining.minus(layout.w());
|
||||||
|
w_used = w_used.plus(layout.h()) },
|
||||||
|
North | West => { todo!() },
|
||||||
|
Above | Below => {}
|
||||||
|
};
|
||||||
|
to.place(layout, component);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Renders items from an iterator.
|
||||||
|
pub struct Map<E, A, B, I, F, G>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = A> + Send + Sync,
|
||||||
|
F: Fn() -> I + Send + Sync,
|
||||||
|
{
|
||||||
|
__: PhantomData<(E, B)>,
|
||||||
|
/// Function that returns iterator over stacked components
|
||||||
|
get_iter: F,
|
||||||
|
/// Function that returns each stacked component
|
||||||
|
get_item: G,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E, A, B, I, F, G> Map<E, 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, E, A, B, I, F> Map<
|
||||||
|
E, A, Push<E::Unit, Align<Fixed<E::Unit, Fill<B>>>>, I, F, fn(A, usize)->B
|
||||||
|
> where
|
||||||
|
E: Output,
|
||||||
|
B: Render<E>,
|
||||||
|
I: Iterator<Item = A> + Send + Sync + 'a,
|
||||||
|
F: Fn() -> I + Send + Sync + 'a
|
||||||
|
{
|
||||||
|
pub const fn $name (
|
||||||
|
size: E::Unit,
|
||||||
|
get_iter: F,
|
||||||
|
get_item: impl Fn(A, usize)->B + Send + Sync
|
||||||
|
) -> Map<
|
||||||
|
E, A,
|
||||||
|
Push<E::Unit, Align<Fixed<E::Unit, B>>>,
|
||||||
|
I, F,
|
||||||
|
impl Fn(A, usize)->Push<E::Unit, Align<Fixed<E::Unit, B>>> + Send + Sync
|
||||||
|
> {
|
||||||
|
Map {
|
||||||
|
__: PhantomData,
|
||||||
|
get_iter,
|
||||||
|
get_item: move |item: A, index: usize|{
|
||||||
|
// FIXME: multiply
|
||||||
|
let mut push: E::Unit = E::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, E, A, B, I, F, G> Content<E> for Map<E, A, B, I, F, G> where
|
||||||
|
E: Output,
|
||||||
|
B: Render<E>,
|
||||||
|
I: Iterator<Item = A> + Send + Sync + 'a,
|
||||||
|
F: Fn() -> I + Send + Sync + 'a,
|
||||||
|
G: Fn(A, usize)->B + Send + Sync
|
||||||
|
{
|
||||||
|
fn layout (&self, area: E::Area) -> E::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.into());
|
||||||
|
min_y = min_y.min(y.into());
|
||||||
|
max_x = max_x.max((x + w).into());
|
||||||
|
max_y = max_y.max((y + h).into());
|
||||||
|
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()).into()
|
||||||
|
}
|
||||||
|
fn render (&self, to: &mut E) {
|
||||||
|
let Self { get_iter, get_item, .. } = self;
|
||||||
|
let mut index = 0;
|
||||||
|
let area = Content::layout(self, to.area());
|
||||||
|
for item in get_iter() {
|
||||||
|
let item = get_item(item, index);
|
||||||
|
//to.place(area.into(), &item);
|
||||||
|
to.place(item.layout(area), &item);
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline] pub fn map_south<O: Output>(
|
||||||
|
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: Output>(
|
||||||
|
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: Output>(
|
||||||
|
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))))
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
///// The syntagm `(when :condition :content)` corresponds to a [When] layout element.
|
///// The syntagm `(when :condition :content)` corresponds to a [When] layout element.
|
||||||
|
|
@ -674,176 +971,6 @@ transform_xy_unit!("padding/x" "padding/y" "padding/xy"|self: Padding, area|{
|
||||||
//)),
|
//)),
|
||||||
//_ => None
|
//_ => None
|
||||||
//})
|
//})
|
||||||
}
|
|
||||||
|
|
||||||
/// Lazily-evaluated [Render]able.
|
|
||||||
pub struct Thunk<E: Output, T: Render<E>, F: Fn()->T>(
|
|
||||||
PhantomData<E>,
|
|
||||||
F
|
|
||||||
);
|
|
||||||
impl<E: Output, T: Render<E>, F: Fn()->T> Thunk<E, T, F> {
|
|
||||||
pub const fn new (thunk: F) -> Self {
|
|
||||||
Self(PhantomData, thunk)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<E: Output, T: Render<E>, F: Fn()->T> Content<E> for Thunk<E, T, F> {
|
|
||||||
fn content (&self) -> impl Render<E> { (self.1)() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ThunkBox<E: Output>(
|
|
||||||
PhantomData<E>,
|
|
||||||
Box<dyn Fn()->Box<dyn Render<E>>>,
|
|
||||||
);
|
|
||||||
impl<E: Output> ThunkBox<E> {
|
|
||||||
pub const fn new (thunk: Box<dyn Fn()->Box<dyn Render<E>>>) -> Self {
|
|
||||||
Self(PhantomData, thunk)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<E: Output> Content<E> for ThunkBox<E> {
|
|
||||||
fn content (&self) -> impl Render<E> { (&self.1)() }
|
|
||||||
}
|
|
||||||
impl<E: Output> From<Box<dyn Fn()->Box<dyn Render<E>>>> for ThunkBox<E> {
|
|
||||||
fn from (f: Box<dyn Fn()->Box<dyn Render<E>>>) -> Self {
|
|
||||||
Self(PhantomData, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//impl<'a, E: Output, F: Fn()->Box<dyn Render<E> + 'a> + 'a> From<F> for ThunkBox<'a, E> {
|
|
||||||
//fn from (f: F) -> Self {
|
|
||||||
//Self(Default::default(), Box::new(f))
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
|
|
||||||
pub struct ThunkRender<E: Output, F: Fn(&mut E)>(PhantomData<E>, F);
|
|
||||||
impl<E: Output, F: Fn(&mut E)> ThunkRender<E, F> {
|
|
||||||
pub fn new (render: F) -> Self { Self(PhantomData, render) }
|
|
||||||
}
|
|
||||||
impl<E: Output, F: Fn(&mut E)> Content<E> for ThunkRender<E, F> {
|
|
||||||
fn render (&self, to: &mut E) { (self.1)(to) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ThunkLayout<
|
|
||||||
E: Output,
|
|
||||||
F1: Fn(E::Area)->E::Area,
|
|
||||||
F2: Fn(&mut E)
|
|
||||||
>(
|
|
||||||
PhantomData<E>,
|
|
||||||
F1,
|
|
||||||
F2
|
|
||||||
);
|
|
||||||
impl<E: Output, F1: Fn(E::Area)->E::Area, F2: Fn(&mut E)> ThunkLayout<E, F1, F2> {
|
|
||||||
pub fn new (layout: F1, render: F2) -> Self { Self(PhantomData, layout, render) }
|
|
||||||
}
|
|
||||||
impl<E, F1, F2> Content<E> for ThunkLayout<E, F1, F2>
|
|
||||||
where
|
|
||||||
E: Output,
|
|
||||||
F1: Fn(E::Area)->E::Area,
|
|
||||||
F2: Fn(&mut E)
|
|
||||||
{
|
|
||||||
fn layout (&self, to: E::Area) -> E::Area { (self.1)(to) }
|
|
||||||
fn render (&self, to: &mut E) { (self.2)(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,
|
|
||||||
render: impl Fn(&mut U, &T, &T)->R
|
|
||||||
) -> Option<R> {
|
|
||||||
if newval != self.value {
|
|
||||||
let result = render(&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)*) } }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Stack<'t, E, F1> {
|
|
||||||
__: PhantomData<&'t (E, F1)>,
|
|
||||||
direction: Direction,
|
|
||||||
callback: F1
|
|
||||||
}
|
|
||||||
impl<'t, E, F1> Stack<'t, E, F1> where
|
|
||||||
E: Output,
|
|
||||||
F1: Fn(&mut dyn FnMut(&(dyn Render<E> + 't))) + 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<'t, E, F1> Content<E> for Stack<'t, E, F1> where
|
|
||||||
Self: 't,
|
|
||||||
E: Output,
|
|
||||||
F1: Fn(&mut dyn FnMut(&(dyn Render<E> + 't))) + Send + Sync,
|
|
||||||
{
|
|
||||||
fn layout (&self, to: E::Area) -> E::Area {
|
|
||||||
let Self { direction, callback, .. } = self;
|
|
||||||
let (mut x, mut y) = (to.x(), to.y());
|
|
||||||
let (mut w_used, mut w_remaining) = (E::Unit::zero(), to.w());
|
|
||||||
let (mut h_used, mut h_remaining) = (E::Unit::zero(), to.h());
|
|
||||||
callback(&mut move|component|{
|
|
||||||
let [_, _, w, h] = component.layout([x, y, w_remaining, h_remaining].into()).xywh();
|
|
||||||
match direction {
|
|
||||||
South => { y = y.plus(h);
|
|
||||||
h_used = h_used.plus(h);
|
|
||||||
h_remaining = h_remaining.minus(h);
|
|
||||||
w_used = w_used.max(w); },
|
|
||||||
East => { x = x.plus(w);
|
|
||||||
w_used = w_used.plus(w);
|
|
||||||
w_remaining = w_remaining.minus(w);
|
|
||||||
h_used = h_used.max(h); },
|
|
||||||
North | West => { todo!() },
|
|
||||||
Above | Below => {},
|
|
||||||
}
|
|
||||||
});
|
|
||||||
match direction {
|
|
||||||
North | West => { todo!() },
|
|
||||||
South | East => { [to.x(), to.y(), w_used.into(), h_used.into()].into() },
|
|
||||||
Above | Below => { [to.x(), to.y(), to.w(), to.h()].into() },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn render (&self, to: &mut E) {
|
|
||||||
let Self { direction, callback, .. } = self;
|
|
||||||
let (mut x, mut y) = (to.x(), to.y());
|
|
||||||
let (mut w_used, mut w_remaining) = (E::Unit::zero(), to.w());
|
|
||||||
let (mut h_used, mut h_remaining) = (E::Unit::zero(), to.h());
|
|
||||||
callback(&mut move|component|{
|
|
||||||
let layout = component.layout([x, y, w_remaining, h_remaining].into());
|
|
||||||
match direction {
|
|
||||||
South => {
|
|
||||||
y = y.plus(layout.h());
|
|
||||||
h_remaining = h_remaining.minus(layout.h());
|
|
||||||
h_used = h_used.plus(layout.h()) },
|
|
||||||
East => {
|
|
||||||
x = x.plus(layout.w());
|
|
||||||
w_remaining = w_remaining.minus(layout.w());
|
|
||||||
w_used = w_used.plus(layout.h()) },
|
|
||||||
North | West => { todo!() },
|
|
||||||
Above | Below => {}
|
|
||||||
};
|
|
||||||
to.place(layout, component);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Stack::down(|add|{
|
/*Stack::down(|add|{
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
@ -862,131 +989,3 @@ impl<'t, E, F1> Content<E> for Stack<'t, E, F1> where
|
||||||
add(&format!("{}/{i}", self.index))?;
|
add(&format!("{}/{i}", self.index))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}));*/
|
}));*/
|
||||||
|
|
||||||
/// Renders items from an iterator.
|
|
||||||
pub struct Map<E, A, B, I, F, G>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = A> + Send + Sync,
|
|
||||||
F: Fn() -> I + Send + Sync,
|
|
||||||
{
|
|
||||||
__: PhantomData<(E, B)>,
|
|
||||||
/// Function that returns iterator over stacked components
|
|
||||||
get_iter: F,
|
|
||||||
/// Function that returns each stacked component
|
|
||||||
get_item: G,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, E, A, B, I, F, G> Map<E, 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, E, A, B, I, F> Map<
|
|
||||||
E, A, Push<E::Unit, Align<Fixed<E::Unit, Fill<B>>>>, I, F, fn(A, usize)->B
|
|
||||||
> where
|
|
||||||
E: Output,
|
|
||||||
B: Render<E>,
|
|
||||||
I: Iterator<Item = A> + Send + Sync + 'a,
|
|
||||||
F: Fn() -> I + Send + Sync + 'a
|
|
||||||
{
|
|
||||||
pub const fn $name (
|
|
||||||
size: E::Unit,
|
|
||||||
get_iter: F,
|
|
||||||
get_item: impl Fn(A, usize)->B + Send + Sync
|
|
||||||
) -> Map<
|
|
||||||
E, A,
|
|
||||||
Push<E::Unit, Align<Fixed<E::Unit, B>>>,
|
|
||||||
I, F,
|
|
||||||
impl Fn(A, usize)->Push<E::Unit, Align<Fixed<E::Unit, B>>> + Send + Sync
|
|
||||||
> {
|
|
||||||
Map {
|
|
||||||
__: PhantomData,
|
|
||||||
get_iter,
|
|
||||||
get_item: move |item: A, index: usize|{
|
|
||||||
// FIXME: multiply
|
|
||||||
let mut push: E::Unit = E::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, E, A, B, I, F, G> Content<E> for Map<E, A, B, I, F, G> where
|
|
||||||
E: Output,
|
|
||||||
B: Render<E>,
|
|
||||||
I: Iterator<Item = A> + Send + Sync + 'a,
|
|
||||||
F: Fn() -> I + Send + Sync + 'a,
|
|
||||||
G: Fn(A, usize)->B + Send + Sync
|
|
||||||
{
|
|
||||||
fn layout (&self, area: E::Area) -> E::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.into());
|
|
||||||
min_y = min_y.min(y.into());
|
|
||||||
max_x = max_x.max((x + w).into());
|
|
||||||
max_y = max_y.max((y + h).into());
|
|
||||||
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()).into()
|
|
||||||
}
|
|
||||||
fn render (&self, to: &mut E) {
|
|
||||||
let Self { get_iter, get_item, .. } = self;
|
|
||||||
let mut index = 0;
|
|
||||||
let area = Content::layout(self, to.area());
|
|
||||||
for item in get_iter() {
|
|
||||||
let item = get_item(item, index);
|
|
||||||
//to.place(area.into(), &item);
|
|
||||||
to.place(item.layout(area), &item);
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline] pub fn map_south<O: Output>(
|
|
||||||
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: Output>(
|
|
||||||
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: Output>(
|
|
||||||
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))))
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue