summaryrefslogtreecommitdiff
path: root/tweening.lisp
blob: 4de5c212f1107d7a165638c8e8fb6ff88bf68b81 (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
(in-package :animise)

(defmacro when-bound (symbol)
  `(when (boundp (quote ,symbol)) ,symbol))

(defvar *duration*)
(defvar *target*)
(defvar *start-time*)

(defmacro sequencing ((&key loop-mode at targeting) &body forms)
  "START and STARTING are synonym keywords, and are used to specify as tart time.

   WITH-TARGET, TARGETING, and TARGET are synonym keywords, used to specify a
   default tween target for all tweens made within the body of this form.

   LOOP-MODE is supplied to the LOOP-MODE slot on the TWEEN-SEQ class that this
   form returns."
  (let ((this-seq (gensym))
        (dyn-vars (append (when targeting
                            `((*target* ,targeting )))
                           (when at 
                             `((*start-time* ,at))))))
    `(let ,dyn-vars
       (let ((,this-seq (in-sequence ,@forms)))
         (setf (loop-mode ,this-seq) ',loop-mode)
         ,this-seq))))

(defun take-action (action &key (delay 20) (at 0))
  (let ((anim (pause delay at)))
    (setf (on-complete anim) action)
    anim))

(defun pausing (&key for at)
  "A light wrapper around PAUSE. Is aware of default parameters that may have
   been set in an enclosing form."
  (pause (or for (when-bound *duration*) 0)
         (or at (when-bound *start-time*) 0)))

(defmacro grouping ((&key for) &body forms)
  "Returns a TWEEN-GROUP instance.

   FOR is used to specify a default duration for any tweens defined in this
   body, where applicable."
  (let ((dyn-vars (append (when for 
                            `((*duration* ,for ))))))
    `(let ,dyn-vars
       (as-group ,@forms))))


(defun keyword->ease-fn (name)
  (case name
    ((:bounce-out :bouncing-out) #'bounce-out)
    ((:cubing-in :cubic-in) #'cubic-in)
    ((:cubing-in-out  :cubic-in-out) #'cubic-in-out)
    ((:cubing-out  :cubic-out) #'cubic-out)
    ((:elastic-out :springing-out :spring-out) #'elastic-out)
    ((:linear :linearly :none) #'linear)
    ((:quading-in :quad-in ) #'quad-in)
    ((:quading-in-out :quad-in-out ) #'quad-in-out)
    ((:quading-out :quad-out ) #'quad-out)
    ((:sine-in :sinusoidal-in ) #'sinusoidal-in)
    ((:sine-in-out  :sinusoidal-in-out) #'sinusoidal-in-out)
    ((:sine-out :sinusoidal-out ) #'sinusoidal-out)))

(defun animating (&key (by :none) the of to for at before)
  "A wrapper around ANIMATE that is aware of any default values defined in the
   the most recently enclosing form.

   BY is either an easing function, or a keyword that indicates an easing
   function. The valid keywords are :BOUNCE-OUT :BOUNCING-OUT :CUBING-IN
   :CUBICALLY-IN :CUBIC-IN :CUBING-IN-OUT :CUBICALLY-IN-OUT :CUBIC-IN-OUT
   :CUBING-OUT :CUBICALLY-OUT :CUBIC-OUT :ELASTIC-OUT :ELASTICALLY-OUT
   :LINEAR :LINEARLY :QUADING-IN :QUAD-IN :QUADRATICALLY-IN :QUADING-IN-OUT
   :QUAD-IN-OUT :QUADRATICALLY-IN-OUT :QUADING-OUT :QUAD-OUT :QUADRATICALLY-OUT
   :SINE-IN :SINUSOIDAL-IN :SINUSOIDALLY-IN :SINE-IN-OUT :SINUSOIDALLY-IN-OUT
   :SINUSOIDAL-IN-OUT :SINE-OUT :SINUSOIDAL-OUT :SINUSOIDALLY-OUT

   THE specifies the ACCESSOR to use for the tween. It should be as symbol
   naming a setf-able function.

   OF becomes the value of the TARGET slot of this TWEEN. If OF is NIL,
   then any default target value already set in an enclosing form is used.

   TO becomes the value of the END-VAL slot this TWEEN.

   FOR becomes the value of the DURATION slot of this TWEEN, superseding any
   default value set in the enclosing form.

   AT specifies a START-TIME, and overrides.
   "
  (animate (or of (when-bound *target*))
           the
           to
           :start (or at (when-bound *start-time*) 0)
           :on-complete before
           :ease (if (functionp by) by (keyword->ease-fn by))
           :duration (or for (when-bound *duration*) 0)))