github.com/Seikaijyu/gio@v0.0.1/widget/material/loader.go (about) 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/Seikaijyu/gio/f32" 12 "github.com/Seikaijyu/gio/layout" 13 "github.com/Seikaijyu/gio/op" 14 "github.com/Seikaijyu/gio/op/clip" 15 "github.com/Seikaijyu/gio/op/paint" 16 ) 17 18 type LoaderStyle struct { 19 Color color.NRGBA 20 } 21 22 func Loader(th *Theme) LoaderStyle { 23 return LoaderStyle{ 24 Color: th.Palette.ContrastBg, 25 } 26 } 27 28 func (l LoaderStyle) Layout(gtx layout.Context) layout.Dimensions { 29 diam := gtx.Constraints.Min.X 30 if minY := gtx.Constraints.Min.Y; minY > diam { 31 diam = minY 32 } 33 if diam == 0 { 34 diam = gtx.Dp(24) 35 } 36 sz := gtx.Constraints.Constrain(image.Pt(diam, diam)) 37 radius := sz.X / 2 38 defer op.Offset(image.Pt(radius, radius)).Push(gtx.Ops).Pop() 39 40 dt := float32((time.Duration(gtx.Now.UnixNano()) % (time.Second)).Seconds()) 41 startAngle := dt * math.Pi * 2 42 endAngle := startAngle + math.Pi*1.5 43 44 defer clipLoader(gtx.Ops, startAngle, endAngle, float32(radius)).Push(gtx.Ops).Pop() 45 paint.ColorOp{ 46 Color: l.Color, 47 }.Add(gtx.Ops) 48 defer op.Offset(image.Pt(-radius, -radius)).Push(gtx.Ops).Pop() 49 paint.PaintOp{}.Add(gtx.Ops) 50 op.InvalidateOp{}.Add(gtx.Ops) 51 return layout.Dimensions{ 52 Size: sz, 53 } 54 } 55 56 func clipLoader(ops *op.Ops, startAngle, endAngle, radius float32) clip.Op { 57 const thickness = .25 58 59 var ( 60 width = radius * thickness 61 delta = endAngle - startAngle 62 63 vy, vx = math.Sincos(float64(startAngle)) 64 65 inner = radius * (1. - thickness*.5) 66 pen = f32.Pt(float32(vx), float32(vy)).Mul(inner) 67 center = f32.Pt(0, 0).Sub(pen) 68 69 p clip.Path 70 ) 71 72 p.Begin(ops) 73 p.Move(pen) 74 p.Arc(center, center, delta) 75 return clip.Stroke{ 76 Path: p.End(), 77 Width: width, 78 }.Op() 79 }