Crossterm interface

This commit is contained in:
2026-07-14 13:52:41 -04:00
parent 3428beef8e
commit fd7192e111
4 changed files with 63 additions and 9 deletions
+21 -2
View File
@@ -17,6 +17,25 @@ pub trait App {
// Rendering // Rendering
async fn layout(&self) -> layout::LayoutItem; async fn layout(&self) -> layout::LayoutItem;
async fn render(&mut self, allocation: layout::Allocation); async fn render(&mut self, allocation: layout::Allocation);
async fn refresh(&mut self) {
crossterm::execute!(
std::io::stdout(),
crossterm::terminal::Clear(crossterm::terminal::ClearType::All)
)
.unwrap();
crossterm::execute!(
std::io::stdout(),
crossterm::terminal::Clear(crossterm::terminal::ClearType::Purge)
)
.unwrap();
crossterm::execute!(std::io::stdout(), crossterm::cursor::Hide).unwrap();
self.render(get_screen().allocate(&self.layout().await))
.await;
}
} }
pub async fn run<A: App>(create_app: impl FnOnce(&state::Context) -> A) { pub async fn run<A: App>(create_app: impl FnOnce(&state::Context) -> A) {
@@ -28,11 +47,11 @@ pub async fn run<A: App>(create_app: impl FnOnce(&state::Context) -> A) {
app.init(ctx).await; app.init(ctx).await;
app.render(get_screen().allocate(&app.layout().await)).await; app.refresh().await;
while let Some(event) = rx.recv().await { while let Some(event) = rx.recv().await {
app.update(event).await; app.update(event).await;
app.render(get_screen().allocate(&app.layout().await)).await; app.refresh().await;
} }
} }
+38 -2
View File
@@ -1,6 +1,10 @@
use std::fmt::Display; use std::{fmt::Display, io::stdout};
use crate::unit::{Point, Rect}; use crate::{
layout::Allocation,
unit::{Point, Rect},
widget::Widget,
};
pub enum Instr { pub enum Instr {
DrawText(Point, String), DrawText(Point, String),
@@ -55,3 +59,35 @@ impl From<Rect> for Point {
} }
} }
} }
impl Allocation {
pub fn draw<W: Widget>(&self, index: usize, widget: W) {
let mut scope = RenderScope::new(self.widget_alloc[index]);
widget.render(&mut scope);
scope.draw();
}
}
impl RenderScope {
pub fn draw(self) {
for inst in self.draw_instructions {
match inst {
Instr::DrawText(point, text) => {
for (i, line) in text.lines().enumerate() {
print_at(
self.rect.x + point.x,
self.rect.y + point.y + i as u16,
line,
);
}
}
Instr::DrawOutline(rect) => {}
}
}
}
}
pub fn print_at(x: u16, y: u16, text: &str) {
crossterm::execute!(stdout(), crossterm::cursor::MoveTo(x, y)).unwrap();
println!("{text}");
}
+1 -1
View File
@@ -4,7 +4,7 @@ pub trait Widget {
fn render(&self, scope: &mut RenderScope); fn render(&self, scope: &mut RenderScope);
} }
impl Widget for str { impl Widget for &str {
fn render(&self, scope: &mut RenderScope) { fn render(&self, scope: &mut RenderScope) {
scope.draw_text(0, self); scope.draw_text(0, self);
} }
+3 -4
View File
@@ -16,14 +16,13 @@ impl App for PulseTradeApp {
async fn layout(&self) -> pulse_ui::layout::LayoutItem { async fn layout(&self) -> pulse_ui::layout::LayoutItem {
layout(vec![ layout(vec![
LayoutItem::Widget(Size::Flex(16)), LayoutItem::Widget(Size::Flex(1)),
LayoutItem::Widget(Size::Flex(9)), LayoutItem::Widget(Size::Flex(1)),
]) ])
} }
async fn render(&mut self, layout: pulse_ui::layout::Allocation) { async fn render(&mut self, layout: pulse_ui::layout::Allocation) {
println!("{:?}", layout); layout.draw(1, "Yo");
println!("{:?}", *self.count.lock().await);
} }
} }