From 482b6241690f7b116b07d06fb4950754f6fdf584 Mon Sep 17 00:00:00 2001 From: facile pop culture reference Date: Wed, 15 Jul 2026 12:57:53 +0300 Subject: [PATCH] add Screen::area and ::clip to implement Align --- dizzle | 2 +- src/draw.rs | 10 +++++++++- src/draw/coord.rs | 5 +++++ src/draw/layout.rs | 40 +++++++++++++++++++++++++++++++--------- src/draw/split.rs | 17 ++++++++--------- src/eval.rs | 24 +++++++++++------------- src/term/output.rs | 24 ++++++++++++++++++++---- 7 files changed, 85 insertions(+), 37 deletions(-) diff --git a/dizzle b/dizzle index af2a107..0050385 160000 --- a/dizzle +++ b/dizzle @@ -1 +1 @@ -Subproject commit af2a10751f87caef8e5526d1f692c941b8de8357 +Subproject commit 0050385e63ea5d3ab9be7c495dae5fc635396cf0 diff --git a/src/draw.rs b/src/draw.rs index 64738bd..a672576 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -24,7 +24,15 @@ use crate::*; pub trait Screen: Xy + Wh + Send + Sync + Sized { type Unit: Coord; /// Render drawable in subarea specified by `area` - fn show > (&mut self, content: T) -> Perhaps>; + fn show (&mut self, content: impl Draw) -> Perhaps>; + /// Get current clipping area + fn area (&self) -> XYWH; + /// Set clipping area + fn clip ( + &mut self, + area: impl Into>>, + draw: impl FnOnce(&mut Self)->T + ) -> T; } /// Implement the [Draw] trait for a particular drawable and [Screen]. diff --git a/src/draw/coord.rs b/src/draw/coord.rs index 40d784d..053258e 100644 --- a/src/draw/coord.rs +++ b/src/draw/coord.rs @@ -33,3 +33,8 @@ pub trait Coord: Send + Sync + Copy /// Convert to [AtomicUsize]. 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) } +} diff --git a/src/draw/layout.rs b/src/draw/layout.rs index 71dca39..e70a449 100644 --- a/src/draw/layout.rs +++ b/src/draw/layout.rs @@ -71,16 +71,16 @@ pub trait Layout: Draw + Sized { Push::XY(self, x.into(), y.into()) } - fn align (self, azimuth: impl Into>) -> impl Draw { + fn align (self, azimuth: impl Into>) -> Align { Align(azimuth.into(), self) } - fn align_c (self) -> impl Draw { + fn align_c (self) -> Align { Align(Some(Azimuth::C), self) } - fn align_x (self) -> impl Draw { + fn align_x (self) -> Align { Align(Some(Azimuth::X), self) } - fn align_y (self) -> impl Draw { + fn align_y (self) -> Align { Align(Some(Azimuth::Y), self) } @@ -287,8 +287,27 @@ impl_draw!(, X: Into>,>|self: Pad pub struct Align(Option, T); -impl_draw!(,>|self: Align, _to: S|{ - todo!() +impl_draw!(,>|self: Align, to: S|{ + use Azimuth::*; + let XYWH(x0, y0, w0, h0) = to.area(); + Ok(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) => todo!(), + Some(NE) => todo!(), + Some(W) => todo!(), + Some(C) => todo!(), + Some(E) => todo!(), + Some(SW) => todo!(), + Some(S) => XYWH(x0 + w0.sub(w) / 2.into(), (y0 + h0).sub(h), w, h), + Some(SE) => todo!(), + Some(X) => todo!(), + Some(Y) => todo!(), + None => to.area() + }, |to|self.1.draw(to))? + } else { + None + }) }); /// Where is [0, 0] located? @@ -315,10 +334,13 @@ pub fn area , U: Into>>> ( Area(origin.into(), it) } -pub struct Area>(Option>, T); +pub struct Area>( + pub Option>, + pub T +); -impl_draw!(,>|self: Area, _to: S|{ - todo!() +impl_draw!(,>|self: Area, to: S|{ + to.clip(self.0, |to|self.1.draw(to)) }); pub struct Origin(Option, T); diff --git a/src/draw/split.rs b/src/draw/split.rs index 37ef914..1cee49c 100644 --- a/src/draw/split.rs +++ b/src/draw/split.rs @@ -1,27 +1,26 @@ use super::*; -use Azimuth::*; -pub const fn east (a: impl Draw, b: impl Draw) -> impl Draw { +pub const fn east , B: Draw> (a: A, b: B) -> impl Draw { Split::East.half(a, b) } -pub const fn north (a: impl Draw, b: impl Draw) -> impl Draw { +pub const fn north , B: Draw> (a: A, b: B) -> impl Draw { Split::North.half(a, b) } -pub const fn west (a: impl Draw, b: impl Draw) -> impl Draw { +pub const fn west , B: Draw> (a: A, b: B) -> impl Draw { Split::West.half(a, b) } -pub const fn south (a: impl Draw, b: impl Draw) -> impl Draw { +pub const fn south , B: Draw> (a: A, b: B) -> impl Draw { Split::South.half(a, b) } -pub const fn above (a: impl Draw, b: impl Draw) -> impl Draw { +pub const fn above , B: Draw> (a: A, b: B) -> impl Draw { Split::Above.half(a, b) } -pub const fn below (a: impl Draw, b: impl Draw) -> impl Draw { +pub const fn below , B: Draw> (a: A, b: B) -> impl Draw { Split::Below.half(a, b) } @@ -47,8 +46,8 @@ impl Split { /// let _ = Split::East.half("", ""); /// let _ = Split::West.half("", ""); /// ``` - pub const fn half (&self, a: impl Draw, b: impl Draw) -> impl Draw { - thunk(move|to: &mut T|{ + pub const fn half , B: Draw> (&self, a: A, b: B) -> impl Draw { + thunk(move|to: &mut S|{ let (area_a, area_b) = to.xywh().split_half(self); let (origin_a, origin_b) = self.origins(); let a = a.align(origin_a); diff --git a/src/eval.rs b/src/eval.rs index 423cb64..d103a0a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -119,19 +119,17 @@ pub fn eval_view <'a, O: Screen + 'a, S> ( ).draw(output), // Second `frags.next()` calls returns the namespace member. - Some("bsp") => { - eval_enum!("bsp", output, state, frags.next(), arg0, Split { - "n" => North, - "s" => South, - "e" => East, - "w" => West, - "a" => Above, - "b" => Below - }).half( - thunk(move|output: &mut O|{state.interpret(output, &arg0)}), - thunk(move|output: &mut O|{state.interpret(output, &arg1)}), - ).draw(output) - }, + Some("bsp") => eval_enum!("bsp", output, state, frags.next(), arg0, Split { + "n" => North, + "s" => South, + "e" => East, + "w" => West, + "a" => Above, + "b" => Below + }).half( + thunk(move|output: &mut O|{state.interpret(output, &arg0)}), + thunk(move|output: &mut O|{state.interpret(output, &arg1)}), + ).draw(output), Some("align") => { let content = thunk(move|output: &mut O|{state.interpret(output, &arg0)}); diff --git a/src/term/output.rs b/src/term/output.rs index b91f919..237860b 100644 --- a/src/term/output.rs +++ b/src/term/output.rs @@ -1,13 +1,10 @@ use crate::*; 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 { type Unit = u16; /// Render drawable in subarea specified by `area` - fn show <'t, T: Draw> (&mut self, content: T) -> Perhaps> { + fn show (&mut self, content: impl Draw) -> Perhaps> { let previous_area = self.1; Ok(if let Some(area) = content.layout(self.1)? { self.1 = area; @@ -21,6 +18,25 @@ impl Screen for Tui { None }) } + + /// Get current clipping area + fn area (&self) -> XYWH { + self.1 + } + + fn clip ( + &mut self, + area: impl Into>>, + 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.