lacci 0.2.2 → 0.3.0

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +8 -1
  4. data/lib/lacci/scarpe_cli.rb +2 -1
  5. data/lib/lacci/scarpe_core.rb +2 -1
  6. data/lib/lacci/version.rb +1 -1
  7. data/lib/scarpe/niente/app.rb +23 -0
  8. data/lib/scarpe/niente/display_service.rb +62 -0
  9. data/lib/scarpe/niente/drawable.rb +57 -0
  10. data/lib/scarpe/niente/logger.rb +29 -0
  11. data/lib/scarpe/niente/shoes_spec.rb +87 -0
  12. data/lib/scarpe/niente.rb +20 -0
  13. data/lib/shoes/app.rb +88 -43
  14. data/lib/shoes/background.rb +2 -2
  15. data/lib/shoes/border.rb +2 -2
  16. data/lib/shoes/builtins.rb +63 -0
  17. data/lib/shoes/changelog.rb +52 -0
  18. data/lib/shoes/colors.rb +3 -1
  19. data/lib/shoes/constants.rb +19 -1
  20. data/lib/shoes/display_service.rb +39 -16
  21. data/lib/shoes/download.rb +2 -2
  22. data/lib/shoes/drawable.rb +380 -0
  23. data/lib/shoes/drawables/arc.rb +49 -0
  24. data/lib/shoes/drawables/arrow.rb +41 -0
  25. data/lib/shoes/drawables/button.rb +73 -0
  26. data/lib/shoes/{widgets → drawables}/check.rb +5 -4
  27. data/lib/shoes/{widgets → drawables}/document_root.rb +3 -3
  28. data/lib/shoes/{widgets → drawables}/edit_box.rb +6 -6
  29. data/lib/shoes/{widgets → drawables}/edit_line.rb +6 -6
  30. data/lib/shoes/{widgets → drawables}/flow.rb +6 -6
  31. data/lib/shoes/{widgets → drawables}/image.rb +6 -6
  32. data/lib/shoes/{widgets → drawables}/line.rb +7 -5
  33. data/lib/shoes/drawables/link.rb +34 -0
  34. data/lib/shoes/drawables/list_box.rb +56 -0
  35. data/lib/shoes/drawables/para.rb +118 -0
  36. data/lib/shoes/drawables/progress.rb +14 -0
  37. data/lib/shoes/drawables/radio.rb +33 -0
  38. data/lib/shoes/drawables/rect.rb +17 -0
  39. data/lib/shoes/{widgets → drawables}/shape.rb +6 -7
  40. data/lib/shoes/{widgets → drawables}/slot.rb +32 -20
  41. data/lib/shoes/{widgets → drawables}/span.rb +8 -7
  42. data/lib/shoes/{widgets → drawables}/stack.rb +6 -4
  43. data/lib/shoes/drawables/star.rb +50 -0
  44. data/lib/shoes/drawables/subscription_item.rb +93 -0
  45. data/lib/shoes/drawables/text_drawable.rb +63 -0
  46. data/lib/shoes/drawables/video.rb +16 -0
  47. data/lib/shoes/drawables/widget.rb +69 -0
  48. data/lib/shoes/drawables.rb +31 -0
  49. data/lib/shoes/errors.rb +28 -0
  50. data/lib/shoes/log.rb +2 -2
  51. data/lib/shoes/ruby_extensions.rb +15 -0
  52. data/lib/shoes/spacing.rb +2 -2
  53. data/lib/shoes-spec.rb +93 -0
  54. data/lib/shoes.rb +27 -7
  55. metadata +55 -28
  56. data/lib/shoes/widget.rb +0 -218
  57. data/lib/shoes/widgets/alert.rb +0 -19
  58. data/lib/shoes/widgets/arc.rb +0 -51
  59. data/lib/shoes/widgets/button.rb +0 -35
  60. data/lib/shoes/widgets/font.rb +0 -14
  61. data/lib/shoes/widgets/link.rb +0 -25
  62. data/lib/shoes/widgets/list_box.rb +0 -25
  63. data/lib/shoes/widgets/para.rb +0 -68
  64. data/lib/shoes/widgets/radio.rb +0 -35
  65. data/lib/shoes/widgets/star.rb +0 -44
  66. data/lib/shoes/widgets/subscription_item.rb +0 -60
  67. data/lib/shoes/widgets/text_widget.rb +0 -51
  68. data/lib/shoes/widgets/video.rb +0 -15
  69. data/lib/shoes/widgets.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aab735aab6fb64d87496b2ebefac1235a3858b1e14f176a2b165bf0c82c10260
4
- data.tar.gz: 961b0b461164093bf51bf2ab7f79ae95e626a561548c7421bdcc75efe199e4e1
3
+ metadata.gz: e32d4245e4dc24e8098d8626ca2ad9ba7d4417b6e392d0c0d43c1b003dece24e
4
+ data.tar.gz: dea4cd304311e63c498e2c679e8d61ec9b550c56c5a87d33bb4c7b499a08b875
5
5
  SHA512:
6
- metadata.gz: 3e3bffa1f9f822b082ed7268458f0a93c49614a3b6169f4648fe57c126d77a4131d5113a15ca2a7421fe3271746ba36eb10faed83a326c4eb9514ec0447eaecf
7
- data.tar.gz: 7f2c9d2e4672faea8f3f5613a9b4bdc4c78b65e9443a669c166a76d95cee2c305095eda4688418bc4b8a3d804e9ea2662fa09f0a906b61435a9aa3d019367cce
6
+ metadata.gz: 360b04b248cc6011c5a37ca50d284d37d1aebd42f60aa15b7eb3f8b47933faca0d5b6738ae462b3cc67bf9b56b3bd426cb375fa8640111ec00a42a01a5aeaf55
7
+ data.tar.gz: 7ef67d55690c0b3ffe845edf747a86a1561dd2aced210d2a870df87f0140eb8aaaab8abbe03212da9557488de655944ecc9d54637679420dc1d8b5594143a5a6
data/Gemfile CHANGED
@@ -4,6 +4,8 @@ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
+ gem "scarpe-components", path: "../scarpe-components"
8
+
7
9
  gem "rake", "~> 13.0"
8
10
 
9
11
  group :test do
data/Gemfile.lock CHANGED
@@ -1,7 +1,13 @@
1
+ PATH
2
+ remote: ../scarpe-components
3
+ specs:
4
+ scarpe-components (0.3.0)
5
+
1
6
  PATH
2
7
  remote: .
3
8
  specs:
4
- lacci (0.2.1)
9
+ lacci (0.3.0)
10
+ scarpe-components
5
11
 
6
12
  GEM
7
13
  remote: https://rubygems.org/
@@ -66,6 +72,7 @@ DEPENDENCIES
66
72
  redcarpet
67
73
  rubocop (~> 1.21)
68
74
  rubocop-shopify
75
+ scarpe-components!
69
76
  yard
70
77
 
71
78
  BUNDLED WITH
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Scarpe
3
+ module Scarpe
4
4
  module CLI
5
5
  DEFAULT_USAGE = <<~'USAGE'
6
6
  Usage: scarpe_core [OPTIONS] <scarpe app file> # Same as "scarpe run"
@@ -23,6 +23,7 @@ class Scarpe
23
23
  end
24
24
 
25
25
  def default_env_categories
26
+ require "shoes"
26
27
  {
27
28
  "Lacci" => [
28
29
  env_or_default("SCARPE_DISPLAY_SERVICE", "(none)"),
@@ -12,9 +12,10 @@ if RUBY_VERSION[0..2] < "3.2"
12
12
  exit(-1)
13
13
  end
14
14
 
15
- class Scarpe; end
15
+ module Scarpe; end
16
16
 
17
17
  # The base error class for Scarpe errors, but not necessarily {Shoes::Error}s
18
+ class Shoes::Error < StandardError; end
18
19
  class Scarpe::Error < StandardError; end
19
20
 
20
21
  require "lacci/version"
data/lib/lacci/version.rb CHANGED
@@ -9,5 +9,5 @@
9
9
  # mostly invisible. Instead, look at the {Shoes} module
10
10
  # to see what's in Lacci.
11
11
  module Lacci
12
- VERSION = "0.2.2"
12
+ VERSION = "0.3.0"
13
13
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Niente
4
+ class App < Drawable
5
+ def initialize(properties)
6
+ super
7
+
8
+ bind_shoes_event(event_name: "init") { init }
9
+ bind_shoes_event(event_name: "run") { run }
10
+ bind_shoes_event(event_name: "destroy") { destroy }
11
+ end
12
+
13
+ def init
14
+ end
15
+
16
+ def run
17
+ send_shoes_event("wait", event_name: "custom_event_loop")
18
+ end
19
+
20
+ def destroy
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Niente
4
+ # This is a "null" DisplayService, doing as little as it
5
+ # can get away with.
6
+ class DisplayService < Shoes::DisplayService
7
+ include Shoes::Log
8
+
9
+ class << self
10
+ attr_accessor :instance
11
+ end
12
+
13
+ def initialize
14
+ if Niente::DisplayService.instance
15
+ raise Shoes::SingletonError, "ERROR! This is meant to be a singleton!"
16
+ end
17
+
18
+ Niente::DisplayService.instance = self
19
+
20
+ log_init("Niente::DisplayService")
21
+ super()
22
+ end
23
+
24
+ # Create a fake display drawable for a specific Shoes drawable, and pair it with
25
+ # the linkable ID for this Shoes drawable.
26
+ #
27
+ # @param drawable_class_name [String] The class name of the Shoes drawable, e.g. Shoes::Button
28
+ # @param drawable_id [String] the linkable ID for drawable events
29
+ # @param properties [Hash] a JSON-serialisable Hash with the drawable's Shoes styles
30
+ # @param is_widget [Boolean] whether the class is a user-defined Shoes::Widget subclass
31
+ # @return [Webview::Drawable] the newly-created Webview drawable
32
+ def create_display_drawable_for(drawable_class_name, drawable_id, properties, is_widget:)
33
+ existing = query_display_drawable_for(drawable_id, nil_ok: true)
34
+ if existing
35
+ @log.warn("There is already a display drawable for #{drawable_id.inspect}! Returning #{existing.class.name}.")
36
+ return existing
37
+ end
38
+
39
+ if drawable_class_name == "App"
40
+ @app = Niente::App.new(properties)
41
+ set_drawable_pairing(drawable_id, @app)
42
+
43
+ return @app
44
+ end
45
+
46
+ display_drawable = Niente::Drawable.new(properties)
47
+ display_drawable.shoes_type = drawable_class_name
48
+ set_drawable_pairing(drawable_id, display_drawable)
49
+
50
+ return display_drawable
51
+ end
52
+
53
+ # Destroy the display service and the app. Quit the process (eventually.)
54
+ #
55
+ # @return [void]
56
+ def destroy
57
+ @app.destroy
58
+ DisplayService.instance = nil
59
+ end
60
+ end
61
+ end
62
+
@@ -0,0 +1,57 @@
1
+ module Niente
2
+ class Drawable < Shoes::Linkable
3
+ attr_reader :shoes_linkable_id
4
+ attr_reader :parent
5
+ attr_reader :children
6
+
7
+ attr_accessor :shoes_type
8
+
9
+ def initialize(props)
10
+ @shoes_linkable_id = props.delete("shoes_linkable_id") || props.delete(:shoes_linkable_id)
11
+ @data = props
12
+
13
+ super(linkable_id: @shoes_linkable_id)
14
+
15
+ bind_shoes_event(event_name: "parent", target: shoes_linkable_id) do |new_parent_id|
16
+ display_parent = DisplayService.instance.query_display_drawable_for(new_parent_id)
17
+ if @parent != display_parent
18
+ set_parent(display_parent)
19
+ end
20
+ end
21
+
22
+ # When Shoes drawables change properties, we get a change notification here
23
+ bind_shoes_event(event_name: "prop_change", target: shoes_linkable_id) do |prop_changes|
24
+ prop_changes.each do |k, v|
25
+ instance_variable_set("@" + k, v)
26
+ end
27
+ properties_changed(prop_changes) if respond_to?(:properties_changed)
28
+ end
29
+
30
+ bind_shoes_event(event_name: "destroy", target: shoes_linkable_id) do
31
+ end
32
+ end
33
+
34
+ def set_parent(new_parent)
35
+ @parent&.remove_child(self)
36
+ new_parent&.add_child(self)
37
+ @parent = new_parent
38
+ end
39
+
40
+ # Do not call directly, use set_parent
41
+ def remove_child(child)
42
+ @children ||= []
43
+ unless @children.include?(child)
44
+ STDERR.puts("remove_child: no such child(#{child.inspect}) for"\
45
+ " parent(#{parent.inspect})!")
46
+ end
47
+ @children.delete(child)
48
+ end
49
+
50
+ # Do not call directly, use set_parent
51
+ def add_child(child)
52
+ @children ||= []
53
+ @children << child
54
+ end
55
+ end
56
+ end
57
+
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "shoes/log"
4
+ require "json"
5
+
6
+ module Niente; end
7
+ class Niente::LogImpl
8
+ include Shoes::Log # for constants
9
+
10
+ class PrintLogger
11
+ def initialize(_)
12
+ end
13
+
14
+ [:error, :warn, :debug, :info].each do |level|
15
+ define_method(level) do |msg|
16
+ puts "#{level}: #{msg}"
17
+ end
18
+ end
19
+ end
20
+
21
+ def logger_for_component(component)
22
+ PrintLogger.new(component.to_s)
23
+ end
24
+
25
+ def configure_logger(log_config)
26
+ end
27
+ end
28
+
29
+ #Shoes::Log.instance = Niente::LogImpl.new
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "minitest"
4
+ require "scarpe/components/string_helpers"
5
+
6
+ module Niente; end
7
+
8
+ class Niente::Test
9
+ def self.run_shoes_spec_test_code(code, class_name: nil, test_name: nil)
10
+ if @shoes_spec_init
11
+ raise Shoes::Errors::MultipleShoesSpecRunsError, "Scarpe-Webview can only run a single Shoes spec per process!"
12
+ end
13
+ @shoes_spec_init = true
14
+
15
+ require "scarpe/components/minitest_export_reporter"
16
+ Minitest::Reporters::ShoesExportReporter.activate!
17
+
18
+ class_name ||= ENV["SHOES_MINITEST_CLASS_NAME"] || "TestShoesSpecCode"
19
+ test_name ||= ENV["SHOES_MINITEST_METHOD_NAME"] || "test_shoes_spec"
20
+
21
+ Shoes::DisplayService.subscribe_to_event("heartbeat", nil) do
22
+ unless @hb_init
23
+ Minitest.run []
24
+ Shoes::App.instance.destroy
25
+ end
26
+ @hb_init = true
27
+ end
28
+
29
+ test_class = Class.new(Niente::ShoesSpecTest)
30
+ Object.const_set(Scarpe::Components::StringHelpers.camelize(class_name), test_class)
31
+ test_name = "test_" + test_name unless test_name.start_with?("test_")
32
+ test_class.define_method(test_name) do
33
+ STDERR.puts "Started running #{class_name.inspect}::#{test_name.inspect}"
34
+ eval(code)
35
+ end
36
+ end
37
+ end
38
+
39
+ class Niente::ShoesSpecTest < Minitest::Test
40
+ Shoes::Drawable.drawable_classes.each do |drawable_class|
41
+ finder_name = drawable_class.dsl_name
42
+
43
+ define_method(finder_name) do |*args|
44
+ app = Shoes::App.instance
45
+
46
+ drawables = app.find_drawables_by(drawable_class, *args)
47
+ raise Shoes::Errors::MultipleDrawablesFoundError, "Found more than one #{finder_name} matching #{args.inspect}!" if drawables.size > 1
48
+ raise Shoes::Errors::NoDrawablesFoundError, "Found no #{finder_name} matching #{args.inspect}!" if drawables.empty?
49
+
50
+ Niente::ShoesSpecProxy.new(drawables[0])
51
+ end
52
+ end
53
+ end
54
+
55
+ class Niente::ShoesSpecProxy
56
+ attr_reader :obj
57
+ attr_reader :linkable_id
58
+ attr_reader :display
59
+
60
+ def initialize(obj)
61
+ @obj = obj
62
+ @linkable_id = obj.linkable_id
63
+ @display = ::Shoes::DisplayService.display_service.query_display_drawable_for(obj.linkable_id)
64
+ end
65
+
66
+ def method_missing(method, ...)
67
+ if @obj.respond_to?(method)
68
+ self.singleton_class.define_method(method) do |*args, **kwargs, &block|
69
+ @obj.send(method, *args, **kwargs, &block)
70
+ end
71
+ send(method, ...)
72
+ else
73
+ super # raise an exception
74
+ end
75
+ end
76
+
77
+ JS_EVENTS = [:click, :hover, :leave]
78
+ JS_EVENTS.each do |event|
79
+ define_method("trigger_#{event}") do |*args, **kwargs|
80
+ ::Shoes::DisplayService.dispatch_event(event.to_s, @linkable_id, *args, **kwargs)
81
+ end
82
+ end
83
+
84
+ def respond_to_missing?(method_name, include_private = false)
85
+ @obj.respond_to_missing?(method_name, include_private)
86
+ end
87
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Niente -- Italian for "nothing" -- is a null display service
4
+ # that doesn't display anything. It does very little, while
5
+ # keeping a certain amount of "mental model" or schema of
6
+ # how a real display service should act.
7
+ module Niente; end
8
+
9
+ require_relative "niente/logger"
10
+ Shoes::Log.instance = Niente::LogImpl.new
11
+
12
+ require_relative "niente/drawable"
13
+ require_relative "niente/app"
14
+ require_relative "niente/display_service"
15
+
16
+ require_relative "niente/shoes_spec"
17
+ Shoes::Spec.instance = Niente::Test
18
+
19
+ Shoes::DisplayService.set_display_service_class(Niente::DisplayService)
20
+
data/lib/shoes/app.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Shoes
4
- class App < Shoes::Widget
3
+ class Shoes
4
+ class App < Shoes::Drawable
5
5
  include Shoes::Log
6
6
 
7
7
  class << self
@@ -10,7 +10,7 @@ module Shoes
10
10
 
11
11
  attr_reader :document_root
12
12
 
13
- display_properties :title, :width, :height, :resizable
13
+ shoes_styles :title, :width, :height, :resizable
14
14
 
15
15
  CUSTOM_EVENT_LOOP_TYPES = ["displaylib", "return", "wait"]
16
16
 
@@ -25,7 +25,7 @@ module Shoes
25
25
 
26
26
  if Shoes::App.instance
27
27
  @log.error("Trying to create a second Shoes::App in the same process! Fail!")
28
- raise "Cannot create multiple Shoes::App objects!"
28
+ raise Shoes::Errors::TooManyInstancesError, "Cannot create multiple Shoes::App objects!"
29
29
  else
30
30
  Shoes::App.instance = self
31
31
  end
@@ -36,26 +36,35 @@ module Shoes
36
36
  super
37
37
 
38
38
  # The draw context tracks current settings like fill and stroke,
39
- # plus potentially other current state that changes from widget
40
- # to widget and slot to slot.
39
+ # plus potentially other current state that changes from drawable
40
+ # to drawable and slot to slot.
41
41
  @draw_context = {
42
42
  "fill" => "",
43
43
  "stroke" => "",
44
+ "rotate" => 0,
44
45
  }
45
46
 
46
- # This creates the DocumentRoot, including its corresponding display widget
47
+ # This creates the DocumentRoot, including its corresponding display drawable
47
48
  @document_root = Shoes::DocumentRoot.new
48
49
 
49
50
  @slots = []
50
51
 
51
- # Now create the App display widget
52
- create_display_widget
52
+ # Now create the App display drawable
53
+ create_display_drawable
53
54
 
54
55
  # Set up testing events *after* Display Service basic objects exist
55
56
  if ENV["SCARPE_APP_TEST"]
56
57
  test_code = File.read ENV["SCARPE_APP_TEST"]
57
58
  if test_code != ""
58
- self.instance_eval test_code
59
+ @test_obj = Object.new
60
+ @test_obj.instance_eval test_code
61
+ end
62
+ end
63
+
64
+ if ENV["SHOES_SPEC_TEST"]
65
+ test_code = File.read ENV["SHOES_SPEC_TEST"]
66
+ unless test_code.empty?
67
+ Shoes::Spec.instance.run_shoes_spec_test_code test_code
59
68
  end
60
69
  end
61
70
 
@@ -70,7 +79,7 @@ module Shoes
70
79
  end
71
80
 
72
81
  @watch_for_event_loop = bind_shoes_event(event_name: "custom_event_loop") do |loop_type|
73
- raise("Unknown event loop type: #{loop_type.inspect}!") unless CUSTOM_EVENT_LOOP_TYPES.include?(loop_type)
82
+ raise(Shoes::Errors::InvalidAttributeValueError, "Unknown event loop type: #{loop_type.inspect}!") unless CUSTOM_EVENT_LOOP_TYPES.include?(loop_type)
74
83
 
75
84
  @event_loop_type = loop_type
76
85
  end
@@ -89,9 +98,9 @@ module Shoes
89
98
  ::Shoes::App.instance.with_slot(@document_root, &@app_code_body)
90
99
  end
91
100
 
92
- # "Container" widgets like flows, stacks, masks and the document root
101
+ # "Container" drawables like flows, stacks, masks and the document root
93
102
  # are considered "slots" in Shoes parlance. When a new slot is created,
94
- # we push it here in order to track what widgets are found in that slot.
103
+ # we push it here in order to track what drawables are found in that slot.
95
104
  def push_slot(slot)
96
105
  @slots.push(slot)
97
106
  end
@@ -115,6 +124,29 @@ module Shoes
115
124
  pop_slot
116
125
  end
117
126
 
127
+ # We use method_missing for drawable-creating methods like "button".
128
+ # The parent's method_missing will auto-create Shoes style getters and setters.
129
+ # This is similar to the method_missing in Shoes::Slot, but different in
130
+ # where the new drawable appears.
131
+ def method_missing(name, *args, **kwargs, &block)
132
+ klass = ::Shoes::Drawable.drawable_class_by_name(name)
133
+ return super unless klass
134
+
135
+ ::Shoes::App.define_method(name) do |*args, **kwargs, &block|
136
+ # Look up the Shoes drawable and create it...
137
+ drawable_instance = klass.new(*args, **kwargs, &block)
138
+
139
+ unless klass.ancestors.include?(::Shoes::TextDrawable)
140
+ # Create this drawable in the current app slot
141
+ drawable_instance.set_parent ::Shoes::App.instance.current_slot
142
+ end
143
+
144
+ drawable_instance
145
+ end
146
+
147
+ send(name, *args, **kwargs, &block)
148
+ end
149
+
118
150
  def current_draw_context
119
151
  @draw_context.dup
120
152
  end
@@ -136,7 +168,9 @@ module Shoes
136
168
  case @event_loop_type
137
169
  when "wait"
138
170
  # Display lib wants us to busy-wait instead of it.
139
- sleep 0.1 until @do_shutdown
171
+ until @do_shutdown
172
+ Shoes::DisplayService.dispatch_event("heartbeat", nil)
173
+ end
140
174
  when "displaylib"
141
175
  # If run event returned, that means we're done.
142
176
  destroy
@@ -144,7 +178,7 @@ module Shoes
144
178
  # We can just return to the main event loop. But we shouldn't call destroy.
145
179
  # Presumably some event loop *outside* our event loop is handling things.
146
180
  else
147
- raise "Internal error! Incorrect event loop type: #{@event_loop_type.inspect}!"
181
+ raise Shoes::Errors::InvalidAttributeValueError, "Internal error! Incorrect event loop type: #{@event_loop_type.inspect}!"
148
182
  end
149
183
  end
150
184
 
@@ -153,7 +187,7 @@ module Shoes
153
187
  send_shoes_event(event_name: "destroy") if send_event
154
188
  end
155
189
 
156
- def all_widgets
190
+ def all_drawables
157
191
  out = []
158
192
 
159
193
  to_add = @document_root.children
@@ -165,13 +199,15 @@ module Shoes
165
199
  out
166
200
  end
167
201
 
168
- # We can add various ways to find widgets here.
202
+ # We can add various ways to find drawables here.
169
203
  # These are sort of like Shoes selectors, used for testing.
170
- def find_widgets_by(*specs)
171
- widgets = all_widgets
204
+ def find_drawables_by(*specs)
205
+ drawables = all_drawables
172
206
  specs.each do |spec|
173
- if spec.is_a?(Class)
174
- widgets.select! { |w| spec === w }
207
+ if spec == Shoes::App
208
+ drawables = [Shoes::App.instance]
209
+ elsif spec.is_a?(Class)
210
+ drawables.select! { |w| spec === w }
175
211
  elsif spec.is_a?(Symbol) || spec.is_a?(String)
176
212
  s = spec.to_s
177
213
  case s[0]
@@ -179,29 +215,47 @@ module Shoes
179
215
  begin
180
216
  # I'm not finding a global_variable_get or similar...
181
217
  global_value = eval s
182
- widgets &= [global_value]
218
+ drawables &= [global_value]
183
219
  rescue
184
- raise "Error getting global variable: #{spec.inspect}"
220
+ raise Shoes::Errors::InvalidAttributeValueError, "Error getting global variable: #{spec.inspect}"
185
221
  end
186
222
  when "@"
187
223
  if Shoes::App.instance.instance_variables.include?(spec.to_sym)
188
- widgets &= [self.instance_variable_get(spec)]
224
+ drawables &= [self.instance_variable_get(spec)]
189
225
  else
190
- raise "Can't find top-level instance variable: #{spec.inspect}!"
226
+ raise Shoes::Errors::InvalidAttributeValueError, "Can't find top-level instance variable: #{spec.inspect}!"
191
227
  end
192
228
  else
229
+ if s.start_with?("id:")
230
+ find_id = Integer(s[3..-1])
231
+ drawable = Shoes::Drawable.drawable_by_id(find_id)
232
+ drawables &= [drawable]
233
+ else
234
+ raise Shoes::Errors::InvalidAttributeValueError, "Don't know how to find drawables by #{spec.inspect}!"
235
+ end
193
236
  end
194
237
  else
195
- raise("Don't know how to find widgets by #{spec.inspect}!")
238
+ raise(Shoes::Errors::InvalidAttributeValueError, "Don't know how to find drawables by #{spec.inspect}!")
196
239
  end
197
240
  end
198
- widgets
241
+ drawables
199
242
  end
200
243
  end
201
244
  end
202
245
 
203
- # DSL methods
204
- class Shoes::App
246
+ # Event handler DSLs get defined in both App and Slot - same code, slightly different results
247
+ events = [:motion, :hover, :leave, :click, :release, :keypress, :animate, :every, :timer]
248
+ events.each do |event|
249
+ Shoes::App.define_method(event) do |*args, &block|
250
+ subscription_item(args:, shoes_api_name: event.to_s, &block)
251
+ end
252
+ Shoes::Slot.define_method(event) do |*args, &block|
253
+ subscription_item(args:, shoes_api_name: event.to_s, &block)
254
+ end
255
+ end
256
+
257
+ # These methods will need to be defined on Slots too, but probably need a rework in general.
258
+ class Shoes::App < Shoes::Drawable
205
259
  def background(...)
206
260
  current_slot.background(...)
207
261
  end
@@ -210,18 +264,6 @@ class Shoes::App
210
264
  current_slot.border(...)
211
265
  end
212
266
 
213
- def motion(&block)
214
- subscription_item(shoes_api_name: "motion", &block)
215
- end
216
-
217
- def hover(&block)
218
- subscription_item(shoes_api_name: "hover", &block)
219
- end
220
-
221
- def click(&block)
222
- subscription_item(shoes_api_name: "click", &block)
223
- end
224
-
225
267
  # Draw context methods
226
268
 
227
269
  def fill(color)
@@ -243,7 +285,7 @@ class Shoes::App
243
285
  # Shape DSL methods
244
286
 
245
287
  def move_to(x, y)
246
- raise("Pass only Numeric arguments to move_to!") unless x.is_a?(Numeric) && y.is_a?(Numeric)
288
+ raise(Shoes::Errors::InvalidAttributeValueError, "Pass only Numeric arguments to move_to!") unless x.is_a?(Numeric) && y.is_a?(Numeric)
247
289
 
248
290
  if current_slot.is_a?(::Shoes::Shape)
249
291
  current_slot.add_shape_command(["move_to", x, y])
@@ -251,13 +293,16 @@ class Shoes::App
251
293
  end
252
294
 
253
295
  def line_to(x, y)
254
- raise("Pass only Numeric arguments to line_to!") unless x.is_a?(Numeric) && y.is_a?(Numeric)
296
+ raise(Shoes::Errors::InvalidAttributeValueError, "Pass only Numeric arguments to line_to!") unless x.is_a?(Numeric) && y.is_a?(Numeric)
255
297
 
256
298
  if current_slot.is_a?(::Shoes::Shape)
257
299
  current_slot.add_shape_command(["line_to", x, y])
258
300
  end
259
301
  end
260
302
 
303
+ def rotate(angle)
304
+ @draw_context["rotate"] = angle
305
+ end
261
306
  # Not implemented yet: curve_to, arc_to
262
307
 
263
308
  alias_method :info, :puts
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Shoes
3
+ class Shoes
4
4
  module Background
5
5
  def self.included(includer)
6
- includer.display_property(:background_color)
6
+ includer.shoes_style(:background_color)
7
7
  end
8
8
 
9
9
  # NOTE: this needs to be passed through in order for the styling to work
data/lib/shoes/border.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Shoes
3
+ class Shoes
4
4
  module Border
5
5
  def self.included(includer)
6
- includer.display_properties :border_color, :options
6
+ includer.shoes_styles :border_color, :options
7
7
  end
8
8
 
9
9
  # Considering a signature like this: