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 }