Documentation ¶
Overview ¶
Package gruid provides a model for building grid-based applications. The interface abstracts rendering and input for different platforms. There are drivers for terminal apps (gruid-tcell), native graphical apps (gruid-sdl) and browser apps (gruid-js).
The package uses an architecture of updating a model in response to messages strongly inspired from the bubbletea module for building terminal apps (https://github.com/charmbracelet/bubbletea), which in turn is based on the Elm Architecture (https://guide.elm-lang.org/architecture/).
The typical usage looks like this:
// model implements gruid.Model interface and represents the // application's state. type model struct { grid gruid.Grid // user interface grid // other fields with the state of the application } func (m *model) Update(msg gruid.Msg) gruid.Effect { // Update your application's state in response to messages. } func (m *model) Draw() gruid.Grid { // Write your rendering into the grid and return it. } func main() { gd := gruid.NewGrid(80, 24) m := &model{grid: gd, ...} // Specify a driver among the provided ones. driver := tcell.NewDriver(...) app := gruid.NewApp(gruid.AppConfig{ Driver: driver, Model: m, }) // Start the main loop of the application. if err := app.Start(context.Background()); err != nil { log.Fatal(err) } }
The values of type gruid.Effect returned by Update are optional and represent concurrently executed functions that produce messages. The gruid.Grid type is a convenient 2-dimensional slice type representing the screen's logical contents. See the relevant types documentation for details and usage.
Index ¶
- type App
- type AppConfig
- type AttrMask
- type Cell
- type Cmd
- type Color
- type Driver
- type DriverPollMsg
- type Effect
- type Frame
- type FrameCell
- type FrameDecoder
- type Grid
- func (gd Grid) At(p Point) Cell
- func (gd Grid) Bounds() Range
- func (gd Grid) Contains(p Point) bool
- func (gd Grid) Copy(src Grid) Point
- func (gd Grid) Fill(c Cell)
- func (gd Grid) Iter(fn func(Point, Cell))
- func (gd Grid) Iterator() GridIterator
- func (gd Grid) Map(fn func(Point, Cell) Cell)
- func (gd Grid) Range() Range
- func (gd Grid) Resize(w, h int) Grid
- func (gd Grid) Set(p Point, c Cell)
- func (gd Grid) Size() Point
- func (gd Grid) Slice(rg Range) Grid
- func (gd Grid) String() string
- type GridIterator
- type Key
- type ModMask
- type Model
- type MouseAction
- type Msg
- type MsgInit
- type MsgKeyDown
- type MsgMouse
- type MsgQuit
- type MsgScreen
- type Point
- type Range
- func (rg Range) Add(p Point) Range
- func (rg Range) Column(x int) Range
- func (rg Range) Columns(x0, x1 int) Range
- func (rg Range) Empty() bool
- func (rg Range) Eq(r Range) bool
- func (rg Range) In(r Range) bool
- func (rg Range) Intersect(r Range) Range
- func (rg Range) Iter(fn func(Point))
- func (rg Range) Line(y int) Range
- func (rg Range) Lines(y0, y1 int) Range
- func (rg Range) Overlaps(r Range) bool
- func (rg Range) RelMsg(msg Msg) Msg
- func (rg Range) Shift(x0, y0, x1, y1 int) Range
- func (rg Range) Size() Point
- func (rg Range) String() string
- func (rg Range) Sub(p Point) Range
- func (rg Range) Union(r Range) Range
- type Style
- type Sub
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type App ¶
type App struct { // CatchPanics ensures that Close is called on the driver before ending // the Start loop. When a panic occurs, it will be recovered, the stack // trace will be printed and an error will be returned. It defaults to // true. CatchPanics bool // contains filtered or unexported fields }
App represents a message and model-driven application with a grid-based user interface.
type AppConfig ¶
type AppConfig struct { Model Model // application state Driver Driver // input and rendering driver // FrameWriter is an optional io.Writer for recording frames. They can // be decoded after a successful Start session with a FrameDecoder. If // nil, no frame recording will be done. It is your responsibility to // call Close on the Writer after Start returns. FrameWriter io.Writer // Logger is optional and is used to log non-fatal IO errors. Logger *log.Logger }
AppConfig contains the configuration options for creating a new App.
type AttrMask ¶
type AttrMask uint32
AttrMask can be used to add custom styling information. It can for example be used to map to specific terminal attributes (with GetStyle), or use special images (with GetImage), when appropriate.
It may be used as a bitmask, like terminal attributes, or as a generic value for constants.
const AttrsDefault AttrMask = 0
AttrsDefault represents the default styling attributes.
type Cell ¶
Cell contains all the content and styling information to represent a cell in the grid.
type Cmd ¶
type Cmd func() Msg
Cmd is an Effect that returns a message. Commands returned by Update are executed on their own goroutine. You can use them for things like single event timers and short-lived IO operations with a single result. A nil command is discarded and does nothing.
Cmd implements the Effect interface.
type Color ¶
type Color uint32
Color is a generic value for representing colors. Those have to be mapped to concrete foreground and background colors for each driver, as appropriate.
const ColorDefault Color = 0
ColorDefault should get special treatment by drivers and be mapped, when it makes sense, to a default color, both for foreground and background.
type Driver ¶
type Driver interface { // Init initializes the driver, so that you can then call its other // methods. Init() error // PollMsgs is a subscription for input messages. It returns an error // in case the driver input loop suffered a non recoverable error. It // should handle cancellation of the passed context and return as // appropriate. PollMsgs(context.Context, chan<- Msg) error // Flush sends grid's last frame changes to the driver. Flush(Frame) // Close may execute needed code to finalize the screen and release // resources. Redundant Close() calls are ignored. After Close() it is // possible to call Init() again. Close() }
Driver handles both user input and rendering. When creating an App and using the Start main loop, you will not have to call those methods directly. You may reuse the same driver for another application after the current application's Start loop ends.
type DriverPollMsg ¶ added in v0.21.0
type DriverPollMsg interface { // The PollMsg returns an input message if any, in a non-blocking way. // If no message can be retrieved, nil should be returned. If a non // recoverable input error happens, an error can be returned. PollMsg() (Msg, error) }
DriverPollMsg is an optional interface that can be satisfied by drivers. Such drivers will be run such that the message polling is executed in the same thread as main using a non-blocking polling message method, instead of PollMsgs. This may be necessary with drivers whose input system is not thread safe.
type Effect ¶
type Effect interface {
// contains filtered or unexported methods
}
Effect is an interface type for representing either command or subscription functions. Those functions generally represent IO operations, either producing a single message or several. They are executed on their own goroutine after being returned by the Update method of the model. A nil effect is discarded and does nothing.
The types Cmd and Sub implement the Effect interface. See their respective documentation for specific usage details.
type Frame ¶
type Frame struct { Time time.Time // time of frame drawing: used for replay Cells []FrameCell // cells that changed from previous frame Width int // width of the whole grid when the frame was issued Height int // height of the whole grid when the frame was issued }
Frame contains the necessary information to draw the frame changes from a frame to the next. One is sent to the driver after every Draw.
type FrameCell ¶
type FrameCell struct { Cell Cell // cell content and styling P Point // absolute position in the whole grid }
FrameCell represents a cell drawing instruction at a specific absolute position in the whole grid.
type FrameDecoder ¶
type FrameDecoder struct {
// contains filtered or unexported fields
}
FrameDecoder manages the decoding of the frame recording stream produced by the running of an application, in case a FrameWriter was provided. It can be used to replay an application session.
func NewFrameDecoder ¶
func NewFrameDecoder(r io.Reader) (*FrameDecoder, error)
NewFrameDecoder returns a FrameDecoder using a given reader as source for frames.
It is your responsibility to call Close on the reader when done.
func (*FrameDecoder) Decode ¶
func (fd *FrameDecoder) Decode(framep *Frame) error
Decode retrieves the next frame from the input stream. The frame pointer should be non nil. If the input is at EOF, it returns the error io.EOF.
type Grid ¶
type Grid struct {
// contains filtered or unexported fields
}
Grid represents the grid that is used to draw a model logical contents that are then sent to the driver. It is a slice type, so it represents a rectangular range within an underlying original grid. Due to how it is represented internally, it is more efficient to iterate whole lines first, as in the following pattern:
max := gd.Size() for y := 0; y < max.Y; y++ { for x := 0; x < max.X; x++ { p := Point{X: x, Y: y} // do something with p and the grid gd } }
Most iterations can be performed using the Slice, Fill, Copy, Map and Iter methods. An alternative choice is to use the Iterator method.
Grid elements must be created with NewGrid.
Example ¶
package main import ( "fmt" "github.com/anaseto/gruid" ) func main() { // Create a new 20x20 grid. gd := gruid.NewGrid(20, 20) // Fill the whole grid with dots. gd.Fill(gruid.Cell{Rune: '.'}) // Define a range (5,5)-(15,15). rg := gruid.NewRange(5, 5, 15, 15) // Define a slice of the grid using the range. rectangle := gd.Slice(rg) // Fill the rectangle with #. rectangle.Fill(gruid.Cell{Rune: '#'}) // Print the grid using a non-styled string representation. fmt.Print(gd) }
Output: .................... .................... .................... .................... .................... .....##########..... .....##########..... .....##########..... .....##########..... .....##########..... .....##########..... .....##########..... .....##########..... .....##########..... .....##########..... .................... .................... .................... .................... ....................
func NewGrid ¶
NewGrid returns a new grid with given width and height in cells. The width and height should be positive or null. The new grid contains all positions (X,Y) with 0 <= X < w and 0 <= Y < h. The grid is filled with Cell{Rune: ' '}.
func (Grid) At ¶
At returns the cell content and styling at a given position. If the position is out of range, it returns the zero value.
func (Grid) Bounds ¶
Bounds returns the range that is covered by this grid slice within the underlying original grid.
func (Grid) Copy ¶
Copy copies elements from a source grid src into the destination grid gd, and returns the copied grid-slice size, which is the minimum of both grids for each dimension. The result is independent of whether the two grids referenced memory overlaps or not.
func (Grid) Iterator ¶
func (gd Grid) Iterator() GridIterator
Iterator returns an iterator that can be used to iterate on the grid. It may be convenient when more flexibility than the provided by the other iteration functions is needed. It is used as follows:
it := gd.Iterator() for it.Next() { // call it.P() or it.Cell() or it.SetCell() as appropriate }
func (Grid) Range ¶
Range returns the range with Min set to (0,0) and Max set to gd.Size(). It may be convenient when using Slice with a range Shift.
func (Grid) Resize ¶
Resize is similar to Slice, but it only specifies new dimensions, and if the range goes beyond the underlying original grid range, it will grow the underlying grid. In case of growth, it preserves the content, and new cells are initialized to Cell{Rune: ' '}.
func (Grid) Set ¶
Set draws cell content and styling at a given position in the grid. If the position is out of range, the function does nothing.
func (Grid) Size ¶
Size returns the grid (width, height) in cells, and is a shorthand for gd.Range().Size().
func (Grid) Slice ¶
Slice returns a rectangular slice of the grid given by a range relative to the grid. If the range is out of bounds of the parent grid, it will be reduced to fit to the available space. The returned grid shares memory with the parent.
This makes it easy to use relative coordinates when working with UI elements.
type GridIterator ¶
type GridIterator struct {
// contains filtered or unexported fields
}
GridIterator represents a stateful iterator for a grid. They are created with the Iterator method.
Example ¶
package main import ( "fmt" "github.com/anaseto/gruid" ) func main() { // Create a new 26x2 grid. gd := gruid.NewGrid(26, 2) // Get an iterator. it := gd.Iterator() // Iterate on the grid and fill it with successive alphabetic // characters. r := 'a' max := gd.Size() for it.Next() { it.SetCell(gruid.Cell{Rune: r}) r++ if it.P().X == max.X-1 { r = 'A' } } // Print the grid using a non-styled string representation. fmt.Print(gd) }
Output: abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ
func (*GridIterator) Cell ¶
func (it *GridIterator) Cell() Cell
Cell returns the Cell in the grid at the iterator's current position.
func (*GridIterator) Next ¶
func (it *GridIterator) Next() bool
Next advances the iterator the next position in the grid.
func (*GridIterator) P ¶
func (it *GridIterator) P() Point
P returns the iterator's current position.
func (*GridIterator) Reset ¶
func (it *GridIterator) Reset()
Reset resets the iterator's state so that it can be used again.
func (*GridIterator) SetCell ¶
func (it *GridIterator) SetCell(c Cell)
SetCell updates the grid cell at the iterator's current position.
func (*GridIterator) SetP ¶
func (it *GridIterator) SetP(p Point)
SetP sets the iterator's current position.
type Key ¶
type Key string
Key represents the name of a key press.
const ( KeyArrowDown Key = "ArrowDown" // can be KP_2 KeyArrowLeft Key = "ArrowLeft" // can be KP_4 KeyArrowRight Key = "ArrowRight" // can be KP_6 KeyArrowUp Key = "ArrowUp" // can be KP_8 KeyBackspace Key = "Backspace" KeyDelete Key = "Delete" KeyEnd Key = "End" // can be KP_1 KeyEnter Key = "Enter" // can be KP_5 (arbitrary choice) KeyEscape Key = "Escape" KeyHome Key = "Home" // can be KP_7 KeyInsert Key = "Insert" KeyPageDown Key = "PageDown" // can be KP_3 KeyPageUp Key = "PageUp" // can be KP_9 KeySpace Key = " " // constant for clarity (single character) KeyTab Key = "Tab" )
This is the list of the supported non single-character named keys. The drivers that support keypad with numlock off may report some KP_* keypad keys as one of this list, as specified in the comments.
type ModMask ¶
type ModMask int16
ModMask is a bit mask of modifier keys.
These values represent modifier keys for a MsgKeyDown message. Those are not supported equally well across all platforms and drivers, for both technical and simplicity reasons. In particular, terminal drivers may not report shift for key presses corresponding to upper case letters. Modifiers may conflict in some cases with browser or system shortcuts too. If you want portability across platforms and drivers, your application should not depend on them for its core functionality.
type Model ¶
type Model interface { // Update is called when a message is received. Use it to update your // model in response to messages and/or send commands or subscriptions. // It is always called the first time with a MsgInit message. Update(Msg) Effect // Draw is called after every Update. Use this function to draw the UI // elements in a grid to be returned. If only parts of the grid are to // be updated, you can return a smaller grid slice, or an empty grid // slice to skip any drawing work. Note that the contents of the grid // slice are then compared to the previous state at the same bounds, // and only the changes are sent to the driver anyway. Draw() Grid }
Model contains the application's state.
type MouseAction ¶
type MouseAction int
MouseAction represents mouse buttons.
const ( MouseMain MouseAction = iota // left button MouseAuxiliary // middle button MouseSecondary // right button MouseWheelUp // wheel impulse up MouseWheelDown // wheel impulse down MouseRelease // button release MouseMove // mouse motion )
This is the list of supported mouse buttons and actions. It is intentionally short for simplicity and best portability across drivers. Pressing several mouse buttons simultaneously is not reported and, in those cases, only one release event will be sent.
func (MouseAction) String ¶
func (ma MouseAction) String() string
type Msg ¶
type Msg interface{}
Msg represents an action and triggers the Update function of the model. Note that nil messages are discarded and do not trigger Update.
type MsgInit ¶
type MsgInit struct{}
MsgInit is a special message that is always sent first to Update after calling Start on the application.
type MsgKeyDown ¶
type MsgKeyDown struct { Key Key // name of the key in MsgKeyDown event // Mod represents modifier keys. They are not portable across // different platforms and drivers. Avoid using them for core // functionality in portable applications. Mod ModMask Time time.Time // time when the event was generated }
MsgKeyDown represents a key press.
type MsgMouse ¶
type MsgMouse struct { Action MouseAction // mouse action (click, release, move) P Point // mouse position in the grid Mod ModMask // modifier keys (unequal driver support) Time time.Time // time when the event was generated }
MsgMouse represents a mouse user input event.
type MsgQuit ¶
MsgQuit may be reported by some drivers to request termination of the application, such as when the main window is closed. It reports the time at which the driver's request was received.
type MsgScreen ¶
type MsgScreen struct { Width int // screen width in cells Height int // screen height in cells Time time.Time // time when the event was generated }
MsgScreen is reported by some drivers when the screen has been exposed in some way and a complete redraw is necessary. It may happen for example after a resize, or after a change of tile set invalidating current displayed content. Note that the application takes care of the redraw, so you may not need to handle it in most cases, unless you want to adapt grid size and layout in response to a potential screen resize.
type Point ¶
Point represents an (X,Y) position in a grid. It follows conventions similar to the ones used by the standard library image.Point.
func (Point) Shift ¶
Shift returns a new point with coordinates shifted by (x,y). It's a shorthand for p.Add(Point{x,y}).
type Range ¶
type Range struct {
Min, Max Point
}
Range represents a rectangle in a grid that contains all the positions P such that Min <= P < Max coordinate-wise. A range is well-formed if Min <= Max. When non-empty, Min represents the upper-left position in the range, and Max-(1,1) the lower-right one.
func NewRange ¶
NewRange returns a new Range with coordinates (x0, y0) for Min and (x1, y1) for Max. The returned range will have minimum and maximum coordinates swapped if necessary, so that the range is well-formed.
func (Range) Column ¶
Column reduces the range to relative column x, or an empty range if out of bounds.
func (Range) Columns ¶
Columns reduces the range to relative columns between x0 (included) and x1 (excluded), or an empty range if out of bounds.
func (Range) Eq ¶
Eq reports whether the two ranges containt the same set of points. All empty ranges are considered equal.
func (Range) Intersect ¶
Intersect returns the largest range contained both by rg and r. If the two ranges do not overlap, the zero range will be returned.
func (Range) Lines ¶
Lines reduces the range to relative lines between y0 (included) and y1 (excluded), or an empty range if out of bounds.
func (Range) RelMsg ¶
RelMsg returns a range-relative version of messages defined by the gruid package. Currently, it only affects mouse messages, which are given positions relative to the range.
func (Range) String ¶ added in v0.12.0
String returns a string representation of the form "(x0,y0)-(x1,y1)".
type Style ¶
type Style struct { Fg Color // foreground color Bg Color // background color Attrs AttrMask // custom styling attributes }
Style represents the styling information of a cell: foreground color, background color and custom attributes.
type Sub ¶
Sub is similar to Cmd, but instead of returning a message, it sends messages to a channel. Subscriptions should only be used for long running functions where more than one message will be produced, for example to send messages delivered by a time.Ticker, or to report messages from listening on a socket. The function should handle the context and terminate as appropriate.
Sub implements the Effect interface.
Directories ¶
Path | Synopsis |
---|---|
Package paths provides utilities for efficient pathfinding in rectangular maps.
|
Package paths provides utilities for efficient pathfinding in rectangular maps. |
Package rl provides some facilities for common roguelike programming needs: event queue, field of view and map generation.
|
Package rl provides some facilities for common roguelike programming needs: event queue, field of view and map generation. |
Package tiles provides common utilities for manipulation of graphical tiles, such as drawing fonts.
|
Package tiles provides common utilities for manipulation of graphical tiles, such as drawing fonts. |
Package ui defines common UI utilities for gruid: menu/table widget, pager, text input, label, text drawing facilities and replay functionality.
|
Package ui defines common UI utilities for gruid: menu/table widget, pager, text input, label, text drawing facilities and replay functionality. |