loader.go raw
1 // SPDX-License-Identifier: Unlicense OR MIT
2
3 package material
4
5 import (
6 "image"
7 "image/color"
8 "math"
9 "time"
10
11 "github.com/p9c/p9/pkg/gel/gio/f32"
12 "github.com/p9c/p9/pkg/gel/gio/layout"
13 "github.com/p9c/p9/pkg/gel/gio/op"
14 "github.com/p9c/p9/pkg/gel/gio/op/clip"
15 "github.com/p9c/p9/pkg/gel/gio/op/paint"
16 "github.com/p9c/p9/pkg/gel/gio/unit"
17 )
18
19 type LoaderStyle struct {
20 Color color.NRGBA
21 }
22
23 func Loader(th *Theme) LoaderStyle {
24 return LoaderStyle{
25 Color: th.Palette.ContrastBg,
26 }
27 }
28
29 func (l LoaderStyle) Layout(gtx layout.Context) layout.Dimensions {
30 diam := gtx.Constraints.Min.X
31 if minY := gtx.Constraints.Min.Y; minY > diam {
32 diam = minY
33 }
34 if diam == 0 {
35 diam = gtx.Px(unit.Dp(24))
36 }
37 sz := gtx.Constraints.Constrain(image.Pt(diam, diam))
38 radius := float64(sz.X) * .5
39 defer op.Save(gtx.Ops).Load()
40 op.Offset(f32.Pt(float32(radius), float32(radius))).Add(gtx.Ops)
41
42 dt := (time.Duration(gtx.Now.UnixNano()) % (time.Second)).Seconds()
43 startAngle := dt * math.Pi * 2
44 endAngle := startAngle + math.Pi*1.5
45
46 clipLoader(gtx.Ops, startAngle, endAngle, radius)
47 paint.ColorOp{
48 Color: l.Color,
49 }.Add(gtx.Ops)
50 op.Offset(f32.Pt(-float32(radius), -float32(radius))).Add(gtx.Ops)
51 paint.PaintOp{}.Add(gtx.Ops)
52 op.InvalidateOp{}.Add(gtx.Ops)
53 return layout.Dimensions{
54 Size: sz,
55 }
56 }
57
58 func clipLoader(ops *op.Ops, startAngle, endAngle, radius float64) {
59 const thickness = .25
60
61 var (
62 width = float32(radius * thickness)
63 delta = float32(endAngle - startAngle)
64
65 vy, vx = math.Sincos(startAngle)
66
67 pen = f32.Pt(float32(vx), float32(vy)).Mul(float32(radius))
68 center = f32.Pt(0, 0).Sub(pen)
69
70 p clip.Path
71 )
72
73 p.Begin(ops)
74 p.Move(pen)
75 p.Arc(center, center, delta)
76 clip.Stroke{
77 Path: p.End(),
78 Style: clip.StrokeStyle{
79 Width: width,
80 Cap: clip.FlatCap,
81 },
82 }.Op().Add(ops)
83 }
84