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