rewrite
This commit is contained in:
@@ -8,6 +8,9 @@ repository = "https://github.com/osui-rs/osui"
|
|||||||
homepage = "https://osui.netlify.app"
|
homepage = "https://osui.netlify.app"
|
||||||
documentation = "https://osui.netlify.app/docs/"
|
documentation = "https://osui.netlify.app/docs/"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
rsx = []
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "osui"
|
name = "osui"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|||||||
+102
-59
@@ -1,86 +1,129 @@
|
|||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod widgets;
|
||||||
|
|
||||||
type Result<T> = std::io::Result<T>;
|
pub use std::io::Result;
|
||||||
|
|
||||||
pub trait Widget {
|
pub trait Widget {
|
||||||
fn draw(&self, w: &mut Writer);
|
fn render(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Writer(String);
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Area {
|
||||||
impl Writer {
|
width: u16,
|
||||||
pub fn write(&mut self, s: &str) {
|
height: u16,
|
||||||
self.0 += s;
|
x: u16,
|
||||||
}
|
y: u16,
|
||||||
|
center_x: bool,
|
||||||
|
center_y: bool,
|
||||||
|
width_auto: bool,
|
||||||
|
height_auto: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Element = Box<dyn Widget>;
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
|
||||||
/////////////////////////////////////////
|
|
||||||
|
|
||||||
pub struct Frame {
|
pub struct Frame {
|
||||||
pub area: (u16, u16),
|
pub area: Area,
|
||||||
pub x: u16,
|
|
||||||
pub y: u16,
|
|
||||||
parent: Option<*const Frame>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
pub fn new(area: (u16, u16), parent: &Frame) -> Frame {
|
pub fn draw<W>(&self, w: &W, mut props: Area) -> Result<()>
|
||||||
Frame {
|
|
||||||
area,
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
parent: Some(parent),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_root(area: (u16, u16)) -> Frame {
|
|
||||||
Frame {
|
|
||||||
area,
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
parent: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render<E>(&self, elem: E)
|
|
||||||
where
|
where
|
||||||
E: Widget,
|
W: Widget,
|
||||||
{
|
{
|
||||||
let mut w = Writer(String::new());
|
let written = w.render();
|
||||||
elem.draw(&mut w);
|
|
||||||
if let Some(_f) = self.parent {
|
let (ww, wh) = utils::str_size(&written);
|
||||||
} else {
|
|
||||||
println!("{}", w.0);
|
if props.width_auto {
|
||||||
}
|
props.width = ww;
|
||||||
}
|
}
|
||||||
|
if props.height_auto {
|
||||||
|
props.height = wh;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Terminal(Frame);
|
if props.width > self.area.width {
|
||||||
|
props.width -= props.width - self.area.width;
|
||||||
|
}
|
||||||
|
|
||||||
impl Terminal {
|
if props.width > self.area.width {
|
||||||
pub fn new() -> Result<Terminal> {
|
props.width -= props.width - self.area.width;
|
||||||
Ok(Terminal(Frame::new_root(crossterm::terminal::size()?)))
|
}
|
||||||
|
|
||||||
|
if props.center_x {
|
||||||
|
props.x = (self.area.width - ww) / 2;
|
||||||
|
}
|
||||||
|
if props.center_y {
|
||||||
|
props.y = (self.area.height - wh) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, line) in written.lines().enumerate() {
|
||||||
|
if i as u16 > props.height {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"\x1b[{};{}H{}",
|
||||||
|
props.x + (i as u16) + 1,
|
||||||
|
props.y + 1,
|
||||||
|
line.chars().take(props.width as usize).collect::<String>()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw<F>(&mut self, f: F) -> Result<()>
|
|
||||||
where
|
|
||||||
F: Fn(&mut Frame),
|
|
||||||
{
|
|
||||||
f(&mut self.0);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Widget for &str {
|
pub fn new(width: u16, height: u16) -> Self {
|
||||||
fn draw(&self, w: &mut Writer) {
|
let mut f = Self::default();
|
||||||
w.write(self);
|
f.area.width(width);
|
||||||
|
f.area.height(height);
|
||||||
|
f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() -> Result<Terminal> {
|
impl Area {
|
||||||
utils::clear()?;
|
pub fn new() -> Self {
|
||||||
utils::hide_cursor()?;
|
Self::default()
|
||||||
Terminal::new()
|
}
|
||||||
|
|
||||||
|
pub fn center_x(&mut self) -> Self {
|
||||||
|
self.center_x = true;
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn center_y(&mut self) -> Self {
|
||||||
|
self.center_y = true;
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn center(&mut self) -> Self {
|
||||||
|
self.center_x = true;
|
||||||
|
self.center_y = true;
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width(&mut self, w: u16) -> Self {
|
||||||
|
self.width = w;
|
||||||
|
self.width_auto = false;
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height(&mut self, h: u16) -> Self {
|
||||||
|
self.height = h;
|
||||||
|
self.height_auto = false;
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Area {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
center_x: false,
|
||||||
|
center_y: false,
|
||||||
|
width_auto: true,
|
||||||
|
height_auto: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-8
@@ -1,12 +1,15 @@
|
|||||||
use osui::*;
|
use osui::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() -> osui::Result<()> {
|
||||||
let mut term = init().unwrap();
|
utils::init()?;
|
||||||
loop {
|
|
||||||
term.draw(app).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn app(frame: &mut Frame) {
|
let (width, height) = crossterm::terminal::size()?;
|
||||||
frame.render("hi");
|
|
||||||
|
let frame = Frame::new(width, height);
|
||||||
|
|
||||||
|
frame.draw(&"Hello?", Area::new())?;
|
||||||
|
|
||||||
|
utils::read()?;
|
||||||
|
|
||||||
|
utils::end()
|
||||||
}
|
}
|
||||||
|
|||||||
+58
-8
@@ -2,23 +2,73 @@ use std::io::Write;
|
|||||||
|
|
||||||
pub fn clear() -> crate::Result<()> {
|
pub fn clear() -> crate::Result<()> {
|
||||||
print!("\x1B[2J\x1B[H");
|
print!("\x1B[2J\x1B[H");
|
||||||
std::io::stdout().flush()?;
|
std::io::stdout().flush()
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hide_cursor() -> crate::Result<()> {
|
pub fn hide_cursor() -> crate::Result<()> {
|
||||||
print!("\x1b[?25l");
|
print!("\x1b[?25l");
|
||||||
std::io::stdout().flush()?;
|
std::io::stdout().flush()
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_cursor() -> crate::Result<()> {
|
pub fn show_cursor() -> crate::Result<()> {
|
||||||
print!("\x1B[?25h");
|
print!("\x1B[?25h");
|
||||||
std::io::stdout().flush()?;
|
std::io::stdout().flush()
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flush() -> crate::Result<()> {
|
pub fn flush() -> crate::Result<()> {
|
||||||
std::io::stdout().flush()?;
|
std::io::stdout().flush()
|
||||||
Ok(())
|
}
|
||||||
|
|
||||||
|
pub fn init() -> crate::Result<()> {
|
||||||
|
crossterm::terminal::enable_raw_mode()?;
|
||||||
|
clear()?;
|
||||||
|
hide_cursor()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end() -> crate::Result<()> {
|
||||||
|
crossterm::terminal::disable_raw_mode()?;
|
||||||
|
clear()?;
|
||||||
|
show_cursor()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn str_size(s: &str) -> (u16, u16) {
|
||||||
|
let mut height = 1;
|
||||||
|
let mut max_width = 0;
|
||||||
|
let mut current_width = 0;
|
||||||
|
|
||||||
|
for b in s.bytes() {
|
||||||
|
if b == b'\n' {
|
||||||
|
height += 1;
|
||||||
|
max_width = max_width.max(current_width);
|
||||||
|
current_width = 0;
|
||||||
|
} else {
|
||||||
|
current_width += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
max_width = max_width.max(current_width);
|
||||||
|
|
||||||
|
(max_width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Event {
|
||||||
|
Key(crossterm::event::KeyEvent),
|
||||||
|
Resize(u16, u16),
|
||||||
|
Mouse(crossterm::event::MouseEvent),
|
||||||
|
Paste(String),
|
||||||
|
FocusGained,
|
||||||
|
FocusLost,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read() -> crate::Result<Event> {
|
||||||
|
let event = crossterm::event::read()?;
|
||||||
|
|
||||||
|
Ok(match event {
|
||||||
|
crossterm::event::Event::Key(k) => Event::Key(k),
|
||||||
|
crossterm::event::Event::Resize(w, h) => Event::Resize(w, h),
|
||||||
|
crossterm::event::Event::FocusGained => Event::FocusGained,
|
||||||
|
crossterm::event::Event::FocusLost => Event::FocusLost,
|
||||||
|
crossterm::event::Event::Mouse(m) => Event::Mouse(m),
|
||||||
|
crossterm::event::Event::Paste(p) => Event::Paste(p),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use crate::Widget;
|
||||||
|
|
||||||
|
impl Widget for &str {
|
||||||
|
fn render(&self) -> String {
|
||||||
|
self.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user