slidefield 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +674 -0
  5. data/README.md +254 -0
  6. data/Rakefile +7 -0
  7. data/bin/slidefield +89 -0
  8. data/examples/complete/assets/K2.jpg +0 -0
  9. data/examples/complete/assets/gobi.jpg +0 -0
  10. data/examples/complete/assets/mount_everest.jpg +0 -0
  11. data/examples/complete/assets/sahara.jpg +0 -0
  12. data/examples/complete/main.sfp +7 -0
  13. data/examples/complete/slides/deserts.sfi +19 -0
  14. data/examples/complete/slides/mountains.sfi +25 -0
  15. data/examples/complete/templates.sfi +95 -0
  16. data/examples/complete/variables.sfi +6 -0
  17. data/examples/minimal/main.sfp +43 -0
  18. data/examples/minimal/ruby-logo.png +0 -0
  19. data/lib/slidefield/animator.rb +104 -0
  20. data/lib/slidefield/errors.rb +6 -0
  21. data/lib/slidefield/interpreter.rb +414 -0
  22. data/lib/slidefield/object_data.rb +78 -0
  23. data/lib/slidefield/object_manager.rb +29 -0
  24. data/lib/slidefield/object_rules.rb +79 -0
  25. data/lib/slidefield/objects/_base.rb +29 -0
  26. data/lib/slidefield/objects/_root.rb +10 -0
  27. data/lib/slidefield/objects/animation.rb +10 -0
  28. data/lib/slidefield/objects/debug.rb +18 -0
  29. data/lib/slidefield/objects/image.rb +47 -0
  30. data/lib/slidefield/objects/include.rb +9 -0
  31. data/lib/slidefield/objects/layout.rb +10 -0
  32. data/lib/slidefield/objects/rect.rb +44 -0
  33. data/lib/slidefield/objects/slide.rb +43 -0
  34. data/lib/slidefield/objects/song.rb +31 -0
  35. data/lib/slidefield/objects/text.rb +57 -0
  36. data/lib/slidefield/parser.rb +99 -0
  37. data/lib/slidefield/version.rb +3 -0
  38. data/lib/slidefield/viewer.rb +89 -0
  39. data/lib/slidefield.rb +27 -0
  40. data/slidefield.gemspec +27 -0
  41. data/test/helper.rb +11 -0
  42. data/test/resources/include_sub.sfp +1 -0
  43. data/test/resources/parse_error.sfp +1 -0
  44. data/test/resources/recursive_include.sfp +1 -0
  45. data/test/resources/sub/include_parent.sfp +1 -0
  46. data/test/resources/unclosed_object.sfp +2 -0
  47. data/test/resources/unknown_object.sfp +1 -0
  48. data/test/resources/wrong_template.sfp +4 -0
  49. data/test/test_animator.rb +244 -0
  50. data/test/test_examples.rb +29 -0
  51. data/test/test_interpreter.rb +1766 -0
  52. data/test/test_object_data.rb +108 -0
  53. data/test/test_object_manager.rb +48 -0
  54. data/test/test_object_rules.rb +87 -0
  55. data/test/test_parser.rb +408 -0
  56. 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
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ task :default => [:test]
5
+ Rake::TestTask.new do |t|
6
+ t.test_files = FileList['test/helper.rb', 'test/test_*.rb']
7
+ end
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
@@ -0,0 +1,7 @@
1
+ \include "variables.sfi"
2
+ \include "templates.sfi"
3
+
4
+ \layout layout_size
5
+
6
+ \include "slides/mountains.sfi"
7
+ \include "slides/deserts.sfi"
@@ -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,6 @@
1
+ % ---- LAYOUT ---- %
2
+ layout_size = 1920x1080
3
+
4
+ % ---- SLIDES ---- %
5
+ title_font = "URW Bookman L"
6
+ info_font = "monospace"
@@ -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
@@ -0,0 +1,6 @@
1
+ module SlideField
2
+ class Error < RuntimeError; end
3
+ class ParseError < Error; end
4
+ class InterpreterError < Error; end
5
+ class RuntimeError < Error; end
6
+ end