gioui.org@v0.6.1-0.20240506124620-7a9ce51988ce/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  	"gioui.org/f32"
    12  	"gioui.org/layout"
    13  	"gioui.org/op"
    14  	"gioui.org/op/clip"
    15  	"gioui.org/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  	gtx.Execute(op.InvalidateCmd{})
    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  }