101 lines
4.0 KiB
Markdown
101 lines
4.0 KiB
Markdown
## `term.ui`
|
|
|
|
A V module for designing terminal UI apps
|
|
|
|
#### Quickstart
|
|
|
|
```v
|
|
import term.ui as tui
|
|
|
|
struct App {
|
|
mut:
|
|
tui &tui.Context = 0
|
|
}
|
|
|
|
fn event(e &tui.Event, x voidptr) {
|
|
println(e)
|
|
if e.typ == .key_down && e.code == .escape {
|
|
exit(0)
|
|
}
|
|
}
|
|
|
|
fn frame(x voidptr) {
|
|
mut app := &App(x)
|
|
|
|
app.tui.clear()
|
|
app.tui.set_bg_color(r: 63, g: 81, b: 181)
|
|
app.tui.draw_rect(20, 6, 41, 10)
|
|
app.tui.draw_text(24, 8, 'Hello from V!')
|
|
app.tui.set_cursor_position(0, 0)
|
|
|
|
app.tui.reset()
|
|
app.tui.flush()
|
|
}
|
|
|
|
fn main() {
|
|
mut app := &App{}
|
|
app.tui = tui.init(
|
|
user_data: app
|
|
event_fn: event
|
|
frame_fn: frame
|
|
hide_cursor: true
|
|
)
|
|
app.tui.run()?
|
|
}
|
|
```
|
|
|
|
See the `/examples/term.ui/` folder for more usage examples.
|
|
|
|
#### Configuration
|
|
|
|
- `user_data voidptr` - a pointer to any `user_data`, it will be passed as the last argument to
|
|
each callback. Used for accessing your app context from the different callbacks.
|
|
- `init_fn fn(voidptr)` - a callback that will be called after initialization
|
|
and before the first event / frame. Useful for initializing any user data.
|
|
- `frame_fn fn(voidptr)` - a callback that will be fired on each frame,
|
|
at a rate of `frame_rate` frames per second.
|
|
`event_fn fn(&Event, voidptr)` - a callback that will be fired for every event received.
|
|
- `cleanup_fn fn(voidptr)` - a callback that will be fired once, before the application exits.
|
|
- `fail_fn fn(string)` - a callback that will be fired
|
|
if a fatal error occurs during app initialization.
|
|
- `buffer_size int = 256` - the internal size of the read buffer.
|
|
Increasing it may help in case you're missing events, but you probably shouldn't lower
|
|
this value unless you make sure you're still receiving all events. In general,
|
|
higher frame rates work better with lower buffer sizes, and vice versa.
|
|
- `frame_rate int = 30` - the number of times per second that the `frame` callback will be fired.
|
|
30fps is a nice balance between smoothness and performance,
|
|
but you can increase or lower it as you wish.
|
|
- `hide_cursor bool` - whether to hide the mouse cursor. Useful if you want to use your own.
|
|
- `capture_events bool` - sets the terminal into raw mode, which makes it intercept some
|
|
escape codes such as `ctrl + c` and `ctrl + z`.
|
|
Useful if you want to use those key combinations in your app.
|
|
- `window_title string` - sets the title of the terminal window.
|
|
This may be changed later, by calling the `set_window_title()` method.
|
|
- `reset []int = [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 19]` - a list of reset signals,
|
|
to setup handlers to cleanup the terminal state when they're received.
|
|
You should not need to change this, unless you know what you're doing.
|
|
|
|
All of these fields may be omitted, in which case, the default value will be used.
|
|
In the case of the various callbacks, they will not be fired if a handler has not been specified.
|
|
|
|
|
|
#### FAQ
|
|
|
|
Q: My terminal (doesn't receive events / doesn't print anything / prints gibberish characters),
|
|
what's up with that?
|
|
A: Please check if your terminal. The module has been tested with `xterm`-based terminals on Linux
|
|
(like `gnome-terminal` and `konsole`), and `Terminal.app` and `iterm2` on macOS.
|
|
If your terminal does not work, open an issue with the output of `echo $TERM`.
|
|
|
|
Q: There are screen tearing issues when doing large prints
|
|
A: This is an issue with how terminals render frames,
|
|
as they may decide to do so in the middle of receiving a frame,
|
|
and cannot be fully fixed unless your console implements the [synchronized updates spec](https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec).
|
|
It can be reduced *drastically*, though, by using the rendering methods built in to the module,
|
|
and by only painting frames when your app's content has actually changed.
|
|
|
|
Q: Why does the module only emit `keydown` events, and not `keyup` like `sokol`/`gg`?
|
|
A: It's because of the way terminals emit events. Every key event is received as a keypress,
|
|
and there isn't a way of telling terminals to send keyboard events differently,
|
|
nor a reliable way of converting these into `keydown` / `keyup` events.
|