wip: component playground; Align primitive

This commit is contained in:
🪞👃🪞 2024-09-07 20:54:49 +03:00
parent 4cca03352a
commit 5fc7da3aca
12 changed files with 181 additions and 42 deletions

View file

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

View file

@ -2,19 +2,18 @@ use crate::*;
// TODO: Convert to component
// pub enum Align { Center, NW, N, NE, E, SE, S, SW, W, }
pub fn center_box (area: Rect, w: u16, h: u16) -> Rect {
let width = w.min(area.width * 3 / 5);
let height = h.min(area.width * 3 / 5);
let x = area.x + (area.width - width) / 2;
let y = area.y + (area.height - height) / 2;
Rect { x, y, width, height }
pub fn center_box (area: [u16;4], w: u16, h: u16) -> [u16;4] {
let width = w.min(area.w() * 3 / 5);
let height = h.min(area.w() * 3 / 5);
let x = area.x() + (area.w() - width) / 2;
let y = area.y() + (area.h() - height) / 2;
[x, y, width, height]
}
/// Trait for structs that compute drawing area before rendering
pub trait Layout<E: Engine>: Render<E> {
fn layout (&self, area: E::Area) -> Perhaps<E::Area>;
}
impl<E: Engine, T: Layout<E>> Layout<E> for &T {
fn layout (&self, area: E::Area) -> Perhaps<E::Area> {
(*self).layout(area)
@ -29,6 +28,8 @@ impl<E: Engine, T: Layout<E>> Layout<E> for Option<T> {
}
}
/// 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) }
/// Enforce minimum size of drawing area
pub enum Min<U: Number, L> { W(U, L), H(U, L), WH(U, U, L), }
/// Enforce maximum size of drawing area

View file

@ -15,7 +15,7 @@ pub(crate) use std::thread::{spawn, JoinHandle};
pub(crate) use std::time::Duration;
pub(crate) use atomic_float::*;
use better_panic::{Settings, Verbosity};
use std::ops::{Add, Sub};
use std::ops::{Add, Sub, Div};
use std::cmp::{Ord, Eq, PartialEq};
use std::fmt::{Debug, Display};
@ -48,6 +48,7 @@ pub type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
pub trait Number: Send + Sync + Copy
+ Add<Self, Output=Self>
+ Sub<Self, Output=Self>
+ Div<Self, Output=Self>
+ Ord + PartialEq + Eq
+ Debug + Display {}
@ -55,6 +56,7 @@ impl<T> Number for T where
T: Send + Sync + Copy
+ Add<Self, Output=Self>
+ Sub<Self, Output=Self>
+ Div<Self, Output=Self>
+ Ord + PartialEq + Eq
+ Debug + Display
{}

View file

@ -36,6 +36,7 @@ impl Engine for Tui {
let better_panic_handler = Settings::auto().verbosity(Verbosity::Full).create_panic_handler();
std::panic::set_hook(Box::new(move |info: &std::panic::PanicInfo|{
stdout().execute(LeaveAlternateScreen).unwrap();
CrosstermBackend::new(stdout()).show_cursor().unwrap();
disable_raw_mode().unwrap();
better_panic_handler(info);
}));

View file

@ -72,3 +72,56 @@ impl<'a> Split<'a, Tui> {
}, areas))
}
}
impl<L: Layout<Tui>> Layout<Tui> for Align<L> where Self: Render<Tui> {
fn layout (&self, outer_area: [u16;4]) -> Perhaps<[u16;4]> {
Ok(match self {
Self::Center(inner) => inner,
Self::NW(inner) => inner,
Self::N(inner) => inner,
Self::NE(inner) => inner,
Self::W(inner) => inner,
Self::E(inner) => inner,
Self::SW(inner) => inner,
Self::S(inner) => inner,
Self::SE(inner) => 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]
},
Self::NW(_) => { todo!() },
Self::N(_) => { todo!() },
Self::NE(_) => { todo!() },
Self::W(_) => { todo!() },
Self::E(_) => { todo!() },
Self::SW(_) => { todo!() },
Self::S(_) => { todo!() },
Self::SE(_) => { todo!() },
}))
}
}
impl<R: Render<Tui> + Layout<Tui>> Render<Tui> for Align<R> {
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
self.layout(to.area())?
.map(|area|to.with_area(area.x(), area.y(), area.w(), area.h()))
.map(|to|match self {
Self::Center(inner) => inner,
Self::NW(inner) => inner,
Self::N(inner) => inner,
Self::NE(inner) => inner,
Self::W(inner) => inner,
Self::E(inner) => inner,
Self::SW(inner) => inner,
Self::S(inner) => inner,
Self::SE(inner) => inner,
}.render(to))
.transpose()
.map(|x|x.flatten())
}
}