separate Input and Output impls

This commit is contained in:
🪞👃🪞 2025-01-05 22:01:54 +01:00
parent a6efde40f8
commit 0e821e098f
77 changed files with 465 additions and 454 deletions

View file

@ -19,7 +19,7 @@ impl<T> Align<T> {
pub fn se (a: T) -> Self { Self(Alignment::SE, a) }
}
impl<E: Engine, T: Content<E>> Content<E> for Align<T> {
impl<E: Output, T: Content<E>> Content<E> for Align<T> {
fn content (&self) -> impl Render<E> {
&self.1
}
@ -46,7 +46,7 @@ impl<E: Engine, T: Content<E>> Content<E> for Align<T> {
};
[x, y, centered.w(), centered.h()].into()
}
fn render (&self, render: &mut E::Output) {
fn render (&self, render: &mut E) {
let content = &self.content();
let it = Render::layout(content, render.area()).xywh();
render.place(it.into(), content)

View file

@ -20,12 +20,12 @@ impl Direction {
pub struct Bsp<X, Y>(Direction, X, Y);
impl<E: Engine, A: Content<E>, B: Content<E>> Content<E> for Bsp<A, B> {
impl<E: Output, 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
}
fn render (&self, to: &mut E::Output) {
fn render (&self, to: &mut E) {
let [area_a, area_b, _] = self.areas(to.area());
let (a, b) = self.contents();
match self.0 {
@ -44,7 +44,7 @@ impl<A, B> Bsp<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>> {
pub trait BspAreas<E: Output, A: Content<E>, B: Content<E>> {
fn direction (&self) -> Direction;
fn contents (&self) -> (&A, &B);
fn areas (&self, outer: E::Area) -> [E::Area;3] {
@ -95,7 +95,7 @@ pub trait BspAreas<E: Engine, A: Content<E>, B: Content<E>> {
}
}
impl<E: Engine, A: Content<E>, B: Content<E>> BspAreas<E, A, B> for Bsp<A, B> {
impl<E: Output, 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) }
}

View file

@ -18,17 +18,17 @@ pub(crate) use std::marker::PhantomData;
let unit = ();
assert_eq!(Content::<Tui>::layout(&unit, area), [20, 20, 0, 0]);
assert_eq!(Content::<TuiOut>::layout(&unit, area), [20, 20, 0, 0]);
assert_eq!(Fill::<Tui>::x(unit).layout(area), [10, 20, 20, 0]);
assert_eq!(Fill::<Tui>::y(unit).layout(area), [20, 10, 0, 20]);
assert_eq!(Fill::<Tui>::xy(unit).layout(area), area);
assert_eq!(Fill::<TuiOut>::x(unit).layout(area), [10, 20, 20, 0]);
assert_eq!(Fill::<TuiOut>::y(unit).layout(area), [20, 10, 0, 20]);
assert_eq!(Fill::<TuiOut>::xy(unit).layout(area), area);
assert_eq!(Fixed::<Tui, u16>::x(4, unit).layout(area), [18, 20, 4, 0]);
assert_eq!(Fixed::<Tui, u16>::y(4, unit).layout(area), [20, 18, 0, 4]);
assert_eq!(Fixed::<Tui, u16>::xy(4, 4, unit).layout(area), [18, 18, 4, 4]);
assert_eq!(Fixed::<TuiOut, u16>::x(4, unit).layout(area), [18, 20, 4, 0]);
assert_eq!(Fixed::<TuiOut, u16>::y(4, unit).layout(area), [20, 18, 0, 4]);
assert_eq!(Fixed::<TuiOut, u16>::xy(4, 4, unit).layout(area), [18, 18, 4, 4]);
let four = ||Fixed::<Tui>::xy(4, 4, unit);
let four = ||Fixed::<TuiOut>::xy(4, 4, unit);
assert_eq!(Align::nw(four()).layout(area), [10, 10, 4, 4]);
assert_eq!(Align::n(four()).layout(area), [18, 10, 4, 4]);
@ -39,7 +39,7 @@ pub(crate) use std::marker::PhantomData;
assert_eq!(Align::sw(four()).layout(area), [10, 26, 4, 4]);
assert_eq!(Align::w(four()).layout(area), [10, 18, 4, 4]);
let two_by_four = ||Fixed::<Tui>::xy(4, 2, unit);
let two_by_four = ||Fixed::<TuiOut>::xy(4, 2, unit);
assert_eq!(Align::nw(two_by_four()).layout(area), [10, 10, 4, 2]);
assert_eq!(Align::n(two_by_four()).layout(area), [18, 10, 4, 2]);

View file

@ -4,7 +4,7 @@ use std::sync::{Arc, atomic::{AtomicUsize, Ordering::Relaxed}};
// TODO: 🡘 🡙 ←🡙→ indicator to expand window when too small
pub trait HasSize<E: Engine> {
pub trait HasSize<E: Output> {
fn size (&self) -> &Measure<E>;
}
@ -18,20 +18,20 @@ pub trait HasSize<E: Engine> {
/// A widget that tracks its render width and height
#[derive(Default)]
pub struct Measure<E: Engine> {
pub struct Measure<E: Output> {
_engine: PhantomData<E>,
pub x: Arc<AtomicUsize>,
pub y: Arc<AtomicUsize>,
}
impl<E: Engine> Content<E> for Measure<E> {
fn render (&self, to: &mut E::Output) {
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: Engine> Clone for Measure<E> {
impl<E: Output> Clone for Measure<E> {
fn clone (&self) -> Self {
Self {
_engine: Default::default(),
@ -41,7 +41,7 @@ impl<E: Engine> Clone for Measure<E> {
}
}
impl<E: Engine> std::fmt::Debug for Measure<E> {
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)
@ -50,7 +50,7 @@ impl<E: Engine> std::fmt::Debug for Measure<E> {
}
}
impl<E: Engine> Measure<E> {
impl<E: Output> Measure<E> {
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()] }
@ -73,18 +73,18 @@ impl<E: Engine> Measure<E> {
///// A scrollable area.
//pub struct Scroll<E, F>(pub F, pub Direction, pub u64, PhantomData<E>)
//where
//E: Engine,
//E: Output,
//F: Send + Sync + Fn(&mut dyn FnMut(&dyn Content<E>)->Usually<()>)->Usually<()>;
//pub trait ContentDebug<E: Engine> {
//pub trait ContentDebug<E: Output> {
//fn debug <W: Content<E>> (other: W) -> DebugOverlay<E, W> {
//DebugOverlay(Default::default(), other)
//}
//}
//impl<E: Engine> ContentDebug<E> for E {}
//impl<E: Output> ContentDebug<E> for E {}
//impl Render<Tui> for Measure<Tui> {
//impl Render<TuiOut> for Measure<TuiOut> {
//fn min_size (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
//Ok(Some([0u16.into(), 0u16.into()].into()))
//}
@ -95,13 +95,13 @@ impl<E: Engine> Measure<E> {
//}
//}
//impl Measure<Tui> {
//impl Measure<TuiOut> {
//pub fn debug (&self) -> ShowMeasure {
//ShowMeasure(&self)
//}
//}
//render!(<Tui>|self: ShowMeasure<'a>|render(|to: &mut TuiOut|Ok({
//render!(Tui: |self: ShowMeasure<'a>|render(|to: &mut TuiOut|Ok({
//let w = self.0.w();
//let h = self.0.h();
//to.blit(&format!(" {w} x {h} "), to.area.x(), to.area.y(), Some(
@ -109,11 +109,11 @@ impl<E: Engine> Measure<E> {
//))
//})));
//pub struct ShowMeasure<'a>(&'a Measure<Tui>);
//pub struct ShowMeasure<'a>(&'a Measure<TuiOut>);
//pub struct DebugOverlay<E: Engine, W: Render<E>>(PhantomData<E>, pub W);
//pub struct DebugOverlay<E: Output, W: Render<E>>(PhantomData<E>, pub W);
//impl<T: Render<Tui>> Render<Tui> for DebugOverlay<Tui, T> {
//impl<T: Render<TuiOut>> Render<TuiOut> for DebugOverlay<Tui, T> {
//fn min_size (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
//self.1.min_size(to)
//}

View file

@ -3,7 +3,7 @@ use crate::*;
/// Show an item only when a condition is true.
pub struct When<A>(pub bool, pub A);
impl<E: Engine, A: Render<E>> Content<E> for When<A> {
impl<E: Output, A: Render<E>> Content<E> for When<A> {
fn layout (&self, to: E::Area) -> E::Area {
let Self(cond, item) = self;
let mut area = E::Area::zero();
@ -16,7 +16,7 @@ impl<E: Engine, A: Render<E>> Content<E> for When<A> {
}
area.into()
}
fn render (&self, to: &mut E::Output) {
fn render (&self, to: &mut E) {
let Self(cond, item) = self;
if *cond { item.render(to) }
}
@ -25,12 +25,12 @@ impl<E: Engine, A: Render<E>> Content<E> for When<A> {
/// 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: Render<E>, B: Render<E>> Content<E> for Either<A, B> {
impl<E: Output, A: Render<E>, B: Render<E>> Content<E> for Either<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) }
}
fn render (&self, to: &mut E::Output) {
fn render (&self, to: &mut E) {
let Self(cond, a, b) = self;
if *cond { a.render(to) } else { b.render(to) }
}
@ -42,7 +42,7 @@ pub struct Map<A, B, I, F, G>(pub F, pub G) where
G: Fn(A, usize)->B + Send + Sync;
impl<E, A, B, I, F, G> Content<E> for Map<A, B, I, F, G> where
E: Engine,
E: Output,
B: Render<E>,
I: Iterator<Item = A> + Send + Sync,
F: Fn() -> I + Send + Sync,
@ -67,7 +67,7 @@ impl<E, A, B, I, F, G> Content<E> for Map<A, B, I, F, G> where
//[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::Output) {
fn render (&self, to: &mut E) {
let Self(get_iterator, callback) = self;
let mut index = 0;
//let area = self.layout(to.area());
@ -83,7 +83,7 @@ impl<E, A, B, I, F, G> Content<E> for Map<A, B, I, F, G> where
/*
//pub fn reduce <E, T, I, R, F>(iterator: I, callback: F) -> Reduce<E, T, I, R, F> where
//E: Engine,
//E: Output,
//I: Iterator<Item = T> + Send + Sync,
//R: Render<E>,
//F: Fn(R, T, usize) -> R + Send + Sync
@ -91,24 +91,24 @@ impl<E, A, B, I, F, G> Content<E> for Map<A, B, I, F, G> where
//Reduce(Default::default(), iterator, callback)
//}
pub struct Reduce<E, T, I, R, F>(PhantomData<(E, R)>, I, F) where
E: Engine,
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: Engine,
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::Output) {
fn render (&self, to: &mut E) {
todo!()
}
}
*/
//macro_rules! define_ops {
//($Trait:ident<$E:ident:$Engine:path> { $(
//($Trait:ident<$E:ident:$Output:path> { $(
//$(#[$attr:meta $($attr_args:tt)*])*
//(
//$fn:ident
@ -117,8 +117,8 @@ impl<E, T, I, R, F> Content<E> for Reduce<E, T, I, R, F> where
//($($arg:ident:$Arg:ty),*)
//)
//)* }) => {
//impl<$E: $Engine> $Trait<E> for E {}
//pub trait $Trait<$E: $Engine> {
//impl<$E: $Output> $Trait<E> for E {}
//pub trait $Trait<$E: $Output> {
//$(
//$(#[$attr $($attr_args)*])*
//fn $fn $(<$($G),+>)?
@ -131,7 +131,7 @@ impl<E, T, I, R, F> Content<E> for Reduce<E, T, I, R, F> where
//}
//define_ops! {
//Layout<E: Engine> {
//Layout<E: Output> {
//(when <A: Render<E>,>
//When(cond: bool, item: A))
///// When `cond` is `true`, render `a`, otherwise render `b`.

View file

@ -3,7 +3,7 @@ use crate::*;
/// Defines an enum that transforms its content
/// along either the X axis, the Y axis, or both.
///
/// The `_Unused` variant wraps the `Engine` type
/// The `_Unused` variant wraps the `Output` type
/// using `PhantomData` to permit the double generic.
macro_rules! transform_xy {
($self:ident : $Enum:ident |$to:ident|$area:expr) => {
@ -13,15 +13,15 @@ macro_rules! transform_xy {
pub fn y (item: T) -> Self { Self::Y(item) }
pub fn xy (item: T) -> Self { Self::XY(item) }
}
impl<E: Engine, T: Content<E>> Content<E> for $Enum<T> {
impl<E: Output, T: Content<E>> Content<E> for $Enum<T> {
fn content (&self) -> impl Render<E> {
match self {
Self::X(item) => item,
Self::Y(item) => item,
Self::XY(item) => item,
Self::XY(item) => item
}
}
fn layout (&$self, $to: <E as Engine>::Area) -> <E as Engine>::Area {
fn layout (&$self, $to: <E as Output>::Area) -> <E as Output>::Area {
use $Enum::*;
$area
}

View file

@ -26,7 +26,7 @@ macro_rules! transform_xy_unit {
}
}
}
impl<E: Engine, T: Content<E>> Content<E> for $Enum<E::Unit, T> {
impl<E: Output, T: Content<E>> Content<E> for $Enum<E::Unit, T> {
fn content (&self) -> impl Render<E> {
Some(match self {
Self::X(_, content) => content,