diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2025-07-05 12:14:33 -0400 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2025-08-20 15:57:23 +0200 |
| commit | b5aed7f856c6a5455daac3dd341e91b52db92ae7 (patch) | |
| tree | 4dcae4cd09eb7df654218aaa693fd7c0411d9a3f | |
| parent | f58b61bd39a59599710c5ea7dcf0af52d6e5b679 (diff) | |
| download | muhqs-game-b5aed7f856c6a5455daac3dd341e91b52db92ae7.tar.gz muhqs-game-b5aed7f856c6a5455daac3dd341e91b52db92ae7.zip | |
add simple spinner
| -rw-r--r-- | go/dummy-ui/main.go | 2 | ||||
| -rw-r--r-- | go/ui/spinner.go | 77 |
2 files changed, 79 insertions, 0 deletions
diff --git a/go/dummy-ui/main.go b/go/dummy-ui/main.go index a3e90f48..fd936466 100644 --- a/go/dummy-ui/main.go +++ b/go/dummy-ui/main.go @@ -34,6 +34,8 @@ func (a *app) build() { a.AddWidget(tI) a.AddWidget(ui.NewTimerBar(0, 10, a.windowWidth, 5, 30*time.Second)) + + a.AddWidget(ui.NewSpinner(100, 400, 50)) } func (a *app) Layout(width, height int) (int, int) { diff --git a/go/ui/spinner.go b/go/ui/spinner.go new file mode 100644 index 00000000..083ec292 --- /dev/null +++ b/go/ui/spinner.go @@ -0,0 +1,77 @@ +package ui + +import ( + "image/color" + "math" + + "github.com/hajimehoshi/ebiten/v2" + "github.com/hajimehoshi/ebiten/v2/vector" +) + +var ( + SPINNER_DEFAULT_FOREGROUND = color.White + SPINNER_DEFAULT_STROKE = 5 +) + +type Spinner struct { + WidgetBase + fg color.Color + alpha uint64 +} + +func NewSpinner(x, y int, diameter int) *Spinner { + s := &Spinner{ + WidgetBase: NewWidgetBase(x, y, diameter, diameter), + fg: SPINNER_DEFAULT_FOREGROUND, + } + s.renderImpl = func() *ebiten.Image { return s.render() } + s.EventHandlersMap["update"] = func() error { + s.alpha = s.alpha + 3 + s.ForceRedraw() + return nil + } + return s +} + +func (s *Spinner) Fg(fg color.Color) *Spinner { + s.fg = fg + return s +} + +func (s *Spinner) render() *ebiten.Image { + img := ebiten.NewImage(s.Width, s.Height) + var path vector.Path + + r := float64((s.Width - 2*SPINNER_DEFAULT_STROKE) / 2) + cx := s.Width/2 + SPINNER_DEFAULT_STROKE + cy := cx + a1 := float64(s.alpha%360) * math.Pi / 180 + a2 := float64((s.alpha+90)%360) * math.Pi / 180 + + path.Arc(float32(cx), float32(cy), float32(r), float32(a2), float32(a1), vector.Clockwise) + + strokeOp := &vector.StrokeOptions{} + strokeOp.Width = float32(SPINNER_DEFAULT_STROKE) + vertices := []ebiten.Vertex{} + indices := []uint16{} + vertices, indices = path.AppendVerticesAndIndicesForStroke(vertices, indices, strokeOp) + + { + r, g, b, a := s.fg.RGBA() + for i := range vertices { + vertices[i].SrcX = 1 + vertices[i].SrcY = 1 + vertices[i].ColorR = float32(r) + vertices[i].ColorG = float32(g) + vertices[i].ColorB = float32(b) + vertices[i].ColorA = float32(a) + } + } + + op := &ebiten.DrawTrianglesOptions{} + op.AntiAlias = true + op.FillRule = ebiten.FillRuleNonZero + op.ColorScaleMode = ebiten.ColorScaleModePremultipliedAlpha + img.DrawTriangles(vertices, indices, whiteSubImage, op) + return img +} |
