Skip to content

Commit

Permalink
make animation.Start idempotent - no-op if started multiple times
Browse files Browse the repository at this point in the history
  • Loading branch information
dweymouth committed Dec 10, 2023
1 parent 7344f9a commit 55eb2d8
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 10 deletions.
40 changes: 33 additions & 7 deletions animation.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fyne

import (
"sync"
"time"
)

Expand Down Expand Up @@ -34,6 +35,22 @@ var (
AnimationLinear = animationLinear
)

// AnimationState represents the state of an animation.
//
// Since: 2.5
type AnimationState int

const (
// AnimationStateNotStarted represents an animation that has been created but not yet started.
AnimationStateNotStarted AnimationState = iota

// AnimationStateRunning represents an animation that is running.
AnimationStateRunning

// AnimationStateStopped represents an animation that has been stopped or has finished running.
AnimationStateStopped
)

// Animation represents an animated element within a Fyne canvas.
// These animations may control individual objects or entire scenes.
//
Expand All @@ -45,7 +62,8 @@ type Animation struct {
RepeatCount int
Tick func(float32)

stopped bool
mutex sync.Mutex
state AnimationState
}

// NewAnimation creates a very basic animation where the callback function will be called for every
Expand All @@ -59,20 +77,28 @@ func NewAnimation(d time.Duration, fn func(float32)) *Animation {

// Start registers the animation with the application run-loop and starts its execution.
func (a *Animation) Start() {
a.stopped = false
CurrentApp().Driver().StartAnimation(a)
a.mutex.Lock()
defer a.mutex.Unlock()
if a.state == AnimationStateRunning {
return
}
a.state = AnimationStateRunning
d := CurrentApp().Driver().(interface{ StartAnimationPrivate(*Animation) })
d.StartAnimationPrivate(a)
}

// Stop will end this animation and remove it from the run-loop.
func (a *Animation) Stop() {
a.stopped = true
a.mutex.Lock()
defer a.mutex.Unlock()
a.state = AnimationStateStopped
}

// Stopped returns true if this animation has been stopped or has completed running.
// State returns the state of this animation.
//
// Since: 2.5
func (a *Animation) Stopped() bool {
return a.stopped
func (a *Animation) State() AnimationState {
return a.state
}

func animationEaseIn(val float32) float32 {
Expand Down
2 changes: 1 addition & 1 deletion internal/animation/animation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestGLDriver_StopAnimation(t *testing.T) {
}
a.Stop()
run.animationMutex.Lock()
assert.True(t, a.Stopped(), "animation was not stopped")
assert.True(t, a.State() == fyne.AnimationStateStopped, "animation was not stopped")
run.animationMutex.Unlock()
}

Expand Down
4 changes: 2 additions & 2 deletions internal/animation/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ func (r *Runner) runAnimations() {
// tick currently running animations
newList := r.animations[:0] // references same underlying backing array
for _, a := range r.animations {
if s := a.a.Stopped(); !s && r.tickAnimation(a) {
if stopped := a.a.State() == fyne.AnimationStateStopped; !stopped && r.tickAnimation(a) {
newList = append(newList, a) // still running
} else if !s {
} else if !stopped {
a.a.Stop() // mark as stopped (completed running)
}
}
Expand Down
4 changes: 4 additions & 0 deletions internal/driver/glfw/animation.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package glfw
import "fyne.io/fyne/v2"

func (d *gLDriver) StartAnimation(a *fyne.Animation) {
a.Start()
}

func (d *gLDriver) StartAnimationPrivate(a *fyne.Animation) {
d.animation.Start(a)
}

Expand Down
4 changes: 4 additions & 0 deletions internal/driver/mobile/animation.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package mobile
import "fyne.io/fyne/v2"

func (d *mobileDriver) StartAnimation(a *fyne.Animation) {
a.Start()
}

func (d *mobileDriver) StartAnimationPrivate(a *fyne.Animation) {
d.animation.Start(a)
}

Expand Down

0 comments on commit 55eb2d8

Please sign in to comment.