Files
pulse-trader/pulse-ui/src/render.rs
T
2026-07-27 19:30:45 +02:00

142 lines
3.3 KiB
Rust

use std::{fmt::Display, io::stdout};
use crate::{
layout::Allocation,
unit::{Point, Rect},
widget::Widget,
};
pub enum Instr {
DrawText(Point, String),
}
pub struct RenderScope {
pub rect: Rect,
draw_instructions: Vec<Instr>,
}
impl RenderScope {
pub fn draw_text<P: Into<Point>, T: Display>(&mut self, at: P, text: T) -> u16 {
let point: Point = at.into();
let lines = text
.to_string()
.lines()
.map(|line| {
let mut chars = line.chars().peekable();
let mut new_line = String::new();
let mut len = 0;
while let Some(c) = chars.next() {
if c == '\x1b' && chars.peek() == Some(&'[') {
new_line.push(c);
while let Some(c) = chars.next() {
new_line.push(c);
if c.is_ascii_alphabetic() {
break;
}
}
continue;
}
new_line.push(c);
len += 1;
if len >= self.rect.width as usize {
new_line.push('\n');
len = 0;
}
}
new_line
})
.collect::<Vec<_>>()
.join("\n");
let lines = lines
.lines()
.take((self.rect.height - point.y) as usize)
.collect::<Vec<_>>();
let lines_len = lines.len();
self.draw_instructions
.push(Instr::DrawText(point, lines.join("\n")));
lines_len as u16
}
}
impl RenderScope {
pub fn new(rect: Rect) -> Self {
Self {
rect,
draw_instructions: Vec::new(),
}
}
}
impl From<(u16, u16)> for Point {
fn from(value: (u16, u16)) -> Self {
Self {
x: value.0,
y: value.1,
}
}
}
impl From<u16> for Point {
fn from(value: u16) -> Self {
Self { x: value, y: value }
}
}
impl From<Rect> for Point {
fn from(value: Rect) -> Self {
Self {
x: value.x,
y: value.y,
}
}
}
impl Allocation {
pub fn draw<W: Widget>(&self, index: usize, widget: W) {
let mut scope = RenderScope::new(self.widgets[index]);
widget.render(&mut scope);
scope.draw();
}
pub fn draw_frame<W: Widget>(&self, index: usize, widget: W) {
let mut scope = RenderScope::new(self.frame[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,
);
}
}
}
}
}
}
pub fn print_at(x: u16, y: u16, text: &str) {
crossterm::execute!(stdout(), crossterm::cursor::MoveTo(x, y)).unwrap();
print!("{text}");
}