▶ Live demo: https://go-widgets.github.io/painter/
The drawing seam of go-widgets: one
Painter interface that every widget draws through, and two painters that
turn the same calls into different things:
PixelPainterwrites into a caller-owned RGBA[]byte, which a native window, a browser<canvas>, an Android surface or an image encoder then presents;CellPainterwrites into a grid of terminal cells (rune, foreground, background) with a 24-bit ANSI serialiser.
A widget never learns which one it was handed. That is what lets
go-widgets/toolkit, whose
Widget.Draw has taken a painter.Painter since its v0.6, run unchanged in a
window, a browser and a terminal.
type Painter interface {
FillRect(r Rect, c RGBA)
StrokeRect(r Rect, c RGBA, lineW int)
FillRoundRect(r Rect, radius int, c RGBA)
StrokeRoundRect(r Rect, radius int, c RGBA, lineW int)
PutPixel(x, y int, c RGBA)
Text(x, y int, s string, ink RGBA)
Size() (w, h int)
}Seven methods, all of which every back-end must implement — so the contract
says what happens where a back-end cannot: a cell grid ignores lineW, and
draws a rounded rectangle square.
What not every surface can do is not in the base interface. A widget that needs it type-asserts, and draws something sensible when the answer is no:
| Interface | Methods | File |
|---|---|---|
Clipper |
PushClip, PopClip |
clip.go |
Translator |
PushTranslate, PopTranslate |
translate.go |
PathPainter |
FillPath, StrokePath |
path.go, pathpaint.go |
ImagePainter |
DrawImage |
image.go |
MaskPainter |
DrawMask |
mask.go |
FacePainter |
TextFace |
face.go |
if c, ok := p.(painter.Clipper); ok {
c.PushClip(bounds)
defer c.PopClip()
}PixelPainter implements all of them. Its anti-aliased paths are rasterised
by go-gfx/gfx/vector, in Go; that is the
module's one dependency.
# pixels, written as a PNG — what a browser canvas or a window would get
go run ./cmd/wui-demo --out demo.png
go run ./cmd/wui-demo --out demo.png --theme dark
# cells, written to stdout as 24-bit ANSI
go run ./cmd/tui-demo
go run ./cmd/tui-demo --theme dark
# pixels in a browser
task serve # http://localhost:8091/The three demos draw the same three sample widgets (widget.go: Label, two
Buttons, a ProgressBar) through the same code; only the painter changes.
Those widgets and the 5×7 font in font.go exist for the demos. The real
widget set, and its full font support, is
go-widgets/toolkit.
The production seam of go-widgets/toolkit and go-widgets/tui. 100% statement
coverage, CGO_ENABLED=0, cross-built for amd64, arm64, riscv64, loong64,
ppc64le and s390x, and GOOS=js GOARCH=wasm.
BSD 3-Clause. See LICENSE.