1个不稳定版本
0.1.0 | 2019年3月28日 |
---|
#768 in 图形API
77KB
2K SLoC
termcandy
termcandy
是一个使用命令式代码编写终端用户界面的库。这意味着您不需要围绕事件循环来结构化程序,只需编写自然的控制流程,让宏魔法来完成剩余的工作。
示例
此程序将绘制一个蓝色球,在用户按下ESC键之前在屏幕上弹跳。
#![feature(proc_macro_hygiene)]
#![feature(never_type)]
#![feature(generators)]
#![feature(label_break_value)]
use std::time::{Instant, Duration};
use termcandy::{widget, select_widget};
use termcandy::events::{self, Key};
use termcandy::graphics::{Style, Color, Attrs};
use tokio::timer;
use futures::Future;
#[widget]
fn bouncing_ball() -> Result<(), failure::Error> {
let mut pos_x = 0;
let mut pos_y = 0;
let mut vel_x = 1;
let mut vel_y = 1;
let mut next_instant = Instant::now();
let style = Style { fg: Color::blue(), bg: Color::default(), attrs: Attrs::bold() };
loop {
select_widget! {
() = timer::Delay::new(next_instant) => {
next_instant += Duration::from_millis(100);
let (w, h) = termcandy::screen_size();
if pos_x <= 0 { vel_x = 1 };
if pos_x >= w as i16 { vel_x = -1 };
if pos_y <= 0 { vel_y = 1 };
if pos_y >= h as i16 { vel_y = -1 };
pos_x += vel_x;
pos_y += vel_y;
},
() = events::key(Key::Esc) => return Ok(()),
never = widget::draw(|surface| {
surface.print("●", pos_x, pos_y, style)
}) => never,
}
}
}
fn main() {
tokio::runtime::current_thread::block_on_all(termcandy::run(bouncing_ball())).expect("oh no!")
}
我们还可以重用上面的代码来制作4个球在它们自己的盒子内弹跳
use termcandy::Widget;
use termcandy::graphics::Rect;
#[widget]
fn four_bouncing_balls() -> Result<(), failure::Error> {
let top_left = bouncing_ball().resize(|w, h| {
Rect { x0: 0, x1: w as i16 / 2, y0: 0, y1: h as i16 / 2 }
});
let top_right = bouncing_ball().resize(|w, h| {
Rect { x0: w as i16 / 2, x1: w as i16, y0: 0, y1: h as i16 / 2 }
});
let bottom_left = bouncing_ball().resize(|w, h| {
Rect { x0: 0, x1: w as i16 / 2, y0: h as i16 / 2, y1: h as i16 }
});
let bottom_right = bouncing_ball().resize(|w, h| {
Rect { x0: w as i16 / 2, x1: w as i16, y0: h as i16 / 2, y1: h as i16 }
});
select_widget! {
() = top_left => (),
() = top_right => (),
() = bottom_left => (),
() = bottom_right => (),
never = widget::draw(|surface| {
surface.draw_v_line(0, surface.height() as i16 - 1, 0);
surface.draw_v_line(0, surface.height() as i16 - 1, surface.width() as i16 / 2);
surface.draw_v_line(0, surface.height() as i16 - 1, surface.width() as i16 - 1);
surface.draw_h_line(0, surface.width() as i16 - 1, 0);
surface.draw_h_line(0, surface.width() as i16 - 1, surface.height() as i16 / 2);
surface.draw_h_line(0, surface.width() as i16 - 1, surface.height() as i16 - 1);
}) => never
}
Ok(())
}
依赖项
~8.5MB
~141K SLoC