//! Every tag this backend has, driven through the C ABI itself. //! //! cargo run -p jolt-tui --example showcase //! //! It calls `tui_*` exactly as jolt does — nodes by handle, props by name, //! events polled off a queue — so it doubles as a check that the ABI is usable //! from the outside and not only from the inside. //! //! Tab and Shift-Tab move, Enter and Space activate, j/k and the arrows move //! the list, the wheel scrolls, Ctrl-C or Ctrl-Q quits. use std::ffi::{CStr, CString}; use jolttui::*; fn node(tag: &str) -> i32 { let tag = CString::new(tag).unwrap(); unsafe { tui_node_new(tag.as_ptr()) } } fn set(id: i32, key: &str, value: &str) { let (key, value) = (CString::new(key).unwrap(), CString::new(value).unwrap()); unsafe { tui_node_set_str(id, key.as_ptr(), value.as_ptr()) } } fn set_num(id: i32, key: &str, value: f64) { let key = CString::new(key).unwrap(); unsafe { tui_node_set_num(id, key.as_ptr(), value) } } fn get(id: i32, key: &str) -> String { let key = CString::new(key).unwrap(); unsafe { CStr::from_ptr(tui_node_get_str(id, key.as_ptr())) } .to_string_lossy() .into_owned() } fn child(parent: i32, tag: &str, props: &[(&str, &str)]) -> i32 { let id = node(tag); for (key, value) in props { set(id, key, value); } tui_node_append(parent, id); id } fn main() { if tui_open(1) == 0 { eprintln!("showcase: this example needs a terminal"); return; } let root = tui_tree_root(); let page = child(root, "vbox", &[]); set_num(page, "margin", 1.0); set_num(page, "spacing", 1.0); child(page, "title", &[("label", "jolt-tui")]); let status = child( page, "dim-label", &[("label", "tab moves · enter activates · ctrl-c quits")], ); let row = child(page, "hbox", &[("orientation", "horizontal")]); set_num(row, "spacing", 2.0); child(row, "button", &[("label", "count")]); child( row, "button", &[("label", "reset"), ("kind", "destructive")], ); child(row, "checkbutton", &[("label", "live")]); child(page, "entry", &[("placeholder", "type something")]); let bar = child(page, "progress", &[("label", "")]); let frame = child(page, "frame", &[("label", "Rows")]); let list = child(frame, "listbox", &[]); for name in ["alpha", "beta", "gamma", "delta"] { child(list, "label", &[("label", name)]); } let mut count = 0.0f64; while tui_should_close() == 0 { tui_tick(50); while tui_tree_poll_event() == 1 { let node = tui_tree_event_node(); let name = unsafe { CStr::from_ptr(tui_tree_event_name()) } .to_string_lossy() .into_owned(); let text = unsafe { CStr::from_ptr(tui_tree_event_text()) } .to_string_lossy() .into_owned(); match name.as_str() { "click" => { let label = get(node, "label"); count = if label == "reset" { 0.0 } else { count + 1.0 }; set_num(bar, "value", (count / 10.0).min(1.0)); set(status, "label", &format!("{label}: {count}")); } "select" | "activate" | "toggled" | "change" => { set(status, "label", &format!("{name} {text}")); } _ => {} } } tui_frame(); } tui_close(); }