1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
//! 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();
}
|