mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 04:06:45 +01:00
refactor + not sure whats up with the double padding
This commit is contained in:
parent
39407c9760
commit
c51d1cf643
10 changed files with 388 additions and 393 deletions
|
|
@ -13,7 +13,15 @@ impl HelpModal {
|
|||
Self { cursor: 0, search: None, exited: false }
|
||||
}
|
||||
}
|
||||
exit!(HelpModal);
|
||||
|
||||
impl Exit for HelpModal {
|
||||
fn exited (&self) -> bool {
|
||||
self.exited
|
||||
}
|
||||
fn exit (&mut self) {
|
||||
self.exited = true
|
||||
}
|
||||
}
|
||||
|
||||
render!(HelpModal |self, buf, area|{
|
||||
make_dim(buf);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
use crate::*;
|
||||
|
||||
submod! {
|
||||
focus
|
||||
handle
|
||||
keymap
|
||||
layout
|
||||
}
|
||||
|
||||
/// Entry point for main loop
|
||||
pub trait App<T: Engine> {
|
||||
fn run (self, context: T) -> Usually<T>;
|
||||
|
|
@ -31,13 +38,122 @@ pub trait Engine: Send + Sync + Sized {
|
|||
) -> Perhaps<Self::Area>;
|
||||
}
|
||||
|
||||
submod! {
|
||||
collect
|
||||
component
|
||||
exit
|
||||
focus
|
||||
handle
|
||||
keymap
|
||||
layout
|
||||
//render
|
||||
pub trait Widget: Send + Sync {
|
||||
type Engine: Engine;
|
||||
fn layout (&self, to: <<Self as Widget>::Engine as Engine>::Area) ->
|
||||
Perhaps<<<Self as Widget>::Engine as Engine>::Area>
|
||||
{
|
||||
Ok(Some(to))
|
||||
}
|
||||
fn render (&self, to: &mut Self::Engine) ->
|
||||
Perhaps<<<Self as Widget>::Engine as Engine>::Area>;
|
||||
}
|
||||
impl<'a, E: Engine> Widget for Box<dyn Widget<Engine = E> + 'a> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
(**self).layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
(**self).render(to)
|
||||
}
|
||||
}
|
||||
impl<E: Engine> Widget for &dyn Widget<Engine = E> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
(*self).layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
(*self).render(to)
|
||||
}
|
||||
}
|
||||
impl<E: Engine> Widget for &mut dyn Widget<Engine = E> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
(**self).layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
(**self).render(to)
|
||||
}
|
||||
}
|
||||
impl<E: Engine, W: Widget<Engine = E>> Widget for Arc<W> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
self.as_ref().layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
self.as_ref().render(to)
|
||||
}
|
||||
}
|
||||
impl<E: Engine, W: Widget<Engine = E>> Widget for Mutex<W> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
self.lock().unwrap().layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
self.lock().unwrap().render(to)
|
||||
}
|
||||
}
|
||||
impl<E: Engine, W: Widget<Engine = E>> Widget for RwLock<W> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
self.read().unwrap().layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
self.read().unwrap().render(to)
|
||||
}
|
||||
}
|
||||
impl<E: Engine, W: Widget<Engine = E>> Widget for Option<W> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
Ok(self.as_ref().map(|widget|widget.layout(to)).transpose()?.flatten())
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
Ok(self.as_ref().map(|widget|widget.render(to)).transpose()?.flatten())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Content: Send + Sync {
|
||||
type Engine: Engine;
|
||||
fn content (&self) -> impl Widget<Engine = <Self as Content>::Engine>;
|
||||
}
|
||||
//impl<E> Content<E> for () where E: Engine {
|
||||
//fn content (&self) -> impl Widget<E> {
|
||||
//()
|
||||
//}
|
||||
//}
|
||||
impl<E: Engine, W: Content<Engine = E>> Widget for W {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
self.content().layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
match self.layout(to.area())? {
|
||||
Some(area) => to.render_in(area, &self.content()),
|
||||
None => Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A UI component.
|
||||
pub trait Component<E: Engine>: Widget<Engine = E> + Handle<E> {}
|
||||
|
||||
/// Everything that implements [Render] and [Handle] is a [Component].
|
||||
impl<E: Engine, C: Widget<Engine = E> + Handle<E>> Component<E> for C {}
|
||||
|
||||
pub trait Exit: Send {
|
||||
fn exited (&self) -> bool;
|
||||
fn exit (&mut self);
|
||||
fn boxed (self) -> Box<dyn Exit> where Self: Sized + 'static {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Marker trait for [Component]s that can [Exit]
|
||||
pub trait ExitableComponent<E>: Exit + Component<E> where E: Engine {
|
||||
/// Perform type erasure for collecting heterogeneous components.
|
||||
fn boxed (self) -> Box<dyn ExitableComponent<E>> where Self: Sized + 'static {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, C: Component<E> + Exit> ExitableComponent<E> for C {}
|
||||
|
|
|
|||
|
|
@ -1,121 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
pub enum Collected<'a, E: Engine> {
|
||||
Box(Box<dyn Widget<Engine = E> + 'a>),
|
||||
Ref(&'a (dyn Widget<Engine = E> + 'a)),
|
||||
}
|
||||
|
||||
impl<'a, E: Engine> Widget for Collected<'a, E> {
|
||||
type Engine = E;
|
||||
fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
|
||||
match self {
|
||||
Self::Box(inner) => (*inner).layout(area),
|
||||
Self::Ref(inner) => (*inner).layout(area),
|
||||
}
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
match self {
|
||||
Self::Box(inner) => (*inner).render(to),
|
||||
Self::Ref(inner) => (*inner).render(to),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Collection<'a, E: Engine>(
|
||||
pub Vec<Collected<'a, E>>
|
||||
);
|
||||
|
||||
impl<'a, E: Engine> Collection<'a, E> {
|
||||
pub fn new () -> Self {
|
||||
Self(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Collect<'a, E: Engine> {
|
||||
fn add_box (self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self;
|
||||
fn add_ref (self, item: &'a dyn Widget<Engine = E>) -> Self;
|
||||
fn add <R: Widget<Engine = E> + Sized + 'a> (self, item: R) -> Self
|
||||
where Self: Sized
|
||||
{
|
||||
self.add_box(Box::new(item))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: Engine> Collect<'a, E> for Collection<'a, E> {
|
||||
fn add_box (mut self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self {
|
||||
self.0.push(Collected::Box(item));
|
||||
self
|
||||
}
|
||||
fn add_ref (mut self, item: &'a dyn Widget<Engine = E>) -> Self {
|
||||
self.0.push(Collected::Ref(item));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Layers<
|
||||
E: Engine,
|
||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = E>)->Usually<()>)->Usually<()>
|
||||
>(pub F, PhantomData<E>);
|
||||
|
||||
impl<
|
||||
E: Engine,
|
||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = E>)->Usually<()>)->Usually<()>
|
||||
> Layers<E, F> {
|
||||
pub fn new (build: F) -> Self {
|
||||
Self(build, Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
// 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 &'a I
|
||||
//);
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Direction { Up, Down, Left, Right }
|
||||
|
||||
impl Direction {
|
||||
pub fn is_down (&self) -> bool {
|
||||
match self { Self::Down => true, _ => false }
|
||||
}
|
||||
pub fn is_right (&self) -> bool {
|
||||
match self { Self::Right => true, _ => false }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Split<'a, E: Engine> {
|
||||
pub items: Collection<'a, E>,
|
||||
pub direction: Direction,
|
||||
pub focus: Option<usize>
|
||||
}
|
||||
|
||||
impl<'a, E: Engine> Split<'a, E> {
|
||||
pub fn new (direction: Direction) -> Self {
|
||||
Self {
|
||||
items: Collection::new(),
|
||||
direction,
|
||||
focus: None
|
||||
}
|
||||
}
|
||||
pub fn down () -> Self {
|
||||
Self::new(Direction::Down)
|
||||
}
|
||||
pub fn right () -> Self {
|
||||
Self::new(Direction::Right)
|
||||
}
|
||||
pub fn focus (mut self, focus: Option<usize>) -> Self {
|
||||
self.focus = focus;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: Engine> Collect<'a, E> for Split<'a, E> {
|
||||
fn add_box (mut self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self {
|
||||
self.items = self.items.add_box(item);
|
||||
self
|
||||
}
|
||||
fn add_ref (mut self, item: &'a dyn Widget<Engine = E>) -> Self {
|
||||
self.items = self.items.add_ref(item);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait Widget: Send + Sync {
|
||||
type Engine: Engine;
|
||||
fn layout (&self, to: <<Self as Widget>::Engine as Engine>::Area) ->
|
||||
Perhaps<<<Self as Widget>::Engine as Engine>::Area>
|
||||
{
|
||||
Ok(Some(to))
|
||||
}
|
||||
fn render (&self, to: &mut Self::Engine) ->
|
||||
Perhaps<<<Self as Widget>::Engine as Engine>::Area>;
|
||||
}
|
||||
impl<'a, E: Engine> Widget for Box<dyn Widget<Engine = E> + 'a> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
(**self).layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
(**self).render(to)
|
||||
}
|
||||
}
|
||||
impl<E: Engine> Widget for &dyn Widget<Engine = E> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
(*self).layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
(*self).render(to)
|
||||
}
|
||||
}
|
||||
impl<E: Engine> Widget for &mut dyn Widget<Engine = E> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
(**self).layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
(**self).render(to)
|
||||
}
|
||||
}
|
||||
impl<E: Engine, W: Widget<Engine = E>> Widget for Arc<W> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
self.as_ref().layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
self.as_ref().render(to)
|
||||
}
|
||||
}
|
||||
impl<E: Engine, W: Widget<Engine = E>> Widget for Mutex<W> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
self.lock().unwrap().layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
self.lock().unwrap().render(to)
|
||||
}
|
||||
}
|
||||
impl<E: Engine, W: Widget<Engine = E>> Widget for RwLock<W> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
self.read().unwrap().layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
self.read().unwrap().render(to)
|
||||
}
|
||||
}
|
||||
impl<E: Engine, W: Widget<Engine = E>> Widget for Option<W> {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
Ok(self.as_ref().map(|widget|widget.layout(to)).transpose()?.flatten())
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
Ok(self.as_ref().map(|widget|widget.render(to)).transpose()?.flatten())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Content: Send + Sync {
|
||||
type Engine: Engine;
|
||||
fn content (&self) -> impl Widget<Engine = <Self as Content>::Engine>;
|
||||
}
|
||||
//impl<E> Content<E> for () where E: Engine {
|
||||
//fn content (&self) -> impl Widget<E> {
|
||||
//()
|
||||
//}
|
||||
//}
|
||||
impl<E: Engine, W: Content<Engine = E>> Widget for W {
|
||||
type Engine = E;
|
||||
fn layout (&self, to: E::Area) -> Perhaps<E::Area> {
|
||||
self.content().layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
match self.layout(to.area())? {
|
||||
Some(area) => to.render_in(area, &self.content()),
|
||||
None => Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A UI component.
|
||||
pub trait Component<E: Engine>: Widget<Engine = E> + Handle<E> {}
|
||||
|
||||
/// Everything that implements [Render] and [Handle] is a [Component].
|
||||
impl<E: Engine, C: Widget<Engine = E> + Handle<E>> Component<E> for C {}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
pub trait Exit: Send {
|
||||
fn exited (&self) -> bool;
|
||||
fn exit (&mut self);
|
||||
fn boxed (self) -> Box<dyn Exit> where Self: Sized + 'static {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export] macro_rules! exit {
|
||||
($T:ty) => {
|
||||
impl Exit for $T {
|
||||
fn exited (&self) -> bool {
|
||||
self.exited
|
||||
}
|
||||
fn exit (&mut self) {
|
||||
self.exited = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Marker trait for [Component]s that can [Exit]
|
||||
pub trait ExitableComponent<E>: Exit + Component<E> where E: Engine {
|
||||
/// Perform type erasure for collecting heterogeneous components.
|
||||
fn boxed (self) -> Box<dyn ExitableComponent<E>> where Self: Sized + 'static {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, C: Component<E> + Exit> ExitableComponent<E> for C {}
|
||||
|
|
@ -1,7 +1,137 @@
|
|||
use crate::*;
|
||||
|
||||
pub enum Collected<'a, E: Engine> {
|
||||
Box(Box<dyn Widget<Engine = E> + 'a>),
|
||||
Ref(&'a (dyn Widget<Engine = E> + 'a)),
|
||||
}
|
||||
|
||||
impl<'a, E: Engine> Widget for Collected<'a, E> {
|
||||
type Engine = E;
|
||||
fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
|
||||
match self {
|
||||
Self::Box(inner) => (*inner).layout(area),
|
||||
Self::Ref(inner) => (*inner).layout(area),
|
||||
}
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
match self {
|
||||
Self::Box(inner) => (*inner).render(to),
|
||||
Self::Ref(inner) => (*inner).render(to),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Collection<'a, E: Engine>(
|
||||
pub Vec<Collected<'a, E>>
|
||||
);
|
||||
|
||||
impl<'a, E: Engine> Collection<'a, E> {
|
||||
pub fn new () -> Self {
|
||||
Self(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Collect<'a, E: Engine> {
|
||||
fn add_box (self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self;
|
||||
fn add_ref (self, item: &'a dyn Widget<Engine = E>) -> Self;
|
||||
fn add <R: Widget<Engine = E> + Sized + 'a> (self, item: R) -> Self
|
||||
where Self: Sized
|
||||
{
|
||||
self.add_box(Box::new(item))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: Engine> Collect<'a, E> for Collection<'a, E> {
|
||||
fn add_box (mut self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self {
|
||||
self.0.push(Collected::Box(item));
|
||||
self
|
||||
}
|
||||
fn add_ref (mut self, item: &'a dyn Widget<Engine = E>) -> Self {
|
||||
self.0.push(Collected::Ref(item));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Layers<
|
||||
E: Engine,
|
||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = E>)->Usually<()>)->Usually<()>
|
||||
>(pub F, PhantomData<E>);
|
||||
|
||||
impl<
|
||||
E: Engine,
|
||||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = E>)->Usually<()>)->Usually<()>
|
||||
> Layers<E, F> {
|
||||
pub fn new (build: F) -> Self {
|
||||
Self(build, Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Direction {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl Direction {
|
||||
pub fn is_down (&self) -> bool {
|
||||
match self { Self::Down => true, _ => false }
|
||||
}
|
||||
pub fn is_right (&self) -> bool {
|
||||
match self { Self::Right => true, _ => false }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Split<'a, E: Engine> {
|
||||
pub items: Collection<'a, E>,
|
||||
pub direction: Direction,
|
||||
pub focus: Option<usize>
|
||||
}
|
||||
|
||||
impl<'a, E: Engine> Split<'a, E> {
|
||||
pub fn new (direction: Direction) -> Self {
|
||||
Self {
|
||||
items: Collection::new(),
|
||||
direction,
|
||||
focus: None
|
||||
}
|
||||
}
|
||||
pub fn down () -> Self {
|
||||
Self::new(Direction::Down)
|
||||
}
|
||||
pub fn right () -> Self {
|
||||
Self::new(Direction::Right)
|
||||
}
|
||||
pub fn focus (mut self, focus: Option<usize>) -> Self {
|
||||
self.focus = focus;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: Engine> Collect<'a, E> for Split<'a, E> {
|
||||
fn add_box (mut self, item: Box<dyn Widget<Engine = E> + 'a>) -> Self {
|
||||
self.items = self.items.add_box(item);
|
||||
self
|
||||
}
|
||||
fn add_ref (mut self, item: &'a dyn Widget<Engine = E>) -> Self {
|
||||
self.items = self.items.add_ref(item);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
||||
impl<T> Align<T> {
|
||||
pub fn inner (&self) -> &T {
|
||||
|
|
@ -20,7 +150,24 @@ impl<T> Align<T> {
|
|||
}
|
||||
|
||||
/// Enforce minimum size of drawing area
|
||||
pub enum Min<U: Number, T> { W(U, T), H(U, T), WH(U, U, T), }
|
||||
pub enum Min<U: Number, T> {
|
||||
/// Enforce minimum width
|
||||
W(U, T),
|
||||
/// Enforce minimum height
|
||||
H(U, T),
|
||||
/// Enforce minimum width and height
|
||||
WH(U, U, T),
|
||||
}
|
||||
|
||||
impl<N: Number, T> Min<N, T> {
|
||||
fn inner (&self) -> &T {
|
||||
match self {
|
||||
Self::W(_, inner) => inner,
|
||||
Self::H(_, inner) => inner,
|
||||
Self::WH(_, _, inner) => inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Widget<Engine = E>> Widget for Min<E::Unit, T> {
|
||||
type Engine = E;
|
||||
|
|
@ -43,18 +190,31 @@ impl<E: Engine, T: Widget<Engine = E>> Widget for Min<E::Unit, T> {
|
|||
// 🡘 🡙 ←🡙→
|
||||
self.layout(to.area())?
|
||||
.map(|area|to.with_area(area.x(), area.y(), area.w(), area.h()))
|
||||
.map(|to|match self {
|
||||
Self::W(_, inner) => inner,
|
||||
Self::H(_, inner) => inner,
|
||||
Self::WH(_, _, inner) => inner,
|
||||
}.render(to))
|
||||
.map(|to|self.inner().render(to))
|
||||
.transpose()
|
||||
.map(|x|x.flatten())
|
||||
}
|
||||
}
|
||||
|
||||
/// Enforce maximum size of drawing area
|
||||
pub enum Max<U: Number, T> { W(U, T), H(U, T), WH(U, U, T), }
|
||||
pub enum Max<U: Number, T> {
|
||||
/// Enforce maximum width
|
||||
W(U, T),
|
||||
/// Enforce maximum height
|
||||
H(U, T),
|
||||
/// Enforce maximum width and height
|
||||
WH(U, U, T),
|
||||
}
|
||||
|
||||
impl<N: Number, T> Max<N, T> {
|
||||
fn inner (&self) -> &T {
|
||||
match self {
|
||||
Self::W(_, inner) => inner,
|
||||
Self::H(_, inner) => inner,
|
||||
Self::WH(_, _, inner) => inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Widget<Engine = E>> Widget for Max<E:: Unit, T> {
|
||||
type Engine = E;
|
||||
|
|
@ -76,18 +236,31 @@ impl<E: Engine, T: Widget<Engine = E>> Widget for Max<E:: Unit, T> {
|
|||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
self.layout(to.area())?
|
||||
.map(|area|to.with_area(area.x(), area.y(), area.w(), area.h()))
|
||||
.map(|to|match self {
|
||||
Self::W(_, inner) => inner,
|
||||
Self::H(_, inner) => inner,
|
||||
Self::WH(_, _, inner) => inner,
|
||||
}.render(to))
|
||||
.map(|to|self.inner().render(to))
|
||||
.transpose()
|
||||
.map(|x|x.flatten())
|
||||
}
|
||||
}
|
||||
|
||||
/// Expand drawing area
|
||||
pub enum Outset<U: Number, T> { W(U, T), H(U, T), WH(U, U, T), }
|
||||
pub enum Outset<N: Number, T> {
|
||||
/// Increase width
|
||||
W(N, T),
|
||||
/// Increase height
|
||||
H(N, T),
|
||||
/// Increase width and height
|
||||
WH(N, N, T)
|
||||
}
|
||||
|
||||
impl<N: Number, T> Outset<N, T> {
|
||||
fn inner (&self) -> &T {
|
||||
match self {
|
||||
Self::W(_, inner) => inner,
|
||||
Self::H(_, inner) => inner,
|
||||
Self::WH(_, _, inner) => inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Widget<Engine = E>> Widget for Outset<E::Unit, T> {
|
||||
type Engine = E;
|
||||
|
|
@ -100,25 +273,38 @@ impl<E: Engine, T: Widget<Engine = E>> Widget for Outset<E::Unit, T> {
|
|||
item.layout([area.x(), area.y() - *h, area.w(), area.h() + *h].into())
|
||||
},
|
||||
Self::WH(w, h, item) => if area.x() < *w || area.y() < *h { Ok(None) } else {
|
||||
item.layout([area.x()-*w, area.y() - *h, area.w() + *w, area.h() + *h].into())
|
||||
item.layout([area.x()- *w, area.y() - *h, area.w() + *w, area.h() + *h].into())
|
||||
}
|
||||
}
|
||||
}
|
||||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
self.layout(to.area())?
|
||||
.map(|area|to.with_area(area.x(), area.y(), area.w(), area.h()))
|
||||
.map(|to|match self {
|
||||
Self::W(_, inner) => inner,
|
||||
Self::H(_, inner) => inner,
|
||||
Self::WH(_, _, inner) => inner,
|
||||
}.render(to))
|
||||
.map(|to|self.inner().render(to))
|
||||
.transpose()
|
||||
.map(|x|x.flatten())
|
||||
}
|
||||
}
|
||||
|
||||
/// Shrink drawing area
|
||||
pub enum Inset<U: Number, T> { W(U, T), H(U, T), WH(U, U, T), }
|
||||
pub enum Inset<N: Number, T> {
|
||||
/// Decrease width
|
||||
W(N, T),
|
||||
/// Decrease height
|
||||
H(N, T),
|
||||
/// Decrease width and height
|
||||
WH(N, N, T),
|
||||
}
|
||||
|
||||
impl<N: Number, T: Widget> Inset<N, T> {
|
||||
fn inner (&self) -> &T {
|
||||
match self {
|
||||
Self::W(_, inner) => inner,
|
||||
Self::H(_, inner) => inner,
|
||||
Self::WH(_, _, inner) => inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Widget<Engine = E>> Widget for Inset<E::Unit, T> {
|
||||
type Engine = E;
|
||||
|
|
@ -138,18 +324,28 @@ impl<E: Engine, T: Widget<Engine = E>> Widget for Inset<E::Unit, T> {
|
|||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
self.layout(to.area())?
|
||||
.map(|area|to.with_area(area.x(), area.y(), area.w(), area.h()))
|
||||
.map(|to|match self {
|
||||
Self::W(_, inner) => inner,
|
||||
Self::H(_, inner) => inner,
|
||||
Self::WH(_, _, inner) => inner,
|
||||
}.render(to))
|
||||
.map(|to|self.inner().render(to))
|
||||
.transpose()
|
||||
.map(|x|x.flatten())
|
||||
}
|
||||
}
|
||||
|
||||
/// Move origin point of drawing area
|
||||
pub enum Offset<U: Number, T: Widget> { X(U, T), Y(U, T), XY(U, U, T), }
|
||||
pub enum Offset<N: Number, T: Widget> {
|
||||
X(N, T),
|
||||
Y(N, T),
|
||||
XY(N, N, T),
|
||||
}
|
||||
|
||||
impl<N: Number, T: Widget> Offset<N, T> {
|
||||
fn inner (&self) -> &T {
|
||||
match self {
|
||||
Self::X(_, inner) => inner,
|
||||
Self::Y(_, inner) => inner,
|
||||
Self::XY(_, _, inner) => inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine, T: Widget<Engine = E>> Widget for Offset<E::Unit, T> {
|
||||
type Engine = E;
|
||||
|
|
@ -169,11 +365,7 @@ impl<E: Engine, T: Widget<Engine = E>> Widget for Offset<E::Unit, T> {
|
|||
fn render (&self, to: &mut E) -> Perhaps<E::Area> {
|
||||
self.layout(to.area())?
|
||||
.map(|area|to.with_area(area.x(), area.y(), area.w(), area.h()))
|
||||
.map(|to|match self {
|
||||
Self::X(_, inner) => inner,
|
||||
Self::Y(_, inner) => inner,
|
||||
Self::XY(_, _, inner) => inner,
|
||||
}.render(to))
|
||||
.map(|to|self.inner().render(to))
|
||||
.transpose()
|
||||
.map(|x|x.flatten())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,87 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
///// Render to output.
|
||||
//pub trait Render<E: Engine>: Send + Sync {
|
||||
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered>;
|
||||
//}
|
||||
|
||||
//impl<E: Engine> Render<E> for () {
|
||||
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
||||
//Ok(None)
|
||||
//}
|
||||
//}
|
||||
|
||||
///// Options can be rendered optionally.
|
||||
//impl<R, E: Engine> Render<E> for Option<R> where R: Render<E> {
|
||||
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
||||
//match self {
|
||||
//Some(component) => component.render(to),
|
||||
//None => Ok(None)
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
||||
///// Boxed references can be rendered.
|
||||
//impl<'a, E: Engine> Render<E> for Box<dyn Render<E> + 'a> {
|
||||
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
||||
//(**self).render(to)
|
||||
//}
|
||||
//}
|
||||
//impl<'a, E: Engine> Render<E> for Box<dyn Layout<E> + 'a> {
|
||||
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
||||
//(**self).render(to)
|
||||
//}
|
||||
//}
|
||||
//impl<'a, E: Engine> Render<E> for Box<dyn Component<E> + 'a> {
|
||||
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
||||
//(**self).render(to)
|
||||
//}
|
||||
//}
|
||||
|
||||
///// Immutable references can be rendered.
|
||||
//impl<R, E: Engine> Render<E> for &R where R: Render<E> {
|
||||
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
||||
//(*self).render(to)
|
||||
//}
|
||||
//}
|
||||
|
||||
///// Mutable references can be rendered.
|
||||
//impl<R, E: Engine> Render<E> for &mut R where R: Render<E> {
|
||||
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
||||
//(**self).render(to)
|
||||
//}
|
||||
//}
|
||||
|
||||
///// Counted references can be rendered.
|
||||
//impl<R, E: Engine> Render<E> for Arc<R> where R: Render<E> {
|
||||
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
||||
//self.as_ref().render(to)
|
||||
//}
|
||||
//}
|
||||
|
||||
///// References behind a [Mutex] can be rendered.
|
||||
//impl<R, E: Engine> Render<E> for Mutex<R> where R: Render<E> {
|
||||
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
||||
//self.lock().unwrap().render(to)
|
||||
//}
|
||||
//}
|
||||
|
||||
///// References behind a [RwLock] can be rendered.
|
||||
//impl<R, E: Engine> Render<E> for RwLock<R> where R: Render<E> {
|
||||
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
||||
//self.read().unwrap().render(to)
|
||||
//}
|
||||
//}
|
||||
|
||||
// FIXME: components are now 2 thunks (layout and render).
|
||||
// maybe this resolves the conflict describe below?
|
||||
///// Boxed closures can be rendered.
|
||||
/////
|
||||
///// Rendering unboxed closures should also be possible;
|
||||
///// but in practice implementing the trait for an unboxed
|
||||
///// `Fn` closure causes an impl conflict.
|
||||
//impl<'a, E: Engine> Render<E> for Box<dyn Fn(&mut E) -> Perhaps<E::Rendered> + Send + Sync + 'a> {
|
||||
//fn render (&self, to: &mut E) -> Perhaps<E::Rendered> {
|
||||
//(*self)(to)
|
||||
//}
|
||||
//}
|
||||
|
|
@ -58,6 +58,19 @@ where
|
|||
F: Send + Sync + Fn(&mut dyn FnMut(&dyn Widget<Engine = Tui>)->Usually<()>)->Usually<()>
|
||||
{
|
||||
type Engine = Tui;
|
||||
fn layout (&self, area: [u16;4]) -> Perhaps<[u16;4]> {
|
||||
let [x, y, ..] = area;
|
||||
let mut w = 0;
|
||||
let mut h = 0;
|
||||
(self.0)(&mut |layer| {
|
||||
if let Some(layer_area) = layer.layout(area)? {
|
||||
w = w.max(layer_area.w());
|
||||
h = h.max(layer_area.h());
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
Ok(Some([x, y, w, h]))
|
||||
}
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
self.layout(to.area())?
|
||||
.map(|area|(self.0)(&mut |layer| {
|
||||
|
|
@ -74,9 +87,10 @@ impl<T: Widget<Engine = Tui>> Widget for Align<T> {
|
|||
Ok(self.inner().layout(outer_area)?.map(|inner_area|match self {
|
||||
Self::Center(_) => {
|
||||
let [_, _, w, h] = inner_area.xywh();
|
||||
let offset_x = (outer_area.w() - w) / 2;
|
||||
let offset_y = (outer_area.h() - h) / 2;
|
||||
[outer_area.x() + offset_x, outer_area.y() + offset_y, w, h]
|
||||
let offset_x = (outer_area.w() / 2).saturating_sub(w / 2);
|
||||
let offset_y = (outer_area.h() / 2).saturating_sub(h / 2);
|
||||
let result = [outer_area.x() + offset_x, outer_area.y() + offset_y, w, h];
|
||||
result
|
||||
},
|
||||
Self::NW(_) => { todo!() },
|
||||
Self::N(_) => { todo!() },
|
||||
|
|
|
|||
|
|
@ -20,7 +20,14 @@ pub struct AddSampleModal {
|
|||
_search: Option<String>,
|
||||
}
|
||||
|
||||
exit!(AddSampleModal);
|
||||
impl Exit for AddSampleModal {
|
||||
fn exited (&self) -> bool {
|
||||
self.exited
|
||||
}
|
||||
fn exit (&mut self) {
|
||||
self.exited = true
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for AddSampleModal {
|
||||
type Engine = Tui;
|
||||
|
|
@ -63,6 +70,7 @@ impl Widget for AddSampleModal {
|
|||
//Lozenge(Style::default()).draw(to)
|
||||
}
|
||||
}
|
||||
|
||||
impl Handle<Tui> for AddSampleModal {
|
||||
fn handle (&mut self, from: &Tui) -> Perhaps<bool> {
|
||||
if handle_keymap(self, &from.event(), KEYMAP_ADD_SAMPLE)? {
|
||||
|
|
|
|||
|
|
@ -37,15 +37,15 @@ impl Content for Demo<Tui> {
|
|||
//Align::Center("FOO")
|
||||
//Layers2::new(|_|Ok(()))
|
||||
//Layers2::new(|add|add(&Align::Center("FOO")))
|
||||
Layers::new(|add|{
|
||||
add(&FillBg(Color::Rgb(0,128,128)))?;
|
||||
//Align::Center(&self.items[self.index] as &dyn Widget<Engine = Tui>)
|
||||
Align::Center(Layers::new(|add|{
|
||||
add(&Outset::WH(1, 1, FillBg(Color::Rgb(0,128,128))))?;
|
||||
add(&Layers::new(|add|{
|
||||
add(&Align::Center("....."))?;
|
||||
add(&Align::Center("FOO"))?;
|
||||
Ok(())
|
||||
}))
|
||||
})
|
||||
//Align::Center(&self.items[self.index] as &dyn Widget<Engine = Tui>)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue