π¦ Feather-Tui

A Rust rewrite of the terminal UI library I originally wrote in C for my school management project.
β οΈ This is my first-ever Rust project β οΈ
Feather-Tui is a simple terminal UI library designed to provide building blocks for text-based user interfaces. It started life as a small C library in my school management system project, aiming to offer an easy-to-use UI framework for terminal applications. Now, Iβm rewriting it in Rust to learn the language and (hopefully) improve both performance and maintainability.
π Progress

- π§ Feather-Tui is still under development.
- β
Some parts are complete, while others are only partially done.
- β¨ These parts may get refined or improved in the future.
- π For now, theyβre good enough to work with.
π Changelog
tui_trg_new_trigger_func! is changed to trg_new_trigger_func!
tui_cbk_new_callback_func! is changed to cbk_new_callback_func!
- New method call
simple_draw for Renderer
- Added some more documentation.
π¦ Crates
https://crates.io/crates/feather-tui
π Usage
I was not unexpecting people to actually use this crate. So here is a quick example I made in 5 minutes. (Comments are generated by Claude AI)
use feather_tui as tui;
tui::trg_new_trigger_func!(up_trig_func, key_char, {
match key_char.downcast_ref::<std::option::Option<char>>().unwrap() {
Some(c) => *c == 'w', None => false, }
});
tui::trg_new_trigger_func!(down_trig_func, key_char, {
match key_char.downcast_ref::<std::option::Option<char>>().unwrap() {
Some(c) => *c == 's', None => false,
}
});
tui::trg_new_trigger_func!(selc_trig_func, key_char, {
match key_char.downcast_ref::<std::option::Option<char>>().unwrap() {
Some(c) => *c == 'e', None => false,
}
});
tui::trg_new_trigger_func!(quit_trig_func, key_char, {
match key_char.downcast_ref::<std::option::Option<char>>().unwrap() {
Some(c) => *c == 'q', None => false,
}
});
tui::cbk_new_callback_func!(callback_func, argument, {
let number_as_str =
argument.downcast_ref::<u32>().expect("Expect callback argument to be a u32").to_string();
tui::ren::Renderer::new(40, 20)
.simple_draw(
&mut tui::con::Container::new()
.with_header(
tui::cpn::hed::Header::new("Callback Trigger")) .with_text(
tui::cpn::txt::Text::new(
&format!("Option {} selected", number_as_str), tui::cpn::txt::TextFlags::COLOR_RED_BACK)));
std::thread::sleep(std::time::Duration::from_secs(1));
});
#[inline]
fn read_key() -> std::option::Option<char> {
tui::inp::key_char().expect(tui::inp::READ_KEY_FAIL_ERRMSG)
}
fn main() {
let mut key_char: std::option::Option<char> = read_key();
let mut container = tui::con::Container::new()
.with_header(tui::cpn::hed::Header::new("Main Menu")) .with_option(
tui::cpn::opt::Option::new(
"Option1", tui::cbk::Callback::new(callback_func, 1u32))) .with_option(
tui::cpn::opt::Option::new(
"Option2", tui::cbk::Callback::new(callback_func, 2u32))) .with_text(
tui::cpn::txt::Text::new(
"Text", tui::cpn::txt::TextFlags::COLOR_YELLOW_BACK | tui::cpn::txt::TextFlags::ALIGN_RIGHT)) .with_selector(
tui::sel::Selector::new(
tui::trg::Trigger::new(up_trig_func, key_char), tui::trg::Trigger::new(down_trig_func, key_char), tui::trg::Trigger::new(selc_trig_func, key_char)));
let mut renderer = tui::ren::Renderer::new(40, 20);
let mut quit_trig = tui::trg::Trigger::new(quit_trig_func, key_char);
let mut should_update = true;
tui::ren::ready();
loop {
key_char = read_key();
container.selector_mut().update_trig_arg(key_char, key_char, key_char);
quit_trig.update_arg(key_char);
if quit_trig.check() {
break; }
if should_update {
renderer.clear(); renderer.render(&mut container); renderer.draw(); }
should_update = container.looper();
}
tui::ren::unready();
}
ποΈ Dependencies
bitflags crossterm
π± Related Projects