indefinite.go raw
1 package gel
2
3 import (
4 "image"
5 "image/color"
6 "math"
7 "time"
8
9 "github.com/p9c/gio/f32"
10 l "github.com/p9c/gio/layout"
11 "github.com/p9c/gio/op"
12 "github.com/p9c/gio/op/clip"
13 "github.com/p9c/gio/op/paint"
14 )
15
16 type Indefinite struct {
17 *Window
18 color color.NRGBA
19 scale float32
20 }
21
22 // Indefinite creates an indefinite loading animation icon
23 func (w *Window) Indefinite() *Indefinite {
24 return &Indefinite{
25 Window: w,
26 color: w.Colors.GetNRGBAFromName("Primary"),
27 }
28 }
29
30 // Scale sets the size of the spinner
31 func (lo *Indefinite) Scale(scale float32) *Indefinite {
32 lo.scale = scale
33 return lo
34 }
35
36 // Color sets the color of the spinner
37 func (lo *Indefinite) Color(color string) *Indefinite {
38 lo.color = lo.Theme.Colors.GetNRGBAFromName(color)
39 return lo
40 }
41
42 // Fn renders the loader
43 func (lo *Indefinite) Fn(gtx l.Context) l.Dimensions {
44 diam := gtx.Constraints.Min.X
45 if minY := gtx.Constraints.Min.Y; minY > diam {
46 diam = minY
47 }
48 if diam == 0 {
49 diam = gtx.Px(lo.Theme.TextSize.Scale(lo.scale))
50 }
51 sz := gtx.Constraints.Constrain(image.Pt(diam, diam))
52 radius := float64(sz.X) * .5
53 defer op.Save(gtx.Ops).Load()
54 op.Offset(f32.Pt(float32(radius), float32(radius))).Add(gtx.Ops)
55 dt := (time.Duration(gtx.Now.UnixNano()) % (time.Second)).Seconds()
56 startAngle := dt * math.Pi * 2
57 endAngle := startAngle + math.Pi*1.5
58 clipLoader(gtx.Ops, startAngle, endAngle, radius)
59 paint.ColorOp{
60 Color: lo.color,
61 }.Add(gtx.Ops)
62 op.Offset(f32.Pt(-float32(radius), -float32(radius))).Add(gtx.Ops)
63 paint.PaintOp{
64 // Rect: f32.Rectangle{Max: l.FPt(sz)},
65 }.Add(gtx.Ops)
66 op.InvalidateOp{}.Add(gtx.Ops)
67 return l.Dimensions{
68 Size: sz,
69 }
70 }
71
72 func clipLoader(ops *op.Ops, startAngle, endAngle, radius float64) {
73 const thickness = .25
74 var (
75 width = float32(radius * thickness)
76 delta = float32(endAngle - startAngle)
77
78 vy, vx = math.Sincos(startAngle)
79
80 pen = f32.Pt(float32(vx), float32(vy)).Mul(float32(radius))
81 center = f32.Pt(0, 0).Sub(pen)
82
83 p clip.Path
84 )
85 p.Begin(ops)
86 p.Move(pen)
87 p.Arc(center, center, delta)
88 clip.Stroke{
89 Path: p.End(),
90 Style: clip.StrokeStyle{
91 Width: width,
92 Cap: clip.FlatCap,
93 },
94 }.Op().Add(ops)
95 }
96