~pierrec/giox

ref: c164e218831e giox/widgetx/anim.go -rw-r--r-- 1.3 KiB
c164e218Pierre Curto cm/iconx: update the set of icons 9 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package widgetx

import (
	"time"

	"gioui.org/layout"
	"gioui.org/op"
)

// Anim manages Frame refreshes based on an interpolator function.
type Anim struct {
	// Next is the interpolator function.
	Next func(float32) (float32, time.Duration)
	next time.Time
	end  float32
	v    float32
	w    float32
}

// Start starts the animation, ending when the value crosses the end value.
func (a *Anim) Start(start, end float32) {
	if start != end {
		a.next = time.Time{}
		a.end = end
		a.v = start
	}
}

// Value returns the current value, without animating.
func (a *Anim) Value() float32 {
	return a.v
}

func (a *Anim) Animating() bool {
	return !a.next.IsZero()
}

// Animate moves the animation forward if possible and returns
// whether or not the animation is complete.
func (a *Anim) Animate(gtx layout.Context) (done bool) {
	switch asc := a.v < a.end; {
	case asc && a.v >= a.end || !asc && a.v <= a.end:
		// Animation done.
		a.next = time.Time{}
		a.v = a.end
		op.InvalidateOp{}.Add(gtx.Ops)
		return true
	case a.next.IsZero():
		// First animation.
		nv, d := a.Next(a.v)
		a.next = gtx.Now.Add(d)
		a.w = nv
	case a.next.Before(gtx.Now) || a.next.Equal(gtx.Now):
		// Next animation.
		nv, d := a.Next(a.w)
		a.next = a.next.Add(d)
		a.v, a.w = a.w, nv
	}
	op.InvalidateOp{At: a.next}.Add(gtx.Ops)
	return false
}