Dx tired. new repo with a baseline
parent
c3070c3b69
commit
f1ddb696e6
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "tuid"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
crossterm = "0.22.1"
|
|
@ -0,0 +1,55 @@
|
|||
use crossterm::{
|
||||
cursor, queue,
|
||||
style::{self, Stylize},
|
||||
terminal::{Clear, ClearType, size},
|
||||
ExecutableCommand, QueueableCommand, Result as CTRes,
|
||||
};
|
||||
use std::io::{stdout, Stdout, Write};
|
||||
use std::sync::Arc;
|
||||
|
||||
mod widget;
|
||||
use widget::*;
|
||||
|
||||
pub struct Size {
|
||||
a: usize,
|
||||
b: usize,
|
||||
}
|
||||
|
||||
impl From<(u16, u16)> for Size {
|
||||
fn from(s: (u16, u16)) -> Self {
|
||||
Self {
|
||||
a: s.0 as usize,
|
||||
b: s.1 as usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Point {
|
||||
a: usize,
|
||||
b: usize,
|
||||
}
|
||||
|
||||
pub trait Data {}
|
||||
|
||||
impl<T> Data for Arc<T> {}
|
||||
|
||||
struct Window<'a, T: Data> {
|
||||
out: Stdout,
|
||||
root_widget: Box<&'a dyn Widget<T>>,
|
||||
}
|
||||
|
||||
impl<'a, T: Data> Window<'a, T> {
|
||||
pub fn new(widget: &'a dyn Widget<T>) -> Self {
|
||||
Self {
|
||||
out: stdout(),
|
||||
root_widget: Box::new(widget),
|
||||
}
|
||||
}
|
||||
pub fn draw(&mut self) -> CTRes<()> {
|
||||
queue![self.out, Clear(ClearType::All)]?;
|
||||
let terminal_size = size();
|
||||
self.root_widget.layout(terminal_size.into());
|
||||
self.out.flush();
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
use crate::{Data, Size, Widget};
|
||||
|
||||
use super::WidgetPod;
|
||||
|
||||
enum Direction {
|
||||
Vertical,
|
||||
Horizont,
|
||||
}
|
||||
|
||||
pub struct Flex<T> {
|
||||
children: Vec<WidgetPod<T, Box<dyn Widget<T>>>>,
|
||||
}
|
||||
|
||||
impl<T: Data> Flex<T> {
|
||||
pub fn new() -> Self {
|
||||
Self { children: vec![] }
|
||||
}
|
||||
|
||||
pub fn with_child(mut self, child: impl Widget<T> + 'static) -> Self {
|
||||
self.children.push(WidgetPod::new(Box::new(child)));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Data> Widget<T> for Flex<T> {
|
||||
fn layout(&mut self, bounds: &Size) -> Size {
|
||||
let mut output = Size { a: 0, b: 0 };
|
||||
for child in &mut self.children {
|
||||
if output.a + child.layout(bounds).a < bounds.a {
|
||||
output.a += child.layout(bounds).a;
|
||||
output.b = child.layout(bounds).b.max(output.b);
|
||||
} else {
|
||||
output.a = child.layout(bounds).a.max(output.a);
|
||||
output.b += child.layout(bounds).b;
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
fn paint(&self, buf: &mut [&mut [char]]) {}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
mod flex;
|
||||
mod text;
|
||||
mod widget;
|
||||
mod widget_pod;
|
||||
pub use flex::*;
|
||||
pub use text::*;
|
||||
pub use widget::*;
|
||||
pub use widget_pod::*;
|
|
@ -0,0 +1,39 @@
|
|||
use crate::{Data, Size, Widget};
|
||||
|
||||
pub struct Text<T: Data> {
|
||||
data: T,
|
||||
text: Box<dyn Fn(&T) -> String>,
|
||||
}
|
||||
|
||||
impl<T: Data> Text<T> {
|
||||
pub fn new(data: T, text: Box<dyn Fn(&T) -> String>) -> Self {
|
||||
Self { data, text }
|
||||
}
|
||||
fn text(&self) -> String {
|
||||
(self.text)(&self.data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Data> Widget<T> for Text<T> {
|
||||
fn layout(&mut self, _bounds: &Size) -> Size {
|
||||
Size {
|
||||
a: self.text().chars().count(),
|
||||
b: self.text().chars().filter(|ch| *ch == '\n').count(),
|
||||
}
|
||||
}
|
||||
fn paint(&self, buf: &mut [&mut [char]]) {
|
||||
let the_text = self.text();
|
||||
let mut the_chars = the_text.chars();
|
||||
for line in buf.iter_mut() {
|
||||
for spot in line.iter_mut() {
|
||||
if let Some(ch) = the_chars.next() {
|
||||
if ch == '\n' {
|
||||
break;
|
||||
} else {
|
||||
*spot = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
use std::ops::{DerefMut, Deref};
|
||||
|
||||
use crate::Size;
|
||||
|
||||
pub trait Widget<T> {
|
||||
fn layout(&mut self, bounds: &Size) -> Size;
|
||||
fn paint(&self, buf: &mut [&mut [char]]);
|
||||
}
|
||||
|
||||
impl<T> Widget<T> for Box<dyn Widget<T>> {
|
||||
fn layout(&mut self, bounds: &Size) -> Size {
|
||||
self.deref_mut().layout(bounds)
|
||||
}
|
||||
|
||||
fn paint(&self, buf: &mut [&mut [char]]) {
|
||||
self.deref().paint(buf)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{Point, Widget, Size, Data};
|
||||
|
||||
|
||||
|
||||
pub struct WidgetPod<T, W> {
|
||||
data: PhantomData<T>,
|
||||
inner: W,
|
||||
origin: Point,
|
||||
}
|
||||
|
||||
impl<T, W: Widget<T>> WidgetPod<T, W> {
|
||||
pub fn new(inner: W) -> Self {
|
||||
Self {
|
||||
data: PhantomData,
|
||||
inner,
|
||||
origin: Point { a: 0, b: 0 },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_origin(&mut self, p: Point) {
|
||||
self.origin = p;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Data, W: Widget<T>> Widget<T> for WidgetPod<T, W> {
|
||||
fn layout(&mut self, bounds: &Size) -> Size {
|
||||
self.inner.layout(bounds)
|
||||
}
|
||||
|
||||
fn paint(&self, buf: &mut [&mut [char]]) {
|
||||
self.inner.paint(buf)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue