purple_shoes 0.0.101

Sign up to get free protection for your applications and to get access to all the features.
Files changed (215) hide show
  1. data/README.md +56 -0
  2. data/VERSION +1 -0
  3. data/bin/pshoes +23 -0
  4. data/bin/pshoes.bat +2 -0
  5. data/lib/plugins/video.rb +88 -0
  6. data/lib/purple_shoes.rb +51 -0
  7. data/lib/shoes/anim.rb +47 -0
  8. data/lib/shoes/app.rb +688 -0
  9. data/lib/shoes/basic.rb +254 -0
  10. data/lib/shoes/colors.rb +149 -0
  11. data/lib/shoes/download.rb +26 -0
  12. data/lib/shoes/help.rb +473 -0
  13. data/lib/shoes/helper_methods.rb +295 -0
  14. data/lib/shoes/main.rb +96 -0
  15. data/lib/shoes/manual.rb +6 -0
  16. data/lib/shoes/ruby.rb +61 -0
  17. data/lib/shoes/slot.rb +104 -0
  18. data/lib/shoes/style.rb +41 -0
  19. data/lib/shoes/text.rb +46 -0
  20. data/lib/shoes/url.rb +14 -0
  21. data/lib/shoes/widget.rb +23 -0
  22. data/samples/class-book.yaml +387 -0
  23. data/samples/cy.png +0 -0
  24. data/samples/loogink.png +0 -0
  25. data/samples/potato_chopping/1258_s001.gif +0 -0
  26. data/samples/potato_chopping/1258_s002.gif +0 -0
  27. data/samples/potato_chopping/1258_s003.gif +0 -0
  28. data/samples/potato_chopping/1258_s004.gif +0 -0
  29. data/samples/potato_chopping/1258_s005.gif +0 -0
  30. data/samples/potato_chopping/1258_s006.gif +0 -0
  31. data/samples/potato_chopping/1258_s007.gif +0 -0
  32. data/samples/potato_chopping/1258_s008.gif +0 -0
  33. data/samples/potato_chopping/1258_s009.gif +0 -0
  34. data/samples/potato_chopping/1258_s010.gif +0 -0
  35. data/samples/potato_chopping/1258_s011.gif +0 -0
  36. data/samples/potato_chopping/1258_s012.gif +0 -0
  37. data/samples/potato_chopping/1258_s013.gif +0 -0
  38. data/samples/potato_chopping/1258_s014.gif +0 -0
  39. data/samples/potato_chopping/1258_s015.gif +0 -0
  40. data/samples/potato_chopping/1258_s016.gif +0 -0
  41. data/samples/potato_chopping/1258_s017.gif +0 -0
  42. data/samples/potato_chopping/1258_s018.gif +0 -0
  43. data/samples/potato_chopping/1258_s019.gif +0 -0
  44. data/samples/potato_chopping/1258_s020.gif +0 -0
  45. data/samples/potato_chopping/1258_s021.gif +0 -0
  46. data/samples/potato_chopping/1258_s022.gif +0 -0
  47. data/samples/potato_chopping/1258_s023.gif +0 -0
  48. data/samples/potato_chopping/1258_s024.gif +0 -0
  49. data/samples/potato_chopping/1258_s025.gif +0 -0
  50. data/samples/potato_chopping/1258_s026.gif +0 -0
  51. data/samples/potato_chopping/1258_s027.gif +0 -0
  52. data/samples/potato_chopping/1258_s028.gif +0 -0
  53. data/samples/potato_chopping/1258_s029.gif +0 -0
  54. data/samples/potato_chopping/1258_s030.gif +0 -0
  55. data/samples/potato_chopping/1258_s031.gif +0 -0
  56. data/samples/potato_chopping/1258_s032.gif +0 -0
  57. data/samples/potato_chopping/1258_s033.gif +0 -0
  58. data/samples/potato_chopping/1258_s034.gif +0 -0
  59. data/samples/potato_chopping/1258_s035.gif +0 -0
  60. data/samples/potato_chopping/1258_s036.gif +0 -0
  61. data/samples/potato_chopping/1258_s037.gif +0 -0
  62. data/samples/potato_chopping/1258_s038.gif +0 -0
  63. data/samples/potato_chopping/1258_s039.gif +0 -0
  64. data/samples/potato_chopping/1258_s040.gif +0 -0
  65. data/samples/potato_chopping/1258_s041.gif +0 -0
  66. data/samples/potato_chopping/1258_s042.gif +0 -0
  67. data/samples/potato_chopping/1258_s043.gif +0 -0
  68. data/samples/potato_chopping/1258_s044.gif +0 -0
  69. data/samples/potato_chopping/1258_s045.gif +0 -0
  70. data/samples/potato_chopping/1258_s046.gif +0 -0
  71. data/samples/potato_chopping/1258_s047.gif +0 -0
  72. data/samples/potato_chopping/1258_s048.gif +0 -0
  73. data/samples/potato_chopping/1258_s049.gif +0 -0
  74. data/samples/potato_chopping/1258_s050.gif +0 -0
  75. data/samples/potato_chopping/1258_s051.gif +0 -0
  76. data/samples/potato_chopping/1258_s052.gif +0 -0
  77. data/samples/potato_chopping/1258_s053.gif +0 -0
  78. data/samples/potato_chopping/1258_s054.gif +0 -0
  79. data/samples/potato_chopping/1258_s055.gif +0 -0
  80. data/samples/potato_chopping/1258_s056.gif +0 -0
  81. data/samples/potato_chopping/1258_s057.gif +0 -0
  82. data/samples/potato_chopping/1258_s058.gif +0 -0
  83. data/samples/potato_chopping/1258_s059.gif +0 -0
  84. data/samples/sample1.rb +30 -0
  85. data/samples/sample10.rb +11 -0
  86. data/samples/sample11.rb +12 -0
  87. data/samples/sample12.rb +22 -0
  88. data/samples/sample13.rb +15 -0
  89. data/samples/sample14.rb +75 -0
  90. data/samples/sample15.rb +20 -0
  91. data/samples/sample16.rb +12 -0
  92. data/samples/sample17.rb +12 -0
  93. data/samples/sample18.rb +24 -0
  94. data/samples/sample19.rb +39 -0
  95. data/samples/sample2.rb +16 -0
  96. data/samples/sample20.rb +26 -0
  97. data/samples/sample21.rb +7 -0
  98. data/samples/sample22.rb +13 -0
  99. data/samples/sample23.rb +10 -0
  100. data/samples/sample24.rb +22 -0
  101. data/samples/sample25.rb +22 -0
  102. data/samples/sample27.rb +19 -0
  103. data/samples/sample28.rb +64 -0
  104. data/samples/sample29.rb +12 -0
  105. data/samples/sample3.rb +10 -0
  106. data/samples/sample30.rb +30 -0
  107. data/samples/sample31.rb +24 -0
  108. data/samples/sample34.rb +29 -0
  109. data/samples/sample35.rb +33 -0
  110. data/samples/sample36.rb +48 -0
  111. data/samples/sample37.rb +10 -0
  112. data/samples/sample38.rb +14 -0
  113. data/samples/sample4.rb +9 -0
  114. data/samples/sample40.rb +19 -0
  115. data/samples/sample42.rb +15 -0
  116. data/samples/sample43.rb +26 -0
  117. data/samples/sample44.rb +57 -0
  118. data/samples/sample45.rb +12 -0
  119. data/samples/sample46.rb +35 -0
  120. data/samples/sample47.rb +20 -0
  121. data/samples/sample48.rb +33 -0
  122. data/samples/sample49.rb +33 -0
  123. data/samples/sample5.rb +8 -0
  124. data/samples/sample50.rb +326 -0
  125. data/samples/sample58.rb +19 -0
  126. data/samples/sample6.rb +11 -0
  127. data/samples/sample7.rb +5 -0
  128. data/samples/sample8.rb +9 -0
  129. data/samples/sample9.rb +12 -0
  130. data/samples/sample99.rb +4 -0
  131. data/samples/sounds/102719__sarge4267__explosion.mp3 +0 -0
  132. data/samples/sounds/145622__andybrannan__train-fog-horn-long-wyomming.aiff +0 -0
  133. data/samples/sounds/46492__phreaksaccount__shields1.ogg +0 -0
  134. data/samples/sounds/61847__simon-rue__boink-v3.wav +0 -0
  135. data/snapshots/sample1.png +0 -0
  136. data/snapshots/sample10.png +0 -0
  137. data/snapshots/sample11.png +0 -0
  138. data/snapshots/sample12.png +0 -0
  139. data/snapshots/sample13.png +0 -0
  140. data/snapshots/sample14.png +0 -0
  141. data/snapshots/sample15.png +0 -0
  142. data/snapshots/sample16.png +0 -0
  143. data/snapshots/sample17.png +0 -0
  144. data/snapshots/sample18.png +0 -0
  145. data/snapshots/sample19.png +0 -0
  146. data/snapshots/sample2.png +0 -0
  147. data/snapshots/sample20.png +0 -0
  148. data/snapshots/sample21.png +0 -0
  149. data/snapshots/sample22.png +0 -0
  150. data/snapshots/sample23.png +0 -0
  151. data/snapshots/sample24.png +0 -0
  152. data/snapshots/sample25.png +0 -0
  153. data/snapshots/sample27.png +0 -0
  154. data/snapshots/sample28.png +0 -0
  155. data/snapshots/sample29.png +0 -0
  156. data/snapshots/sample3-osx.png +0 -0
  157. data/snapshots/sample3.png +0 -0
  158. data/snapshots/sample30.png +0 -0
  159. data/snapshots/sample31.png +0 -0
  160. data/snapshots/sample33.png +0 -0
  161. data/snapshots/sample34.png +0 -0
  162. data/snapshots/sample35.png +0 -0
  163. data/snapshots/sample36.png +0 -0
  164. data/snapshots/sample37.png +0 -0
  165. data/snapshots/sample38.png +0 -0
  166. data/snapshots/sample4.png +0 -0
  167. data/snapshots/sample40.png +0 -0
  168. data/snapshots/sample42.png +0 -0
  169. data/snapshots/sample43.png +0 -0
  170. data/snapshots/sample44-linux.png +0 -0
  171. data/snapshots/sample44.png +0 -0
  172. data/snapshots/sample45.png +0 -0
  173. data/snapshots/sample46.png +0 -0
  174. data/snapshots/sample47.png +0 -0
  175. data/snapshots/sample48.png +0 -0
  176. data/snapshots/sample49.png +0 -0
  177. data/snapshots/sample5.png +0 -0
  178. data/snapshots/sample50.png +0 -0
  179. data/snapshots/sample58.png +0 -0
  180. data/snapshots/sample6.png +0 -0
  181. data/snapshots/sample7.png +0 -0
  182. data/snapshots/sample8.png +0 -0
  183. data/snapshots/sample9.png +0 -0
  184. data/snapshots/sample99.png +0 -0
  185. data/static/code_highlighter.js +188 -0
  186. data/static/code_highlighter_ruby.js +26 -0
  187. data/static/man-editor-notepad.png +0 -0
  188. data/static/man-editor-osx.png +0 -0
  189. data/static/man-ele-background.png +0 -0
  190. data/static/man-ele-border.png +0 -0
  191. data/static/man-ele-button.png +0 -0
  192. data/static/man-ele-check.png +0 -0
  193. data/static/man-ele-editbox.png +0 -0
  194. data/static/man-ele-editline.png +0 -0
  195. data/static/man-ele-image.png +0 -0
  196. data/static/man-ele-listbox.png +0 -0
  197. data/static/man-ele-progress.png +0 -0
  198. data/static/man-ele-radio.png +0 -0
  199. data/static/man-ele-shape.png +0 -0
  200. data/static/man-ele-textblock.png +0 -0
  201. data/static/man-ele-video.png +0 -0
  202. data/static/man-shot1.png +0 -0
  203. data/static/manual-en.txt +3969 -0
  204. data/static/manual-ja.txt +3882 -0
  205. data/static/manual.css +184 -0
  206. data/static/purple_shoes-icon.png +0 -0
  207. data/static/rshoes-icon.png +0 -0
  208. data/static/shoes-manual-apps.png +0 -0
  209. data/static/sound_jars/jl1.0.1.jar +0 -0
  210. data/static/sound_jars/jogg-0.0.7.jar +0 -0
  211. data/static/sound_jars/jorbis-0.0.15.jar +0 -0
  212. data/static/sound_jars/mp3spi1.9.5.jar +0 -0
  213. data/static/sound_jars/tritonus_share.jar +0 -0
  214. data/static/sound_jars/vorbisspi1.0.3.jar +0 -0
  215. metadata +271 -0
@@ -0,0 +1,254 @@
1
+ class Shoes
2
+ class Basic
3
+ include Mod
4
+ def initialize args
5
+ @initials = args
6
+ args.each do |k, v|
7
+ instance_variable_set "@#{k}", v
8
+ end
9
+
10
+ (@app.order << self) unless @noorder
11
+ (@app.cslot.contents << self) unless @nocontrol
12
+
13
+ @parent = @app.cslot
14
+
15
+ Basic.class_eval do
16
+ attr_accessor *args.keys
17
+ end
18
+
19
+ if @real
20
+ if @real.is_a? Swt::Image
21
+ @width = @full_width if @width.zero?
22
+ @height = @full_height if @height.zero?
23
+ elsif @real.is_a? Symbol
24
+ # do nothing
25
+ else
26
+ @width, @height = @real.getSize.x, @real.getSize.y
27
+ end
28
+ end
29
+
30
+ set_margin
31
+ @width += (@margin_left + @margin_right)
32
+ @height += (@margin_top + @margin_bottom)
33
+
34
+ [:app, :real].each{|k| args.delete k}
35
+ @args = args
36
+ @dps = []
37
+ end
38
+
39
+ attr_reader :args, :initials
40
+ attr_accessor :parent, :pl, :ln, :dps
41
+
42
+ def hided
43
+ @app.hided or @hided
44
+ end
45
+
46
+ def move x, y
47
+ @app.cslot.contents -= [self]
48
+ move3 x, y
49
+ self
50
+ end
51
+
52
+ def move2 x, y
53
+ move3 x, y
54
+ end
55
+
56
+ def move3 x, y
57
+ unless @app.cs.isDisposed
58
+ @app.cs.redraw @left, @top, @width, @height, false
59
+ @app.cs.redraw x, y, @width, @height, false
60
+ end
61
+ @left, @top = x, y
62
+ end
63
+
64
+ def positioning x, y, max
65
+ if parent.is_a?(Flow) and x + @width <= parent.left + parent.width
66
+ move3 x + parent.margin_left, max.top + parent.margin_top
67
+ max = self if max.height < @height
68
+ else
69
+ move3 parent.left + parent.margin_left, max.top + max.height + parent.margin_top
70
+ max = self
71
+ end
72
+ max
73
+ end
74
+
75
+ def clear
76
+ @app.cs.removePaintListener pl if pl
77
+ @app.cs.removeListener Swt::SWT::MouseDown, ln if ln
78
+ @app.cs.removeListener Swt::SWT::MouseUp, ln if ln
79
+ @real.dispose unless @real.is_a? Symbol
80
+ @dps.each{|dp| dp.dispose if dp}
81
+ @dps.clear
82
+ @parent.contents -= [self]
83
+ @app.mscs -= [self]
84
+ hide
85
+ end
86
+
87
+ def show
88
+ @hided = true
89
+ toggle
90
+ end
91
+
92
+ def hide
93
+ @hided = false
94
+ toggle
95
+ end
96
+
97
+ def toggle
98
+ @hided = !@hided
99
+ @app.cs.redraw @left, @top, @width, @height, false unless @app.cs.isDisposed
100
+ self
101
+ end
102
+
103
+ def fix_size
104
+ flag = false
105
+ set_margin
106
+ case self
107
+ when EditBox, Button
108
+ if 0 < @initials[:width] and @initials[:width] <= 1.0
109
+ @width = @parent.width * @initials[:width] - @margin_left - @margin_right
110
+ flag = true
111
+ end
112
+ if 0 < @initials[:height] and @initials[:height] <= 1.0
113
+ @height = @parent.height * @initials[:height] - @margin_top - @margin_bottom
114
+ flag = true
115
+ end
116
+ when EditLine, ListBox
117
+ if 0 < @initials[:width] and @initials[:width] <= 1.0
118
+ @width = @parent.width * @initials[:width] - @margin_left - @margin_right
119
+ @height = 20
120
+ flag = true
121
+ end
122
+ else
123
+ end
124
+ if flag
125
+ @real.setSize @width, @height
126
+ move @left, @top
127
+ end
128
+ end
129
+ end
130
+
131
+ class Image < Basic; end
132
+
133
+ class Pattern < Basic
134
+ def positioning x, y, max
135
+ self.width = self.height = 0
136
+ super
137
+ end
138
+ def move2 x, y
139
+ @left, @top, @width, @height = parent.left, parent.top, parent.width, parent.height
140
+ @width = @args[:width] unless @args[:width].zero?
141
+ @height = @args[:height] unless @args[:height].zero?
142
+ unless @real
143
+ m = self.class.to_s.downcase[7..-1]
144
+ args = eval "{#{@args.keys.map{|k| "#{k}: @#{k}"}.join(', ')}}"
145
+ args = [@pattern, args.merge({create_real: true, nocontrol: true})]
146
+ pt = @app.send(m, *args)
147
+ @real = pt.real
148
+ end
149
+ end
150
+ end
151
+ class Background < Pattern; end
152
+ class Border < Pattern; end
153
+
154
+ class ShapeBase < Basic; end
155
+ class Rect < ShapeBase; end
156
+ class Oval < ShapeBase; end
157
+ class Line < ShapeBase; end
158
+ class Star < ShapeBase; end
159
+ class Shape < ShapeBase
160
+ def move_to x, y
161
+ real.moveTo x + left, y + top
162
+ end
163
+ def line_to x, y
164
+ real.lineTo x + left, y + top
165
+ end
166
+ def quad_to cx, cy, x, y
167
+ real.quadTo cx + left, cy + top, x + left, y + top
168
+ end
169
+ end
170
+
171
+ class TextBlock < Basic
172
+ def initialize args
173
+ @links = []
174
+ super
175
+ end
176
+ attr_reader :links
177
+ def text
178
+ @args[:markup]
179
+ end
180
+ def text= s
181
+ style markup: s
182
+ end
183
+ def positioning x, y, max
184
+ self.text = @args[:markup]
185
+ super.tap{|s| s.height += (@margin_top + @margin_bottom) if s == self}
186
+ end
187
+ def move x, y
188
+ self.text = @args[:markup]
189
+ super
190
+ end
191
+ def clear
192
+ @links.each &:clear
193
+ @links.clear
194
+ super
195
+ end
196
+ end
197
+ class Banner < TextBlock; end
198
+ class Title < TextBlock; end
199
+ class Subtitle < TextBlock; end
200
+ class Tagline < TextBlock; end
201
+ class Caption < TextBlock; end
202
+ class Para < TextBlock; end
203
+ class Inscription < TextBlock; end
204
+
205
+ class Native < Basic
206
+ def text
207
+ @real.getText
208
+ end
209
+ def text=(s)
210
+ @real.setText s.to_s
211
+ end
212
+ def move x, y
213
+ @real.setLocation x, y
214
+ super
215
+ end
216
+ def move2 x, y
217
+ @real.setLocation x, y
218
+ super
219
+ end
220
+ def clear
221
+ @real.dispose
222
+ @parent.contents -= [self]
223
+ end
224
+ def toggle
225
+ @hided = !@hided
226
+ @real.setVisible !@hided unless @real.isDisposed
227
+ self
228
+ end
229
+ end
230
+
231
+ class Button < Native; end
232
+ class ToggleButton < Button
233
+ def checked?
234
+ real.getSelection
235
+ end
236
+ def checked=(tof)
237
+ real.setSelection tof
238
+ block.call if tof
239
+ end
240
+ end
241
+ class Radio < ToggleButton; end
242
+
243
+ class EditLine < Native; end
244
+ class EditBox < Native; end
245
+ class ListBox < Native; end
246
+ class Progress < Native
247
+ def fraction
248
+ @real.isDisposed ? 0 : real.getSelection / 100.0
249
+ end
250
+ def fraction= n
251
+ real.setSelection n * 100 unless @real.isDisposed
252
+ end
253
+ end
254
+ end
@@ -0,0 +1,149 @@
1
+ class Shoes
2
+ colors = [
3
+ [:aliceblue, 240, 248, 255],
4
+ [:antiquewhite, 250, 235, 215],
5
+ [:aqua, 0, 255, 255],
6
+ [:aquamarine, 127, 255, 212],
7
+ [:azure, 240, 255, 255],
8
+ [:beige, 245, 245, 220],
9
+ [:bisque, 255, 228, 196],
10
+ [:black, 0, 0, 0],
11
+ [:blanchedalmond, 255, 235, 205],
12
+ [:blue, 0, 0, 255],
13
+ [:blueviolet, 138, 43, 226],
14
+ [:brown, 165, 42, 42],
15
+ [:burlywood, 222, 184, 135],
16
+ [:cadetblue, 95, 158, 160],
17
+ [:chartreuse, 127, 255, 0],
18
+ [:chocolate, 210, 105, 30],
19
+ [:coral, 255, 127, 80],
20
+ [:cornflowerblue, 100, 149, 237],
21
+ [:cornsilk, 255, 248, 220],
22
+ [:crimson, 220, 20, 60],
23
+ [:cyan, 0, 255, 255],
24
+ [:darkblue, 0, 0, 139],
25
+ [:darkcyan, 0, 139, 139],
26
+ [:darkgoldenrod, 184, 134, 11],
27
+ [:darkgray, 169, 169, 169],
28
+ [:darkgreen, 0, 100, 0],
29
+ [:darkkhaki, 189, 183, 107],
30
+ [:darkmagenta, 139, 0, 139],
31
+ [:darkolivegreen, 85, 107, 47],
32
+ [:darkorange, 255, 140, 0],
33
+ [:darkorchid, 153, 50, 204],
34
+ [:darkred, 139, 0, 0],
35
+ [:darksalmon, 233, 150, 122],
36
+ [:darkseagreen, 143, 188, 143],
37
+ [:darkslateblue, 72, 61, 139],
38
+ [:darkslategray, 47, 79, 79],
39
+ [:darkturquoise, 0, 206, 209],
40
+ [:darkviolet, 148, 0, 211],
41
+ [:deeppink, 255, 20, 147],
42
+ [:deepskyblue, 0, 191, 255],
43
+ [:dimgray, 105, 105, 105],
44
+ [:dodgerblue, 30, 144, 255],
45
+ [:firebrick, 178, 34, 34],
46
+ [:floralwhite, 255, 250, 240],
47
+ [:forestgreen, 34, 139, 34],
48
+ [:fuchsia, 255, 0, 255],
49
+ [:gainsboro, 220, 220, 220],
50
+ [:ghostwhite, 248, 248, 255],
51
+ [:gold, 255, 215, 0],
52
+ [:goldenrod, 218, 165, 32],
53
+ [:gray, 128, 128, 128],
54
+ [:green, 0, 128, 0],
55
+ [:greenyellow, 173, 255, 47],
56
+ [:honeydew, 240, 255, 240],
57
+ [:hotpink, 255, 105, 180],
58
+ [:indianred, 205, 92, 92],
59
+ [:indigo, 75, 0, 130],
60
+ [:ivory, 255, 255, 240],
61
+ [:khaki, 240, 230, 140],
62
+ [:lavender, 230, 230, 250],
63
+ [:lavenderblush, 255, 240, 245],
64
+ [:lawngreen, 124, 252, 0],
65
+ [:lemonchiffon, 255, 250, 205],
66
+ [:lightblue, 173, 216, 230],
67
+ [:lightcoral, 240, 128, 128],
68
+ [:lightcyan, 224, 255, 255],
69
+ [:lightgoldenrodyellow, 250, 250, 210],
70
+ [:lightgreen, 144, 238, 144],
71
+ [:lightgrey, 211, 211, 211],
72
+ [:lightpink, 255, 182, 193],
73
+ [:lightsalmon, 255, 160, 122],
74
+ [:lightseagreen, 32, 178, 170],
75
+ [:lightskyblue, 135, 206, 250],
76
+ [:lightslategray, 119, 136, 153],
77
+ [:lightsteelblue, 176, 196, 222],
78
+ [:lightyellow, 255, 255, 224],
79
+ [:lime, 0, 255, 0],
80
+ [:limegreen, 50, 205, 50],
81
+ [:linen, 250, 240, 230],
82
+ [:magenta, 255, 0, 255],
83
+ [:maroon, 128, 0, 0],
84
+ [:mediumaquamarine, 102, 205, 170],
85
+ [:mediumblue, 0, 0, 205],
86
+ [:mediumorchid, 186, 85, 211],
87
+ [:mediumpurple, 147, 112, 219],
88
+ [:mediumseagreen, 60, 179, 113],
89
+ [:mediumslateblue, 123, 104, 238],
90
+ [:mediumspringgreen, 0, 250, 154],
91
+ [:mediumturquoise, 72, 209, 204],
92
+ [:mediumvioletred, 199, 21, 133],
93
+ [:midnightblue, 25, 25, 112],
94
+ [:mintcream, 245, 255, 250],
95
+ [:mistyrose, 255, 228, 225],
96
+ [:moccasin, 255, 228, 181],
97
+ [:navajowhite, 255, 222, 173],
98
+ [:navy, 0, 0, 128],
99
+ [:oldlace, 253, 245, 230],
100
+ [:olive, 128, 128, 0],
101
+ [:olivedrab, 107, 142, 35],
102
+ [:orange, 255, 165, 0],
103
+ [:orangered, 255, 69, 0],
104
+ [:orchid, 218, 112, 214],
105
+ [:palegoldenrod, 238, 232, 170],
106
+ [:palegreen, 152, 251, 152],
107
+ [:paleturquoise, 175, 238, 238],
108
+ [:palevioletred, 219, 112, 147],
109
+ [:papayawhip, 255, 239, 213],
110
+ [:peachpuff, 255, 218, 185],
111
+ [:peru, 205, 133, 63],
112
+ [:pink, 255, 192, 203],
113
+ [:plum, 221, 160, 221],
114
+ [:powderblue, 176, 224, 230],
115
+ [:purple, 128, 0, 128],
116
+ [:red, 255, 0, 0],
117
+ [:rosybrown, 188, 143, 143],
118
+ [:royalblue, 65, 105, 225],
119
+ [:saddlebrown, 139, 69, 19],
120
+ [:salmon, 250, 128, 114],
121
+ [:sandybrown, 244, 164, 96],
122
+ [:seagreen, 46, 139, 87],
123
+ [:seashell, 255, 245, 238],
124
+ [:sienna, 160, 82, 45],
125
+ [:silver, 192, 192, 192],
126
+ [:skyblue, 135, 206, 235],
127
+ [:slateblue, 106, 90, 205],
128
+ [:slategray, 112, 128, 144],
129
+ [:snow, 255, 250, 250],
130
+ [:springgreen, 0, 255, 127],
131
+ [:steelblue, 70, 130, 180],
132
+ [:tan, 210, 180, 140],
133
+ [:teal, 0, 128, 128],
134
+ [:thistle, 216, 191, 216],
135
+ [:tomato, 255, 99, 71],
136
+ [:turquoise, 64, 224, 208],
137
+ [:violet, 238, 130, 238],
138
+ [:wheat, 245, 222, 179],
139
+ [:white, 255, 255, 255],
140
+ [:whitesmoke, 245, 245, 245],
141
+ [:yellow, 255, 255, 0],
142
+ [:yellowgreen, 154, 205, 50],
143
+ ]
144
+
145
+ App.class_eval do
146
+ colors.each{|c, r, g, b| define_method(c){[r, g, b]}}
147
+ end
148
+ colors.each{|c, r, g, b| COLORS[c] = [r, g, b]}
149
+ end
@@ -0,0 +1,26 @@
1
+ class Shoes
2
+ class Download
3
+ def initialize name, args, &blk
4
+ require 'open-uri'
5
+ Thread.new do
6
+ open name,
7
+ content_length_proc: lambda{|len| @content_length, @started = len, true},
8
+ progress_proc: lambda{|size| @progress = size} do |sio|
9
+ open(args[:save], 'wb'){|fw| fw.print sio.read} if args[:save]
10
+ #blk[sio] if blk
11
+ @finished = true
12
+ end
13
+ end
14
+ end
15
+
16
+ attr_reader :progress, :content_length
17
+
18
+ def started?
19
+ @started
20
+ end
21
+
22
+ def finished?
23
+ @finished
24
+ end
25
+ end
26
+ end
data/lib/shoes/help.rb ADDED
@@ -0,0 +1,473 @@
1
+ require 'hpricot'
2
+ require 'nkf'
3
+
4
+ class Manual < Shoes
5
+ url '/', :index
6
+ url '/manual/(\d+)', :index
7
+ #url '/mk_search_page', :mk_search_page
8
+
9
+ include Hpricot
10
+ #include HH::Markup
11
+
12
+ def index pnum = 0
13
+ font LANG == 'ja' ? 'MS UI Gothic' : 'Arial'
14
+ #style Link, underline: false, weight: 'bold'
15
+ #style LinkHover, stroke: '#06E'
16
+ self.scroll_top = 0
17
+ TOC.clear; TOC_LIST.clear
18
+ table_of_contents.each{|toc| TOC << toc}
19
+ pnum == '999' ? mk_search_page : manual( *get_title_and_desc(pnum.to_i) )
20
+ end
21
+
22
+ def get_title_and_desc pnum
23
+ chapter, section = PNUMS[pnum]
24
+ return nil unless chapter
25
+ if section
26
+ [pnum, DOCS[chapter][1][:sections][section][1][:title],
27
+ DOCS[chapter][1][:sections][section][1][:description],
28
+ DOCS[chapter][1][:sections][section][1][:methods]]
29
+ else
30
+ [pnum, DOCS[chapter][0], DOCS[chapter][1][:description], []]
31
+ end
32
+ end
33
+
34
+ def table_of_contents
35
+ PNUMS.map.with_index do |e, pnum|
36
+ chapter, section = e
37
+ title = section ? DOCS[chapter][1][:sections][section][1][:title] : DOCS[chapter][0]
38
+ title = title.sub('The', '').split(' ').first
39
+ TOC_LIST << [title, section]
40
+ section ? [' ', link(title){visit "/manual/#{pnum}"}, "\n"] : [link(fg(title, magenta)){visit "/manual/#{pnum}"}, "\n"]
41
+ end.flatten
42
+ end
43
+
44
+ def manual pnum, docs_title, docs_description, docs_methods
45
+ flow do
46
+ show_header docs_title
47
+ show_toc
48
+ paras = mk_paras docs_description
49
+ flow width: 0.8, margin: [10, 0, 20, 0] do
50
+ show_page paras, true
51
+ show_methods docs_methods
52
+ para link('top'){visit "/manual/0"}, " ",
53
+ link('prev'){visit "/manual/#{(pnum-1)%PEND}"}, " ",
54
+ link('next'){visit "/manual/#{(pnum+1)%PEND}"}, " ",
55
+ link('end'){visit "/manual/#{PEND-1}"}
56
+ end
57
+ end
58
+ end
59
+
60
+ def show_header docs_title
61
+ background tr_color("#ddd")..white, angle: 90
62
+ background black..magenta, height: 90
63
+ para fg("The Purple Shoes Manual #{VERSION}", gray), left: 120, top: 10
64
+ title fg(docs_title, white), left: 120, top: 30, font: 'Coolvetica'
65
+ image File.join(DIR, '../static/purple_shoes-icon.png'), left: 5, top: -12, width: 110, height: 110, nocontrol: true
66
+ end
67
+
68
+ def show_toc
69
+ stack(height: 120){}
70
+ flow width: 0.2, margin_left: 10 do
71
+ flow(margin_right: 20) do
72
+ background black.push(0.7), curve: 5
73
+ inscription "Not findng it?\n", 'Try ', link(fg 'Search', white){visit '/manual/999'}, '!', align: 'center', stroke: lightgrey
74
+ end
75
+ stack(height: 10){}
76
+ para *TOC
77
+ para link(fg 'to_html', green){html_manual}
78
+ end
79
+ end
80
+
81
+ def show_methods docs_methods, term = nil
82
+ docs_methods.each do |m, d|
83
+ flow do
84
+ background rgb(60, 60, 60), curve: 5
85
+ n = m.index("\u00BB")
86
+ if n
87
+ para ' ', fg(strong(m[0...n]), white), fg(strong(m[n..-1]), rgb(160, 160, 160))
88
+ else
89
+ para ' ', fg(strong(m), white)
90
+ end
91
+ end
92
+ para NL
93
+ show_page mk_paras(d.gsub('&', '\u0026')), false, term
94
+ end
95
+ end
96
+
97
+ def show_page paras, intro = false, term = nil
98
+ paras.each_with_index do |text, i|
99
+ if text =~ CODE_RE
100
+ text.gsub CODE_RE do |lines|
101
+ lines = lines.split NL
102
+ n = lines[1] =~ /\#\!ruby/ ? 2 : 1
103
+ _code = lines[n...-1].join(NL+' ')
104
+ flow do
105
+ background rgb(190, 190, 190), curve: 5
106
+ inscription link(fg('Run this', magenta)){eval mk_executable(_code), TOPLEVEL_BINDING}, ' ', align: 'right'
107
+ if _code.include? 'te-su-to'
108
+ para fg(code(' ' + _code), maroon), NL, margin: [-10, 10, 0, 20]
109
+ else
110
+ #para code(highlight(' ' + _code, nil)), NL, margin: [-10, 10, 0, 20]
111
+ para fg(code(' ' + _code), blueviolet), NL, margin: [-10, 10, 0, 20]
112
+ end
113
+ end
114
+ para NL
115
+ end
116
+ next
117
+ end
118
+
119
+ if text =~ /\A \* (.+)/m
120
+ $1.split(/^ \* /).each do |txt|
121
+ image File.join(DIR, '../static/purple_shoes-icon.png'), width: 20, height: 20
122
+ flow(width: 510){show_paragraph txt, intro, i, term}
123
+ end
124
+ else
125
+ show_paragraph text, intro, i, term
126
+ para NL
127
+ end
128
+ end
129
+ end
130
+
131
+ def show_paragraph txt, intro, i, term = nil
132
+ txt = txt.gsub("\n", ' ').gsub(/`(.+?)`/m){fg code($1), rgb(255, 30, 0)}.
133
+ gsub(/\^(.+?)\^/m, '\1').gsub(/'''(.+?)'''/m){strong($1)}.gsub(/''(.+?)''/m){em($1)}.
134
+ gsub(/\[\[BR\]\]/i, "\n")
135
+ txts = txt.split(/(\[\[\S+?\]\])/m).map{|s| s.split(/(\[\[\S+? .+?\]\])/m)}.flatten
136
+ case txts[0]
137
+ when /\A==== (.+) ====/; caption *marker($1, term), size: 24
138
+ when /\A=== (.+) ===/; tagline *marker($1, term), size: 12, weight: 'bold'
139
+ when /\A== (.+) ==/; subtitle *marker($1, term)
140
+ when /\A= (.+) =/; title *marker($1, term)
141
+ when /\A\{COLORS\}/; flow{color_page}
142
+ when /\A\{SAMPLES\}/; flow{sample_page}
143
+ else
144
+ para *mk_links(txts, term).flatten, NL, (intro and i.zero?) ? {size: 16} : ''
145
+ txt.gsub IMAGE_RE do
146
+ para NL
147
+ image File.join(DIR, "../static/#{$3}"), eval("{#{$2 or "margin_left: 50"}}")
148
+ end
149
+ end
150
+ end
151
+
152
+ def mk_links txts, term = nil
153
+ txts.map{|txt| txt.gsub(IMAGE_RE, '')}.
154
+ map{|txt| txt =~ /\[\[(\S+?)\]\]/m ? (t = $1.split('.'); link(ins *marker(t.last, term)){visit "/manual/#{find_pnum t.first}"}) : txt}.
155
+ map{|txt| txt =~ /\[\[(\S+?) (.+?)\]\]/m ? (url = $1; link(ins *marker($2, term)){visit url =~ /^http/ ? url : "/manual/#{find_pnum url}"}) :
156
+ (txt.is_a?(String) ? marker(txt, term) : txt)}
157
+ end
158
+
159
+ def mk_paras str
160
+ str.split("\n\n") - ['']
161
+ end
162
+
163
+ def mk_executable code
164
+ if code =~ /\# Not yet available/
165
+ "Shoes.app{para 'Sorry, not yet available...'}"
166
+ else
167
+ code
168
+ end
169
+ end
170
+
171
+ def color_page
172
+ COLORS.each do |color, v|
173
+ r, g, b = v
174
+ c = v.dark? ? white : black
175
+ flow width: 0.33 do
176
+ background send(color)
177
+ para fg(strong(color), c), align: 'center'
178
+ para fg("rgb(#{r}, #{g}, #{b})", c), align: 'center'
179
+ end
180
+ end
181
+ para NL
182
+ end
183
+
184
+ def sample_page
185
+ mk_sample_names.each do |file|
186
+ stack width: 80 do
187
+ inscription file[0...-3]
188
+ img = image File.join(DIR, "../snapshots/#{file[0..-3]}png"), width: 50, height: 50
189
+ img.click{Dir.chdir(File.join DIR, '../samples'){instance_eval(IO.read(file),file,0)}}
190
+ para NL
191
+ end
192
+ end
193
+ end
194
+
195
+ def mk_sample_names
196
+ Dir[File.join(DIR, '../samples/sample*.rb')].map do |file|
197
+ orig_name = File.basename file
198
+ dummy_name = orig_name.sub(/sample(.*)\.rb/){
199
+ first, second = $1.split('-')
200
+ "%02d%s%s" % [first.to_i, ('-' if second), second]
201
+ }
202
+ [dummy_name, orig_name]
203
+ end.sort.map &:last
204
+ end
205
+
206
+ def find_pnum page
207
+ TOC_LIST.each_with_index do |e, i|
208
+ title, section = e
209
+ return i if title == page
210
+ end
211
+ end
212
+
213
+ def self.load_docs path
214
+ str = IO.read(path).force_encoding("UTF-8")
215
+ (str.split(/^= (.+?) =/)[1..-1]/2).map do |k, v|
216
+ sparts = v.split(/^== (.+?) ==/)
217
+ sections = (sparts[1..-1]/2).map do |k2, v2|
218
+ meth = v2.split(/^=== (.+?) ===/)
219
+ k2t = k2[/^(?:The )?([\-\w]+)/, 1]
220
+ meth_plain = meth[0].gsub(IMAGE_RE, '')
221
+ h = {title: k2, section: k, description: meth[0], methods: (meth[1..-1]/2)}
222
+ [k2t, h]
223
+ end
224
+ h = {description: sparts[0], sections: sections, class: "toc" + k.downcase.gsub(/\W+/, '')}
225
+ [k, h]
226
+ end
227
+ end
228
+
229
+ def self.mk_page_numbers docs
230
+ pnum = []
231
+ docs.length.times do |i|
232
+ pnum << [i, nil]
233
+ docs[i][1][:sections].length.times do |j|
234
+ pnum << [i, j]
235
+ end
236
+ end
237
+ pnum
238
+ end
239
+
240
+ def html_manual
241
+ dir = ask_save_folder
242
+ return unless dir
243
+ FileUtils.mkdir_p File.join(dir, 'static')
244
+ FileUtils.mkdir_p File.join(dir, 'snapshots')
245
+ %w[rshoes-icon.png purple_shoes-icon.png shoes-manual-apps.png manual.css code_highlighter.js code_highlighter_ruby.js].
246
+ each{|x| FileUtils.cp "#{DIR}/../static/#{x}", "#{dir}/static"}
247
+ Dir[File.join DIR, '../static/man-*.png'].each{|x| FileUtils.cp x, "#{dir}/static"}
248
+ Dir[File.join DIR, '../snapshots/sample*.png'].each{|x| FileUtils.cp x, "#{dir}/snapshots"}
249
+
250
+ TOC_LIST.length.times do |n|
251
+ num, title, desc, methods = get_title_and_desc n
252
+ open File.join(dir, "#{TOC_LIST[n][0]}.html"), 'w' do |f|
253
+ f.puts mk_html(title, desc, methods, TOC_LIST[n+1], get_title_and_desc(n+1), mk_sidebar_list(num))
254
+ end
255
+ end
256
+ end
257
+
258
+ def mk_html title, desc, methods, next_file, next_title, menu
259
+ man = self
260
+ Hpricot do
261
+ xhtml_transitional do
262
+ head do
263
+ meta :"http-equiv" => "Content-Type", "content" => "text/html; charset=utf-8"
264
+ title "The Purple Shoes Manual // #{title}"
265
+ script type: "text/javascript", src: "static/code_highlighter.js"
266
+ script type: "text/javascript", src: "static/code_highlighter_ruby.js"
267
+ style type: "text/css" do
268
+ text "@import 'static/manual.css';"
269
+ end
270
+ end
271
+ body do
272
+ div.main! do
273
+ div.manual! do
274
+ h2 "The Purple Shoes Manual #{VERSION}"
275
+ h1 title
276
+
277
+ paras = man.mk_paras desc
278
+ div.intro{text man.manual_p(paras.shift)}
279
+
280
+ html_paragraph = proc do
281
+ paras.each do |str|
282
+ if str =~ CODE_RE
283
+ pre{code.rb $1.gsub(/^\s*?\n/, '')}
284
+ else
285
+ cmd, str = case str
286
+ when /\A==== (.+) ====/; [:h4, $1]
287
+ when /\A=== (.+) ===/; [:h3, $1]
288
+ when /\A== (.+) ==/; [:h2, $1]
289
+ when /\A= (.+) =/; [:h1, $1]
290
+ when /\A\{COLORS\}/
291
+ COLORS.each do |color, v|
292
+ f = v.dark? ? "white" : "black"
293
+ div.color(style: "background: #{color}; color: #{f}"){h3 color.to_s; p("rgb(%d, %d, %d)" % v)}
294
+ end
295
+ when /\A\{SAMPLES\}/
296
+ man.mk_sample_names.each do |name|
297
+ name = name[0...-3]
298
+ div.sample do
299
+ h3 name
300
+ text '<a href="snapshots/%s.png"><img src="snapshots/%s.png" alt="%s" border=0 width=50 height=50></a>' % [name, name, name]
301
+ end
302
+ end
303
+ when /\A \* (.+)/m
304
+ ul{$1.split(/^ \* /).each{|x| li{self << man.manual_p(x)}}}
305
+ else
306
+ [:p, str]
307
+ end
308
+ send(cmd){self << man.manual_p(str)} if cmd.is_a?(Symbol)
309
+ end
310
+ end
311
+ end
312
+
313
+ html_paragraph.call
314
+
315
+ methods.each do |m, d|
316
+ n = m.index("\u00BB")
317
+ n ? (sig, val = m[0...n-1], m[n-1..-1]) : (sig, val = m, nil)
318
+ aname = sig[/^[^(=]+=?/].gsub(/\s/, '').downcase
319
+ a name: aname
320
+ div.divmethod do
321
+ a sig, href: "##{aname}"
322
+ text val if val
323
+ end
324
+ div.desc do
325
+ paras = man.mk_paras d
326
+ html_paragraph.call
327
+ end
328
+ end
329
+
330
+ p.next{text "Next: "; a next_title[1], href: "#{next_file[0]}.html"} if next_title
331
+ end
332
+ div.sidebar do
333
+ img src: "static/purple_shoes-icon.png"
334
+ ul do
335
+ li{a.prime "HELP", href: "./"}
336
+ menu.each do |m|
337
+ li do
338
+ unless m.is_a?(Array)
339
+ a m, href: "#{m}.html"
340
+ else
341
+ ul.sub do
342
+ m.each do |sm|
343
+ li{a sm, href: "#{sm}.html"}
344
+ end
345
+ end
346
+ end
347
+ end
348
+ end
349
+ end
350
+ end
351
+ end
352
+ end
353
+ end
354
+ end.to_html
355
+ end
356
+
357
+ def mk_sidebar_list num
358
+ toc = []
359
+ [0..3, 4..9, 10..16, 17..32, 33..37].each do |r|
360
+ toc.push TOC_LIST[r.first][0]
361
+ toc.push(TOC_LIST[r.first+1..r.last].to_a.map &:first) if r.include?(num)
362
+ end
363
+ toc
364
+ end
365
+
366
+ def manual_p str
367
+ str.gsub(/\n+\s*/, " ").
368
+ gsub(/&/, '&amp;').gsub(/>/, '&gt;').gsub(/>/, '&lt;').gsub(/"/, '&quot;').
369
+ gsub(/`(.+?)`/m, '<code>\1</code>').gsub(/\[\[BR\]\]/i, "<br />\n").
370
+ gsub(/\^(.+?)\^/m, '\1').
371
+ gsub(/'''(.+?)'''/m, '<strong>\1</strong>').gsub(/''(.+?)''/m, '<em>\1</em>').
372
+ gsub(/\[\[((http|https):\/\/\S+?)\]\]/m, '<a href="\1" target="_new">\1</a>').
373
+ gsub(/\[\[((http|https):\/\/\S+?) (.+?)\]\]/m, '<a href="\1" target="_new">\3</a>').
374
+ gsub(/\[\[(\S+?)\]\]/m) do
375
+ ms, mn = $1.split(".", 2)
376
+ if mn
377
+ '<a href="' + ms + '.html#' + mn + '">' + mn + '</a>'
378
+ else
379
+ '<a href="' + ms + '.html">' + ms + '</a>'
380
+ end
381
+ end.
382
+ gsub(/\[\[(\S+?) (.+?)\]\]/m, '<a href="\1.html">\2</a>').
383
+ gsub(/\!(\{[^}\n]+\})?([^!\n]+\.\w+)\!/) do
384
+ '<img src="' + "static/#$2" + '" />'
385
+ end
386
+ end
387
+
388
+ def mk_search_page
389
+ flow do
390
+ show_header 'Search'
391
+ show_toc
392
+ pnum, docs_title, docs_description, docs_methods = get_title_and_desc(25)
393
+ paras = mk_paras docs_description
394
+
395
+ flow width: 0.8, margin: [10, 0, 20, 0] do
396
+ el = edit_line width: 300
397
+ button 'search' do
398
+ term = el.text.strip
399
+ unless term.empty?
400
+ descs, methods = search term
401
+ @f.clear{show_search_result term, descs, methods}
402
+ aflush
403
+ end
404
+ end
405
+ stack(height: 20){}
406
+ @f = flow{}
407
+ end
408
+ end
409
+ end
410
+
411
+ def search term
412
+ descs, methods = [], []
413
+ PNUMS.each_with_index do |(chapter, section), pnum|
414
+ pnum, docs_title, docs_description, docs_methods = get_title_and_desc(pnum)
415
+ paras = mk_paras(docs_description)
416
+ descs << [chapter, section, docs_title, paras] if paras.map{|txt| txt.gsub(CODE_RE, '').gsub(IMAGE_RE, '')}.join(' ').index(term)
417
+ docs_methods.each do |docs_method|
418
+ m, d = docs_method
419
+ methods << [chapter, section, docs_title, docs_method] if m.index(term) or d.gsub(CODE_RE, '').gsub(IMAGE_RE, '').index(term)
420
+ end
421
+ end
422
+ return descs, methods
423
+ end
424
+
425
+ def show_search_result term, descs, methods
426
+ return subtitle 'Not Found' if descs.empty? and methods.empty?
427
+ methods.each do |(chapter, section, docs_title, docs_method)|
428
+ flow margin: [10, 10, 0, 5] do
429
+ background rgb(200, 200, 200), curve: 5
430
+ para "#{DOCS[chapter][0]}: #{docs_title.sub('The', '').split(' ').first}: ",
431
+ link(docs_method[0]){@f.clear{title docs_title; show_methods [docs_method], term}; aflush}, NL
432
+ end
433
+ stack(height: 2){}
434
+ end
435
+ descs.each do |(chapter, section, docs_title, paras)|
436
+ flow margin_left: 10 do
437
+ if section
438
+ background gray, curve: 5
439
+ tagline link(fg(docs_title, white)){@f.clear{title docs_title; show_page paras, true, term}; aflush}, width: 320
440
+ inscription "Sub-Section under #{DOCS[chapter][0]}", stroke: lightgrey, width: 180
441
+ else
442
+ background black.push(0.8), curve: 5
443
+ subtitle link(fg(docs_title, white)){@f.clear{title docs_title; show_page paras, true, term}; aflush}, width: 320
444
+ inscription 'Section Header', stroke: lightgrey, width: 100
445
+ end
446
+ end
447
+ stack(height: 2){}
448
+ end
449
+ para NL
450
+ end
451
+
452
+ def marker txt, term
453
+ if term && txt
454
+ tmp = txt.split(term).map{|s| [s, bg(term, yellow)]}.flatten
455
+ txt =~ /#{term}$/ ? tmp : tmp[0...-1]
456
+ else
457
+ [txt]
458
+ end
459
+ end
460
+
461
+ IMAGE_RE = /\!(\{([^}\n]+)\})?([^!\n]+\.\w+)\!/
462
+ CODE_RE = /\{{3}(?:\s*\#![^\n]+)?(.+?)\}{3}/m
463
+ NL = "\n"
464
+ LANG = $lang.downcase[0, 2]
465
+ DOCS = load_docs($lang =~ /\.txt$/ ? $lang : File.join(DIR, "../static/manual-#{LANG}.txt"))
466
+ PNUMS = mk_page_numbers DOCS
467
+ PEND = PNUMS.length
468
+ TOC, TOC_LIST = [], []
469
+ COLORS = Shoes::COLORS
470
+ VERSION = SHOES_VERSION
471
+ end
472
+
473
+ Shoes.app title: 'The Purple Shoes Manual', width: 720, height: 640