runner.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package animation
  2. import (
  3. "sync"
  4. "time"
  5. "fyne.io/fyne/v2"
  6. )
  7. // Runner is the main driver for animations package
  8. type Runner struct {
  9. animationMutex sync.RWMutex
  10. animations []*anim
  11. pendingAnimations []*anim
  12. runnerStarted bool
  13. }
  14. // Start will register the passed application and initiate its ticking.
  15. func (r *Runner) Start(a *fyne.Animation) {
  16. r.animationMutex.Lock()
  17. defer r.animationMutex.Unlock()
  18. if !r.runnerStarted {
  19. r.runnerStarted = true
  20. r.animations = append(r.animations, newAnim(a))
  21. r.runAnimations()
  22. } else {
  23. r.pendingAnimations = append(r.pendingAnimations, newAnim(a))
  24. }
  25. }
  26. // Stop causes an animation to stop ticking (if it was still running) and removes it from the runner.
  27. func (r *Runner) Stop(a *fyne.Animation) {
  28. r.animationMutex.Lock()
  29. defer r.animationMutex.Unlock()
  30. newList := make([]*anim, 0, len(r.animations))
  31. stopped := false
  32. for _, item := range r.animations {
  33. if item.a != a {
  34. newList = append(newList, item)
  35. } else {
  36. item.setStopped()
  37. stopped = true
  38. }
  39. }
  40. r.animations = newList
  41. if stopped {
  42. return
  43. }
  44. newList = make([]*anim, 0, len(r.pendingAnimations))
  45. for _, item := range r.pendingAnimations {
  46. if item.a != a {
  47. newList = append(newList, item)
  48. } else {
  49. item.setStopped()
  50. }
  51. }
  52. r.pendingAnimations = newList
  53. }
  54. func (r *Runner) runAnimations() {
  55. draw := time.NewTicker(time.Second / 60)
  56. go func() {
  57. for done := false; !done; {
  58. <-draw.C
  59. r.animationMutex.Lock()
  60. oldList := r.animations
  61. r.animationMutex.Unlock()
  62. newList := make([]*anim, 0, len(oldList))
  63. for _, a := range oldList {
  64. if !a.isStopped() && r.tickAnimation(a) {
  65. newList = append(newList, a)
  66. }
  67. }
  68. r.animationMutex.Lock()
  69. r.animations = append(newList, r.pendingAnimations...)
  70. r.pendingAnimations = nil
  71. done = len(r.animations) == 0
  72. r.animationMutex.Unlock()
  73. }
  74. r.animationMutex.Lock()
  75. r.runnerStarted = false
  76. r.animationMutex.Unlock()
  77. draw.Stop()
  78. }()
  79. }
  80. // tickAnimation will process a frame of animation and return true if this should continue animating
  81. func (r *Runner) tickAnimation(a *anim) bool {
  82. if time.Now().After(a.end) {
  83. if a.reverse {
  84. a.a.Tick(0.0)
  85. if a.repeatsLeft == 0 {
  86. return false
  87. }
  88. a.reverse = false
  89. } else {
  90. a.a.Tick(1.0)
  91. if a.a.AutoReverse {
  92. a.reverse = true
  93. }
  94. }
  95. if !a.reverse {
  96. if a.repeatsLeft == 0 {
  97. return false
  98. }
  99. if a.repeatsLeft > 0 {
  100. a.repeatsLeft--
  101. }
  102. }
  103. a.start = time.Now()
  104. a.end = a.start.Add(a.a.Duration)
  105. return true
  106. }
  107. delta := time.Since(a.start).Milliseconds()
  108. val := float32(delta) / float32(a.total)
  109. curve := a.a.Curve
  110. if curve == nil {
  111. curve = fyne.AnimationEaseInOut
  112. }
  113. if a.reverse {
  114. a.a.Tick(curve(1 - val))
  115. } else {
  116. a.a.Tick(curve(val))
  117. }
  118. return true
  119. }