scarpe 0.2.1 → 0.2.2

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.
Files changed (240) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -0
  3. data/.yardopts +11 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +112 -0
  6. data/README.md +31 -24
  7. data/Rakefile +13 -1
  8. data/docs/yard/catscradle.md +44 -0
  9. data/docs/yard/template/default/fulldoc/html/setup.rb +13 -0
  10. data/docs/yard/template/default/layout/html/setup.rb +9 -0
  11. data/examples/background_with_image.rb +16 -0
  12. data/examples/bloopsaphone/working/bronx_army_knife.rb +66 -0
  13. data/examples/bloopsaphone/working/morning_serenity.rb +21 -0
  14. data/examples/bloopsaphone/working/simpsons_theme_song_by_why.rb +6 -4
  15. data/examples/button_go_away.rb +1 -1
  16. data/examples/check.rb +18 -0
  17. data/examples/clear_and_append.rb +24 -0
  18. data/examples/download_and_show_image.rb +28 -0
  19. data/examples/edit_box.rb +3 -5
  20. data/examples/fonts.rb +2 -2
  21. data/examples/get_headers.rb +10 -0
  22. data/examples/highlander.rb +2 -0
  23. data/examples/link.rb +2 -2
  24. data/examples/local_fonts.rb +4 -0
  25. data/examples/local_images.rb +4 -0
  26. data/examples/motion_events.rb +20 -0
  27. data/examples/parse_xl_funnies.rb +58 -0
  28. data/examples/radio/radio.rb +16 -0
  29. data/examples/radio/radio_groups.rb +18 -0
  30. data/examples/radio/radio_same_slot.rb +6 -0
  31. data/examples/ruby_racer.rb +13 -15
  32. data/examples/selfitude.rb +18 -0
  33. data/examples/shapes/shapes_fill.rb +4 -3
  34. data/examples/shoes_school.rb +2 -4
  35. data/examples/show_hide.rb +6 -0
  36. data/examples/skip_ci/change_my_audio_source.rb +21 -0
  37. data/examples/skip_ci/guitar_fretboard.rb +137 -0
  38. data/examples/video.rb +10 -0
  39. data/exe/scarpe +42 -66
  40. data/fonts/Pacifico.ttf +0 -0
  41. data/lacci/Gemfile +22 -0
  42. data/lacci/Gemfile.lock +72 -0
  43. data/lacci/Rakefile +12 -0
  44. data/lacci/lacci.gemspec +37 -0
  45. data/lacci/lib/lacci/scarpe_cli.rb +70 -0
  46. data/lacci/lib/lacci/scarpe_core.rb +21 -0
  47. data/lacci/lib/lacci/version.rb +13 -0
  48. data/lacci/lib/shoes/app.rb +264 -0
  49. data/{lib/scarpe → lacci/lib/shoes}/background.rb +1 -1
  50. data/{lib/scarpe → lacci/lib/shoes}/border.rb +1 -1
  51. data/{lib/scarpe → lacci/lib/shoes}/colors.rb +1 -1
  52. data/lacci/lib/shoes/constants.rb +29 -0
  53. data/{lib/scarpe → lacci/lib/shoes}/display_service.rb +40 -45
  54. data/lacci/lib/shoes/download.rb +123 -0
  55. data/lacci/lib/shoes/log.rb +71 -0
  56. data/lacci/lib/shoes/spacing.rb +9 -0
  57. data/{lib/scarpe → lacci/lib/shoes}/widget.rb +63 -43
  58. data/{lib/scarpe → lacci/lib/shoes/widgets}/alert.rb +3 -3
  59. data/{lib/scarpe → lacci/lib/shoes/widgets}/arc.rb +7 -5
  60. data/{lib/scarpe → lacci/lib/shoes/widgets}/button.rb +3 -3
  61. data/lacci/lib/shoes/widgets/check.rb +28 -0
  62. data/lacci/lib/shoes/widgets/document_root.rb +20 -0
  63. data/{lib/scarpe → lacci/lib/shoes/widgets}/edit_box.rb +10 -5
  64. data/{lib/scarpe → lacci/lib/shoes/widgets}/edit_line.rb +2 -2
  65. data/lacci/lib/shoes/widgets/flow.rb +22 -0
  66. data/lacci/lib/shoes/widgets/font.rb +14 -0
  67. data/{lib/scarpe → lacci/lib/shoes/widgets}/image.rb +3 -7
  68. data/lacci/lib/shoes/widgets/line.rb +18 -0
  69. data/{lib/scarpe → lacci/lib/shoes/widgets}/link.rb +2 -2
  70. data/{lib/scarpe → lacci/lib/shoes/widgets}/list_box.rb +2 -2
  71. data/{lib/scarpe → lacci/lib/shoes/widgets}/para.rb +4 -26
  72. data/lacci/lib/shoes/widgets/radio.rb +35 -0
  73. data/lacci/lib/shoes/widgets/shape.rb +37 -0
  74. data/lacci/lib/shoes/widgets/slot.rb +75 -0
  75. data/{lib/scarpe → lacci/lib/shoes/widgets}/span.rb +2 -2
  76. data/lacci/lib/shoes/widgets/stack.rb +24 -0
  77. data/{lib/scarpe → lacci/lib/shoes/widgets}/star.rb +6 -9
  78. data/lacci/lib/shoes/widgets/subscription_item.rb +60 -0
  79. data/lacci/lib/shoes/widgets/text_widget.rb +51 -0
  80. data/lacci/lib/shoes/widgets/video.rb +15 -0
  81. data/lacci/lib/shoes/widgets.rb +29 -0
  82. data/lacci/lib/shoes.rb +127 -0
  83. data/lacci/test/test_colors.rb +39 -0
  84. data/lacci/test/test_helper.rb +9 -0
  85. data/lacci/test/test_lacci.rb +9 -0
  86. data/lib/scarpe/cats_cradle.rb +249 -0
  87. data/lib/scarpe/evented_assertions.rb +88 -0
  88. data/lib/scarpe/version.rb +1 -1
  89. data/lib/scarpe/wv/alert.rb +3 -2
  90. data/lib/scarpe/wv/app.rb +30 -8
  91. data/lib/scarpe/wv/arc.rb +5 -6
  92. data/lib/scarpe/wv/background.rb +10 -1
  93. data/lib/scarpe/wv/border.rb +5 -3
  94. data/lib/scarpe/wv/button.rb +11 -9
  95. data/lib/scarpe/wv/check.rb +29 -0
  96. data/lib/scarpe/wv/control_interface.rb +14 -20
  97. data/lib/scarpe/wv/control_interface_test.rb +13 -28
  98. data/lib/scarpe/wv/document_root.rb +3 -45
  99. data/lib/scarpe/wv/edit_box.rb +5 -7
  100. data/lib/scarpe/wv/edit_line.rb +2 -2
  101. data/lib/scarpe/wv/flow.rb +10 -20
  102. data/lib/scarpe/wv/font.rb +36 -0
  103. data/lib/scarpe/wv/html.rb +3 -2
  104. data/lib/scarpe/wv/image.rb +7 -2
  105. data/lib/scarpe/wv/line.rb +4 -7
  106. data/lib/scarpe/wv/link.rb +1 -0
  107. data/lib/scarpe/wv/list_box.rb +3 -3
  108. data/lib/scarpe/wv/para.rb +16 -14
  109. data/lib/scarpe/wv/radio.rb +34 -0
  110. data/lib/scarpe/wv/shape.rb +44 -8
  111. data/lib/scarpe/wv/slot.rb +81 -0
  112. data/lib/scarpe/wv/spacing.rb +1 -1
  113. data/lib/scarpe/wv/span.rb +10 -8
  114. data/lib/scarpe/wv/stack.rb +10 -30
  115. data/lib/scarpe/wv/star.rb +11 -12
  116. data/lib/scarpe/wv/subscription_item.rb +50 -0
  117. data/lib/scarpe/wv/video.rb +34 -0
  118. data/lib/scarpe/wv/web_wrangler.rb +238 -58
  119. data/lib/scarpe/wv/webview_local_display.rb +27 -5
  120. data/lib/scarpe/wv/webview_relay_display.rb +18 -119
  121. data/lib/scarpe/wv/webview_relay_util.rb +143 -0
  122. data/lib/scarpe/wv/widget.rb +80 -11
  123. data/lib/scarpe/wv/wv_display_worker.rb +17 -4
  124. data/lib/scarpe/wv.rb +33 -4
  125. data/lib/scarpe/wv_local.rb +1 -1
  126. data/lib/scarpe/wv_relay.rb +1 -1
  127. data/lib/scarpe.rb +3 -32
  128. data/scarpe-components/.gitignore +1 -0
  129. data/scarpe-components/Gemfile +22 -0
  130. data/scarpe-components/README.md +35 -0
  131. data/scarpe-components/Rakefile +12 -0
  132. data/scarpe-components/lib/scarpe/components/base64.rb +29 -0
  133. data/scarpe-components/lib/scarpe/components/file_helpers.rb +65 -0
  134. data/scarpe-components/lib/scarpe/components/modular_logger.rb +113 -0
  135. data/scarpe-components/lib/scarpe/components/print_logger.rb +43 -0
  136. data/{lib/scarpe → scarpe-components/lib/scarpe/components}/promises.rb +102 -35
  137. data/scarpe-components/lib/scarpe/components/segmented_file_loader.rb +170 -0
  138. data/scarpe-components/lib/scarpe/components/unit_test_helpers.rb +217 -0
  139. data/scarpe-components/lib/scarpe/components/version.rb +7 -0
  140. data/scarpe-components/scarpe-components.gemspec +38 -0
  141. data/scarpe-components/test/test_components.rb +9 -0
  142. data/scarpe-components/test/test_helper.rb +23 -0
  143. data/scarpe-components/test/test_promises.rb +260 -0
  144. data/scarpe-components/test/test_segmented_app_files.rb +182 -0
  145. data/{lib/scarpe → spikes}/glibui/widget.rb +2 -2
  146. data/{lib/scarpe → spikes}/glibui.rb +1 -1
  147. data/templates/basic_class_template.erb +1 -1
  148. data/templates/class_template_with_event_bind.erb +1 -1
  149. data/templates/class_template_with_shapes.erb +1 -1
  150. data/templates/webview_template.erb +0 -3
  151. metadata +151 -118
  152. data/examples/fill.rb +0 -25
  153. data/examples/legacy/not_checked/shoes-contrib/basic/class-book.yaml +0 -387
  154. data/examples/legacy/not_checked/shoes-contrib/good/good-clock.rb +0 -51
  155. data/examples/legacy/not_checked/shoes-contrib/good/good-follow.rb +0 -26
  156. data/examples/legacy/not_checked/shoes-contrib/good/good-reminder.rb +0 -174
  157. data/examples/legacy/not_checked/shoes-contrib/good/good-vjot.rb +0 -56
  158. data/examples/legacy/not_checked/shoes-contrib/simple/simple-timer.rb +0 -13
  159. data/examples/legacy/not_checked/shoes-dep-samples/good-clock.rb +0 -51
  160. data/examples/legacy/not_checked/shoes-dep-samples/good-follow.rb +0 -26
  161. data/examples/legacy/not_checked/shoes-dep-samples/good-reminder.rb +0 -174
  162. data/examples/legacy/not_checked/shoes-dep-samples/good-vjot.rb +0 -56
  163. data/examples/legacy/not_checked/shoes-dep-samples/simple-accordion.rb +0 -75
  164. data/examples/legacy/not_checked/shoes-dep-samples/simple-anim-shapes.rb +0 -17
  165. data/examples/legacy/not_checked/shoes-dep-samples/simple-anim-text.rb +0 -13
  166. data/examples/legacy/not_checked/shoes-dep-samples/simple-arc.rb +0 -23
  167. data/examples/legacy/not_checked/shoes-dep-samples/simple-bounce.rb +0 -24
  168. data/examples/legacy/not_checked/shoes-dep-samples/simple-calc.rb +0 -70
  169. data/examples/legacy/not_checked/shoes-dep-samples/simple-chipmunk.rb +0 -26
  170. data/examples/legacy/not_checked/shoes-dep-samples/simple-control-sizes.rb +0 -24
  171. data/examples/legacy/not_checked/shoes-dep-samples/simple-curve.rb +0 -26
  172. data/examples/legacy/not_checked/shoes-dep-samples/simple-dialogs.rb +0 -29
  173. data/examples/legacy/not_checked/shoes-dep-samples/simple-draw.rb +0 -13
  174. data/examples/legacy/not_checked/shoes-dep-samples/simple-editor.rb +0 -28
  175. data/examples/legacy/not_checked/shoes-dep-samples/simple-form.rb +0 -28
  176. data/examples/legacy/not_checked/shoes-dep-samples/simple-form.shy +0 -0
  177. data/examples/legacy/not_checked/shoes-dep-samples/simple-mask.rb +0 -21
  178. data/examples/legacy/not_checked/shoes-dep-samples/simple-menu.rb +0 -31
  179. data/examples/legacy/not_checked/shoes-dep-samples/simple-menu1.rb +0 -35
  180. data/examples/legacy/not_checked/shoes-dep-samples/simple-rubygems.rb +0 -29
  181. data/examples/legacy/not_checked/shoes-dep-samples/simple-slide.rb +0 -45
  182. data/examples/legacy/not_checked/shoes-dep-samples/simple-sphere.rb +0 -28
  183. data/examples/legacy/not_checked/shoes-dep-samples/simple-sqlite3.rb +0 -13
  184. data/examples/legacy/not_checked/shoes-dep-samples/simple-timer.rb +0 -13
  185. data/examples/legacy/not_checked/shoes-dep-samples/simple-video.rb +0 -13
  186. data/examples/legacy/not_checked/simple/anim-text.rb +0 -13
  187. data/examples/legacy/not_checked/simple/arc.rb +0 -23
  188. data/examples/legacy/not_checked/simple/bounce.rb +0 -24
  189. data/examples/legacy/not_checked/simple/chipmunk.rb +0 -26
  190. data/examples/legacy/not_checked/simple/curve.rb +0 -26
  191. data/examples/legacy/not_checked/simple/dialogs.rb +0 -29
  192. data/examples/legacy/not_checked/simple/downloader.rb +0 -40
  193. data/examples/legacy/not_checked/simple/draw.rb +0 -13
  194. data/examples/legacy/not_checked/simple/mask.rb +0 -21
  195. data/examples/legacy/not_checked/simple/slide.rb +0 -45
  196. data/examples/legacy/not_checked/simple/sphere.rb +0 -28
  197. data/lib/constants.rb +0 -5
  198. data/lib/scarpe/app.rb +0 -78
  199. data/lib/scarpe/document_root.rb +0 -20
  200. data/lib/scarpe/fill.rb +0 -23
  201. data/lib/scarpe/flow.rb +0 -19
  202. data/lib/scarpe/line.rb +0 -25
  203. data/lib/scarpe/logger.rb +0 -155
  204. data/lib/scarpe/shape.rb +0 -19
  205. data/lib/scarpe/spacing.rb +0 -9
  206. data/lib/scarpe/stack.rb +0 -70
  207. data/lib/scarpe/text_widget.rb +0 -42
  208. data/lib/scarpe/unit_test_helpers.rb +0 -163
  209. data/lib/scarpe/widgets.rb +0 -30
  210. data/lib/scarpe/wv/fill.rb +0 -30
  211. data/lib/scarpe/wv/shape_helper.rb +0 -44
  212. data/scarpe-0.2.0.gem +0 -0
  213. /data/{lib/scarpe → spikes}/glibui/README.md +0 -0
  214. /data/{lib/scarpe → spikes}/glibui/alert.rb +0 -0
  215. /data/{lib/scarpe → spikes}/glibui/app.rb +0 -0
  216. /data/{lib/scarpe → spikes}/glibui/background.rb +0 -0
  217. /data/{lib/scarpe → spikes}/glibui/border.rb +0 -0
  218. /data/{lib/scarpe → spikes}/glibui/button.rb +0 -0
  219. /data/{lib/scarpe → spikes}/glibui/dimensions.rb +0 -0
  220. /data/{lib/scarpe → spikes}/glibui/document_root.rb +0 -0
  221. /data/{lib/scarpe → spikes}/glibui/edit_box.rb +0 -0
  222. /data/{lib/scarpe → spikes}/glibui/edit_line.rb +0 -0
  223. /data/{lib/scarpe → spikes}/glibui/flow.rb +0 -0
  224. /data/{lib/scarpe → spikes}/glibui/html.rb +0 -0
  225. /data/{lib/scarpe → spikes}/glibui/image.rb +0 -0
  226. /data/{lib/scarpe → spikes}/glibui/link.rb +0 -0
  227. /data/{lib/scarpe → spikes}/glibui/local_display.rb +0 -0
  228. /data/{lib/scarpe → spikes}/glibui/para.rb +0 -0
  229. /data/{lib/scarpe → spikes}/glibui/spacing.rb +0 -0
  230. /data/{lib/scarpe → spikes}/glibui/stack.rb +0 -0
  231. /data/{lib/scarpe → spikes}/glibui/text_widget.rb +0 -0
  232. /data/{lib/scarpe → spikes}/libui/alert.rb +0 -0
  233. /data/{lib/scarpe → spikes}/libui/button.rb +0 -0
  234. /data/{lib/scarpe → spikes}/libui/colors.rb +0 -0
  235. /data/{lib/scarpe → spikes}/libui/core.rb +0 -0
  236. /data/{lib/scarpe → spikes}/libui/flow.rb +0 -0
  237. /data/{lib/scarpe → spikes}/libui/libui.rb +0 -0
  238. /data/{lib/scarpe → spikes}/libui/notepad.md +0 -0
  239. /data/{lib/scarpe → spikes}/libui/para.rb +0 -0
  240. /data/{lib/scarpe → spikes}/libui/stack.rb +0 -0
@@ -7,10 +7,16 @@
7
7
 
8
8
  require "json"
9
9
 
10
+ require "scarpe/components/unit_test_helpers"
11
+ require "scarpe/evented_assertions"
12
+
10
13
  class Scarpe
11
14
  DEFAULT_ASSERTION_TIMEOUT = 1.0
12
15
 
13
16
  class ControlInterface
17
+ include Scarpe::Test::EventedAssertions
18
+ include Scarpe::Test::Helpers
19
+
14
20
  def timed_out?
15
21
  @did_time_out
16
22
  end
@@ -44,32 +50,6 @@ class Scarpe
44
50
  data
45
51
  end
46
52
 
47
- # This does a final return of results. If it gets called
48
- # multiple times, the test fails because that's not okay.
49
- def return_results(result_bool, msg, data = {})
50
- result_file = ENV["SCARPE_TEST_RESULTS"] || "./scarpe_results.txt"
51
-
52
- result_structs = [result_bool, msg, data.merge(test_metadata)]
53
-
54
- # Multiple different sets of results is bad, even if both are passing.
55
- if @results_returned && @results_returned[0..1] != result_structs[0..1]
56
- # Just raising here doesn't reliably fail the test.
57
- # See: https://github.com/scarpe-team/scarpe/issues/212
58
- @log.error("Writing multi-result failure file to #{result_file.inspect}!")
59
-
60
- new_res_data = { first_result: @results_returned, second_result: result_structs }.merge(test_metadata)
61
- bad_result = [false, "Returned two sets of results!", new_res_data]
62
- File.write(result_file, JSON.pretty_generate(bad_result))
63
-
64
- return
65
- end
66
-
67
- @log.debug("Writing results file #{result_file.inspect} to disk!")
68
- File.write(result_file, JSON.pretty_generate(result_structs))
69
-
70
- @results_returned = result_structs
71
- end
72
-
73
53
  # Need to be able to query widgets in test code
74
54
 
75
55
  def all_wv_widgets
@@ -106,6 +86,11 @@ class Scarpe
106
86
  # We want an assertions library, but one that runs inside the spawned
107
87
  # Webview sub-process.
108
88
 
89
+ # Note that we do *not* extract this assertions library to use elsewhere
90
+ # because it's very focused on evented assertions that start and stop
91
+ # over a period of time. Instantaneous procedural asserts don't want to
92
+ # use this API.
93
+
109
94
  def return_when_assertions_done
110
95
  assertions_may_exist
111
96
 
@@ -218,8 +203,8 @@ class Scarpe
218
203
  end
219
204
  end
220
205
 
221
- # A Promise but with helper functions
222
- class TestPromise < Promise
206
+ # A {Scarpe::Promise} but with helper functions for Webview testing.
207
+ class TestPromise < Scarpe::Promise
223
208
  def initialize(iface:, state: nil, wait_for: [], &scheduler)
224
209
  @iface = iface
225
210
  super(state: state, parents: wait_for, &scheduler)
@@ -1,50 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Scarpe
4
- class WebviewDocumentRoot < Scarpe::WebviewWidget
5
- include Scarpe::WebviewBackground
6
-
7
- def initialize(properties)
8
- @callbacks = {}
9
-
10
- super
11
- end
12
-
13
- def element(&blck)
14
- HTML.render do |h|
15
- h.div(style: style.merge(height: "100%"), &blck)
16
- end
17
- end
18
-
19
- # Bind a Scarpe callback name; see Scarpe::Widget for how the naming is set up
20
- def bind(name, &block)
21
- @callbacks[name] = block
22
- end
23
-
24
- # All JS callbacks to Scarpe widgets are dispatched
25
- # via this handler, which is set up in Scarpe::App
26
- def handle_callback(name, *args)
27
- @callbacks[name].call(*args)
28
- end
29
-
30
- # The document root knows when a frame has finished. It registers end-of-frame callbacks and calls them
31
- # when requested. It also tracks when a redraw has been requested. Note that often frames will be
32
- # very rare if nothing is changing, with seconds or minutes passing in between them.
33
-
34
- def request_redraw!
35
- wrangler = WebviewDisplayService.instance.wrangler
36
- if wrangler.is_running
37
- wrangler.replace(self.to_html)
38
- end
39
- end
40
-
41
- # The document root manages the connection between widgets and the WebviewWrangler.
42
- # By centralising this and wrapping in API functions, we can keep from executing
43
- # random Javascript, mostly.
44
-
45
- # A Widget can request one or more of these as insertion points in the DOM
46
- def get_element_wrangler(html_id)
47
- Scarpe::WebWrangler::ElementWrangler.new(html_id)
48
- end
4
+ # A WebviewDocumentRoot is a WebviewFlow, with all the same properties
5
+ # and basic behavior.
6
+ class WebviewDocumentRoot < Scarpe::WebviewFlow
49
7
  end
50
8
  end
@@ -30,15 +30,13 @@ class Scarpe
30
30
  end
31
31
  end
32
32
 
33
- private
33
+ protected
34
34
 
35
35
  def style
36
- styles = {}
37
-
38
- styles[:height] = Dimensions.length(height)
39
- styles[:width] = Dimensions.length(width)
40
-
41
- styles.compact
36
+ super.merge({
37
+ height: Dimensions.length(height),
38
+ width: Dimensions.length(width),
39
+ }.compact)
42
40
  end
43
41
  end
44
42
  end
@@ -30,10 +30,10 @@ class Scarpe
30
30
  end
31
31
  end
32
32
 
33
- private
33
+ protected
34
34
 
35
35
  def style
36
- styles = {}
36
+ styles = super
37
37
 
38
38
  styles[:width] = Dimensions.length(@width) if @width
39
39
 
@@ -1,32 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Scarpe
4
- class WebviewFlow < Scarpe::WebviewWidget
5
- include Scarpe::WebviewBackground
6
- include Scarpe::WebviewBorder
7
-
4
+ class WebviewFlow < Scarpe::WebviewSlot
8
5
  def initialize(properties)
9
6
  super
10
7
  end
11
8
 
12
- def element(&block)
13
- HTML.render do |h|
14
- h.div(id: html_id, style:, &block)
15
- end
16
- end
17
-
18
- private
9
+ protected
19
10
 
20
11
  def style
21
- styles = super
22
-
23
- styles[:display] = "flex"
24
- styles["flex-direction"] = "row"
25
- styles["flex-wrap"] = "wrap"
26
- styles[:width] = Dimensions.length(@width) if @width
27
- styles[:height] = Dimensions.length(@height) if @height
28
-
29
- styles
12
+ {
13
+ display: "flex",
14
+ "flex-direction": "row",
15
+ "flex-wrap": "wrap",
16
+ "align-content": "flex-start",
17
+ "justify-content": "flex-start",
18
+ "align-items": "flex-start",
19
+ }.merge(super)
30
20
  end
31
21
  end
32
22
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "scarpe/components/base64"
4
+
5
+ class Scarpe
6
+ class WebviewFont < WebviewWidget
7
+ include Components::Base64
8
+ attr_accessor :font
9
+
10
+ def initialize(properties)
11
+ @font = properties[:font]
12
+ super
13
+ end
14
+
15
+ def font_name
16
+ File.basename(@font, ".*")
17
+ end
18
+
19
+ def element
20
+ HTML.render do |h|
21
+ h.link(href: @font, rel: "stylesheet")
22
+ h.style do
23
+ <<~CSS
24
+ @font-face {
25
+ font-family: #{font_name};
26
+ src: url("data:font/truetype;base64,#{encode_file_to_base64(@font)}") format('truetype');
27
+ }
28
+ * {
29
+ font-family: #{font_name};
30
+ }
31
+ CSS
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,8 +2,9 @@
2
2
 
3
3
  class Scarpe
4
4
  class HTML
5
- CONTENT_TAGS = [:div, :p, :button, :ul, :li, :textarea, :a, :strong, :em, :code, :u, :line, :span, :svg].freeze
6
- VOID_TAGS = [:input, :img, :polygon, :path].freeze
5
+ CONTENT_TAGS = [:div, :p, :button, :ul, :li, :textarea, :a, :video, :strong, :style, :em, :code, :u, :line, :span, :svg].freeze
6
+ VOID_TAGS = [:input, :img, :polygon, :source, :link, :path].freeze
7
+
7
8
  TAGS = (CONTENT_TAGS + VOID_TAGS).freeze
8
9
 
9
10
  class << self
@@ -1,9 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "scarpe/components/base64"
4
+
3
5
  class Scarpe
4
6
  class WebviewImage < WebviewWidget
7
+ include Components::Base64
5
8
  def initialize(properties)
6
9
  super
10
+
11
+ @url = valid_url?(@url) ? @url : "data:image/png;base64,#{encode_file_to_base64(@url)}"
7
12
  end
8
13
 
9
14
  def element
@@ -18,10 +23,10 @@ class Scarpe
18
23
  end
19
24
  end
20
25
 
21
- private
26
+ protected
22
27
 
23
28
  def style
24
- styles = {}
29
+ styles = super
25
30
 
26
31
  styles[:width] = Dimensions.length(@width) if @width
27
32
  styles[:height] = Dimensions.length(@height) if @height
@@ -1,10 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "shape_helper"
4
3
  class Scarpe
5
4
  class WebviewLine < Scarpe::WebviewWidget
6
- include ShapeHelper
7
-
8
5
  def initialize(properties)
9
6
  super(properties)
10
7
  end
@@ -19,18 +16,18 @@ class Scarpe
19
16
  end
20
17
  end
21
18
 
22
- private
19
+ protected
23
20
 
24
21
  def style
25
- {
22
+ super.merge({
26
23
  left: "#{@left}px",
27
24
  top: "#{@top}px",
28
- }
25
+ })
29
26
  end
30
27
 
31
28
  def line_style
32
29
  {
33
- stroke: " #{@color}",
30
+ stroke: @draw_context["stroke"],
34
31
  "stroke-width": "4",
35
32
  }
36
33
  end
@@ -23,6 +23,7 @@ class Scarpe
23
23
  id: html_id,
24
24
  href: @click,
25
25
  onclick: (handler_js_code("click") if @has_block),
26
+ style: style,
26
27
  }.compact
27
28
  end
28
29
  end
@@ -36,15 +36,15 @@ class Scarpe
36
36
  end
37
37
  end
38
38
 
39
- private
39
+ protected
40
40
 
41
41
  def style
42
- styles = {}
42
+ styles = super
43
43
 
44
44
  styles[:height] = Dimensions.length(height) if height
45
45
  styles[:width] = Dimensions.length(width) if width
46
46
 
47
- styles.compact
47
+ styles
48
48
  end
49
49
  end
50
50
  end
@@ -57,6 +57,22 @@ class Scarpe
57
57
  element { child_markup }
58
58
  end
59
59
 
60
+ protected
61
+
62
+ def style
63
+ super.merge({
64
+ color: rgb_to_hex(@stroke),
65
+ "font-size": font_size,
66
+ "font-family": @font,
67
+ }.compact)
68
+ end
69
+
70
+ def font_size
71
+ font_size = @size.is_a?(Symbol) ? SIZES[@size] : @size
72
+
73
+ Dimensions.length(font_size)
74
+ end
75
+
60
76
  private
61
77
 
62
78
  def child_markup
@@ -72,19 +88,5 @@ class Scarpe
72
88
  def options
73
89
  @html_attributes.merge(id: html_id, style: style)
74
90
  end
75
-
76
- def style
77
- {
78
- "color" => rgb_to_hex(@stroke),
79
- "font-size" => font_size,
80
- "font-family" => @font,
81
- }.compact
82
- end
83
-
84
- def font_size
85
- font_size = @size.is_a?(Symbol) ? SIZES[@size] : @size
86
-
87
- Dimensions.length(font_size)
88
- end
89
91
  end
90
92
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Scarpe
4
+ class WebviewRadio < Scarpe::WebviewWidget
5
+ attr_reader :text
6
+
7
+ def initialize(properties)
8
+ super
9
+
10
+ bind("click") do
11
+ send_self_event(event_name: "click", target: shoes_linkable_id)
12
+ end
13
+ end
14
+
15
+ def properties_changed(changes)
16
+ items = changes.delete("checked")
17
+ html_element.toggle_input_button(items)
18
+
19
+ super
20
+ end
21
+
22
+ def element
23
+ HTML.render do |h|
24
+ h.input(type: :radio, id: html_id, onclick: handler_js_code("click"), name: group_name, value: "hmm #{text}", checked: @checked, style: style)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def group_name
31
+ @group || @parent
32
+ end
33
+ end
34
+ end
@@ -1,21 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "shape_helper"
4
-
5
3
  class Scarpe
4
+ # Should inherit from Slot?
6
5
  class WebviewShape < Scarpe::WebviewWidget
7
- include ShapeHelper
8
-
9
6
  def initialize(properties)
10
- @color = color_for_fill
11
7
  super(properties)
12
8
  end
13
9
 
10
+ def to_html
11
+ @children ||= []
12
+ child_markup = @children.map(&:to_html).join
13
+
14
+ color = @draw_context["fill"] || "black"
15
+ self_markup = HTML.render do |h|
16
+ h.div(id: html_id, style: style) do
17
+ h.svg(width: "400", height: "500") do
18
+ h.path(d: path_from_shape_commands, style: "fill:#{color};stroke-width:2;")
19
+ end
20
+ end
21
+ end
22
+
23
+ # Put child markup first for backward compatibility, but I'm pretty sure this is wrong.
24
+ child_markup + self_markup
25
+ end
26
+
14
27
  def element(&block)
28
+ color = @draw_context["fill"] || "black"
15
29
  HTML.render do |h|
16
30
  h.div(id: html_id, style: style) do
17
31
  h.svg(width: "400", height: "500") do
18
- h.path(d: shape_path, style: "fill:#{@color};stroke-width:2;")
32
+ h.path(d: path_from_shape_commands, style: "fill:#{color};stroke-width:2;")
19
33
  end
20
34
  block.call(h) if block_given?
21
35
  end
@@ -24,11 +38,33 @@ class Scarpe
24
38
 
25
39
  private
26
40
 
41
+ # We have a set of Shoes shape commands, but we need SVG objects like paths.
42
+ def path_from_shape_commands
43
+ current_path = ""
44
+
45
+ @shape_commands.each do |cmd, *args|
46
+ case cmd
47
+ when "move_to"
48
+ x, y = *args
49
+ current_path += "M #{x} #{y} "
50
+ when "line_to"
51
+ x, y = *args
52
+ current_path += "L #{x} #{y} "
53
+ else
54
+ raise "Unknown shape command! #{cmd.inspect}"
55
+ end
56
+ end
57
+
58
+ current_path
59
+ end
60
+
61
+ protected
62
+
27
63
  def style
28
- {
64
+ super.merge({
29
65
  width: "400",
30
66
  height: "900",
31
- }
67
+ })
32
68
  end
33
69
  end
34
70
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Scarpe
4
+ class WebviewSlot < Scarpe::WebviewWidget
5
+ include Scarpe::WebviewBackground
6
+ include Scarpe::WebviewBorder
7
+ include Scarpe::WebviewSpacing
8
+
9
+ def initialize(properties)
10
+ @event_callbacks = {}
11
+
12
+ super
13
+ end
14
+
15
+ def element(&block)
16
+ HTML.render do |h|
17
+ h.div(attributes.merge(id: html_id, style: style), &block)
18
+ end
19
+ end
20
+
21
+ def set_event_callback(obj, event_name, js_code)
22
+ event_name = event_name.to_s
23
+ @event_callbacks[event_name] ||= {}
24
+ if @event_callbacks[event_name][obj]
25
+ raise "Can't have two callbacks on the same event, from the same object, on the same parent!"
26
+ end
27
+
28
+ @event_callbacks[event_name][obj] = js_code
29
+
30
+ update_dom_event(event_name)
31
+ end
32
+
33
+ def remove_event_callback(obj, event_name)
34
+ event_name = event_name.to_s
35
+ @event_callbacks[event_name] ||= {}
36
+ @event_callbacks[event_name].delete(obj)
37
+
38
+ update_dom_event(event_name)
39
+ end
40
+
41
+ def remove_event_callbacks(obj)
42
+ changed = []
43
+
44
+ @event_callbacks.each do |event_name, items|
45
+ changed << event_name if items.delete(obj)
46
+ end
47
+
48
+ changed.each { |event_name| update_dom_event(event_name) }
49
+ end
50
+
51
+ protected
52
+
53
+ def update_dom_event(event_name)
54
+ html_element.set_attribute(event_name, @event_callbacks[event_name].values.join(";"))
55
+ end
56
+
57
+ def attributes
58
+ attr = {}
59
+
60
+ @event_callbacks.each do |event_name, handlers|
61
+ attr[event_name] = handlers.values.join(";")
62
+ end
63
+
64
+ attr
65
+ end
66
+
67
+ def style
68
+ styles = super
69
+
70
+ styles[:"margin-top"] = @margin_top if @margin_top
71
+ styles[:"margin-bottom"] = @margin_bottom if @margin_bottom
72
+ styles[:"margin-left"] = @margin_left if @margin_left
73
+ styles[:"margin-right"] = @margin_right if @margin_right
74
+
75
+ styles[:width] = Dimensions.length(@width) if @width
76
+ styles[:height] = Dimensions.length(@height) if @height
77
+
78
+ styles
79
+ end
80
+ end
81
+ end
@@ -5,7 +5,7 @@ class Scarpe
5
5
  SPACING_DIRECTIONS = [:left, :right, :top, :bottom]
6
6
 
7
7
  def style
8
- styles = (super if defined?(super)) || {}
8
+ styles = defined?(super) ? super : {}
9
9
 
10
10
  extract_spacing_styles_for(:margin, styles, @margin)
11
11
  extract_spacing_styles_for(:padding, styles, @padding)
@@ -43,20 +43,22 @@ class Scarpe
43
43
  element { @text }
44
44
  end
45
45
 
46
- private
47
-
48
- def options
49
- @html_attributes.merge(id: html_id, style: style)
50
- end
46
+ protected
51
47
 
52
48
  def style
53
49
  {
54
- "color" => @stroke,
55
- "font-size" => font_size,
56
- "font-family" => @font,
50
+ color: @stroke,
51
+ "font-size": font_size,
52
+ "font-family": @font,
57
53
  }.compact
58
54
  end
59
55
 
56
+ private
57
+
58
+ def options
59
+ @html_attributes.merge(id: html_id, style: style)
60
+ end
61
+
60
62
  def font_size
61
63
  font_size = @size.is_a?(Symbol) ? SIZES[@size] : @size
62
64
 
@@ -1,42 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Scarpe
4
- class WebviewStack < Scarpe::WebviewWidget
5
- include Scarpe::WebviewBackground
6
- include Scarpe::WebviewBorder
7
- include Scarpe::WebviewSpacing
8
-
9
- def initialize(properties)
10
- super
11
- end
12
-
13
- def element(&block)
14
- HTML.render do |h|
15
- h.div(id: html_id, style: style, &block)
16
- end
17
- end
18
-
4
+ class WebviewStack < Scarpe::WebviewSlot
19
5
  def get_style
20
6
  style
21
7
  end
22
8
 
23
- private
9
+ protected
24
10
 
25
11
  def style
26
- styles = super
27
-
28
- styles["margin-top"] = @margin_top if @margin_top
29
- styles["margin-bottom"] = @margin_bottom if @margin_bottom
30
- styles["margin-left"] = @margin_left if @margin_left
31
- styles["margin-right"] = @margin_right if @margin_right
32
-
33
- styles[:display] = "flex"
34
- styles["flex-direction"] = "column"
35
- styles[:width] = Dimensions.length(@width) if @width
36
- styles[:height] = Dimensions.length(@height) if @height
37
- styles["overflow"] = "auto" if @scroll
38
-
39
- styles
12
+ {
13
+ display: "flex",
14
+ "flex-direction": "column",
15
+ "align-content": "flex-start",
16
+ "justify-content": "flex-start",
17
+ "align-items": "flex-start",
18
+ overflow: @scroll ? "auto" : nil,
19
+ }.compact.merge(super)
40
20
  end
41
21
  end
42
22
  end