diff --git a/crates/tek_core/src/audio.rs b/crates/tek_core/src/audio.rs index d0f151cd..7838cdc0 100644 --- a/crates/tek_core/src/audio.rs +++ b/crates/tek_core/src/audio.rs @@ -310,7 +310,7 @@ impl Widget for JackDevice { fn layout (&self, to: E::Size) -> Perhaps { self.state.read().unwrap().layout(to) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { self.state.read().unwrap().render(to) } } diff --git a/crates/tek_core/src/engine.rs b/crates/tek_core/src/engine.rs index 0f321ebd..6ec8317d 100644 --- a/crates/tek_core/src/engine.rs +++ b/crates/tek_core/src/engine.rs @@ -35,26 +35,26 @@ pub trait Output { fn area_mut (&mut self) -> &mut E::Area; fn render_in (&mut self, area: E::Area, widget: &dyn Widget) - -> Perhaps; + -> Usually<()>; } pub trait Widget: Send + Sync { type Engine: Engine; - fn layout ( - &self, to: ::Size + fn layout (&self, + to: ::Size ) -> Perhaps<::Size> { Ok(Some(to)) } - fn render ( - &self, to: &mut ::Output - ) -> Perhaps<<::Engine as Engine>::Area>; + fn render (&self, + to: &mut ::Output + ) -> Usually<()>; } impl<'a, E: Engine> Widget for Box + 'a> { type Engine = E; fn layout (&self, to: E::Size) -> Perhaps { (**self).layout(to) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { (**self).render(to) } } @@ -63,7 +63,7 @@ impl Widget for &dyn Widget { fn layout (&self, to: E::Size) -> Perhaps { (*self).layout(to) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { (*self).render(to) } } @@ -72,7 +72,7 @@ impl Widget for &mut dyn Widget { fn layout (&self, to: E::Size) -> Perhaps { (**self).layout(to) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { (**self).render(to) } } @@ -81,7 +81,7 @@ impl> Widget for Arc { fn layout (&self, to: E::Size) -> Perhaps { self.as_ref().layout(to) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { self.as_ref().render(to) } } @@ -90,7 +90,7 @@ impl> Widget for Mutex { fn layout (&self, to: E::Size) -> Perhaps { self.lock().unwrap().layout(to) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { self.lock().unwrap().render(to) } } @@ -99,7 +99,7 @@ impl> Widget for RwLock { fn layout (&self, to: E::Size) -> Perhaps { self.read().unwrap().layout(to) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { self.read().unwrap().render(to) } } @@ -108,8 +108,8 @@ impl> Widget for Option { fn layout (&self, to: E::Size) -> Perhaps { Ok(self.as_ref().map(|widget|widget.layout(to)).transpose()?.flatten()) } - fn render (&self, to: &mut E::Output) -> Perhaps { - Ok(self.as_ref().map(|widget|widget.render(to)).transpose()?.flatten()) + fn render (&self, to: &mut E::Output) -> Usually<()> { + self.as_ref().map(|widget|widget.render(to)).unwrap_or(Ok(())) } } @@ -127,10 +127,10 @@ impl> Widget for W { fn layout (&self, to: E::Size) -> Perhaps { self.content().layout(to) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { match self.layout(to.area().wh().into())? { Some(wh) => to.render_in(to.area().clip(wh).into(), &self.content()), - None => Ok(None) + None => Ok(()) } } } @@ -428,17 +428,17 @@ impl> Widget for Align { fn layout (&self, outer_area: E::Size) -> Perhaps { self.inner().layout(outer_area) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { let outer_area = to.area(); Ok(if let Some(inner_size) = self.layout(outer_area.wh().into())? { let inner_area = outer_area.clip(inner_size); if let Some(aligned) = align(&self, outer_area.into(), inner_area.into()) { to.render_in(aligned, self.inner())? } else { - None + () } } else { - None + () }) } } @@ -483,10 +483,10 @@ impl> Widget for Min { }.into())) } // TODO: 🡘 🡙 ←🡙→ - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { Ok(self.layout(to.area().wh().into())? .map(|size|to.render_in(to.area().clip(size).into(), self.inner())) - .transpose()?.flatten()) + .transpose()?.unwrap_or(())) } } @@ -515,10 +515,10 @@ impl> Widget for Max { Self::XY(w, h, _) => [to.w().min(w), to.h().min(h)], }.into())) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { Ok(self.layout(to.area().wh().into())? .map(|size|to.render_in(to.area().clip(size).into(), self.inner())) - .transpose()?.flatten()) + .transpose()?.unwrap_or(())) } } @@ -547,10 +547,10 @@ impl> Widget for Grow { Self::XY(w, h, _) => [to.w() + w, to.h() + h], }.into())) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { Ok(self.layout(to.area().wh().into())? .map(|size|to.render_in(to.area().clip(size).into(), self.inner())) - .transpose()?.flatten()) + .transpose()?.unwrap_or(())) } } @@ -579,10 +579,10 @@ impl> Widget for Shrink { Self::XY(w, h, _) => [to.w() - w, to.h() - h] }.into())) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { Ok(self.layout(to.area().wh().into())? .map(|size|to.render_in(to.area().clip(size).into(), self.inner())) - .transpose()?.flatten()) + .transpose()?.unwrap_or(())) } } @@ -627,7 +627,7 @@ impl> Widget for Inset { Self::XY(x, y, ref inner) => Shrink::XY(x + x, y + y, inner as &dyn Widget), }.layout(to) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { match *self { Self::X(x, ref inner) => Plus::X(x, inner as &dyn Widget), Self::Y(y, ref inner) => Plus::Y(y, inner as &dyn Widget), @@ -645,7 +645,7 @@ impl> Widget for Outset { Self::XY(x, y, ref inner) => Grow::XY(x + x, y + y, inner as &dyn Widget), }.layout(to) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { match *self { Self::X(x, ref inner) => Plus::X(x, inner as &dyn Widget), Self::Y(y, ref inner) => Plus::Y(y, inner as &dyn Widget), @@ -681,14 +681,14 @@ impl> Widget for Plus { fn layout (&self, to: E::Size) -> Perhaps { self.inner().layout(to) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { let area = to.area(); Ok(self.layout(area.wh().into())? .map(|size|to.render_in(match *self { Self::X(x, _) => [area.x() + x, area.y(), size.w(), size.h()], Self::Y(y, _) => [area.x(), area.y() + y, size.w(), size.h()], Self::XY(x, y, _) => [area.x() + x, area.y() + y, size.w(), size.h()], - }.into(), self.inner())).transpose()?.flatten()) + }.into(), self.inner())).transpose()?.unwrap_or(())) } } @@ -719,14 +719,14 @@ impl> Widget for Minus { fn layout (&self, to: E::Size) -> Perhaps { self.inner().layout(to) } - fn render (&self, to: &mut E::Output) -> Perhaps { + fn render (&self, to: &mut E::Output) -> Usually<()> { let area = to.area(); Ok(self.layout(area.wh().into())? .map(|size|to.render_in(match *self { Self::X(x, _) => [area.x().minus(x), area.y(), size.w(), size.h()], Self::Y(y, _) => [area.x(), area.y().minus(y), size.w(), size.h()], Self::XY(x, y, _) => [area.x().minus(x), area.y().minus(y), size.w(), size.h()], - }.into(), self.inner())).transpose()?.flatten()) + }.into(), self.inner())).transpose()?.unwrap_or(())) } } diff --git a/crates/tek_core/src/tui.rs b/crates/tek_core/src/tui.rs index 5af2de17..3fd8b8c1 100644 --- a/crates/tek_core/src/tui.rs +++ b/crates/tek_core/src/tui.rs @@ -13,12 +13,19 @@ use crossterm::terminal::{ pub struct Tui { exited: Arc, - buffer: usize, - buffers: [Buffer;2], + buffer: Buffer, backend: CrosstermBackend, event: RwLock>, area: [u16;4], } +pub struct TuiInput { + event: TuiEvent, + exited: Arc, +} +pub struct TuiOutput { + buffer: Buffer, + area: [u16;4], +} impl Engine for Tui { type Unit = u16; @@ -26,7 +33,7 @@ impl Engine for Tui { type Area = [Self::Unit;4]; type Input = TuiInput; type Handled = bool; - type Output = Self; + type Output = TuiOutput; fn exited (&self) -> bool { self.exited.fetch_and(true, Ordering::Relaxed) } @@ -48,28 +55,6 @@ impl Engine for Tui { disable_raw_mode().map_err(Into::into) } } -impl Output for Tui { - #[inline] fn area (&self) -> ::Area { - self.area - } - #[inline] fn area_mut (&mut self) -> &mut ::Area { - &mut self.area - } - #[inline] fn render_in (&mut self, - area: ::Area, - widget: &dyn Widget - ) -> Perhaps<::Area> { - let last = self.area(); - *self.area_mut() = area; - let next = widget.render(self)?; - *self.area_mut() = last; - Ok(next) - } -} -pub struct TuiInput { - event: TuiEvent, - exited: Arc, -} impl Input for TuiInput { type Event = TuiEvent; fn event (&self) -> &TuiEvent { @@ -82,6 +67,86 @@ impl Input for TuiInput { self.exited.store(true, Ordering::Relaxed); } } +//impl Output for Tui { + //#[inline] fn area (&self) -> ::Area { + //self.area + //} + //#[inline] fn area_mut (&mut self) -> &mut ::Area { + //&mut self.area + //} + //#[inline] fn render_in (&mut self, + //area: ::Area, + //widget: &dyn Widget + //) -> Perhaps<::Area> { + //let last = self.area(); + //*self.area_mut() = area; + //let next = widget.render(self)?; + //*self.area_mut() = last; + //Ok(next) + //} +//} +impl Output for TuiOutput { + #[inline] fn area (&self) -> [u16;4] { + self.area + } + #[inline] fn area_mut (&mut self) -> &mut [u16;4] { + &mut self.area + } + #[inline] fn render_in (&mut self, + area: [u16;4], + widget: &dyn Widget + ) -> Usually<()> { + let last = self.area(); + *self.area_mut() = area; + widget.render(self)?; + *self.area_mut() = last; + Ok(()) + } +} +impl TuiOutput { + pub fn buffer_update (&mut self, + area: [u16;4], + callback: &impl Fn(&mut Cell, u16, u16) + ) { + buffer_update(&mut self.buffer, area, callback); + } + pub fn fill_bg (&mut self, area: [u16;4], color: Color) { + self.buffer_update(area, &|cell,_,_|{cell.set_bg(color);}) + } + pub fn fill_fg (&mut self, area: [u16;4], color: Color) { + self.buffer_update(area, &|cell,_,_|{cell.set_fg(color);}) + } + pub fn fill_ul (&mut self, area: [u16;4], color: Color) { + self.buffer_update(area, &|cell,_,_|{ + cell.modifier = ratatui::prelude::Modifier::UNDERLINED; + cell.underline_color = color; + }) + } + pub fn fill_char (&mut self, area: [u16;4], c: char) { + self.buffer_update(area, &|cell,_,_|{cell.set_char(c);}) + } + pub fn make_dim (&mut self) { + for cell in self.buffer.content.iter_mut() { + cell.bg = ratatui::style::Color::Rgb(30,30,30); + cell.fg = ratatui::style::Color::Rgb(100,100,100); + cell.modifier = ratatui::style::Modifier::DIM; + } + } + pub fn blit ( + &mut self, text: &impl AsRef, x: u16, y: u16, style: Option