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.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/Gemfile.lock +8 -1
- data/lib/lacci/scarpe_cli.rb +2 -1
- data/lib/lacci/scarpe_core.rb +2 -1
- data/lib/lacci/version.rb +1 -1
- data/lib/scarpe/niente/app.rb +23 -0
- data/lib/scarpe/niente/display_service.rb +62 -0
- data/lib/scarpe/niente/drawable.rb +57 -0
- data/lib/scarpe/niente/logger.rb +29 -0
- data/lib/scarpe/niente/shoes_spec.rb +87 -0
- data/lib/scarpe/niente.rb +20 -0
- data/lib/shoes/app.rb +88 -43
- data/lib/shoes/background.rb +2 -2
- data/lib/shoes/border.rb +2 -2
- data/lib/shoes/builtins.rb +63 -0
- data/lib/shoes/changelog.rb +52 -0
- data/lib/shoes/colors.rb +3 -1
- data/lib/shoes/constants.rb +19 -1
- data/lib/shoes/display_service.rb +39 -16
- data/lib/shoes/download.rb +2 -2
- data/lib/shoes/drawable.rb +380 -0
- data/lib/shoes/drawables/arc.rb +49 -0
- data/lib/shoes/drawables/arrow.rb +41 -0
- data/lib/shoes/drawables/button.rb +73 -0
- data/lib/shoes/{widgets → drawables}/check.rb +5 -4
- data/lib/shoes/{widgets → drawables}/document_root.rb +3 -3
- data/lib/shoes/{widgets → drawables}/edit_box.rb +6 -6
- data/lib/shoes/{widgets → drawables}/edit_line.rb +6 -6
- data/lib/shoes/{widgets → drawables}/flow.rb +6 -6
- data/lib/shoes/{widgets → drawables}/image.rb +6 -6
- data/lib/shoes/{widgets → drawables}/line.rb +7 -5
- data/lib/shoes/drawables/link.rb +34 -0
- data/lib/shoes/drawables/list_box.rb +56 -0
- data/lib/shoes/drawables/para.rb +118 -0
- data/lib/shoes/drawables/progress.rb +14 -0
- data/lib/shoes/drawables/radio.rb +33 -0
- data/lib/shoes/drawables/rect.rb +17 -0
- data/lib/shoes/{widgets → drawables}/shape.rb +6 -7
- data/lib/shoes/{widgets → drawables}/slot.rb +32 -20
- data/lib/shoes/{widgets → drawables}/span.rb +8 -7
- data/lib/shoes/{widgets → drawables}/stack.rb +6 -4
- data/lib/shoes/drawables/star.rb +50 -0
- data/lib/shoes/drawables/subscription_item.rb +93 -0
- data/lib/shoes/drawables/text_drawable.rb +63 -0
- data/lib/shoes/drawables/video.rb +16 -0
- data/lib/shoes/drawables/widget.rb +69 -0
- data/lib/shoes/drawables.rb +31 -0
- data/lib/shoes/errors.rb +28 -0
- data/lib/shoes/log.rb +2 -2
- data/lib/shoes/ruby_extensions.rb +15 -0
- data/lib/shoes/spacing.rb +2 -2
- data/lib/shoes-spec.rb +93 -0
- data/lib/shoes.rb +27 -7
- metadata +55 -28
- data/lib/shoes/widget.rb +0 -218
- data/lib/shoes/widgets/alert.rb +0 -19
- data/lib/shoes/widgets/arc.rb +0 -51
- data/lib/shoes/widgets/button.rb +0 -35
- data/lib/shoes/widgets/font.rb +0 -14
- data/lib/shoes/widgets/link.rb +0 -25
- data/lib/shoes/widgets/list_box.rb +0 -25
- data/lib/shoes/widgets/para.rb +0 -68
- data/lib/shoes/widgets/radio.rb +0 -35
- data/lib/shoes/widgets/star.rb +0 -44
- data/lib/shoes/widgets/subscription_item.rb +0 -60
- data/lib/shoes/widgets/text_widget.rb +0 -51
- data/lib/shoes/widgets/video.rb +0 -15
- data/lib/shoes/widgets.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e32d4245e4dc24e8098d8626ca2ad9ba7d4417b6e392d0c0d43c1b003dece24e
|
4
|
+
data.tar.gz: dea4cd304311e63c498e2c679e8d61ec9b550c56c5a87d33bb4c7b499a08b875
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 360b04b248cc6011c5a37ca50d284d37d1aebd42f60aa15b7eb3f8b47933faca0d5b6738ae462b3cc67bf9b56b3bd426cb375fa8640111ec00a42a01a5aeaf55
|
7
|
+
data.tar.gz: 7ef67d55690c0b3ffe845edf747a86a1561dd2aced210d2a870df87f0140eb8aaaab8abbe03212da9557488de655944ecc9d54637679420dc1d8b5594143a5a6
|
data/Gemfile
CHANGED
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.
|
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
|
data/lib/lacci/scarpe_cli.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
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)"),
|
data/lib/lacci/scarpe_core.rb
CHANGED
@@ -12,9 +12,10 @@ if RUBY_VERSION[0..2] < "3.2"
|
|
12
12
|
exit(-1)
|
13
13
|
end
|
14
14
|
|
15
|
-
|
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
@@ -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
|
-
|
4
|
-
class App < Shoes::
|
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
|
-
|
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
|
40
|
-
# to
|
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
|
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
|
52
|
-
|
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
|
-
|
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"
|
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
|
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
|
-
|
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
|
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
|
202
|
+
# We can add various ways to find drawables here.
|
169
203
|
# These are sort of like Shoes selectors, used for testing.
|
170
|
-
def
|
171
|
-
|
204
|
+
def find_drawables_by(*specs)
|
205
|
+
drawables = all_drawables
|
172
206
|
specs.each do |spec|
|
173
|
-
if spec
|
174
|
-
|
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
|
-
|
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
|
-
|
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
|
238
|
+
raise(Shoes::Errors::InvalidAttributeValueError, "Don't know how to find drawables by #{spec.inspect}!")
|
196
239
|
end
|
197
240
|
end
|
198
|
-
|
241
|
+
drawables
|
199
242
|
end
|
200
243
|
end
|
201
244
|
end
|
202
245
|
|
203
|
-
#
|
204
|
-
|
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
|
data/lib/shoes/background.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
class Shoes
|
4
4
|
module Background
|
5
5
|
def self.included(includer)
|
6
|
-
includer.
|
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