// Command counter is the smallest complete gophics app, and the one the
// homepage and the getting-started guide both show.
//
// It is a real example rather than a snippet in the docs so that it compiles
// in CI and its screenshot is generated from this exact source — a sample that
// only exists as HTML drifts from the API, and this one already had.
//
// The whole program:
//
// go run ./examples/counter # a window
// GOOS=js GOARCH=wasm go build # the same UI in a browser
package main
import (
"fmt"
"log"
"golang.org/x/image/font/gofont/gobold"
"golang.org/x/image/font/gofont/goregular"
"github.com/doug/gophics/app"
"github.com/doug/gophics/geom"
"github.com/doug/gophics/theme"
"github.com/doug/gophics/widget"
)
// Counter is a widget: a plain struct value describing what to show.
type Counter struct{ Start int }
func (Counter) CreateState() widget.State { return &counterState{} }
// counterState holds what changes. StateBase[Counter] gives it SetState and a
// typed W() — the current Counter value, with no cast.
type counterState struct {
widget.StateBase[Counter]
n int
}
func (s *counterState) Init(widget.Ctx) { s.n = s.W().Start }
func (s *counterState) Build(ctx widget.Ctx) widget.Widget {
// Pinned to the light theme rather than following the system setting.
//
// Most apps should follow it — theme.Of does that by default, and the
// other examples rely on it. This one is the figure on the home page,
// shown beside a still of itself, and a screenshot cannot follow anybody's
// colour scheme. Pinning both to light keeps the pair honest; the
// alternative is shipping two stills and picking between them, which is a
// lot of machinery for a counter.
th := theme.Light()
return widget.Provide[theme.Theme]{Value: th, Child: widget.Fill{Color: th.Bg,
Child: widget.Center(widget.Column(
widget.Text{Value: "TAPS", Size: th.Type.Caption, Color: th.Muted},
widget.Sized{H: 4},
widget.Text{
Value: fmt.Sprintf("%d", s.n),
Size: th.Type.Display,
Font: theme.FontBold,
Color: th.Text,
},
widget.Sized{H: 18},
theme.Button{
Label: "Increment",
Primary: true,
OnTap: func() { s.SetState(func() { s.n++ }) },
},
))}}
}
func main() {
err := app.Run(Counter{Start: 3}, app.Config{
Title: "counter",
Size: geom.Size{W: 320, H: 220},
// Light in both schemes, matching the pinned theme above.
Background: theme.Light().Bg,
Font: goregular.TTF,
FontFamilies: map[string][]byte{
theme.FontBold: gobold.TTF,
},
})
if err != nil {
log.Fatal(err)
}
}