mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 19:56:44 +01:00
simplify
This commit is contained in:
parent
291b917970
commit
238ac2e888
25 changed files with 1018 additions and 1147 deletions
|
|
@ -3,6 +3,9 @@
|
|||
#![feature(impl_trait_in_assoc_type)]
|
||||
|
||||
pub(crate) use std::marker::PhantomData;
|
||||
pub(crate) use std::fmt::{Debug, Display};
|
||||
pub(crate) use std::ops::{Add, Sub, Mul, Div};
|
||||
pub(crate) use std::sync::{Arc, atomic::{AtomicUsize, Ordering::Relaxed}};
|
||||
pub(crate) use tengri_core::*;
|
||||
#[cfg(feature = "dsl")] pub(crate) use ::tengri_dsl::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -48,32 +48,21 @@
|
|||
|
||||
use crate::*;
|
||||
use Direction::*;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
mod map; pub use self::map::*;
|
||||
mod memo; pub use self::memo::*;
|
||||
mod stack; pub use self::stack::*;
|
||||
mod thunk; pub use self::thunk::*;
|
||||
|
||||
/// Renders multiple things on top of each other,
|
||||
#[macro_export] macro_rules! lay {
|
||||
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::b(bsp, $expr);)*; bsp }}
|
||||
}
|
||||
|
||||
/// 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 }};
|
||||
}
|
||||
|
||||
#[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 }}
|
||||
}
|
||||
|
||||
#[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 }};
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! row (($($expr:expr),* $(,)?) =>
|
||||
{{ let bsp = (); $(let bsp = Bsp::e(bsp, $expr);)*; bsp }});
|
||||
/// Show an item only when a condition is true.
|
||||
pub struct When<A>(pub bool, pub A);
|
||||
impl<A> When<A> {
|
||||
|
|
@ -408,7 +397,7 @@ transform_xy_unit!("padding/x" "padding/y" "padding/xy"|self: Padding, area|{
|
|||
$op:literal $(/)? [$head: ident, $tail: ident] $expr:expr
|
||||
) => {
|
||||
impl<S,$($($A),+)?> FromDsl<S> for $Struct$(<$($A),+>)? {
|
||||
fn try_from_dsl (
|
||||
fn from_dsl (
|
||||
_state: &S, _dsl: &impl Dsl
|
||||
) -> Perhaps<Self> {
|
||||
todo!()
|
||||
|
|
@ -423,7 +412,7 @@ transform_xy_unit!("padding/x" "padding/y" "padding/xy"|self: Padding, area|{
|
|||
$op:literal $(/)? [$head: ident, $tail: ident] $expr:expr
|
||||
) => {
|
||||
impl<S,$($($A),+)?> FromDsl<S> for $Struct$(<$($A),+>)? {
|
||||
fn try_from_dsl (
|
||||
fn from_dsl (
|
||||
_state: &S, _dsl: &impl Dsl
|
||||
) -> Perhaps<Self> {
|
||||
todo!()
|
||||
|
|
@ -686,3 +675,353 @@ transform_xy_unit!("padding/x" "padding/y" "padding/xy"|self: Padding, area|{
|
|||
//_ => 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<E, F> {
|
||||
__: PhantomData<E>,
|
||||
direction: Direction,
|
||||
callback: F
|
||||
}
|
||||
impl<E, F> Stack<E, F> {
|
||||
pub fn new (direction: Direction, callback: F) -> Self {
|
||||
Self { direction, callback, __: Default::default(), }
|
||||
}
|
||||
pub fn north (callback: F) -> Self {
|
||||
Self::new(North, callback)
|
||||
}
|
||||
pub fn south (callback: F) -> Self {
|
||||
Self::new(South, callback)
|
||||
}
|
||||
pub fn east (callback: F) -> Self {
|
||||
Self::new(East, callback)
|
||||
}
|
||||
pub fn west (callback: F) -> Self {
|
||||
Self::new(West, callback)
|
||||
}
|
||||
}
|
||||
impl<E: Output, F: Fn(&mut dyn FnMut(&dyn Render<E>)->())->()> Content<E> for Stack<E, F> {
|
||||
fn layout (&self, to: E::Area) -> E::Area {
|
||||
let mut x = to.x();
|
||||
let mut y = 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());
|
||||
(self.callback)(&mut move |component: &dyn Render<E>|{
|
||||
let [_, _, w, h] = component.layout([x, y, w_remaining, h_remaining].into()).xywh();
|
||||
match self.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!()
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
});
|
||||
match self.direction {
|
||||
North | West => {
|
||||
todo!()
|
||||
},
|
||||
South | East => {
|
||||
[to.x(), to.y(), w_used.into(), h_used.into()].into()
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
fn render (&self, to: &mut E) {
|
||||
let mut x = to.x();
|
||||
let mut y = 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());
|
||||
(self.callback)(&mut move |component: &dyn Render<E>|{
|
||||
let layout = component.layout([x, y, w_remaining, h_remaining].into());
|
||||
match self.direction {
|
||||
South => {
|
||||
y = y.plus(layout.h());
|
||||
h_remaining = h_remaining.minus(layout.h());
|
||||
h_used = h_used.plus(layout.h());
|
||||
to.place(layout, component);
|
||||
},
|
||||
East => {
|
||||
x = x.plus(layout.w());
|
||||
w_remaining = w_remaining.minus(layout.w());
|
||||
w_used = w_used.plus(layout.h());
|
||||
to.place(layout, component);
|
||||
},
|
||||
North | West => {
|
||||
todo!()
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*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(())
|
||||
}));*/
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 east (
|
||||
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::x(push, Align::w(Fixed::x(size, get_item(item, index))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn south (
|
||||
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
|
||||
> where
|
||||
E: Output,
|
||||
B: Render<E>,
|
||||
I: Iterator<Item = A> + Send + Sync + 'a,
|
||||
F: Fn() -> I + Send + Sync + 'a
|
||||
{
|
||||
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::y(push, Align::n(Fixed::y(size, get_item(item, index))))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
//! Groupings of elements.
|
||||
use crate::*;
|
||||
|
||||
/// A function or closure that emits renderables.
|
||||
pub trait Collector<E: Engine>: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)) {}
|
||||
|
||||
/// Any function or closure that emits renderables for the given engine matches [CollectCallback].
|
||||
impl<E, F> Collector<E> for F
|
||||
where E: Engine, F: Send + Sync + Fn(&mut dyn FnMut(&dyn Render<E>)) {}
|
||||
|
||||
pub trait Render<E: Engine> {
|
||||
fn area (&self, to: E::Area) -> E::Area;
|
||||
fn render (&self, to: &mut E::Output);
|
||||
}
|
||||
|
||||
impl<E: Engine, C: Content<E>> Render<E> for C {
|
||||
fn area (&self, to: E::Area) -> E::Area {
|
||||
Content::area(self, to)
|
||||
}
|
||||
fn render (&self, to: &mut E::Output) {
|
||||
Content::render(self, to)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct Reduce<A, B, I, F, G>(pub PhantomData<A>, pub F, pub G) where
|
||||
A: Send + Sync, B: Send + Sync,
|
||||
I: Iterator<Item = B> + Send + Sync,
|
||||
F: Fn() -> I + Send + Sync,
|
||||
G: Fn(A, B, usize)->A + Send + Sync;
|
||||
|
||||
impl<A, B, I, F, G> Reduce<A, B, I, F, G> where
|
||||
A: Send + Sync, B: Send + Sync,
|
||||
I: Iterator<Item = B> + Send + Sync,
|
||||
F: Fn() -> I + Send + Sync,
|
||||
G: Fn(A, B, usize)->A + Send + Sync
|
||||
{
|
||||
pub const fn new (f: F, g: G) -> Self { Self(Default::default(), f, g) }
|
||||
}
|
||||
|
||||
impl<E: Output, A, B, I, F, G> Content<E> for Reduce<A, B, I, F, G> where
|
||||
A: Send + Sync, B: Send + Sync,
|
||||
I: Iterator<Item = B> + Send + Sync,
|
||||
F: Fn() -> I + Send + Sync,
|
||||
G: Fn(A, B, usize)->A + Send + Sync
|
||||
{
|
||||
fn content (&self) -> impl Render<E> {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
//pub fn reduce <E, T, I, R, F>(iterator: I, callback: F) -> Reduce<E, T, I, R, F> where
|
||||
//E: Output,
|
||||
//I: Iterator<Item = T> + Send + Sync,
|
||||
//R: Render<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: Output,
|
||||
I: Iterator<Item = T> + Send + Sync,
|
||||
R: Render<E>,
|
||||
F: Fn(R, T, usize) -> R + Send + Sync;
|
||||
impl<E, T, I, R, F> Content<E> for Reduce<E, T, I, R, F> where
|
||||
E: Output,
|
||||
I: Iterator<Item = T> + Send + Sync,
|
||||
R: Render<E>,
|
||||
F: Fn(R, T, usize) -> R + Send + Sync
|
||||
{
|
||||
fn render (&self, to: &mut E) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//macro_rules! define_ops {
|
||||
//($Trait:ident<$E:ident:$Output:path> { $(
|
||||
//$(#[$attr:meta $($attr_args:tt)*])*
|
||||
//(
|
||||
//$fn:ident
|
||||
//$(<$($G:ident$(:$Gen:path)?, )+>)?
|
||||
//$Op:ident
|
||||
//($($arg:ident:$Arg:ty),*)
|
||||
//)
|
||||
//)* }) => {
|
||||
//impl<$E: $Output> $Trait<E> for E {}
|
||||
//pub trait $Trait<$E: $Output> {
|
||||
//$(
|
||||
//$(#[$attr $($attr_args)*])*
|
||||
//fn $fn $(<$($G),+>)?
|
||||
//($($arg:$Arg),*)-> $Op<$($(, $G)+)?>
|
||||
//$(where $($G: $($Gen + Send + Sync)?),+)?
|
||||
//{ $Op($($arg),*) }
|
||||
//)*
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
||||
//define_ops! {
|
||||
//Layout<E: Output> {
|
||||
//(when <A: Render<E>,>
|
||||
//When(cond: bool, item: A))
|
||||
///// When `cond` is `true`, render `a`, otherwise render `b`.
|
||||
//(either <A: Render<E>, B: Render<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: Render<E>,>
|
||||
//Opt(option: Option<A>, cb: F))
|
||||
///// Maps items of iterator through callback.
|
||||
//(map <A, B: Render<E>, I: Iterator<Item = A>, F: Fn() -> I, G: Fn(A, usize)->B,>
|
||||
//Map(get_iterator: F, callback: G))
|
||||
//}
|
||||
//}
|
||||
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 east (
|
||||
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::x(push, Align::w(Fixed::x(size, get_item(item, index))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn south (
|
||||
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
|
||||
> where
|
||||
E: Output,
|
||||
B: Render<E>,
|
||||
I: Iterator<Item = A> + Send + Sync + 'a,
|
||||
F: Fn() -> I + Send + Sync + 'a
|
||||
{
|
||||
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::y(push, Align::n(Fixed::y(size, get_item(item, index))))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))))
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
//use crate::*;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
#[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)*) } }
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
use crate::*;
|
||||
use Direction::*;
|
||||
|
||||
pub struct Stack<E, F> {
|
||||
__: PhantomData<E>,
|
||||
direction: Direction,
|
||||
callback: F
|
||||
}
|
||||
impl<E, F> Stack<E, F> {
|
||||
pub fn new (direction: Direction, callback: F) -> Self {
|
||||
Self { direction, callback, __: Default::default(), }
|
||||
}
|
||||
pub fn north (callback: F) -> Self {
|
||||
Self::new(North, callback)
|
||||
}
|
||||
pub fn south (callback: F) -> Self {
|
||||
Self::new(South, callback)
|
||||
}
|
||||
pub fn east (callback: F) -> Self {
|
||||
Self::new(East, callback)
|
||||
}
|
||||
pub fn west (callback: F) -> Self {
|
||||
Self::new(West, callback)
|
||||
}
|
||||
}
|
||||
impl<E: Output, F: Fn(&mut dyn FnMut(&dyn Render<E>)->())->()> Content<E> for Stack<E, F> {
|
||||
fn layout (&self, to: E::Area) -> E::Area {
|
||||
let mut x = to.x();
|
||||
let mut y = 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());
|
||||
(self.callback)(&mut move |component: &dyn Render<E>|{
|
||||
let [_, _, w, h] = component.layout([x, y, w_remaining, h_remaining].into()).xywh();
|
||||
match self.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!()
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
});
|
||||
match self.direction {
|
||||
North | West => {
|
||||
todo!()
|
||||
},
|
||||
South | East => {
|
||||
[to.x(), to.y(), w_used.into(), h_used.into()].into()
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
fn render (&self, to: &mut E) {
|
||||
let mut x = to.x();
|
||||
let mut y = 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());
|
||||
(self.callback)(&mut move |component: &dyn Render<E>|{
|
||||
let layout = component.layout([x, y, w_remaining, h_remaining].into());
|
||||
match self.direction {
|
||||
South => {
|
||||
y = y.plus(layout.h());
|
||||
h_remaining = h_remaining.minus(layout.h());
|
||||
h_used = h_used.plus(layout.h());
|
||||
to.place(layout, component);
|
||||
},
|
||||
East => {
|
||||
x = x.plus(layout.w());
|
||||
w_remaining = w_remaining.minus(layout.w());
|
||||
w_used = w_used.plus(layout.h());
|
||||
to.place(layout, component);
|
||||
},
|
||||
North | West => {
|
||||
todo!()
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*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(())
|
||||
}));*/
|
||||
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
use crate::*;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// 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) }
|
||||
}
|
||||
|
|
@ -1,5 +1,274 @@
|
|||
mod area; pub use self::area::*;
|
||||
mod coordinate; pub use self::coordinate::*;
|
||||
mod direction; pub use self::direction::*;
|
||||
mod measure; pub use self::measure::*;
|
||||
mod size; pub use self::size::*;
|
||||
use crate::*;
|
||||
use Direction::*;
|
||||
|
||||
/// 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 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] }
|
||||
}
|
||||
|
||||
pub trait Size<N: Coordinate>: From<[N;2]> + Debug + Copy {
|
||||
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 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 zero () -> [N;2] {
|
||||
[N::zero(), N::zero()]
|
||||
}
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Coordinate> Size<N> for (N, N) {
|
||||
fn x (&self) -> N { self.0 }
|
||||
fn y (&self) -> N { self.1 }
|
||||
}
|
||||
|
||||
impl<N: Coordinate> Size<N> for [N;2] {
|
||||
fn x (&self) -> N { self[0] }
|
||||
fn y (&self) -> N { self[1] }
|
||||
}
|
||||
|
||||
pub trait HasSize<E: Output> {
|
||||
fn size (&self) -> &Measure<E>;
|
||||
fn width (&self) -> usize {
|
||||
self.size().w()
|
||||
}
|
||||
fn height (&self) -> usize {
|
||||
self.size().h()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Output, T: Has<Measure<E>>> HasSize<E> for T {
|
||||
fn size (&self) -> &Measure<E> {
|
||||
self.get()
|
||||
}
|
||||
}
|
||||
|
||||
/// A widget that tracks its render width and height
|
||||
#[derive(Default)]
|
||||
pub struct Measure<E: Output> {
|
||||
_engine: PhantomData<E>,
|
||||
pub x: Arc<AtomicUsize>,
|
||||
pub y: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
// TODO: 🡘 🡙 ←🡙→ indicator to expand window when too small
|
||||
impl<E: Output> Content<E> for Measure<E> {
|
||||
fn render (&self, to: &mut E) {
|
||||
self.x.store(to.area().w().into(), Relaxed);
|
||||
self.y.store(to.area().h().into(), Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Output> Clone for Measure<E> {
|
||||
fn clone (&self) -> Self {
|
||||
Self {
|
||||
_engine: Default::default(),
|
||||
x: self.x.clone(),
|
||||
y: self.y.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Output> std::fmt::Debug for Measure<E> {
|
||||
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<E: Output> Measure<E> {
|
||||
pub fn new () -> Self {
|
||||
Self {
|
||||
_engine: PhantomData::default(),
|
||||
x: Arc::new(0.into()),
|
||||
y: Arc::new(0.into()),
|
||||
}
|
||||
}
|
||||
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 w (&self) -> usize {
|
||||
self.x.load(Relaxed)
|
||||
}
|
||||
pub fn h (&self) -> usize {
|
||||
self.y.load(Relaxed)
|
||||
}
|
||||
pub fn wh (&self) -> [usize;2] {
|
||||
[self.w(), self.h()]
|
||||
}
|
||||
pub fn format (&self) -> Arc<str> {
|
||||
format!("{}x{}", self.w(), self.h()).into()
|
||||
}
|
||||
pub fn of <T: Render<E>> (&self, item: T) -> Bsp<Fill<&Self>, T> {
|
||||
Bsp::b(Fill::xy(self), item)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,98 +0,0 @@
|
|||
use crate::*;
|
||||
use std::fmt::Debug;
|
||||
|
||||
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] }
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
use std::fmt::{Debug, Display};
|
||||
use std::ops::{Add, Sub, Mul, Div};
|
||||
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
use crate::*;
|
||||
use crate::Direction::*;
|
||||
|
||||
/// 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
use crate::*;
|
||||
use std::sync::{Arc, atomic::{AtomicUsize, Ordering::Relaxed}};
|
||||
|
||||
pub trait HasSize<E: Output> {
|
||||
fn size (&self) -> &Measure<E>;
|
||||
fn width (&self) -> usize {
|
||||
self.size().w()
|
||||
}
|
||||
fn height (&self) -> usize {
|
||||
self.size().h()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Output, T: Has<Measure<E>>> HasSize<E> for T {
|
||||
fn size (&self) -> &Measure<E> {
|
||||
self.get()
|
||||
}
|
||||
}
|
||||
|
||||
/// A widget that tracks its render width and height
|
||||
#[derive(Default)]
|
||||
pub struct Measure<E: Output> {
|
||||
_engine: PhantomData<E>,
|
||||
pub x: Arc<AtomicUsize>,
|
||||
pub y: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
// TODO: 🡘 🡙 ←🡙→ indicator to expand window when too small
|
||||
impl<E: Output> Content<E> for Measure<E> {
|
||||
fn render (&self, to: &mut E) {
|
||||
self.x.store(to.area().w().into(), Relaxed);
|
||||
self.y.store(to.area().h().into(), Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Output> Clone for Measure<E> {
|
||||
fn clone (&self) -> Self {
|
||||
Self {
|
||||
_engine: Default::default(),
|
||||
x: self.x.clone(),
|
||||
y: self.y.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Output> std::fmt::Debug for Measure<E> {
|
||||
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<E: Output> Measure<E> {
|
||||
pub fn new () -> Self {
|
||||
Self {
|
||||
_engine: PhantomData::default(),
|
||||
x: Arc::new(0.into()),
|
||||
y: Arc::new(0.into()),
|
||||
}
|
||||
}
|
||||
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 w (&self) -> usize {
|
||||
self.x.load(Relaxed)
|
||||
}
|
||||
pub fn h (&self) -> usize {
|
||||
self.y.load(Relaxed)
|
||||
}
|
||||
pub fn wh (&self) -> [usize;2] {
|
||||
[self.w(), self.h()]
|
||||
}
|
||||
pub fn format (&self) -> Arc<str> {
|
||||
format!("{}x{}", self.w(), self.h()).into()
|
||||
}
|
||||
pub fn of <T: Render<E>> (&self, item: T) -> Bsp<Fill<&Self>, T> {
|
||||
Bsp::b(Fill::xy(self), item)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
use crate::*;
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub trait Size<N: Coordinate>: From<[N;2]> + Debug + Copy {
|
||||
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 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 zero () -> [N;2] {
|
||||
[N::zero(), N::zero()]
|
||||
}
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
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] }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue