wip: removing Render and Layout from core

This commit is contained in:
🪞👃🪞 2024-09-09 15:12:34 +03:00
parent c4a5ee7b6e
commit eeb323b742
11 changed files with 148 additions and 165 deletions

View file

@ -16,13 +16,13 @@ pub trait Device<E: Engine>: Component<E> + Process {
} }
/// All things that implement the required traits can be treated as `Device`. /// All things that implement the required traits can be treated as `Device`.
impl<D, E: Engine> Device<E> for D where D: Component<E> + Process {} impl<E: Engine, W: Widget<Engine = E> + Process> Device<E> for W {}
impl<'a, E: Engine> Render<E> for Box<dyn Device<E> + 'a> { //impl<'a, E: Engine> Render<E> for Box<dyn Device<E> + 'a> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { //fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
(**self).render(to) //(**self).render(to)
} //}
} //}
/// Wraps [Client] or [DynamicAsyncClient] in place. /// Wraps [Client] or [DynamicAsyncClient] in place.
pub enum JackClient { pub enum JackClient {

View file

@ -16,7 +16,7 @@ impl<E: Engine> std::fmt::Debug for JackDevice<E> {
f.debug_struct("JackDevice").field("ports", &self.ports).finish() f.debug_struct("JackDevice").field("ports", &self.ports).finish()
} }
} }
impl<E: Engine> Render<E> for JackDevice<E> { impl<E: Engine> Widget for JackDevice<E> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
self.state.read().unwrap().render(to) self.state.read().unwrap().render(to)
} }

View file

@ -35,5 +35,5 @@ submod! {
handle handle
keymap keymap
layout layout
render //render
} }

View file

@ -1,25 +1,24 @@
use crate::*; use crate::*;
pub enum Collected<'a, E: Engine> { pub enum Collected<'a, E: Engine> {
Box(Box<dyn Layout<E> + 'a>), Box(Box<dyn Widget<Engine = E> + 'a>),
Ref(&'a (dyn Layout<E> + 'a)), Ref(&'a (dyn Widget<Engine = E> + 'a)),
} }
impl<'a, E: Engine> Render<E> for Collected<'a, E> { impl<'a, E: Engine> Widget for Collected<'a, E> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { type Engine = E;
match self {
Self::Box(inner) => (*inner).render(to),
Self::Ref(inner) => (*inner).render(to),
}
}
}
impl<'a, E: Engine> Layout<E> for Collected<'a, E> {
fn layout (&self, area: E::Area) -> Perhaps<E::Area> { fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
match self { match self {
Self::Box(inner) => (*inner).layout(area), Self::Box(inner) => (*inner).layout(area),
Self::Ref(inner) => (*inner).layout(area), Self::Ref(inner) => (*inner).layout(area),
} }
} }
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
match self {
Self::Box(inner) => (*inner).render(to),
Self::Ref(inner) => (*inner).render(to),
}
}
} }
pub struct Collection<'a, E: Engine>( pub struct Collection<'a, E: Engine>(
@ -33,9 +32,9 @@ impl<'a, E: Engine> Collection<'a, E> {
} }
pub trait Collect<'a, E: Engine> { pub trait Collect<'a, E: Engine> {
fn add_box (self, item: Box<dyn Layout<E> + 'a>) -> Self; fn add_box (self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self;
fn add_ref (self, item: &'a dyn Layout<E>) -> Self; fn add_ref (self, item: &'a dyn Widget<Engine = E>) -> Self;
fn add <R: Layout<E> + Sized + 'a> (self, item: R) -> Self fn add <R: Widget<Engine = E> + Sized + 'a> (self, item: R) -> Self
where Self: Sized where Self: Sized
{ {
self.add_box(Box::new(item)) self.add_box(Box::new(item))
@ -43,17 +42,17 @@ pub trait Collect<'a, E: Engine> {
} }
impl<'a, E: Engine> Collect<'a, E> for Collection<'a, E> { impl<'a, E: Engine> Collect<'a, E> for Collection<'a, E> {
fn add_box (mut self, item: Box<dyn Layout<E> + 'a>) -> Self { fn add_box (mut self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self {
self.0.push(Collected::Box(item)); self.0.push(Collected::Box(item));
self self
} }
fn add_ref (mut self, item: &'a dyn Layout<E>) -> Self { fn add_ref (mut self, item: &'a dyn Widget<Engine = E>) -> Self {
self.0.push(Collected::Ref(item)); self.0.push(Collected::Ref(item));
self self
} }
} }
pub struct Layers<'a, E: Engine>(pub &'a [&'a dyn Layout<E>]); pub struct Layers<'a, E: Engine>(pub &'a [&'a dyn Widget<Engine = E>]);
// this actually works, except for the type inference // this actually works, except for the type inference
//pub struct Layers<'a, E: Engine + 'a, I: std::iter::IntoIterator<Item = &'a dyn Render<E>>>( //pub struct Layers<'a, E: Engine + 'a, I: std::iter::IntoIterator<Item = &'a dyn Render<E>>>(
@ -69,11 +68,11 @@ impl<'a, E: Engine> Layered<'a, E> {
} }
impl<'a, E: Engine> Collect<'a, E> for Layered<'a, E> { impl<'a, E: Engine> Collect<'a, E> for Layered<'a, E> {
fn add_box (mut self, item: Box<dyn Layout<E> + 'a>) -> Self { fn add_box (mut self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self {
self.0 = self.0.add_box(item); self.0 = self.0.add_box(item);
self self
} }
fn add_ref (mut self, item: &'a dyn Layout<E>) -> Self { fn add_ref (mut self, item: &'a dyn Widget<Engine = E>) -> Self {
self.0 = self.0.add_ref(item); self.0 = self.0.add_ref(item);
self self
} }
@ -118,11 +117,11 @@ impl<'a, E: Engine> Split<'a, E> {
} }
impl<'a, E: Engine> Collect<'a, E> for Split<'a, E> { impl<'a, E: Engine> Collect<'a, E> for Split<'a, E> {
fn add_box (mut self, item: Box<dyn Layout<E> + 'a>) -> Self { fn add_box (mut self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self {
self.items = self.items.add_box(item); self.items = self.items.add_box(item);
self self
} }
fn add_ref (mut self, item: &'a dyn Layout<E>) -> Self { fn add_ref (mut self, item: &'a dyn Widget<Engine = E>) -> Self {
self.items = self.items.add_ref(item); self.items = self.items.add_ref(item);
self self
} }

View file

@ -1,10 +1,10 @@
use crate::*; use crate::*;
/// A UI component. /// A UI component.
pub trait Component<E: Engine>: Render<E> + Handle<E> + Layout<E> {} pub trait Component<E: Engine>: Widget<Engine = E> + Handle<E> {}
/// Everything that implements [Render] and [Handle] is a [Component]. /// Everything that implements [Render] and [Handle] is a [Component].
impl<E: Engine, C: Render<E> + Handle<E> + Layout<E>> Component<E> for C {} impl<E: Engine, C: Widget<Engine = E> + Handle<E>> Component<E> for C {}
/// Marker trait for [Component]s that can [Exit] /// Marker trait for [Component]s that can [Exit]
pub trait ExitableComponent<E>: Exit + Component<E> where E: Engine { pub trait ExitableComponent<E>: Exit + Component<E> where E: Engine {

View file

@ -1,7 +1,7 @@
use crate::*; use crate::*;
/// A component that may contain [Focusable] components. /// A component that may contain [Focusable] components.
pub trait Focus <const N: usize, E: Engine>: Render<E> + Handle<E> { pub trait Focus <const N: usize, E: Engine>: Widget<Engine = E> + Handle<E> {
fn focus (&self) -> usize; fn focus (&self) -> usize;
fn focus_mut (&mut self) -> &mut usize; fn focus_mut (&mut self) -> &mut usize;
fn focusable (&self) -> [&dyn Focusable<E>;N]; fn focusable (&self) -> [&dyn Focusable<E>;N];
@ -33,13 +33,13 @@ pub trait Focus <const N: usize, E: Engine>: Render<E> + Handle<E> {
} }
/// A component that may be focused. /// A component that may be focused.
pub trait Focusable<E: Engine>: Render<E> + Handle<E> { pub trait Focusable<E: Engine>: Widget<Engine = E> + Handle<E> {
fn is_focused (&self) -> bool; fn is_focused (&self) -> bool;
fn set_focused (&mut self, focused: bool); fn set_focused (&mut self, focused: bool);
} }
impl<F: Focusable<E>, E: Engine> Focusable<E> for Option<F> impl<F: Focusable<E>, E: Engine> Focusable<E> for Option<F>
where Option<F>: Render<E> where Option<F>: Widget<Engine = E>
{ {
fn is_focused (&self) -> bool { fn is_focused (&self) -> bool {
match self { match self {

View file

@ -2,46 +2,46 @@ use crate::*;
// TODO: Convert to component // TODO: Convert to component
// pub enum Align { Center, NW, N, NE, E, SE, S, SW, W, } // pub enum Align { Center, NW, N, NE, E, SE, S, SW, W, }
pub fn center_box (area: [u16;4], w: u16, h: u16) -> [u16;4] { //pub fn center_box (area: [u16;4], w: u16, h: u16) -> [u16;4] {
let width = w.min(area.w() * 3 / 5); //let width = w.min(area.w() * 3 / 5);
let height = h.min(area.w() * 3 / 5); //let height = h.min(area.w() * 3 / 5);
let x = area.x() + (area.w() - width) / 2; //let x = area.x() + (area.w() - width) / 2;
let y = area.y() + (area.h() - height) / 2; //let y = area.y() + (area.h() - height) / 2;
[x, y, width, height] //[x, y, width, height]
} //}
/// Trait for structs that compute drawing area before rendering ///// Trait for structs that compute drawing area before rendering
pub trait Layout<E: Engine>: Render<E> { //pub trait Layout<E: Engine>: Render<E> {
fn layout (&self, area: E::Area) -> Perhaps<E::Area>; //fn layout (&self, area: E::Area) -> Perhaps<E::Area>;
} //}
impl<'a, E: Engine> Layout<E> for Box<dyn Layout<E> + 'a> { //impl<'a, E: Engine> Layout<E> for Box<dyn Layout<E> + 'a> {
fn layout (&self, area: E::Area) -> Perhaps<E::Area> { //fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
(**self).layout(area) //(**self).layout(area)
} //}
} //}
impl<'a, E: Engine> Layout<E> for Box<dyn Component<E> + 'a> { //impl<'a, E: Engine> Layout<E> for Box<dyn Component<E> + 'a> {
fn layout (&self, area: E::Area) -> Perhaps<E::Area> { //fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
(**self).layout(area) //(**self).layout(area)
} //}
} //}
impl<E: Engine, T: Layout<E>> Layout<E> for &T { //impl<E: Engine, T: Layout<E>> Layout<E> for &T {
fn layout (&self, area: E::Area) -> Perhaps<E::Area> { //fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
(*self).layout(area) //(*self).layout(area)
} //}
} //}
impl<E: Engine, T: Layout<E>> Layout<E> for &mut T { //impl<E: Engine, T: Layout<E>> Layout<E> for &mut T {
fn layout (&self, area: E::Area) -> Perhaps<E::Area> { //fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
(**self).layout(area) //(**self).layout(area)
} //}
} //}
impl<E: Engine, T: Layout<E>> Layout<E> for Option<T> { //impl<E: Engine, T: Layout<E>> Layout<E> for Option<T> {
fn layout (&self, area: E::Area) -> Perhaps<E::Area> { //fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
match self { //match self {
Some(layout) => layout.layout(area), //Some(layout) => layout.layout(area),
None => Ok(None) //None => Ok(None)
} //}
} //}
} //}
/// Override X and Y coordinates, aligning to corner, side, or center of area /// Override X and Y coordinates, aligning to corner, side, or center of area
pub enum Align<L> { Center(L), NW(L), N(L), NE(L), W(L), E(L), SW(L), S(L), SE(L) } pub enum Align<L> { Center(L), NW(L), N(L), NE(L), W(L), E(L), SW(L), S(L), SE(L) }

View file

@ -1,77 +1,77 @@
use crate::*; use crate::*;
/// Render to output. ///// Render to output.
pub trait Render<E: Engine>: Send + Sync { //pub trait Render<E: Engine>: Send + Sync {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered>; //fn render (&self, to: &mut E) -> Perhaps<E::Rendered>;
} //}
impl<E: Engine> Render<E> for () { //impl<E: Engine> Render<E> for () {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { //fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
Ok(None) //Ok(None)
} //}
} //}
/// Options can be rendered optionally. ///// Options can be rendered optionally.
impl<R, E: Engine> Render<E> for Option<R> where R: Render<E> { //impl<R, E: Engine> Render<E> for Option<R> where R: Render<E> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { //fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
match self { //match self {
Some(component) => component.render(to), //Some(component) => component.render(to),
None => Ok(None) //None => Ok(None)
} //}
} //}
} //}
/// Boxed references can be rendered. ///// Boxed references can be rendered.
impl<'a, E: Engine> Render<E> for Box<dyn Render<E> + 'a> { //impl<'a, E: Engine> Render<E> for Box<dyn Render<E> + 'a> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { //fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
(**self).render(to) //(**self).render(to)
} //}
} //}
impl<'a, E: Engine> Render<E> for Box<dyn Layout<E> + 'a> { //impl<'a, E: Engine> Render<E> for Box<dyn Layout<E> + 'a> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { //fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
(**self).render(to) //(**self).render(to)
} //}
} //}
impl<'a, E: Engine> Render<E> for Box<dyn Component<E> + 'a> { //impl<'a, E: Engine> Render<E> for Box<dyn Component<E> + 'a> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { //fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
(**self).render(to) //(**self).render(to)
} //}
} //}
/// Immutable references can be rendered. ///// Immutable references can be rendered.
impl<R, E: Engine> Render<E> for &R where R: Render<E> { //impl<R, E: Engine> Render<E> for &R where R: Render<E> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { //fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
(*self).render(to) //(*self).render(to)
} //}
} //}
/// Mutable references can be rendered. ///// Mutable references can be rendered.
impl<R, E: Engine> Render<E> for &mut R where R: Render<E> { //impl<R, E: Engine> Render<E> for &mut R where R: Render<E> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { //fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
(**self).render(to) //(**self).render(to)
} //}
} //}
/// Counted references can be rendered. ///// Counted references can be rendered.
impl<R, E: Engine> Render<E> for Arc<R> where R: Render<E> { //impl<R, E: Engine> Render<E> for Arc<R> where R: Render<E> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { //fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
self.as_ref().render(to) //self.as_ref().render(to)
} //}
} //}
/// References behind a [Mutex] can be rendered. ///// References behind a [Mutex] can be rendered.
impl<R, E: Engine> Render<E> for Mutex<R> where R: Render<E> { //impl<R, E: Engine> Render<E> for Mutex<R> where R: Render<E> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { //fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
self.lock().unwrap().render(to) //self.lock().unwrap().render(to)
} //}
} //}
/// References behind a [RwLock] can be rendered. ///// References behind a [RwLock] can be rendered.
impl<R, E: Engine> Render<E> for RwLock<R> where R: Render<E> { //impl<R, E: Engine> Render<E> for RwLock<R> where R: Render<E> {
fn render (&self, to: &mut E) -> Perhaps<E::Rendered> { //fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
self.read().unwrap().render(to) //self.read().unwrap().render(to)
} //}
} //}
// FIXME: components are now 2 thunks (layout and render). // FIXME: components are now 2 thunks (layout and render).
// maybe this resolves the conflict describe below? // maybe this resolves the conflict describe below?

View file

@ -98,12 +98,11 @@ macro_rules! border {
const SE: &'static str = $se; const SE: &'static str = $se;
$($x)* $($x)*
} }
impl Layout<Tui> for $T { impl Widget for $T {
type Engine = Tui;
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
Ok(Some(area)) Ok(Some(area))
} }
}
impl Render<Tui> for $T {
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> { fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
self.draw(to) self.draw(to)
} }

View file

@ -1,14 +1,12 @@
use crate::*; use crate::*;
impl Layout<Tui> for &str { impl Widget for &str {
type Engine = Tui;
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
let [x, y, ..] = area; let [x, y, ..] = area;
// TODO: line breaks // TODO: line breaks
Ok(Some([x, y, self.len() as u16, 1])) Ok(Some([x, y, self.len() as u16, 1]))
} }
}
impl Render<Tui> for &str {
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> { fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
let area = self.layout(to.area())?.unwrap(); let area = self.layout(to.area())?.unwrap();
to.blit(&self, area.x(), area.y(), None)?; to.blit(&self, area.x(), area.y(), None)?;
@ -16,15 +14,13 @@ impl Render<Tui> for &str {
} }
} }
pub struct Styled<T: Layout<Tui>>(pub Option<Style>, pub T); pub struct Styled<T: Widget<Engine = Tui>>(pub Option<Style>, pub T);
impl Layout<Tui> for Styled<&str> { impl Widget for Styled<&str> {
type Engine = Tui;
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
Ok(Some([area.x(), area.y(), self.1.len() as u16, 1])) Ok(Some([area.x(), area.y(), self.1.len() as u16, 1]))
} }
}
impl Render<Tui> for Styled<&str> {
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> { fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
let area = self.layout(to.area())?.unwrap(); let area = self.layout(to.area())?.unwrap();
Ok(Some([area.x(), area.y(), self.1.len() as u16, 1])) Ok(Some([area.x(), area.y(), self.1.len() as u16, 1]))
@ -33,12 +29,11 @@ impl Render<Tui> for Styled<&str> {
pub struct FillBg(pub Color); pub struct FillBg(pub Color);
impl Layout<Tui> for FillBg { impl Widget for FillBg {
type Engine = Tui;
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
Ok(Some(area)) Ok(Some(area))
} }
}
impl Render<Tui> for FillBg {
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> { fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
to.fill_bg(to.area(), self.0); to.fill_bg(to.area(), self.0);
Ok(Some(to.area)) Ok(Some(to.area))

View file

@ -1,25 +1,15 @@
use crate::*; use crate::*;
impl<'a> Render<Tui> for Layered<'a, Tui> { impl<'a> Widget for Split<'a, Tui> {
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> { type Engine = Tui;
let area = to.area();
for layer in self.0.0.iter() {
layer.render(to)?;
}
Ok(Some(area))
}
}
impl<'a> Layout<Tui> for Split<'a, Tui> {
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> { fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
todo!() todo!()
} }
}
impl<'a> Render<Tui> for Split<'a, Tui> {
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> { fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
Ok(Some(self.render_areas(to)?.0)) Ok(Some(self.render_areas(to)?.0))
} }
} }
// TODO // TODO
impl<'a> Split<'a, Tui> { impl<'a> Split<'a, Tui> {
pub fn render_areas (&self, to: &mut Tui) -> Usually<([u16;4], Vec<Option<[u16;4]>>)> { pub fn render_areas (&self, to: &mut Tui) -> Usually<([u16;4], Vec<Option<[u16;4]>>)> {