diff --git a/dizzle b/dizzle index a3d7719..b6c1bb5 160000 --- a/dizzle +++ b/dizzle @@ -1 +1 @@ -Subproject commit a3d7719bcc955552a5dbcf755115333872e87de4 +Subproject commit b6c1bb5f9400c28de1709df78c18e0d4d5618a15 diff --git a/src/layout/axis.rs b/src/layout/axis.rs index 0ea9cfa..1a02ab8 100644 --- a/src/layout/axis.rs +++ b/src/layout/axis.rs @@ -308,9 +308,11 @@ impl <'a, S: Screen, I: Draw> Draw 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, X: Into> + Copy> Draw 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!() + })) } } diff --git a/src/layout/azimuth.rs b/src/layout/azimuth.rs index 53c8853..c948a9a 100644 --- a/src/layout/azimuth.rs +++ b/src/layout/azimuth.rs @@ -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(Split, N, A, B); + +/// Define a split with first component having fixed size along the transverse axis. +pub fn bar , B: Draw> ( + split: Split, n: impl Into, a: A, b: B +) -> Bar { + Bar(split, n.into(), a, b) +} + +impl, B: Draw> Draw for Bar { + fn draw (&self, to: &mut S) -> Drawn { + #[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, b: impl Draw, +) -> UsuallyRef<'a, (Option>, Option>)> { + 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(Split, A, B); /// ``` @@ -200,7 +246,7 @@ pub struct Pair(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, B: Draw> ( +pub fn split , B: Draw> ( split: Split, a: A, b: B ) -> Pair { 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, - b: impl Draw, + split: &Split, to: &mut S, a: impl Draw, b: impl Draw, ) -> UsuallyRef<'a, (Option>, Option>)> { let area_a = to.size(None, a)?; Ok(match split { @@ -329,6 +372,21 @@ fn stack_drawn ( 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, B: Draw> (&self, n: S::Unit, a: A, b: B) + -> impl Draw + { + Bar(*self, n, a, b) + } + /// ``` /// use tengri::*; /// let _ = Split::Above.stack(&"", &""); diff --git a/src/lib.rs b/src/lib.rs index d68e831..92d0b69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1316,16 +1316,6 @@ pub trait AsMutOpt { 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 { fn as_mut_opt (&mut self) -> Option<&mut T>; } fn draw (&self, to: &mut S) -> Drawn; } - ///// Emit a [Draw]able. - ///// - ///// Speculative. How to avoid conflicts with [Draw] proper? - //pub trait View { - //fn view (&self) -> impl Draw ; - //} - - //impl View for () { - //fn view (&self) -> impl Draw { - //() - //} - //} - - ///// Return a [Draw]able. - ///// - ///// ``` - ///// # use tengri::*; - ///// let _ = view::(||"drawable"); - ///// let _ = view::(||Some("drawable")); - ///// ``` - //pub const fn view Draw, F: Fn()->T> (view: F) -> impl View { - //ViewThunk(view, PhantomData) - //} - - ///// Because we can't implement [Draw] for `F: FnOnce...` without conflicts. - //pub struct ViewThunk(pub F, std::marker::PhantomData); - - //impl Draw, F: Fn()->T> View for ViewThunk { - //fn view (&self) -> impl Draw { - //self.0() - //} - //} - /// Because we can't implement [Draw] for `F: FnOnce...` without conflicts. pub struct DrawThunk(pub F, std::marker::PhantomData); @@ -1646,7 +1603,6 @@ pub trait AsMutOpt { 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 { 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)] - /// #[namespace(Color get_color)] - /// struct App; - /// - /// fn get_color (state: &App, src: impl Language) -> Perhaps { - /// 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>> for App { - /// fn interpret_expr <'a> (&'a self, to: &mut Tui, lang: &'a impl Language) - /// -> Usually>> - /// { - /// self.keyword(to, lang) - /// } - /// } - /// - /// impl Keywords> for App { - /// fn keywords () -> impl Iterator Perhaps>> { - /// [ - /// 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 : 'static { - fn keywords <'a> () -> impl Iterator 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 PerhapsRef<'a, $U>> { - [ $($kw),* ].into_iter() - } - } - } - } -} - #[cfg(feature = "term")] pub use self::term::*; #[cfg(feature = "term")] mod term; diff --git a/src/term.rs b/src/term.rs index 8b19db3..dffe505 100644 --- a/src/term.rs +++ b/src/term.rs @@ -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> Draw for ShowSizeOf { }) }); -#[cfg(feature = "text")] pub use self::tui_text::*; +//#[cfg(feature = "text")] pub use self::tui_text::*; #[cfg(feature = "text")] mod tui_text { use super::*;