121 lines
2.1 KiB
Rust
121 lines
2.1 KiB
Rust
use crossterm::{
|
|
cursor, queue,
|
|
style::{self, Stylize},
|
|
terminal::{self, size, Clear, ClearType},
|
|
ExecutableCommand, QueueableCommand, Result as CTRes,
|
|
};
|
|
use std::{
|
|
io::{stdout, Stdout, Write},
|
|
ops::DerefMut,
|
|
};
|
|
use std::{ops::Deref, sync::Arc};
|
|
|
|
mod box_constraints;
|
|
mod event;
|
|
mod point;
|
|
mod rect;
|
|
mod size;
|
|
mod theme;
|
|
mod vec2;
|
|
mod widget;
|
|
pub use box_constraints::*;
|
|
pub use event::Event;
|
|
pub use point::*;
|
|
pub use rect::*;
|
|
pub use size::*;
|
|
pub use vec2::*;
|
|
pub use widget::*;
|
|
|
|
pub trait Data {}
|
|
|
|
impl<T> Data for Arc<T> {}
|
|
|
|
pub struct DataWrapper<T> {
|
|
changed: bool,
|
|
data: T,
|
|
}
|
|
|
|
impl<T: Data> DataWrapper<T> {
|
|
pub fn new(data: T) -> Self {
|
|
Self {
|
|
changed: true,
|
|
data,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> DataWrapper<T> {
|
|
fn changed(&mut self) -> bool {
|
|
if self.changed {
|
|
self.changed = false;
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> Deref for DataWrapper<T> {
|
|
type Target = T;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.data
|
|
}
|
|
}
|
|
|
|
impl<T> DerefMut for DataWrapper<T> {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
self.changed = true;
|
|
&mut self.data
|
|
}
|
|
}
|
|
|
|
pub struct Window<T: Data> {
|
|
out: Stdout,
|
|
buf: Vec<char>,
|
|
size: Size,
|
|
data: DataWrapper<T>,
|
|
root_widget: Box<dyn Widget<T>>,
|
|
}
|
|
|
|
impl<'a, T: Data> Window<T> {
|
|
pub fn new<W>(data: T, root: W) -> Self
|
|
where
|
|
W: Widget<T> + 'static,
|
|
{
|
|
Self {
|
|
out: stdout(),
|
|
buf: vec![],
|
|
size: Size::ZERO,
|
|
data: DataWrapper::new(data),
|
|
root_widget: Box::new(root),
|
|
}
|
|
}
|
|
fn draw(&mut self) -> CTRes<()> {
|
|
// self.root_widget.event(&mut self.data, );
|
|
self.root_widget.update(&self.data);
|
|
let terminal_size = size()?;
|
|
if self.data.changed() || self.size != terminal_size.into() {
|
|
self.size = terminal_size.into();
|
|
queue![self.out, Clear(ClearType::All)]?;
|
|
self.out.flush()?;
|
|
self.buf = vec![' '; terminal_size.0 as usize * terminal_size.1 as usize];
|
|
self.root_widget.deref_mut().layout(&terminal_size.into());
|
|
self
|
|
.root_widget
|
|
.deref_mut()
|
|
.paint(&mut self.buf, Point::ZERO, &terminal_size.into());
|
|
for ch in &self.buf {
|
|
print!["{}", ch];
|
|
}
|
|
self.out.flush()?;
|
|
}
|
|
Ok(())
|
|
}
|
|
pub fn run(&mut self) -> CTRes<()> {
|
|
loop {
|
|
self.draw()?;
|
|
}
|
|
}
|
|
}
|