Compare commits

...

4 commits

Author SHA1 Message Date
facile pop culture reference
b318d498e5 implement Split::bar
Some checks failed
/ build (push) Has been cancelled
2026-08-31 19:04:16 +03:00
facile pop culture reference
e55a7da3b4 remove unused and commented stuff 2026-08-31 19:04:05 +03:00
facile pop culture reference
7c9816a07e move Keywords to dizzle 2026-08-31 19:03:51 +03:00
facile pop culture reference
7f067b848f bump dizzle 2026-08-30 20:18:07 +03:00
5 changed files with 79 additions and 145 deletions

2
dizzle

@ -1 +1 @@
Subproject commit a3d7719bcc955552a5dbcf755115333872e87de4
Subproject commit b6c1bb5f9400c28de1709df78c18e0d4d5618a15

View file

@ -308,9 +308,11 @@ impl <'a, S: Screen, I: Draw<S>> Draw<S> for Full<'a, S, I> {
Self::WH(..) => (Some(x0), Some(y0), Some(w0), Some(h0)),
_ => unreachable!()
};
Ok(to.draw(to.area(), item)?.map(|XYWH(x2, y2, w2, h2)|XYWH(
x1.unwrap_or(x2), y1.unwrap_or(y2), w1.unwrap_or(w2), h1.unwrap_or(h2),
)))
Ok(to
.draw(to.area(), item)?
.map(|XYWH(x2, y2, w2, h2)|XYWH(
x1.unwrap_or(x2), y1.unwrap_or(y2), w1.unwrap_or(w2), h1.unwrap_or(h2),
)))
}
}
@ -326,14 +328,14 @@ impl <'a, S: Screen, I: Draw<S>, X: Into<Option<S::Unit>> + Copy> Draw<S> for Ex
};
let w1 = w1.unwrap_or(w0);
let h1 = h1.unwrap_or(h0);
let area = XYWH(x0, y0, w1, h1);
let area = to.draw(area, item)?;
Ok(area.map(|XYWH(x2, y2, w2, h2)|match self {
Self::W(..) => XYWH(x0, y2, w1, h2),
Self::H(..) => XYWH(x2, y0, w2, h1),
Self::WH(..) => XYWH(x0, y0, w1, h1),
_ => unreachable!()
}))
Ok(to
.draw(XYWH(x0, y0, w1, h1), item)?
.map(|XYWH(x2, y2, w2, h2)|match self {
Self::W(..) => XYWH(x0, y2, w1, h2),
Self::H(..) => XYWH(x2, y0, w2, h1),
Self::WH(..) => XYWH(x0, y0, w1, h1),
_ => unreachable!()
}))
}
}

View file

@ -185,6 +185,52 @@ fn_kw_layout!(kw_split |state, output, expr| {
#[default] Below
}
/// Two components, first one has fixed size along the transverse axis.
pub struct Bar<N, A, B>(Split, N, A, B);
/// Define a split with first component having fixed size along the transverse axis.
pub fn bar <S: Screen, A: Draw<S>, B: Draw<S>> (
split: Split, n: impl Into<S::Unit>, a: A, b: B
) -> Bar<S::Unit, A, B> {
Bar(split, n.into(), a, b)
}
impl<S: Screen, A: Draw<S>, B: Draw<S>> Draw<S> for Bar<S::Unit, A, B> {
fn draw (&self, to: &mut S) -> Drawn<S::Unit> {
#[cfg(feature = "prof")] profiling::scope!("bar_draw");
let Self(split, n, a, b, ..) = self;
let (area_a, area_b) = bar_areas(to, split, *n, a, b)?;
let (drawn_a, drawn_b) = draw_stacks(split, to, a, area_a, None, b, area_b, None)?;
Ok(stack_drawn(split, drawn_a, drawn_b))
}
}
pub fn bar_areas <'a, S: Screen> (
to: &mut S, split: &Split, n: S::Unit, a: impl Draw<S>, b: impl Draw<S>,
) -> UsuallyRef<'a, (Option<XYWH<S::Unit>>, Option<XYWH<S::Unit>>)> {
let XYWH(x0, y0, w0, h0) = to.area();
Ok(match split {
Split::South => (
to.size(XYWH(x0, y0, w0, n), a)?,
to.size(XYWH(x0, y0 + n, w0, h0 - n), b)?,
),
Split::East => (
to.size(XYWH(x0, y0, n, h0), a)?,
to.size(XYWH(x0 + n, y0, w0 - n, h0), b)?,
),
Split::North => (
to.size(XYWH(x0, y0 + h0 - n, w0, n), a)?,
to.size(XYWH(x0, y0, w0, h0 - n), b)?,
),
Split::West => (
to.size(XYWH(x0 + w0 - n, y0, n, h0), a)?,
to.size(XYWH(x0, y0, w0 - n, h0), b)?,
),
_ => todo!()
})
}
/// Dynamically laid out split
pub struct Pair<A, B>(Split, A, B);
/// ```
@ -200,7 +246,7 @@ pub struct Pair<A, B>(Split, A, B);
/// assert_eq!(size_of(&split(East, split(South, "foo", "bar"), "baz"))?, Some(XYWH(0, 0, 6, 2)));
/// # return Ok(()); }
/// ```
pub fn split <'a, S: Screen, A: Draw<S>, B: Draw<S>> (
pub fn split <S: Screen, A: Draw<S>, B: Draw<S>> (
split: Split, a: A, b: B
) -> Pair<A, B> {
Pair(split, a, b)
@ -258,10 +304,7 @@ fn draw_stacks <'a, S: Screen> (
/// # Ok(()) }
/// ```
pub fn stack_areas <'a, S: Screen> (
split: &Split,
to: &mut S,
a: impl Draw<S>,
b: impl Draw<S>,
split: &Split, to: &mut S, a: impl Draw<S>, b: impl Draw<S>,
) -> UsuallyRef<'a, (Option<XYWH<S::Unit>>, Option<XYWH<S::Unit>>)> {
let area_a = to.size(None, a)?;
Ok(match split {
@ -329,6 +372,21 @@ fn stack_drawn <S: Coord> (
impl Split {
/// ```
/// use tengri::*;
/// let _ = Split::Above.stack(&"", &"");
/// let _ = Split::Below.stack(&"", &"");
/// let _ = Split::North.stack(&"", &"");
/// let _ = Split::South.stack(&"", &"");
/// let _ = Split::East.stack(&"", &"");
/// let _ = Split::West.stack(&"", &"");
/// ```
pub const fn bar <'a, S: Screen, A: Draw<S>, B: Draw<S>> (&self, n: S::Unit, a: A, b: B)
-> impl Draw<S>
{
Bar(*self, n, a, b)
}
/// ```
/// use tengri::*;
/// let _ = Split::Above.stack(&"", &"");

View file

@ -1316,16 +1316,6 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
/// Drawable that supports dynamic dispatch.
///
/// Drawables are composable, e.g. the [when] and [either] conditionals
/// or the layout constraints.
///
/// Drawables are consumable, i.e. the [Draw::draw] method receives an
/// owned `self` and does not return it, consuming the drawable.
///
/// To draw a thing multiple times, instead of explicitly constructing it
/// every time, implement the [View] trait instead, which will construct
/// a [Draw]able.
///
/// ```
/// use tengri::*;
/// struct MyWidget(bool);
@ -1339,39 +1329,6 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
fn draw (&self, to: &mut S) -> Drawn<S::Unit>;
}
///// Emit a [Draw]able.
/////
///// Speculative. How to avoid conflicts with [Draw] proper?
//pub trait View<T: Screen> {
//fn view (&self) -> impl Draw<T> ;
//}
//impl<T: Screen> View<T> for () {
//fn view (&self) -> impl Draw<T> {
//()
//}
//}
///// Return a [Draw]able.
/////
///// ```
///// # use tengri::*;
///// let _ = view::<Tui, _, _>(||"drawable");
///// let _ = view::<Tui, _, _>(||Some("drawable"));
///// ```
//pub const fn view <S: Screen, T: for<'a> Draw<S>, F: Fn()->T> (view: F) -> impl View<S> {
//ViewThunk(view, PhantomData)
//}
///// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
//pub struct ViewThunk<S: Screen, F>(pub F, std::marker::PhantomData<S>);
//impl<S: Screen, T: for<'a> Draw<S>, F: Fn()->T> View<S> for ViewThunk<S, F> {
//fn view (&self) -> impl Draw<S> {
//self.0()
//}
//}
/// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
pub struct DrawThunk<S: Screen, F>(pub F, std::marker::PhantomData<S>);
@ -1646,7 +1603,6 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
#[cfg(feature = "draw")] pub use self::color::*;
#[cfg(feature = "draw")] mod color {
use crate::*;
use dizzle::LanguageError::*;
use ::ratatui::style::Color;
use ::rand::distributions::uniform::UniformSampler;
pub(crate) use ::palette::{
@ -1898,86 +1854,5 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
}
}
#[cfg(feature = "eval")] pub use self::eval::*;
#[cfg(feature = "eval")] mod eval {
use crate::*;
/// ```
/// # use ::tengri::{*, dizzle::*, ratatui::prelude::Color};
///
/// #[namespace(bool)]
/// #[namespace(u8)]
/// #[namespace(u16)]
/// #[namespace(Option<u16>)]
/// #[namespace(Color get_color)]
/// struct App;
///
/// fn get_color (state: &App, src: impl Language) -> Perhaps<Color> {
/// Ok(if let Some(color) = Tui::eval_color_expr(state, &src)? {
/// Some(color)
/// } else if let Some(sym) = src.word()? {
/// Some(match sym {
/// ":color/bg" => Color::Rgb(28, 32, 36),
/// ":color/fg" => Color::Rgb(98, 92, 96),
/// _ => return Err(format!("not a color: {sym}").into())
/// })
/// } else {
/// return Err(format!("not a color: {:?}", src.src()?).into())
/// })
/// }
///
/// impl Interpret<Tui, Option<XYWH<u16>>> for App {
/// fn interpret_expr <'a> (&'a self, to: &mut Tui, lang: &'a impl Language)
/// -> Usually<Option<XYWH<u16>>>
/// {
/// self.keyword(to, lang)
/// }
/// }
///
/// impl Keywords<Tui, XYWH<u16>> for App {
/// fn keywords () -> impl Iterator<Item = fn(&Self, &mut Tui, &str) -> Perhaps<XYWH<u16>>> {
/// [
/// kw_when, kw_either, kw_split, kw_align,
/// kw_exact, kw_min, kw_max, kw_push,
/// kw_tui_text, kw_tui_fg, kw_tui_bg
/// ].into_iter()
/// }
/// }
///
/// # fn main () -> tengri::Usually<()> {
/// let state = App;
/// let mut out = Tui::new(80, 25);
/// state.interpret_expr(&mut out, &"")?;
/// state.interpret_expr(&mut out, &"text Hello world!")?;
/// state.interpret_expr(&mut out, &"fg (g 0) (text Hello world!)")?;
/// state.interpret_expr(&mut out, &"bg (g 2) (text Hello world!)")?;
/// state.interpret_expr(&mut out, &"(bg (g 3) (fg (g 4) (text Hello world!)))")?;
/// # Ok(()) }
/// ```
pub trait Keywords <U, V>: 'static {
fn keywords <'a> () -> impl Iterator<Item = fn(&Self, &mut U, &str) -> PerhapsRef<'a, V>>;
fn keyword <'a> (&self, to: &mut U, expr: &'a (impl Language + ?Sized)) -> PerhapsRef<'a, V> {
if let Some(expr) = expr.src()? {
for keyword in Self::keywords() {
if let Some(result) = keyword(self, to, &expr)? {
return Ok(Some(result))
}
}
}
Ok(None)
}
}
#[macro_export] macro_rules! impl_keywords {
($T:ty, $U:ty, $V:ty [ $($kw:ident),* ]) => {
impl Keywords<$T, $U> for $V {
fn keywords <'a> () -> impl Iterator<Item = fn(&Self, &mut $T, &str) -> PerhapsRef<'a, $U>> {
[ $($kw),* ].into_iter()
}
}
}
}
}
#[cfg(feature = "term")] pub use self::term::*;
#[cfg(feature = "term")] mod term;

View file

@ -1,5 +1,4 @@
use crate::*;
use Color::*;
//use unicode_width::{UnicodeWidthStr, UnicodeWidthChar};
//use rand::distributions::uniform::UniformSampler;
pub(crate) use ::{
@ -268,7 +267,7 @@ impl Tui {
let Size { width, height } = backend.size().expect("get size failed");
let mut prev = Tui::new(width, height);
let mut next = Tui::new(width, height);
Ok(Task::new_sleep(Some("tengri output"), exited.clone(), sleep, move |perf| {
Ok(Task::new_sleep(Some("tengri output"), exited.clone(), sleep, move |_perf| {
let Size { width, height } = backend.size().expect("get size failed");
if let Some(state) = state.try_read() {
prev.resize(&mut backend, width, height);
@ -409,7 +408,7 @@ impl<'a, T: Draw<Tui>> Draw<Tui> for ShowSizeOf<T> {
})
});
#[cfg(feature = "text")] pub use self::tui_text::*;
//#[cfg(feature = "text")] pub use self::tui_text::*;
#[cfg(feature = "text")] mod tui_text {
use super::*;