scarpe 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shoes
4
+ class Widget
5
+ class ResponseWrapper
6
+ attr_reader :response
7
+
8
+ def initialize(response)
9
+ @response = response
10
+ end
11
+
12
+ def headers
13
+ @response.each_header.to_h
14
+ end
15
+
16
+ def body
17
+ @response.body
18
+ end
19
+ end
20
+
21
+ def download(url, method: "GET", save: nil, styles: {}, &block)
22
+ require "net/http"
23
+ require "openssl"
24
+ require "nokogiri"
25
+
26
+ @block = block
27
+
28
+ Thread.new do
29
+ logger = Shoes::Log.logger("Shoes::App#download")
30
+ begin
31
+ uri = URI(url)
32
+ response = perform_request(uri, method, styles)
33
+
34
+ if response.is_a?(Net::HTTPRedirection)
35
+ new_location = response["location"]
36
+ new_uri = URI(new_location)
37
+ response = perform_request(new_uri, method, styles)
38
+ end
39
+
40
+ wrapped_response = ResponseWrapper.new(response) # Wrap the response
41
+ handle_response(wrapped_response, save, styles)
42
+ rescue Net::HTTPError, Net::OpenTimeout, Net::ReadTimeout => e
43
+ handle_error(e, logger)
44
+ rescue StandardError => e
45
+ handle_error(e.message, logger) # Pass the error message as a string
46
+ end
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def perform_request(uri, method, styles)
53
+ port = uri.port || (uri.scheme == "https" ? 443 : 80)
54
+ http = Net::HTTP.start(uri.host, port, use_ssl: uri.scheme == "https", verify_mode: OpenSSL::SSL::VERIFY_NONE)
55
+
56
+ request = Net::HTTP.const_get(method.capitalize).new(uri.request_uri)
57
+ apply_styles(request, styles)
58
+
59
+ http.request(request)
60
+ end
61
+
62
+ def apply_styles(request, styles)
63
+ headers = styles[:headers]
64
+ request["Content-Type"] = headers["Content-Type"] if headers && headers["Content-Type"]
65
+ request.body = styles[:body] if styles[:body]
66
+ # Add more custom styles to the request as needed
67
+ end
68
+
69
+ def handle_response(response, save, styles)
70
+ case response.response.code.to_i
71
+ when 200..299
72
+ content = response.body
73
+ # headers = response.headers # Access headers directly
74
+ if save
75
+ save_content(content, save)
76
+ parse_rss(content) # Parse the downloaded XML content
77
+ else
78
+ handle_finish_event(response) # Pass response and headers to handle_finish_event
79
+ end
80
+ else
81
+ handle_failure(response.response.code)
82
+ end
83
+ end
84
+
85
+ def save_content(content, file_name)
86
+ file = nil
87
+ begin
88
+ file = File.open(file_name, "w")
89
+ file.write(content)
90
+ rescue Errno::EACCES, Errno::ENOENT => e
91
+ raise FileError, "File error occurred: #{e.message}"
92
+ else
93
+ @block&.call
94
+ ensure
95
+ file&.close
96
+ end
97
+ end
98
+
99
+ def handle_finish_event(response)
100
+ passed = Struct.new(:response).new(response) # Create a new Struct with response attribute
101
+ @block&.call(passed) # Pass it ok
102
+ end
103
+
104
+ def handle_failure(code, logger)
105
+ logger.error("Failed to download content. Response code: #{code}")
106
+ end
107
+
108
+ def handle_error(error, logger)
109
+ logger.error("An error occurred while downloading: #{error}")
110
+ end
111
+
112
+ def parse_rss(content)
113
+ doc = Nokogiri::XML(content)
114
+ items = doc.xpath("//item")
115
+ items.each do |item|
116
+ item.xpath("title").text
117
+ item.xpath("link").text
118
+ item.xpath("description").text
119
+ # Do something with the parsed content or use it if needed
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Old-style Shoes logging is really simple. We need more logging for our
4
+ # framework, so we add a not-included-in-old-Shoes module for it. This adds
5
+ # the *possibility* of logging, but Scarpe includes a much more
6
+ # comprehensive solution that plugs into this one.
7
+
8
+ # If used alone, this will fail because the @instance is nil. It needs
9
+ # an implementation to be plugged in.
10
+
11
+ module Shoes
12
+ LOG_LEVELS = [:debug, :info, :warn, :error, :fatal].freeze
13
+
14
+ # Include this module to get a @log instance variable to log as your
15
+ # configured component.
16
+ module Log
17
+ # These constants will wind up included in a lot of places. Should they move?
18
+ DEFAULT_COMPONENT = "default"
19
+ DEFAULT_LOG_CONFIG = {
20
+ "default" => "info",
21
+ }
22
+ DEFAULT_DEBUG_LOG_CONFIG = {
23
+ "default" => "debug",
24
+ }
25
+
26
+ class << self
27
+ attr_reader :instance
28
+ attr_reader :current_log_config
29
+
30
+ def instance=(impl_object)
31
+ raise(Shoes::Error, "Already have an instance for Shoes::Log!") if @instance
32
+
33
+ @instance = impl_object
34
+ end
35
+
36
+ def logger(component = self)
37
+ @instance.logger_for_component(component)
38
+ end
39
+
40
+ def configure_logger(log_config)
41
+ @instance.configure_logger(log_config)
42
+ end
43
+ end
44
+
45
+ def log_init(component = self)
46
+ @log = Shoes::Log.instance.logger_for_component(component)
47
+ end
48
+ end
49
+
50
+ class LoggedWrapper
51
+ include ::Shoes::Log
52
+ def initialize(instance, component = instance)
53
+ log_init(component)
54
+
55
+ @instance = instance
56
+ end
57
+
58
+ def method_missing(method, ...)
59
+ self.singleton_class.define_method(method) do |*args, **kwargs, &block|
60
+ ret = @instance.send(method, *args, **kwargs, &block)
61
+ @log.info("Method: #{method} Args: #{args.inspect} KWargs: #{kwargs.inspect} Block: #{block ? "y" : "n"} Return: #{ret.inspect}")
62
+ ret
63
+ end
64
+ send(method, ...)
65
+ end
66
+
67
+ def respond_to_missing?(method_name, include_private = false)
68
+ @instance.respond_to_missing?(method_name, include_private)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shoes
4
+ module Spacing
5
+ def self.included(includer)
6
+ includer.display_properties :margin, :padding, :margin_top, :margin_left, :margin_right, :margin_bottom, :options
7
+ end
8
+ end
9
+ end
@@ -1,26 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Scarpe::Widget
4
- #
5
- # Interface:
6
- # A Scarpe::Widget defines the "element" method to indicate that it has custom markup of
7
- # some kind. A Widget with no element method renders as its children's markup, joined.
8
-
9
- class Scarpe
10
- class Widget < DisplayService::Linkable
11
- include Scarpe::Log
12
- include Scarpe::Colors
3
+ module Shoes
4
+ # Shoes::Widget
5
+ #
6
+ # This is the display-service portable Shoes Widget interface. Visible Shoes
7
+ # widgets like buttons inherit from this. Compound widgets made of multiple
8
+ # different smaller Widgets inherit from it in their various apps or libraries.
9
+ # The Shoes Widget helps build a Shoes-side widget tree, with parents and
10
+ # children. Any API that applies to all widgets (e.g. remove) should be
11
+ # defined here.
12
+ #
13
+ class Widget < Shoes::Linkable
14
+ include Shoes::Log
15
+ include Shoes::Colors
13
16
 
14
17
  class << self
15
- attr_accessor :widget_classes, :alias_name
16
-
17
- def alias_as(name)
18
- self.alias_name = name
19
- end
18
+ attr_accessor :widget_classes
20
19
 
21
20
  def inherited(subclass)
22
- self.widget_classes ||= []
23
- self.widget_classes << subclass
21
+ Shoes::Widget.widget_classes ||= []
22
+ Shoes::Widget.widget_classes << subclass
24
23
  super
25
24
  end
26
25
 
@@ -30,7 +29,7 @@ class Scarpe
30
29
  end
31
30
 
32
31
  def widget_class_by_name(name)
33
- widget_classes.detect { |k| k.dsl_name == name.to_s || k.alias_name.to_s == name.to_s }
32
+ widget_classes.detect { |k| k.dsl_name == name.to_s }
34
33
  end
35
34
 
36
35
  private
@@ -56,19 +55,26 @@ class Scarpe
56
55
  linkable_properties_hash[name] = true
57
56
  end
58
57
 
58
+ # Add these names as display properties
59
59
  def display_properties(*names)
60
60
  names.each { |n| display_property(n) }
61
61
  end
62
62
 
63
63
  def display_property_names
64
- linkable_properties.map { |prop| prop[:name] }
64
+ parent_prop_names = self != Shoes::Widget ? self.superclass.display_property_names : []
65
+
66
+ parent_prop_names | linkable_properties.map { |prop| prop[:name] }
65
67
  end
66
68
 
67
69
  def display_property_name?(name)
68
- linkable_properties_hash[name.to_s]
70
+ linkable_properties_hash[name.to_s] ||
71
+ (self != Shoes::Widget && superclass.display_property_name?(name))
69
72
  end
70
73
  end
71
74
 
75
+ # Shoes uses a "hidden" style property for hide/show
76
+ display_property :hidden
77
+
72
78
  def initialize(*args, **kwargs)
73
79
  log_init("Widget")
74
80
 
@@ -81,6 +87,14 @@ class Scarpe
81
87
  super() # linkable_id defaults to object_id
82
88
  end
83
89
 
90
+ def inspect
91
+ "#<#{self.class}:#{self.object_id} " +
92
+ "@linkable_id=#{@linkable_id.inspect} @parent=#{@parent.inspect} " +
93
+ "@children=#{@children.inspect} properties=#{display_property_values.inspect}>"
94
+ end
95
+
96
+ private
97
+
84
98
  def bind_self_event(event_name, &block)
85
99
  raise("Widget has no linkable_id! #{inspect}") unless linkable_id
86
100
 
@@ -91,24 +105,31 @@ class Scarpe
91
105
  bind_shoes_event(event_name:, &block)
92
106
  end
93
107
 
94
- def display_properties
108
+ public
109
+
110
+ def display_property_values
111
+ all_property_names = self.class.display_property_names
112
+
95
113
  properties = {}
96
- self.class.display_property_names.each do |prop|
114
+ all_property_names.each do |prop|
97
115
  properties[prop] = instance_variable_get("@" + prop)
98
116
  end
99
117
  properties["shoes_linkable_id"] = self.linkable_id
100
118
  properties
101
119
  end
102
120
 
121
+ private
122
+
103
123
  def create_display_widget
104
124
  klass_name = self.class.name.delete_prefix("Scarpe::").delete_prefix("Shoes::")
105
125
 
106
126
  # Should we save a reference to widget for later reference?
107
- DisplayService.display_service.create_display_widget_for(klass_name, self.linkable_id, display_properties)
127
+ ::Shoes::DisplayService.display_service.create_display_widget_for(klass_name, self.linkable_id, display_property_values)
108
128
  end
109
129
 
130
+ public
131
+
110
132
  attr_reader :parent
111
- attr_reader :children
112
133
 
113
134
  def set_parent(new_parent)
114
135
  @parent&.remove_child(self)
@@ -117,28 +138,27 @@ class Scarpe
117
138
  send_shoes_event(new_parent.linkable_id, event_name: "parent", target: linkable_id)
118
139
  end
119
140
 
120
- # Do not call directly, use set_parent
121
- def remove_child(child)
122
- @children ||= []
123
- unless @children.include?(child)
124
- @log.warn("remove_child: no such child(#{child.inspect}) for parent(#{parent.inspect})!")
125
- end
126
- @children.delete(child)
141
+ # Removes the element from the Shoes::Widget tree
142
+ def destroy
143
+ @parent&.remove_child(self)
144
+ send_shoes_event(event_name: "destroy", target: linkable_id)
127
145
  end
146
+ alias_method :remove, :destroy
128
147
 
129
- # Do not call directly, use set_parent
130
- def add_child(child)
131
- @children ||= []
132
- @children << child
148
+ # Hide the widget.
149
+ def hide
150
+ self.hidden = true
133
151
  end
134
152
 
135
- # Removes the element from the Scarpe::Widget tree
136
- def destroy
137
- @parent&.remove_child(self)
138
- send_shoes_event(event_name: "destroy", target: linkable_id)
153
+ # Show the widget.
154
+ def show
155
+ self.hidden = false
139
156
  end
140
157
 
141
- alias_method :destroy_self, :destroy
158
+ # Hide the widget if it is currently shown. Show it if it is currently hidden.
159
+ def toggle
160
+ self.hidden = !self.hidden
161
+ end
142
162
 
143
163
  # We use method_missing for widget-creating methods like "button",
144
164
  # and also to auto-create display-property getters and setters.
@@ -172,12 +192,12 @@ class Scarpe
172
192
  klass = Widget.widget_class_by_name(name)
173
193
  return super unless klass
174
194
 
175
- ::Scarpe::Widget.define_method(name) do |*args, **kwargs, &block|
195
+ ::Shoes::Widget.define_method(name) do |*args, **kwargs, &block|
176
196
  # Look up the Shoes widget and create it...
177
197
  widget_instance = klass.new(*args, **kwargs, &block)
178
198
 
179
- unless klass.ancestors.include?(Scarpe::TextWidget)
180
- widget_instance.set_parent(self)
199
+ unless klass.ancestors.include?(Shoes::TextWidget)
200
+ widget_instance.set_parent Shoes::App.instance.current_slot
181
201
  end
182
202
 
183
203
  widget_instance
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Scarpe
4
- class Alert < Scarpe::Widget
3
+ module Shoes
4
+ class Alert < Shoes::Widget
5
5
  display_property :text
6
6
 
7
7
  def initialize(text)
@@ -10,7 +10,7 @@ class Scarpe
10
10
  super
11
11
 
12
12
  bind_self_event("click") do
13
- destroy_self
13
+ remove
14
14
  end
15
15
 
16
16
  create_display_widget
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Scarpe
4
- class InvalidAttributeValueError < Scarpe::Error; end
3
+ module Shoes
4
+ class InvalidAttributeValueError < Shoes::Error; end
5
5
 
6
- class Arc < Scarpe::Widget
7
- display_properties :left, :top, :width, :height, :angle1, :angle2
6
+ class Arc < Shoes::Widget
7
+ display_properties :left, :top, :width, :height, :angle1, :angle2, :draw_context
8
8
 
9
9
  def initialize(*args)
10
10
  @left, @top, @width, @height, @angle1, @angle2 = args
@@ -16,7 +16,9 @@ class Scarpe
16
16
  @angle1 = convert_to_float(@angle1, "angle1")
17
17
  @angle2 = convert_to_float(@angle2, "angle2")
18
18
 
19
- super()
19
+ @draw_context = Shoes::App.instance.current_draw_context
20
+
21
+ super
20
22
  create_display_widget
21
23
  end
22
24
 
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Scarpe
4
- class Button < Scarpe::Widget
5
- include Scarpe::Log
3
+ module Shoes
4
+ class Button < Shoes::Widget
5
+ include Shoes::Log
6
6
  display_properties :text, :width, :height, :top, :left, :color, :padding_top, :padding_bottom, :text_color, :size, :font_size
7
7
 
8
8
  def initialize(text, width: nil, height: nil, top: nil, left: nil, color: nil, padding_top: nil, padding_bottom: nil, size: 12, text_color: nil,
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shoes
4
+ class Check < Shoes::Widget
5
+ display_properties :checked
6
+
7
+ def initialize(checked = nil, &block)
8
+ @block = block
9
+ super
10
+
11
+ bind_self_event("click") { click }
12
+ create_display_widget
13
+ end
14
+
15
+ def click(&block)
16
+ @block = block
17
+ self.checked = !checked?
18
+ end
19
+
20
+ def checked?
21
+ @checked ? true : false
22
+ end
23
+
24
+ def checked(value)
25
+ self.checked = value
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shoes
4
+ class DocumentRoot < Shoes::Flow
5
+ def initialize
6
+ @height = "100%"
7
+ @width = @margin = @padding = nil
8
+ @options = {}
9
+
10
+ super
11
+
12
+ create_display_widget
13
+ end
14
+
15
+ # The default inspect string can be absolutely huge in console output, and it's frequently printed.
16
+ def inspect
17
+ "<Shoes::DocumentRoot>"
18
+ end
19
+ end
20
+ end
@@ -1,17 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Scarpe
4
- class EditBox < Scarpe::Widget
3
+ module Shoes
4
+ class EditBox < Shoes::Widget
5
5
  display_properties :text, :height, :width
6
6
 
7
- def initialize(text = nil, height: nil, width: nil, &block)
8
- @text = text.nil? ? block&.call : text || ""
7
+ def initialize(text = "", height: nil, width: nil, &block)
8
+ @text = text
9
+ @callback = block
9
10
 
10
11
  super
11
12
 
12
13
  bind_self_event("change") do |new_text|
13
14
  self.text = new_text
14
- @callback&.call(new_text)
15
+ @callback&.call(self)
15
16
  end
16
17
 
17
18
  create_display_widget
@@ -20,5 +21,9 @@ class Scarpe
20
21
  def change(&block)
21
22
  @callback = block
22
23
  end
24
+
25
+ def append(new_text)
26
+ self.text = self.text + new_text
27
+ end
23
28
  end
24
29
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Scarpe
4
- class EditLine < Scarpe::Widget
3
+ module Shoes
4
+ class EditLine < Shoes::Widget
5
5
  display_properties :text, :width
6
6
 
7
7
  def initialize(text = "", width: nil, &block)
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shoes
4
+ class Flow < Shoes::Slot
5
+ include Shoes::Background
6
+ include Shoes::Border
7
+ include Shoes::Spacing
8
+
9
+ display_properties :width, :height, :margin, :padding
10
+
11
+ def initialize(width: "100%", height: nil, margin: nil, padding: nil, **options, &block)
12
+ @options = options
13
+
14
+ super
15
+
16
+ # Create the display-side widget *before* instance_eval, which will add child widgets with their display widgets
17
+ create_display_widget
18
+
19
+ Shoes::App.instance.with_slot(self, &block) if block_given?
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shoes
4
+ class Font < Shoes::Widget
5
+ display_properties :font
6
+
7
+ def initialize(font)
8
+ @font = font
9
+ super
10
+
11
+ create_display_widget
12
+ end
13
+ end
14
+ end
@@ -1,10 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fastimage"
4
- require "open-uri"
5
-
6
- class Scarpe
7
- class Image < Scarpe::Widget
3
+ module Shoes
4
+ class Image < Shoes::Widget
8
5
  display_properties :url, :width, :height, :top, :left, :click
9
6
 
10
7
  def initialize(url, width: nil, height: nil, top: nil, left: nil, click: nil)
@@ -21,10 +18,9 @@ class Scarpe
21
18
  def replace(url)
22
19
  self.url = url
23
20
  end
24
- end
25
21
 
26
- class Widget
27
22
  def size
23
+ require "fastimage"
28
24
  width, height = FastImage.size(@url)
29
25
 
30
26
  [width, height]
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shoes
4
+ class Line < Shoes::Widget
5
+ display_properties :left, :top, :x2, :y2, :draw_context
6
+
7
+ def initialize(left, top, x2, y2)
8
+ @left = left
9
+ @top = top
10
+ @x2 = x2
11
+ @y2 = y2
12
+ @draw_context = Shoes::App.instance.current_draw_context
13
+
14
+ super
15
+ create_display_widget
16
+ end
17
+ end
18
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Scarpe
4
- class Link < Scarpe::TextWidget
3
+ module Shoes
4
+ class Link < Shoes::TextWidget
5
5
  display_properties :text, :click, :has_block
6
6
 
7
7
  def initialize(text, click: nil, &block)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Scarpe
4
- class ListBox < Scarpe::Widget
3
+ module Shoes
4
+ class ListBox < Shoes::Widget
5
5
  display_properties :selected_item, :items, :height, :width
6
6
 
7
7
  def initialize(args = {}, &block)