mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
wip: component playground; Align primitive
This commit is contained in:
parent
4cca03352a
commit
5fc7da3aca
12 changed files with 181 additions and 42 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue