mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-07 12:16:42 +01:00
wip: return () from render method
This commit is contained in:
parent
5d00e9f284
commit
e3fa292a3c
3 changed files with 167 additions and 140 deletions
|
|
@ -13,12 +13,19 @@ use crossterm::terminal::{
|
|||
|
||||
pub struct Tui {
|
||||
exited: Arc<AtomicBool>,
|
||||
buffer: usize,
|
||||
buffers: [Buffer;2],
|
||||
buffer: Buffer,
|
||||
backend: CrosstermBackend<Stdout>,
|
||||
event: RwLock<Option<TuiEvent>>,
|
||||
area: [u16;4],
|
||||
}
|
||||
pub struct TuiInput {
|
||||
event: TuiEvent,
|
||||
exited: Arc<AtomicBool>,
|
||||
}
|
||||
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<Tui> for Tui {
|
||||
#[inline] fn area (&self) -> <Self as Engine>::Area {
|
||||
self.area
|
||||
}
|
||||
#[inline] fn area_mut (&mut self) -> &mut <Self as Engine>::Area {
|
||||
&mut self.area
|
||||
}
|
||||
#[inline] fn render_in (&mut self,
|
||||
area: <Self as Engine>::Area,
|
||||
widget: &dyn Widget<Engine = Self>
|
||||
) -> Perhaps<<Self as Engine>::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<AtomicBool>,
|
||||
}
|
||||
impl Input<Tui> for TuiInput {
|
||||
type Event = TuiEvent;
|
||||
fn event (&self) -> &TuiEvent {
|
||||
|
|
@ -82,6 +67,86 @@ impl Input<Tui> for TuiInput {
|
|||
self.exited.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
//impl Output<Tui> for Tui {
|
||||
//#[inline] fn area (&self) -> <Self as Engine>::Area {
|
||||
//self.area
|
||||
//}
|
||||
//#[inline] fn area_mut (&mut self) -> &mut <Self as Engine>::Area {
|
||||
//&mut self.area
|
||||
//}
|
||||
//#[inline] fn render_in (&mut self,
|
||||
//area: <Self as Engine>::Area,
|
||||
//widget: &dyn Widget<Engine = Self>
|
||||
//) -> Perhaps<<Self as Engine>::Area> {
|
||||
//let last = self.area();
|
||||
//*self.area_mut() = area;
|
||||
//let next = widget.render(self)?;
|
||||
//*self.area_mut() = last;
|
||||
//Ok(next)
|
||||
//}
|
||||
//}
|
||||
impl Output<Tui> 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<Engine = Tui>
|
||||
) -> 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<str>, x: u16, y: u16, style: Option<Style>
|
||||
) {
|
||||
let text = text.as_ref();
|
||||
let buf = &mut self.buffer;
|
||||
if x < buf.area.width && y < buf.area.height {
|
||||
buf.set_string(x, y, text, style.unwrap_or(Style::default()));
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn with_rect (&mut self, area: [u16;4]) -> &mut Self {
|
||||
self.area = area;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Tui {
|
||||
/// Run the main loop.
|
||||
|
|
@ -93,8 +158,7 @@ impl Tui {
|
|||
let engine = Self {
|
||||
exited: Arc::new(AtomicBool::new(false)),
|
||||
event: RwLock::new(None),
|
||||
buffer: 0,
|
||||
buffers: [Buffer::empty(area), Buffer::empty(area)],
|
||||
buffer: Buffer::empty(area),
|
||||
area: area.xywh(),
|
||||
backend,
|
||||
};
|
||||
|
|
@ -140,69 +204,30 @@ impl Tui {
|
|||
let exited = engine.read().unwrap().exited.clone();
|
||||
let engine = engine.clone();
|
||||
let state = state.clone();
|
||||
let mut buffer = Buffer::empty(
|
||||
engine.read().unwrap().backend.size().expect("get size failed")
|
||||
);
|
||||
spawn(move || loop {
|
||||
if exited.fetch_and(true, Ordering::Relaxed) {
|
||||
break
|
||||
}
|
||||
if let Ok(state) = state.try_read() {
|
||||
let mut engine = engine.write().unwrap();
|
||||
engine.area = engine.backend.size().expect("get size failed").xywh();
|
||||
state.render(&mut engine).expect("render failed");
|
||||
engine.flip();
|
||||
let area = engine.read().unwrap().backend.size().expect("get size failed").xywh();
|
||||
let mut output = TuiOutput { buffer, area };
|
||||
state.render(&mut output).expect("render failed");
|
||||
buffer = engine.write().unwrap().flip(output.buffer);
|
||||
}
|
||||
std::thread::sleep(sleep);
|
||||
})
|
||||
}
|
||||
pub fn buffer (&mut self) -> &mut Buffer {
|
||||
&mut self.buffers[self.buffer]
|
||||
}
|
||||
fn flip (&mut self) {
|
||||
let previous_buffer = &self.buffers[1 - self.buffer];
|
||||
let current_buffer = &self.buffers[self.buffer];
|
||||
let updates = previous_buffer.diff(current_buffer);
|
||||
//pub fn buffer (&mut self) -> &mut Buffer {
|
||||
//&mut self.buffers[self.buffer]
|
||||
//}
|
||||
fn flip (&mut self, mut buffer: Buffer) -> Buffer {
|
||||
let updates = self.buffer.diff(&buffer);
|
||||
self.backend.draw(updates.into_iter()).expect("failed to render");
|
||||
self.buffers[1 - self.buffer].reset();
|
||||
self.buffer = 1 - self.buffer;
|
||||
}
|
||||
pub fn buffer_update (&mut self, area: [u16;4], callback: &impl Fn(&mut Cell, u16, u16)) {
|
||||
buffer_update(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<str>, x: u16, y: u16, style: Option<Style>
|
||||
) -> Perhaps<[u16;4]> {
|
||||
let text = text.as_ref();
|
||||
let buf = self.buffer();
|
||||
if x < buf.area.width && y < buf.area.height {
|
||||
buf.set_string(x, y, text, style.unwrap_or(Style::default()));
|
||||
}
|
||||
Ok(Some([x, y, text.len() as u16, 1]))
|
||||
}
|
||||
#[inline]
|
||||
pub fn with_rect (&mut self, area: [u16;4]) -> &mut Self {
|
||||
self.area = area;
|
||||
self
|
||||
std::mem::swap(&mut self.buffer, &mut buffer);
|
||||
buffer
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -279,11 +304,10 @@ impl Widget for &str {
|
|||
// TODO: line breaks
|
||||
Ok(Some([self.len() as u16, 1]))
|
||||
}
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
||||
let [x, y, ..] = to.area();
|
||||
let [w, h] = self.layout(to.area().wh())?.unwrap();
|
||||
to.blit(&self, x, y, None)?;
|
||||
Ok(Some([x, y, w, h]))
|
||||
Ok(to.blit(&self, x, y, None))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -294,9 +318,10 @@ impl Widget for Styled<&str> {
|
|||
fn layout (&self, area: [u16;2]) -> Perhaps<[u16;2]> {
|
||||
Ok(Some([self.1.len() as u16, 1]))
|
||||
}
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
let _ = self.layout(to.area().wh())?.unwrap();
|
||||
Ok(Some([to.area.x(), to.area.y(), self.1.len() as u16, 1]))
|
||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
||||
todo!()
|
||||
//let _ = self.layout(to.area().wh())?.unwrap();
|
||||
//Ok(Some([to.area.x(), to.area.y(), self.1.len() as u16, 1]))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -307,9 +332,8 @@ impl Widget for Background {
|
|||
fn layout (&self, _: [u16;2]) -> Perhaps<[u16;2]> {
|
||||
Ok(Some([0,0]))
|
||||
}
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
to.fill_bg(to.area(), self.0);
|
||||
Ok(Some(to.area))
|
||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
||||
Ok(to.fill_bg(to.area(), self.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -322,12 +346,12 @@ impl<T: Widget<Engine = Tui>> Widget for Fixed<u16, T> {
|
|||
Self::XY(w, h, _) => (to.w() < *w && to.h() < *h).then(||[to.w() - *w, to.h() - *h])
|
||||
}.map(|offset_area|self.inner().layout(offset_area.into())).transpose()?.flatten())
|
||||
}
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
||||
// 🡘 🡙 ←🡙→
|
||||
if let Some(size) = self.layout(to.area().wh())? {
|
||||
to.render_in(to.area().clip(size), self.inner())
|
||||
} else {
|
||||
Ok(None)
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -371,7 +395,7 @@ where
|
|||
};
|
||||
Ok(Some([w, h]))
|
||||
}
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
||||
let area = to.area();
|
||||
let mut w = 0;
|
||||
let mut h = 0;
|
||||
|
|
@ -381,8 +405,10 @@ where
|
|||
if h >= area.h() {
|
||||
return Ok(())
|
||||
}
|
||||
let area = Plus::Y(h, component as &dyn Widget<Engine = Tui>).render(to)?;
|
||||
if let Some([_, _, width, height]) = area {
|
||||
// FIXME
|
||||
let area = Plus::Y(h, component as &dyn Widget<Engine = Tui>).layout(area.wh())?;
|
||||
if let Some([width, height]) = area {
|
||||
Plus::Y(h, component as &dyn Widget<Engine = Tui>).render(to)?;
|
||||
h += height;
|
||||
w = w.max(width)
|
||||
};
|
||||
|
|
@ -394,8 +420,9 @@ where
|
|||
if w >= area.w() {
|
||||
return Ok(())
|
||||
}
|
||||
let area = Plus::X(w, component as &dyn Widget<Engine = Tui>).render(to)?;
|
||||
if let Some([_, _, width, height]) = area {
|
||||
let area = Plus::X(w, component as &dyn Widget<Engine = Tui>).layout(area.wh())?;
|
||||
if let Some([width, height]) = area {
|
||||
Plus::X(w, component as &dyn Widget<Engine = Tui>).render(to)?;
|
||||
w += width;
|
||||
h = h.max(height)
|
||||
};
|
||||
|
|
@ -404,7 +431,7 @@ where
|
|||
},
|
||||
_ => todo!()
|
||||
};
|
||||
Ok(Some([area.x(), area.y(), w, h]))
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -425,7 +452,7 @@ where
|
|||
})?;
|
||||
Ok(Some([w, h]))
|
||||
}
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
||||
self.layout(to.area().wh())?
|
||||
.map(|size|(self.0)(&mut |layer|{
|
||||
to.render_in(to.area().clip(size), &layer).map(|_|())
|
||||
|
|
@ -442,7 +469,7 @@ impl<S: BorderStyle> Widget for Border<S> {
|
|||
fn layout (&self, to: [u16;2]) -> Perhaps<[u16;2]> {
|
||||
Outset::XY(1, 1, "").layout(to)
|
||||
}
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
||||
let area = to.area();
|
||||
if area.w() > 2 && area.y() > 2 {
|
||||
to.blit(&self.0.nw(), area.x(), area.y(), self.0.style())?;
|
||||
|
|
@ -498,7 +525,7 @@ pub trait BorderStyle: Send + Sync {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn draw <'a> (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
fn draw <'a> (&self, to: &mut TuiOutput) -> Usually<()> {
|
||||
self.draw_horizontal(to, None)?;
|
||||
self.draw_vertical(to, None)?;
|
||||
self.draw_corners(to, None)?;
|
||||
|
|
@ -506,7 +533,7 @@ pub trait BorderStyle: Send + Sync {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn draw_horizontal (&self, to: &mut Tui, style: Option<Style>) -> Usually<[u16;4]> {
|
||||
fn draw_horizontal (&self, to: &mut TuiOutput, style: Option<Style>) -> Usually<[u16;4]> {
|
||||
let area = to.area();
|
||||
let style = style.or_else(||self.style_horizontal());
|
||||
let [x, x2, y, y2] = area.lrtb();
|
||||
|
|
@ -517,16 +544,16 @@ pub trait BorderStyle: Send + Sync {
|
|||
Ok(area)
|
||||
}
|
||||
#[inline]
|
||||
fn draw_north (&self, to: &mut Tui, x: u16, y: u16, style: Option<Style>) -> Perhaps<[u16;4]> {
|
||||
fn draw_north (&self, to: &mut TuiOutput, x: u16, y: u16, style: Option<Style>) -> Usually<()> {
|
||||
to.blit(&Self::N, x, y, style)
|
||||
}
|
||||
#[inline]
|
||||
fn draw_south (&self, to: &mut Tui, x: u16, y: u16, style: Option<Style>) -> Perhaps<[u16;4]> {
|
||||
fn draw_south (&self, to: &mut TuiOutput, x: u16, y: u16, style: Option<Style>) -> Usually<()> {
|
||||
to.blit(&Self::S, x, y, style)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn draw_vertical (&self, to: &mut Tui, style: Option<Style>) -> Usually<[u16;4]> {
|
||||
fn draw_vertical (&self, to: &mut TuiOutput, style: Option<Style>) -> Usually<[u16;4]> {
|
||||
let area = to.area();
|
||||
let style = style.or_else(||self.style_vertical());
|
||||
let [x, x2, y, y2] = area.lrtb();
|
||||
|
|
@ -538,7 +565,7 @@ pub trait BorderStyle: Send + Sync {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn draw_corners (&self, to: &mut Tui, style: Option<Style>) -> Usually<[u16;4]> {
|
||||
fn draw_corners (&self, to: &mut TuiOutput, style: Option<Style>) -> Usually<[u16;4]> {
|
||||
let area = to.area();
|
||||
let style = style.or_else(||self.style_corners());
|
||||
let [x, y, width, height] = area.xywh();
|
||||
|
|
@ -590,7 +617,7 @@ macro_rules! border {
|
|||
fn layout (&self, area: [u16;2]) -> Perhaps<[u16;2]> {
|
||||
Ok(Some(area))
|
||||
}
|
||||
fn render (&self, to: &mut Tui) -> Perhaps<[u16;4]> {
|
||||
fn render (&self, to: &mut TuiOutput) -> Usually<()> {
|
||||
self.draw(to)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue