slidefield 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +674 -0
- data/README.md +254 -0
- data/Rakefile +7 -0
- data/bin/slidefield +89 -0
- data/examples/complete/assets/K2.jpg +0 -0
- data/examples/complete/assets/gobi.jpg +0 -0
- data/examples/complete/assets/mount_everest.jpg +0 -0
- data/examples/complete/assets/sahara.jpg +0 -0
- data/examples/complete/main.sfp +7 -0
- data/examples/complete/slides/deserts.sfi +19 -0
- data/examples/complete/slides/mountains.sfi +25 -0
- data/examples/complete/templates.sfi +95 -0
- data/examples/complete/variables.sfi +6 -0
- data/examples/minimal/main.sfp +43 -0
- data/examples/minimal/ruby-logo.png +0 -0
- data/lib/slidefield/animator.rb +104 -0
- data/lib/slidefield/errors.rb +6 -0
- data/lib/slidefield/interpreter.rb +414 -0
- data/lib/slidefield/object_data.rb +78 -0
- data/lib/slidefield/object_manager.rb +29 -0
- data/lib/slidefield/object_rules.rb +79 -0
- data/lib/slidefield/objects/_base.rb +29 -0
- data/lib/slidefield/objects/_root.rb +10 -0
- data/lib/slidefield/objects/animation.rb +10 -0
- data/lib/slidefield/objects/debug.rb +18 -0
- data/lib/slidefield/objects/image.rb +47 -0
- data/lib/slidefield/objects/include.rb +9 -0
- data/lib/slidefield/objects/layout.rb +10 -0
- data/lib/slidefield/objects/rect.rb +44 -0
- data/lib/slidefield/objects/slide.rb +43 -0
- data/lib/slidefield/objects/song.rb +31 -0
- data/lib/slidefield/objects/text.rb +57 -0
- data/lib/slidefield/parser.rb +99 -0
- data/lib/slidefield/version.rb +3 -0
- data/lib/slidefield/viewer.rb +89 -0
- data/lib/slidefield.rb +27 -0
- data/slidefield.gemspec +27 -0
- data/test/helper.rb +11 -0
- data/test/resources/include_sub.sfp +1 -0
- data/test/resources/parse_error.sfp +1 -0
- data/test/resources/recursive_include.sfp +1 -0
- data/test/resources/sub/include_parent.sfp +1 -0
- data/test/resources/unclosed_object.sfp +2 -0
- data/test/resources/unknown_object.sfp +1 -0
- data/test/resources/wrong_template.sfp +4 -0
- data/test/test_animator.rb +244 -0
- data/test/test_examples.rb +29 -0
- data/test/test_interpreter.rb +1766 -0
- data/test/test_object_data.rb +108 -0
- data/test/test_object_manager.rb +48 -0
- data/test/test_object_rules.rb +87 -0
- data/test/test_parser.rb +408 -0
- metadata +199 -0
data/README.md
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
# SlideField
|
2
|
+
|
3
|
+
**A presentation software that reads plain text files written in its own
|
4
|
+
interpreted language.**
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Requirements: ruby, sdl, sdl_ttf, freeimage
|
9
|
+
|
10
|
+
$ gem install slidefield
|
11
|
+
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
$ slidefield [options] [file ...]
|
16
|
+
|
17
|
+
### Comments
|
18
|
+
|
19
|
+
% single-line comment
|
20
|
+
%{ multi-line
|
21
|
+
comment %}
|
22
|
+
|
23
|
+
### Variables
|
24
|
+
|
25
|
+
A variable can only be created once inside each object (with the `=` operator).
|
26
|
+
However they can be modified freely using any other available operator.
|
27
|
+
The type of the variable cannot be changed after the variable creation.
|
28
|
+
|
29
|
+
variable = value
|
30
|
+
variable += value
|
31
|
+
variable -= value
|
32
|
+
variable *= value
|
33
|
+
variable /= value
|
34
|
+
|
35
|
+
|
36
|
+
### Value types
|
37
|
+
|
38
|
+
Integers:
|
39
|
+
|
40
|
+
variable = 42
|
41
|
+
variable += 2 % add
|
42
|
+
variable -= 10 % subtract
|
43
|
+
variable *= 6 % multiply
|
44
|
+
variable /= 10 % divide
|
45
|
+
% variable is 20
|
46
|
+
|
47
|
+
Character strings:
|
48
|
+
|
49
|
+
variable = "hello"
|
50
|
+
variable += " world!\n" % append
|
51
|
+
variable -= "!" % remove the bang
|
52
|
+
variable *= "3" % multiply by 3
|
53
|
+
% variable is "hello world\nhello world\nhello world\n"
|
54
|
+
|
55
|
+
Size or point coordinates:
|
56
|
+
|
57
|
+
variable = 2x4
|
58
|
+
variable += 100x80 % add
|
59
|
+
variable -= 10x0 % subtract
|
60
|
+
variable *= 3x4 % multiply
|
61
|
+
variable /= 2x2 % divide
|
62
|
+
% variable is 138x168
|
63
|
+
|
64
|
+
Colors (red, blue, green & alpha in hexadecimal notation):
|
65
|
+
|
66
|
+
variable = #C0FF33FF
|
67
|
+
variable += #03003300 % add
|
68
|
+
variable -= #0C240055 % subtract
|
69
|
+
% variable is #B7DB66AA
|
70
|
+
|
71
|
+
Booleans:
|
72
|
+
|
73
|
+
variable = :true
|
74
|
+
opposite = :false
|
75
|
+
|
76
|
+
Variables can also store custom objects. See the 'Templates' section below.
|
77
|
+
|
78
|
+
### Objects
|
79
|
+
|
80
|
+
Variables are bound to the object in which they are created into.
|
81
|
+
Most SlideField object have reserved variables ("*properties*")
|
82
|
+
with a predefined type.
|
83
|
+
All properties are mandatory unless otherwise specified.
|
84
|
+
|
85
|
+
Nested objects inherit their parent's variables.
|
86
|
+
All slide objects (marked as such in the list below) can be infinitely nested.
|
87
|
+
|
88
|
+
% Syntax:
|
89
|
+
\object_name
|
90
|
+
\object_name { ... }
|
91
|
+
\object_name value
|
92
|
+
\object_name value { ... }
|
93
|
+
|
94
|
+
The shortcut syntax `\object value` assigns `value` to the first property
|
95
|
+
compatible with the value's type.
|
96
|
+
|
97
|
+
### Object List
|
98
|
+
|
99
|
+
**(Anywhere)** Load another file at the current location:
|
100
|
+
|
101
|
+
\include "relative/path/to/file.sfp"
|
102
|
+
\include {
|
103
|
+
source = "relative/path/to/file.sfp"
|
104
|
+
}
|
105
|
+
|
106
|
+
**(Anywhere)** Print debug information about any value to standard output:
|
107
|
+
|
108
|
+
\debug any_value
|
109
|
+
|
110
|
+
**(Top-level, required, maximum 1)** Configure the output window:
|
111
|
+
|
112
|
+
\layout 1920x1080
|
113
|
+
\layout {
|
114
|
+
size = 1920x1080
|
115
|
+
fullscreen = :true % optional
|
116
|
+
}
|
117
|
+
|
118
|
+
**(Top-level, required)** Create a slide:
|
119
|
+
|
120
|
+
\slide { ... }
|
121
|
+
|
122
|
+
**(Slide)** Animation between slides:
|
123
|
+
|
124
|
+
\animation "fade" { ... }
|
125
|
+
\animation {
|
126
|
+
name = "fade"
|
127
|
+
%{
|
128
|
+
other possible values are:
|
129
|
+
name = "slide right"
|
130
|
+
name = "slide left"
|
131
|
+
name = "slide down"
|
132
|
+
name = "slide up"
|
133
|
+
name = "zoom"
|
134
|
+
%}
|
135
|
+
duration = 400 % in ms (optional)
|
136
|
+
}
|
137
|
+
*Note: The animation is applied only to nested objects.*
|
138
|
+
|
139
|
+
**(Slide)** Add an image:
|
140
|
+
|
141
|
+
\image "relative/path/to/image.png"
|
142
|
+
\image {
|
143
|
+
source = "relative/path/to/image.png"
|
144
|
+
size = 0x0 % automatic if 0 (optional)
|
145
|
+
color = #FFFFFFFF % color filter (optional)
|
146
|
+
position = 0x0 % optional
|
147
|
+
z_order = 0 % optional
|
148
|
+
}
|
149
|
+
|
150
|
+
**(Slide)** Add a rectangle:
|
151
|
+
|
152
|
+
\rect 100x100
|
153
|
+
\rect {
|
154
|
+
size = 100x100
|
155
|
+
fill = #FFFFFFFF % optional
|
156
|
+
position = 0x0 % optional
|
157
|
+
z_order = 0 % optional
|
158
|
+
}
|
159
|
+
|
160
|
+
**(Slide)** Play an audio file:
|
161
|
+
|
162
|
+
\song "relative/path/to/audio.ogg"
|
163
|
+
\song {
|
164
|
+
source = "relative/path/to/audio.ogg"
|
165
|
+
volume = 100 % optional
|
166
|
+
loop = :true % optional
|
167
|
+
}
|
168
|
+
|
169
|
+
**(Slide)** Add text:
|
170
|
+
|
171
|
+
\text "Hello World!"
|
172
|
+
\text {
|
173
|
+
content = "Hello World!"
|
174
|
+
color = #FFFFFFFF % optional
|
175
|
+
font = "sans" % font name or relative font path (optional)
|
176
|
+
% font = "./my_font.ttf"
|
177
|
+
height = 20 % font height in pixels (optional)
|
178
|
+
width = 0 % maximum width (automatic if 0, optional)
|
179
|
+
spacing = 0 % line spacing (optional)
|
180
|
+
align = "left" % optional
|
181
|
+
%{
|
182
|
+
other possible values are:
|
183
|
+
align = "right"
|
184
|
+
align = "center"
|
185
|
+
align = "justify"
|
186
|
+
%}
|
187
|
+
position = 0x0 % optional
|
188
|
+
z_order = 0 % optional
|
189
|
+
}
|
190
|
+
|
191
|
+
### Filters
|
192
|
+
Filters are like methods in an object-oriented programming language.
|
193
|
+
They can be chained infinitely.
|
194
|
+
|
195
|
+
variable = (filter)value
|
196
|
+
variable = (second_filter)(first_filter)value
|
197
|
+
|
198
|
+
Point to integer:
|
199
|
+
|
200
|
+
point = 1920x1080
|
201
|
+
x = (x)point
|
202
|
+
% x is 1920
|
203
|
+
|
204
|
+
y = (y)point
|
205
|
+
% y is 1080
|
206
|
+
|
207
|
+
Integer to point:
|
208
|
+
|
209
|
+
point = (x)1920
|
210
|
+
% point is 1920x0
|
211
|
+
|
212
|
+
point += (y)1080
|
213
|
+
% point is 1920x1080
|
214
|
+
|
215
|
+
Line count:
|
216
|
+
|
217
|
+
lines = (lines)"Lorem\nIpsum"
|
218
|
+
% lines is 2
|
219
|
+
|
220
|
+
### Templates
|
221
|
+
Custom objects can be created using templates.
|
222
|
+
|
223
|
+
template_name = \object_name { ... }
|
224
|
+
\&template_name
|
225
|
+
|
226
|
+
% creation
|
227
|
+
slide_template = \slide {
|
228
|
+
\image background { size = 1920x1080; }
|
229
|
+
\text title { height = 72; }
|
230
|
+
}
|
231
|
+
|
232
|
+
% usage
|
233
|
+
\&slide_template {
|
234
|
+
title = "Hello World!"
|
235
|
+
background = "relative/path/to/image.png"
|
236
|
+
}
|
237
|
+
|
238
|
+
Equivalent of the above example without using templates:
|
239
|
+
|
240
|
+
\slide {
|
241
|
+
title = "Hello World!"
|
242
|
+
background = "relative/path/to/image.png"
|
243
|
+
\image background { size = 1920x1080; }
|
244
|
+
\text title { height = 72; }
|
245
|
+
}
|
246
|
+
|
247
|
+
## Contributing
|
248
|
+
|
249
|
+
1. [Fork it](https://bitbucket.org/cfi30/slidefield/fork)
|
250
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
251
|
+
3. Test your changes (`rake`)
|
252
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
253
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
254
|
+
6. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/slidefield
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This program is free software: you can redistribute it and/or modify
|
3
|
+
# it under the terms of the GNU General Public License as published by
|
4
|
+
# the Free Software Foundation, either version 3 of the License, or
|
5
|
+
# (at your option) any later version.
|
6
|
+
#
|
7
|
+
# This program is distributed in the hope that it will be useful,
|
8
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
9
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
10
|
+
# GNU General Public License for more details.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU General Public License
|
13
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
14
|
+
|
15
|
+
require 'slidefield'
|
16
|
+
require 'optparse'
|
17
|
+
|
18
|
+
def parse_opts
|
19
|
+
options = []
|
20
|
+
|
21
|
+
OptionParser.new do |opts|
|
22
|
+
opts.program_name = "SlideField"
|
23
|
+
opts.version = SlideField::VERSION
|
24
|
+
opts.banner = "Usage: slidefield [options] [file ...]"
|
25
|
+
|
26
|
+
opts.on '-c', '--check', "Check input only" do
|
27
|
+
options << :check
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on_tail '-v', '--version', "Show version number and copyright" do
|
31
|
+
puts opts.ver
|
32
|
+
puts <<GPL
|
33
|
+
Copyright (C) 2014 by Christian Fillion
|
34
|
+
|
35
|
+
This program is free software; you can redistribute it and/or
|
36
|
+
modify it under the terms of the GNU General Public License as
|
37
|
+
published by the Free Software Foundation, either version 3 of
|
38
|
+
the License, or (at your option) any later version.
|
39
|
+
|
40
|
+
This program is distributed in the hope that it will be useful,
|
41
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
42
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
43
|
+
General Public License for more details.
|
44
|
+
GPL
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
|
48
|
+
opts.on_tail '-h', '--help', "Show this message" do
|
49
|
+
puts opts.help
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
end.parse!
|
53
|
+
|
54
|
+
options
|
55
|
+
end
|
56
|
+
|
57
|
+
begin
|
58
|
+
begin
|
59
|
+
options = parse_opts
|
60
|
+
rescue OptionParser::InvalidOption => e
|
61
|
+
raise SlideField::Error, e
|
62
|
+
end
|
63
|
+
|
64
|
+
files = ARGV
|
65
|
+
|
66
|
+
# read from standard input by default
|
67
|
+
files << '-' if files.empty?
|
68
|
+
|
69
|
+
files.each {|file|
|
70
|
+
interpreter = SlideField::Interpreter.new
|
71
|
+
if '-' == file
|
72
|
+
interpreter.run_string STDIN.read
|
73
|
+
else
|
74
|
+
path = File.absolute_path file
|
75
|
+
interpreter.run_file path
|
76
|
+
end
|
77
|
+
|
78
|
+
next if options.include? :check
|
79
|
+
|
80
|
+
project_root = interpreter.root
|
81
|
+
viewer = SlideField::Viewer.new project_root
|
82
|
+
viewer.caption = project_root.context
|
83
|
+
viewer.show
|
84
|
+
}
|
85
|
+
rescue SlideField::Error => e
|
86
|
+
warn "#{e.class}: #{e}"
|
87
|
+
rescue Interrupt
|
88
|
+
puts
|
89
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,19 @@
|
|
1
|
+
\&slide_tpl {
|
2
|
+
title = "Sahara"
|
3
|
+
|
4
|
+
infos = "<b>Area:</b> 9,400,000 km²\n"
|
5
|
+
infos += "<b>Notes:</b> The world's hottest desert"
|
6
|
+
|
7
|
+
background_src = "../assets/sahara.jpg"
|
8
|
+
background_link = "https://en.wikipedia.org/wiki/File:Sahara_satellite_hires.jpg"
|
9
|
+
}
|
10
|
+
|
11
|
+
\&slide_tpl {
|
12
|
+
title = "Gobi"
|
13
|
+
|
14
|
+
infos = "<b>Area:</b> 1,295,000 km²\n"
|
15
|
+
infos += "<b>Notes:</b> The expansion of the Gobi is\nattributed mostly to human activities"
|
16
|
+
|
17
|
+
background_src = "../assets/gobi.jpg"
|
18
|
+
background_link = "https://en.wikipedia.org/wiki/File:Khongoryn_Els,_Gurvansaikhan_NP,_Gobi_desert,_Mongolia.jpg"
|
19
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
\&slide_tpl {
|
2
|
+
title = "Mount Everest"
|
3
|
+
|
4
|
+
infos = "<b>Country:</b> Nepal\n"
|
5
|
+
infos += "<b>Elevation:</b> 8,848 m\n"
|
6
|
+
infos += "<b>First ascent:</b> 29 May 1953\n"
|
7
|
+
infos += "<b>Easiest route:</b> South Col\n"
|
8
|
+
infos += "<b>Notes:</b> Earth's highest mountain"
|
9
|
+
|
10
|
+
background_src = "../assets/mount_everest.jpg"
|
11
|
+
background_link = "https://en.wikipedia.org/wiki/File:Mount_Everest_as_seen_from_Drukair2_PLW_edit.jpg"
|
12
|
+
}
|
13
|
+
|
14
|
+
\&slide_tpl {
|
15
|
+
title = "K2"
|
16
|
+
|
17
|
+
infos = "<b>Country:</b> Pakistan\n"
|
18
|
+
infos += "<b>Elevation:</b> 8,611 m\n"
|
19
|
+
infos += "<b>First ascent:</b> 31 July 1954\n"
|
20
|
+
infos += "<b>Easiest route:</b> Abruzzi Spur\n"
|
21
|
+
infos += "<b>Notes:</b> The mountain was first\nsurveyed by a European team in 1856"
|
22
|
+
|
23
|
+
background_src = "../assets/K2.jpg"
|
24
|
+
background_link = "https://en.wikipedia.org/wiki/File:K2_2006b.jpg"
|
25
|
+
}
|
@@ -0,0 +1,95 @@
|
|
1
|
+
background_tpl = \image {
|
2
|
+
size = layout_size
|
3
|
+
}
|
4
|
+
|
5
|
+
title_tpl = \text {
|
6
|
+
color = #FFFFFFFF
|
7
|
+
font = title_font
|
8
|
+
height = 100
|
9
|
+
position = 100x70
|
10
|
+
z_order = 1
|
11
|
+
|
12
|
+
% support alignment
|
13
|
+
x = (x)position
|
14
|
+
x *= 2
|
15
|
+
width = (x)layout_size
|
16
|
+
width -= x
|
17
|
+
|
18
|
+
% shadow
|
19
|
+
\text #00000099 {
|
20
|
+
position += 2x2
|
21
|
+
z_order -= 1
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
infobox_tpl = \rect {
|
26
|
+
padding = 10
|
27
|
+
text_height = 40
|
28
|
+
z_order = 1
|
29
|
+
|
30
|
+
box_height = (lines)content
|
31
|
+
box_height *= text_height
|
32
|
+
box_height += padding
|
33
|
+
|
34
|
+
size = 650x0
|
35
|
+
size += (y)box_height
|
36
|
+
|
37
|
+
position = layout_size
|
38
|
+
position -= size
|
39
|
+
position /= 2x1
|
40
|
+
position -= 0x100
|
41
|
+
|
42
|
+
fill = #FFFFFF69
|
43
|
+
|
44
|
+
\text {
|
45
|
+
position += (x)padding
|
46
|
+
position += (y)padding
|
47
|
+
|
48
|
+
height = text_height
|
49
|
+
color = #011010FF
|
50
|
+
font = info_font
|
51
|
+
|
52
|
+
% shadow
|
53
|
+
\text {
|
54
|
+
position += 1x1
|
55
|
+
color = #FFFFFF99
|
56
|
+
z_order -= 1
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
credit_tpl = \text {
|
62
|
+
position = 10x-30
|
63
|
+
position += (y)(y)layout_size
|
64
|
+
|
65
|
+
color = #FFFFFFFF
|
66
|
+
z_order = 1
|
67
|
+
|
68
|
+
\text {
|
69
|
+
position += 1x1
|
70
|
+
color = #000000FF
|
71
|
+
z_order -= 1
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
slide_tpl = \slide {
|
76
|
+
\animation "fade" {
|
77
|
+
\&background_tpl background_src
|
78
|
+
}
|
79
|
+
|
80
|
+
\&title_tpl {
|
81
|
+
content = "<b>"
|
82
|
+
content += title
|
83
|
+
}
|
84
|
+
|
85
|
+
\animation "slide left" {
|
86
|
+
\&infobox_tpl {
|
87
|
+
content = infos
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
\&credit_tpl {
|
92
|
+
content = "<b>Photo Credit:</b> "
|
93
|
+
content += background_link
|
94
|
+
}
|
95
|
+
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
layout_size = 1366x768
|
2
|
+
|
3
|
+
\layout layout_size
|
4
|
+
|
5
|
+
\slide {
|
6
|
+
\text "Hello World!" { height = 50; }
|
7
|
+
\text "Press <b>Enter</b> to display the next slide" {
|
8
|
+
position = 0x50
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
\slide {
|
13
|
+
\text "Second Slide"
|
14
|
+
\text "Press <b>Backspace</b> to return to the previous slide" {
|
15
|
+
position = 0x30
|
16
|
+
width = 200
|
17
|
+
}
|
18
|
+
|
19
|
+
\text "This example contains 3 slides.\n(Press <b>Enter</b> again)" {
|
20
|
+
position = 0x70
|
21
|
+
width = (x)layout_size
|
22
|
+
align = "right"
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
\slide {
|
27
|
+
\rect {
|
28
|
+
fill = #FFFFFFFF % RRGGBBAA
|
29
|
+
size = layout_size
|
30
|
+
}
|
31
|
+
|
32
|
+
\image "ruby-logo.png" {
|
33
|
+
position = layout_size
|
34
|
+
position -= 62x62
|
35
|
+
position /= 2x2
|
36
|
+
}
|
37
|
+
|
38
|
+
\text {
|
39
|
+
content = "Last Slide\nPress <b>Escape</b> to quit"
|
40
|
+
color = #000000FF
|
41
|
+
font = "monospace"
|
42
|
+
}
|
43
|
+
}
|
Binary file
|
@@ -0,0 +1,104 @@
|
|
1
|
+
class SlideField::Animator
|
2
|
+
attr_accessor :current, :forward
|
3
|
+
|
4
|
+
def initialize(layout_size)
|
5
|
+
@layout_size = layout_size
|
6
|
+
reset
|
7
|
+
end
|
8
|
+
|
9
|
+
def need_redraw?
|
10
|
+
@animations.each {|k,v| return true if v.enabled }
|
11
|
+
@animations.empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def reset
|
15
|
+
@animations = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def frame(*args)
|
19
|
+
struct = Struct.new :time, :current?, :forward?
|
20
|
+
@frame = struct.new *args
|
21
|
+
yield
|
22
|
+
@frame = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def transform(obj)
|
26
|
+
raise "Can not animate outside a frame" unless @frame
|
27
|
+
|
28
|
+
tr_struct = Struct.new :skip_draw?, :x_offset, :y_offset, :scale, :opacity
|
29
|
+
tr = tr_struct.new false, 0, 0, 1.0, 1.0
|
30
|
+
|
31
|
+
anim = animation_for obj.ancestor(:animation)
|
32
|
+
|
33
|
+
# no animation
|
34
|
+
return tr if anim.nil?
|
35
|
+
|
36
|
+
elapsed = @frame.time - anim.start_time
|
37
|
+
position = elapsed / anim.duration
|
38
|
+
anim.enabled = false if position > 1.0
|
39
|
+
|
40
|
+
# animation finished
|
41
|
+
unless anim.enabled
|
42
|
+
tr[:skip_draw?] = !@frame.current? # don't draw the previous slide anymore
|
43
|
+
return tr
|
44
|
+
end
|
45
|
+
|
46
|
+
width, height = @layout_size
|
47
|
+
|
48
|
+
case anim.name
|
49
|
+
when "fade"
|
50
|
+
if @frame.current?
|
51
|
+
tr.opacity = position
|
52
|
+
else
|
53
|
+
tr.opacity = 1.0 - position
|
54
|
+
end
|
55
|
+
when "slide right"
|
56
|
+
tr.x_offset = slide_offset position, width, false
|
57
|
+
when "slide left"
|
58
|
+
tr.x_offset = slide_offset position, width, true
|
59
|
+
when "slide down"
|
60
|
+
tr.y_offset = slide_offset position, height, false
|
61
|
+
when "slide up"
|
62
|
+
tr.y_offset = slide_offset position, height, true
|
63
|
+
when "zoom"
|
64
|
+
if @frame.current?
|
65
|
+
tr.scale = position
|
66
|
+
else
|
67
|
+
tr.scale = 1.0 - position
|
68
|
+
end
|
69
|
+
else
|
70
|
+
# the validator has missed ?!
|
71
|
+
# TODO: validate at interpret time
|
72
|
+
raise SlideField::RuntimeError,
|
73
|
+
"Unsupported animation '#{anim.name}'"
|
74
|
+
end
|
75
|
+
|
76
|
+
tr
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
def animation_for(data)
|
81
|
+
return @animations[data] if @animations.has_key? data
|
82
|
+
|
83
|
+
anim_struct = Struct.new :enabled, :start_time, :name, :duration
|
84
|
+
anim = anim_struct.new false, 0.0, '', 0
|
85
|
+
|
86
|
+
if data
|
87
|
+
anim.enabled = true
|
88
|
+
anim.start_time = @frame.time.to_f
|
89
|
+
anim.name = data.get :name
|
90
|
+
anim.duration = data.get :duration
|
91
|
+
end
|
92
|
+
|
93
|
+
@animations[data] = anim
|
94
|
+
end
|
95
|
+
|
96
|
+
def slide_offset(position, size, inverse)
|
97
|
+
inverse = !inverse unless @frame.forward?
|
98
|
+
|
99
|
+
offset = size * position
|
100
|
+
offset -= size if @frame.current?
|
101
|
+
offset = 0 - offset if inverse
|
102
|
+
offset
|
103
|
+
end
|
104
|
+
end
|