mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-09-18 13:26:42 +02:00
Compare commits
4 commits
8e7286e409
...
b318d498e5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b318d498e5 | ||
|
|
e55a7da3b4 | ||
|
|
7c9816a07e | ||
|
|
7f067b848f |
5 changed files with 79 additions and 145 deletions
2
dizzle
2
dizzle
|
|
@ -1 +1 @@
|
||||||
Subproject commit a3d7719bcc955552a5dbcf755115333872e87de4
|
Subproject commit b6c1bb5f9400c28de1709df78c18e0d4d5618a15
|
||||||
|
|
@ -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)),
|
Self::WH(..) => (Some(x0), Some(y0), Some(w0), Some(h0)),
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
Ok(to.draw(to.area(), item)?.map(|XYWH(x2, y2, w2, h2)|XYWH(
|
Ok(to
|
||||||
x1.unwrap_or(x2), y1.unwrap_or(y2), w1.unwrap_or(w2), h1.unwrap_or(h2),
|
.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 w1 = w1.unwrap_or(w0);
|
||||||
let h1 = h1.unwrap_or(h0);
|
let h1 = h1.unwrap_or(h0);
|
||||||
let area = XYWH(x0, y0, w1, h1);
|
Ok(to
|
||||||
let area = to.draw(area, item)?;
|
.draw(XYWH(x0, y0, w1, h1), item)?
|
||||||
Ok(area.map(|XYWH(x2, y2, w2, h2)|match self {
|
.map(|XYWH(x2, y2, w2, h2)|match self {
|
||||||
Self::W(..) => XYWH(x0, y2, w1, h2),
|
Self::W(..) => XYWH(x0, y2, w1, h2),
|
||||||
Self::H(..) => XYWH(x2, y0, w2, h1),
|
Self::H(..) => XYWH(x2, y0, w2, h1),
|
||||||
Self::WH(..) => XYWH(x0, y0, w1, h1),
|
Self::WH(..) => XYWH(x0, y0, w1, h1),
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,52 @@ fn_kw_layout!(kw_split |state, output, expr| {
|
||||||
#[default] Below
|
#[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);
|
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)));
|
/// assert_eq!(size_of(&split(East, split(South, "foo", "bar"), "baz"))?, Some(XYWH(0, 0, 6, 2)));
|
||||||
/// # return Ok(()); }
|
/// # 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
|
split: Split, a: A, b: B
|
||||||
) -> Pair<A, B> {
|
) -> Pair<A, B> {
|
||||||
Pair(split, a, b)
|
Pair(split, a, b)
|
||||||
|
|
@ -258,10 +304,7 @@ fn draw_stacks <'a, S: Screen> (
|
||||||
/// # Ok(()) }
|
/// # Ok(()) }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn stack_areas <'a, S: Screen> (
|
pub fn stack_areas <'a, S: Screen> (
|
||||||
split: &Split,
|
split: &Split, to: &mut S, a: impl Draw<S>, b: impl Draw<S>,
|
||||||
to: &mut S,
|
|
||||||
a: impl Draw<S>,
|
|
||||||
b: impl Draw<S>,
|
|
||||||
) -> UsuallyRef<'a, (Option<XYWH<S::Unit>>, Option<XYWH<S::Unit>>)> {
|
) -> UsuallyRef<'a, (Option<XYWH<S::Unit>>, Option<XYWH<S::Unit>>)> {
|
||||||
let area_a = to.size(None, a)?;
|
let area_a = to.size(None, a)?;
|
||||||
Ok(match split {
|
Ok(match split {
|
||||||
|
|
@ -329,6 +372,21 @@ fn stack_drawn <S: Coord> (
|
||||||
|
|
||||||
impl Split {
|
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::*;
|
/// use tengri::*;
|
||||||
/// let _ = Split::Above.stack(&"", &"");
|
/// let _ = Split::Above.stack(&"", &"");
|
||||||
|
|
|
||||||
125
src/lib.rs
125
src/lib.rs
|
|
@ -1316,16 +1316,6 @@ pub trait AsMutOpt<T> { fn as_mut_opt (&mut self) -> Option<&mut T>; }
|
||||||
|
|
||||||
/// Drawable that supports dynamic dispatch.
|
/// 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::*;
|
/// use tengri::*;
|
||||||
/// struct MyWidget(bool);
|
/// 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>;
|
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.
|
/// Because we can't implement [Draw] for `F: FnOnce...` without conflicts.
|
||||||
pub struct DrawThunk<S: Screen, F>(pub F, std::marker::PhantomData<S>);
|
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")] pub use self::color::*;
|
||||||
#[cfg(feature = "draw")] mod color {
|
#[cfg(feature = "draw")] mod color {
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use dizzle::LanguageError::*;
|
|
||||||
use ::ratatui::style::Color;
|
use ::ratatui::style::Color;
|
||||||
use ::rand::distributions::uniform::UniformSampler;
|
use ::rand::distributions::uniform::UniformSampler;
|
||||||
pub(crate) use ::palette::{
|
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")] pub use self::term::*;
|
||||||
#[cfg(feature = "term")] mod term;
|
#[cfg(feature = "term")] mod term;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use Color::*;
|
|
||||||
//use unicode_width::{UnicodeWidthStr, UnicodeWidthChar};
|
//use unicode_width::{UnicodeWidthStr, UnicodeWidthChar};
|
||||||
//use rand::distributions::uniform::UniformSampler;
|
//use rand::distributions::uniform::UniformSampler;
|
||||||
pub(crate) use ::{
|
pub(crate) use ::{
|
||||||
|
|
@ -268,7 +267,7 @@ impl Tui {
|
||||||
let Size { width, height } = backend.size().expect("get size failed");
|
let Size { width, height } = backend.size().expect("get size failed");
|
||||||
let mut prev = Tui::new(width, height);
|
let mut prev = Tui::new(width, height);
|
||||||
let mut next = 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");
|
let Size { width, height } = backend.size().expect("get size failed");
|
||||||
if let Some(state) = state.try_read() {
|
if let Some(state) = state.try_read() {
|
||||||
prev.resize(&mut backend, width, height);
|
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 {
|
#[cfg(feature = "text")] mod tui_text {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue