aboutsummaryrefslogtreecommitdiffhomepage
path: root/gm/SkAnimTimer.h
blob: 725171a8fe55034ab223565f8653016571cf22c2 (plain)
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkTime.h"

#ifndef SkAnimTimer_DEFINED
#define SkAnimTimer_DEFINED

/**
 *  Class to track a "timer". It supports 3 states: stopped, paused, running.
 *
 *  The caller must call updateTime() to resync with the clock (typically just before
 *  using the timer). Forcing the caller to do this ensures that the timer's return values
 *  are consistent if called repeatedly, as they only reflect the time since the last
 *  calle to updateTimer().
 */
class SkAnimTimer {
public:
    enum State {
        kStopped_State,
        kPaused_State,
        kRunning_State
    };

    /**
     *  Class begins in the "stopped" state.
     */
    SkAnimTimer() : fBaseTime(0), fCurrTime(0), fState(kStopped_State) {}

    bool isStopped() const { return kStopped_State == fState; }
    bool isRunning() const { return kRunning_State == fState; }
    bool isPaused() const { return kPaused_State == fState; }

    /**
     *  Stops the timer, and resets it, such that the next call to run or togglePauseResume
     *  will begin at time 0.
     */
    void stop() {
        this->setState(kStopped_State);
    }

    /**
     *  If the timer is paused or stopped, it will resume (or start if it was stopped).
     */
    void run() {
        this->setState(kRunning_State);
    }

    /**
     *  If the timer is stopped, this has no effect, else it toggles between paused and running.
     */
    void togglePauseResume() {
        if (kRunning_State == fState) {
            this->setState(kPaused_State);
        } else {
            this->setState(kRunning_State);
        }
    }

    /**
     *  Call this each time you want to sample the clock for the timer. This is NOT done
     *  automatically, so that repeated calls to msec() or secs() will always return the
     *  same value.
     *
     *  This may safely be called with the timer in any state.
     */
    void updateTime() {
        if (kRunning_State == fState) {
            fCurrTime = SkTime::GetMSecs();
        }
    }

    /**
     *  Return the time in milliseconds the timer has been in the running state.
     *  Returns 0 if the timer is stopped.
     */
    SkMSec msec() const { return fCurrTime - fBaseTime; }

    /**
     *  Return the time in seconds the timer has been in the running state.
     *  Returns 0 if the timer is stopped.
     */
    double secs() const {
        return this->msec() * 0.001;
    }

    /**
     *  Return the time in seconds the timer has been in the running state,
     *  scaled by "speed" and (if not zero) mod by period.
     *  Returns 0 if the timer is stopped.
     */
    SkScalar scaled(SkScalar speed, SkScalar period = 0) const {
        double value = this->secs() * speed;
        if (period) {
            value = ::fmod(value, SkScalarToDouble(period));
        }
        return SkDoubleToScalar(value);
    }

private:
    SkMSec  fBaseTime;
    SkMSec  fCurrTime;
    State   fState;

    void setState(State newState) {
        switch (newState) {
            case kStopped_State:
                fBaseTime = fCurrTime = 0;
                fState = kStopped_State;
                break;
            case kPaused_State:
                if (kRunning_State == fState) {
                    fState = kPaused_State;
                } // else stay stopped or paused
                break;
            case kRunning_State:
                switch (fState) {
                    case kStopped_State:
                        fBaseTime = fCurrTime = SkTime::GetMSecs();
                        break;
                    case kPaused_State: {// they want "resume"
                        SkMSec now = SkTime::GetMSecs();
                        fBaseTime += now - fCurrTime;
                        fCurrTime = now;
                    } break;
                    case kRunning_State:
                        break;
                }
                fState = kRunning_State;
                break;
        }
    }
};

#endif