Update copyright year to 2014 by running admin/update-copyright.
[emacs.git] / lisp / play / animate.el
blob8b286ab5d0715ea55b1de99ca6a3791b398424c4
1 ;;; animate.el --- make text dance
3 ;; Copyright (C) 2001-2014 Free Software Foundation, Inc.
5 ;; Maintainer: Richard Stallman <rms@gnu.org>
6 ;; Keywords: games
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
23 ;;; Commentary:
25 ;; (animate-string STRING VPOS &optional HPOS)
26 ;; makes the string STRING appear starting at VPOS, HPOS
27 ;; by having each letter swoop into place from random starting position.
29 ;; animate-birthday-present was the first application of this program.
31 ;;; Code:
33 ;;; STRING is the string to be displayed,
34 ;;; and DEST-X, DEST-Y say where on the screen
35 ;;; it should end up.
37 ;;; This function returns a list describing
38 ;;; all the characters and the paths they should take.
39 ;;; Each element has the form
40 ;;; (CHAR START-Y START-X DEST-Y DEST-X).
42 ;;; The start position of each character is chosen randomly.
43 ;;; The destination is chosen to put it in the right place
44 ;;; in the string when the whole string finally reaches its
45 ;;; specified position.
47 (defun animate-initialize (string vpos hpos)
48 (let ((characters nil))
49 (dotimes (i (length string))
50 (setq characters
51 (cons (list (aref string i)
52 ;; Random starting positions.
53 (random (window-height))
54 (random (1- (window-width)))
55 ;; All the chars should end up
56 ;; on the specified line.
57 vpos
58 ;; The Ith character in the string
59 ;; needs to end up I positions later.
60 (+ hpos i))
61 characters)))
62 characters))
64 ;;; Display the characters in CHARACTERS,
65 ;;; each one FRACTION of the way from its start to its destination.
66 ;;; If FRACTION is 0, the characters appear in their starting positions.
67 ;;; If FRACTION is 1, the characters appear in their destinations.
69 (defun animate-step (characters fraction)
70 (let ((remains (- 1 fraction)))
71 (dolist (item characters)
72 (let ((vpos (+ (* remains (nth 1 item))
73 (* fraction (nth 3 item))))
74 (hpos (+ (* remains (nth 2 item))
75 (* fraction (nth 4 item)))))
76 (animate-place-char (car item) vpos hpos)))))
78 ;;; Place the character CHAR at position VPOS, HPOS in the current buffer.
79 (defun animate-place-char (char vpos hpos)
80 (goto-char (window-start))
81 (let (abbrev-mode)
82 (dotimes (i vpos)
83 (end-of-line)
84 (if (= (forward-line 1) 1)
85 (insert "\n"))))
86 (beginning-of-line)
87 (move-to-column (floor hpos) t)
88 (unless (eolp) (delete-char 1))
89 (insert-char char 1))
91 (defvar animate-n-steps 10
92 "*Number of steps `animate-string' will place a char before its last position.")
94 (defvar animation-buffer-name nil
95 "String naming the default buffer for animations.
96 When nil animations displayed in the buffer named *Animation*.")
98 ;;;###autoload
99 (defun animate-string (string vpos &optional hpos)
100 "Display STRING animations starting at position VPOS, HPOS.
101 The characters start at randomly chosen places,
102 and all slide in parallel to their final positions,
103 passing through `animate-n-steps' positions before the final ones.
104 If HPOS is nil (or omitted), center the string horizontally
105 in the current window."
106 (let ((characters
107 (animate-initialize string vpos
108 (or hpos
109 ;; HPOS unspecified, so compute
110 ;; it so as to center the string.
111 (max 0 (/ (- (window-width) (length string)) 2)))))
112 (show-trailing-whitespace nil)
113 ;; Make sure indentation does not use tabs.
114 ;; They would confuse things.
115 (indent-tabs-mode nil))
116 (dotimes (i animate-n-steps)
117 ;; Bind buffer-undo-list so it will be unchanged when we are done.
118 ;; (We're going to undo all our changes anyway.)
119 (let (buffer-undo-list
120 list-to-undo)
121 ;; Display the characters at the Ith position.
122 ;; This inserts them in the buffer.
123 (animate-step characters (/ i 1.0 animate-n-steps))
124 ;; Make sure buffer is displayed starting at the beginning.
125 (set-window-start nil 1)
126 ;; Display it, and wait just a little while.
127 (sit-for .05)
128 ;; Now undo the changes we made in the buffer.
129 (setq list-to-undo buffer-undo-list)
130 (while list-to-undo
131 (let ((undo-in-progress t))
132 (setq list-to-undo (primitive-undo 1 list-to-undo))))))
133 ;; Insert the characters in their final positions.
134 (animate-step characters 1)
135 ;; Put the cursor at the end of the text on the line.
136 (end-of-line)
137 ;; Redisplay so they appear on the screen there.
138 (sit-for 0)
139 ;; This is so that the undo command, used afterwards,
140 ;; will undo the "animate" calls one by one.
141 (undo-boundary)))
143 ;;;###autoload
144 (defun animate-sequence (list-of-strings space)
145 "Display animation strings from LIST-OF-STRING with buffer *Animation*.
146 Strings will be separated from each other by SPACE lines.
147 When the variable `animation-buffer-name' is non-nil display
148 animation in the buffer named by variable's value, creating the
149 buffer if one does not exist."
150 (let ((vpos (/ (- (window-height)
151 1 ;; For the mode-line
152 (* (1- (length list-of-strings)) space)
153 (length list-of-strings))
154 2)))
155 (switch-to-buffer (get-buffer-create
156 (or animation-buffer-name
157 "*Animation*")))
158 (erase-buffer)
159 (sit-for 0)
160 (while list-of-strings
161 (animate-string (car list-of-strings) vpos)
162 (setq vpos (+ vpos space 1))
163 (setq list-of-strings (cdr list-of-strings)))))
165 ;;;###autoload
166 (defun animate-birthday-present (&optional name)
167 "Return a birthday present in the buffer *Birthday-Present*.
168 When optional arg NAME is non-nil or called-interactively, prompt for
169 NAME of birthday present receiver and return a birthday present in
170 the buffer *Birthday-Present-for-Name*."
171 (interactive (list (read-string "Birthday present for: "
172 nil nil)))
173 ;; Make a suitable buffer to display the birthday present in.
174 (switch-to-buffer (get-buffer-create
175 (if name
176 (concat "*A-Present-for-" (capitalize name) "*")
177 "*Birthday-Present*")))
178 (erase-buffer)
179 ;; Display the empty buffer.
180 (sit-for 0)
182 (if name
183 (animate-string "Happy Birthday," 6)
184 (animate-string "Happy Birthday" 6))
185 (when name (animate-string (format "%s" (capitalize name)) 7))
186 (sit-for 1)
188 (animate-string "You are my sunshine," 10 30)
189 (sit-for .5)
190 (animate-string "My only sunshine." 11 30)
191 (sit-for .5)
192 (animate-string "I'm awful sad that" 12 30)
193 (sit-for .5)
194 (animate-string "You've moved away." 13 30)
195 (sit-for .5)
196 (animate-string "Let's talk together" 15 30)
197 (sit-for .5)
198 (animate-string "And love more deeply." 16 30)
199 (sit-for .5)
200 (animate-string "Please bring back" 17 30)
201 (animate-string "my sunshine" 18 34)
202 (animate-string "to stay!" 19 34))
204 (provide 'animate)
206 ;;; animate.el ends here