Compare commits

...

2 commits

Author SHA1 Message Date
facile pop culture reference
aa0dd37d88 implement align for all azimuths
Some checks are pending
/ build (push) Waiting to run
2026-07-15 14:28:19 +03:00
facile pop culture reference
482b624169 add Screen::area and ::clip to implement Align 2026-07-15 12:57:53 +03:00
7 changed files with 85 additions and 37 deletions

2
dizzle

@ -1 +1 @@
Subproject commit af2a10751f87caef8e5526d1f692c941b8de8357 Subproject commit 0050385e63ea5d3ab9be7c495dae5fc635396cf0

View file

@ -24,7 +24,15 @@ use crate::*;
pub trait Screen: Xy<Self::Unit> + Wh<Self::Unit> + Send + Sync + Sized { pub trait Screen: Xy<Self::Unit> + Wh<Self::Unit> + Send + Sync + Sized {
type Unit: Coord; type Unit: Coord;
/// Render drawable in subarea specified by `area` /// Render drawable in subarea specified by `area`
fn show <T: Draw<Self>> (&mut self, content: T) -> Perhaps<XYWH<Self::Unit>>; fn show (&mut self, content: impl Draw<Self>) -> Perhaps<XYWH<Self::Unit>>;
/// Get current clipping area
fn area (&self) -> XYWH<Self::Unit>;
/// Set clipping area
fn clip <T> (
&mut self,
area: impl Into<Option<XYWH<Self::Unit>>>,
draw: impl FnOnce(&mut Self)->T
) -> T;
} }
/// Implement the [Draw] trait for a particular drawable and [Screen]. /// Implement the [Draw] trait for a particular drawable and [Screen].

View file

@ -33,3 +33,8 @@ pub trait Coord: Send + Sync + Copy
/// Convert to [AtomicUsize]. /// Convert to [AtomicUsize].
fn atomic (self) -> AtomicUsize { AtomicUsize::new(self.into()) } fn atomic (self) -> AtomicUsize { AtomicUsize::new(self.into()) }
} }
/// TUI works in u16 coordinates.
impl Coord for u16 {
fn plus (self, other: Self) -> Self { self.saturating_add(other) }
}

View file

@ -71,16 +71,16 @@ pub trait Layout<S: Screen>: Draw<S> + Sized {
Push::XY(self, x.into(), y.into()) Push::XY(self, x.into(), y.into())
} }
fn align (self, azimuth: impl Into<Option<Azimuth>>) -> impl Draw<S> { fn align (self, azimuth: impl Into<Option<Azimuth>>) -> Align<Self> {
Align(azimuth.into(), self) Align(azimuth.into(), self)
} }
fn align_c (self) -> impl Draw<S> { fn align_c (self) -> Align<Self> {
Align(Some(Azimuth::C), self) Align(Some(Azimuth::C), self)
} }
fn align_x (self) -> impl Draw<S> { fn align_x (self) -> Align<Self> {
Align(Some(Azimuth::X), self) Align(Some(Azimuth::X), self)
} }
fn align_y (self) -> impl Draw<S> { fn align_y (self) -> Align<Self> {
Align(Some(Azimuth::Y), self) Align(Some(Azimuth::Y), self)
} }
@ -287,8 +287,27 @@ impl_draw!(<T: Screen, I: Draw<T>, X: Into<Option<T::Unit>>,>|self: Pad<T, I, X>
pub struct Align<T>(Option<Azimuth>, T); pub struct Align<T>(Option<Azimuth>, T);
impl_draw!(<S: Screen, T: Draw<S>,>|self: Align<T>, _to: S|{ impl_draw!(<S: Screen, T: Draw<S>,>|self: Align<T>, to: S|{
todo!() use Azimuth::*;
let XYWH(x0, y0, w0, h0) = to.area();
if let Some(XYWH(x, y, w, h)) = self.1.layout(to.area())? {
to.clip(match self.0 {
Some(NW) => XYWH(x0, y0, w, h),
Some(N) => XYWH(x0 + w0.sub(w) / 2.into(), y0, w, h),
Some(NE) => XYWH((x0 + w0).sub(w), y0, w, h),
Some(W) => XYWH(x0, y0 + h0.sub(h) / 2.into(), w, h),
Some(C) => XYWH(x0 + w0.sub(w) / 2.into(), y0 + h0.sub(h) / 2.into(), w, h),
Some(E) => XYWH((x0 + w0).sub(w), y0 + h0.sub(h) / 2.into(), w, h),
Some(SW) => XYWH(x0, (y0 + h0).sub(h), w, h),
Some(S) => XYWH(x0 + w0.sub(w) / 2.into(), (y0 + h0).sub(h), w, h),
Some(SE) => XYWH((x0 + w0).sub(w), (y0 + h0).sub(h), w, h),
Some(X) => XYWH(x0 + w0.sub(w) / 2.into(), y, w, h),
Some(Y) => XYWH(x, y0 + h0.sub(h) / 2.into(), w, h),
None => to.area()
}, |to|self.1.draw(to))
} else {
self.1.draw(to)
}
}); });
/// Where is [0, 0] located? /// Where is [0, 0] located?
@ -315,10 +334,13 @@ pub fn area <S: Screen, T: Draw<S>, U: Into<Option<XYWH<S::Unit>>>> (
Area(origin.into(), it) Area(origin.into(), it)
} }
pub struct Area<S: Screen, T: Draw<S>>(Option<XYWH<S::Unit>>, T); pub struct Area<S: Screen, T: Draw<S>>(
pub Option<XYWH<S::Unit>>,
pub T
);
impl_draw!(<S: Screen, T: Draw<S>,>|self: Area<S, T>, _to: S|{ impl_draw!(<S: Screen, T: Draw<S>,>|self: Area<S, T>, to: S|{
todo!() to.clip(self.0, |to|self.1.draw(to))
}); });
pub struct Origin<T>(Option<Azimuth>, T); pub struct Origin<T>(Option<Azimuth>, T);

View file

@ -1,27 +1,26 @@
use super::*; use super::*;
use Azimuth::*;
pub const fn east <T: Screen> (a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> { pub const fn east <S: Screen, A: Draw<S>, B: Draw<S>> (a: A, b: B) -> impl Draw<S> {
Split::East.half(a, b) Split::East.half(a, b)
} }
pub const fn north <T: Screen> (a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> { pub const fn north <S: Screen, A: Draw<S>, B: Draw<S>> (a: A, b: B) -> impl Draw<S> {
Split::North.half(a, b) Split::North.half(a, b)
} }
pub const fn west <T: Screen> (a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> { pub const fn west <S: Screen, A: Draw<S>, B: Draw<S>> (a: A, b: B) -> impl Draw<S> {
Split::West.half(a, b) Split::West.half(a, b)
} }
pub const fn south <T: Screen> (a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> { pub const fn south <S: Screen, A: Draw<S>, B: Draw<S>> (a: A, b: B) -> impl Draw<S> {
Split::South.half(a, b) Split::South.half(a, b)
} }
pub const fn above <T: Screen> (a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> { pub const fn above <S: Screen, A: Draw<S>, B: Draw<S>> (a: A, b: B) -> impl Draw<S> {
Split::Above.half(a, b) Split::Above.half(a, b)
} }
pub const fn below <T: Screen> (a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> { pub const fn below <S: Screen, A: Draw<S>, B: Draw<S>> (a: A, b: B) -> impl Draw<S> {
Split::Below.half(a, b) Split::Below.half(a, b)
} }
@ -47,8 +46,8 @@ impl Split {
/// let _ = Split::East.half("", ""); /// let _ = Split::East.half("", "");
/// let _ = Split::West.half("", ""); /// let _ = Split::West.half("", "");
/// ``` /// ```
pub const fn half <T: Screen> (&self, a: impl Draw<T>, b: impl Draw<T>) -> impl Draw<T> { pub const fn half <S: Screen, A: Draw<S>, B: Draw<S>> (&self, a: A, b: B) -> impl Draw<S> {
thunk(move|to: &mut T|{ thunk(move|to: &mut S|{
let (area_a, area_b) = to.xywh().split_half(self); let (area_a, area_b) = to.xywh().split_half(self);
let (origin_a, origin_b) = self.origins(); let (origin_a, origin_b) = self.origins();
let a = a.align(origin_a); let a = a.align(origin_a);

View file

@ -119,19 +119,17 @@ pub fn eval_view <'a, O: Screen + 'a, S> (
).draw(output), ).draw(output),
// Second `frags.next()` calls returns the namespace member. // Second `frags.next()` calls returns the namespace member.
Some("bsp") => { Some("bsp") => eval_enum!("bsp", output, state, frags.next(), arg0, Split {
eval_enum!("bsp", output, state, frags.next(), arg0, Split { "n" => North,
"n" => North, "s" => South,
"s" => South, "e" => East,
"e" => East, "w" => West,
"w" => West, "a" => Above,
"a" => Above, "b" => Below
"b" => Below }).half(
}).half( thunk(move|output: &mut O|{state.interpret(output, &arg0)}),
thunk(move|output: &mut O|{state.interpret(output, &arg0)}), thunk(move|output: &mut O|{state.interpret(output, &arg1)}),
thunk(move|output: &mut O|{state.interpret(output, &arg1)}), ).draw(output),
).draw(output)
},
Some("align") => { Some("align") => {
let content = thunk(move|output: &mut O|{state.interpret(output, &arg0)}); let content = thunk(move|output: &mut O|{state.interpret(output, &arg0)});

View file

@ -1,13 +1,10 @@
use crate::*; use crate::*;
use ratatui::{prelude::{Style, Position, Backend, Color}}; use ratatui::{prelude::{Style, Position, Backend, Color}};
/// TUI works in u16 coordinates.
impl Coord for u16 { fn plus (self, other: Self) -> Self { self.saturating_add(other) } }
impl Screen for Tui { impl Screen for Tui {
type Unit = u16; type Unit = u16;
/// Render drawable in subarea specified by `area` /// Render drawable in subarea specified by `area`
fn show <'t, T: Draw<Self>> (&mut self, content: T) -> Perhaps<XYWH<u16>> { fn show (&mut self, content: impl Draw<Self>) -> Perhaps<XYWH<u16>> {
let previous_area = self.1; let previous_area = self.1;
Ok(if let Some(area) = content.layout(self.1)? { Ok(if let Some(area) = content.layout(self.1)? {
self.1 = area; self.1 = area;
@ -21,6 +18,25 @@ impl Screen for Tui {
None None
}) })
} }
/// Get current clipping area
fn area (&self) -> XYWH<Self::Unit> {
self.1
}
fn clip <T> (
&mut self,
area: impl Into<Option<XYWH<u16>>>,
draw: impl FnOnce(&mut Self)->T
) -> T {
let prev = self.1;
if let Some(area) = area.into() {
self.1 = area.into();
}
let result = draw(self);
self.1 = prev;
result
}
} }
/// Enable TUI output for state struct. /// Enable TUI output for state struct.