-
Notifications
You must be signed in to change notification settings - Fork 787
Home
termui is initialized with:
if err := ui.Init(); err != nil {
log.Fatalf("failed to initialize termui: %v", err)
}
defer ui.Close()
which basically wraps the termbox-go Init()
function and sets some sane defaults like 256 colors and mouse support. Close
also wraps the termbox-go Close
function. Initializing termui sets up the terminal to display widgets that you create and Close
resets terminal settings to their normal state.
There are several built in widgets, and custom widgets can also be created. Each widget inherits from Block
which provides utilities for managing position, size, a border, and a title. Widgets also have to implement a Draw(Buffer)
method which draws its contents onto a provided Buffer
object. Buffers
represent a rectangular region of a terminal, and contain Cells
which represent individual terminal cells. Cell
s hold a character and a Style
, which contains foreground and background colors and any modifications like underline, etc.
Custom widgets can be created simply by inheriting from Block
and implementing a custom Draw
method. A widget's data is typically stored in its fields, and can be updated over time.
In a larger application, a modular approach could often be to create custom widgets that inherit from any of the built in widgets like LineChart
, and also implement an update
method that is unique to the widget and updates the widget fields used by Draw
.
To position a widget absolutely, call the SetRect(x0, y0, x1, y1)
method which defines the area that the widget draws to.
To position widgets in a relative way, you can create a Grid
which stores widgets in rows and columns that take up a percentage of the screen. The Grid
sizes the widgets initially, and also resizes them when the terminal resizes.
termui
provides event handling for keypresses, mouse actions, and screen resizing. termui.PollEvents()
returns a channel that converts and propogates events originating from termbox. Event types are detailed in events.go.
To update widget data on an interval, use Go's built in tickers.
Event loop example:
uiEvents := ui.PollEvents()
ticker := time.NewTicker(time.Second).C
for {
select {
case e := <-uiEvents:
switch e.ID { // event string/identifier
case "q", "<C-c>": // press 'q' or 'C-c' to quit
return
case "<MouseLeft>":
payload := e.Payload.(ui.Mouse)
x, y := payload.X, payload.Y
case "<Resize>":
payload := e.Payload.(ui.Resize)
width, height := payload.Width, payload.Height
}
switch e.Type {
case ui.KeyboardEvent: // handle all key presses
eventID = e.ID // keypress string
}
// use Go's built-in tickers for updating and drawing data
case <-ticker:
drawFunction()
}
}
Rendering widgets or a Grid
works by calling the termui.Render(Drawable)
function. Any struct that implements Drawable
can be rendered. Drawable
requires the GetRect
and SetRect
methods for widget sizing (which are implemented by Block
so you usually don't have to worry about those since most widgets inherit from Block
) and also Draw(Buffer)
, which is unique to the widget. Render
works by creating a Buffer
, filling it with empty Cell
s, passing the Buffer
to the widget through its Draw
method, and then iterating over the drawn Cell
s which are passed to termbox-go. Grid
's Draw
method works by having each of its widgets Draw
to the Buffer
that it is given.