hokusai-zero 0.1.1

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 (166) hide show
  1. checksums.yaml +7 -0
  2. data/Dockerfile +26 -0
  3. data/Gemfile +15 -0
  4. data/Gemfile.lock +91 -0
  5. data/LICENSE +21 -0
  6. data/README.md +28 -0
  7. data/ast/genheader +3 -0
  8. data/ast/include/hashmap.c +1151 -0
  9. data/ast/include/hashmap.c.license +20 -0
  10. data/ast/include/hashmap.h +54 -0
  11. data/ast/src/core/ast.c +448 -0
  12. data/ast/src/core/ast.h +259 -0
  13. data/ast/src/core/common.h +24 -0
  14. data/ast/src/core/component.c +85 -0
  15. data/ast/src/core/component.h +35 -0
  16. data/ast/src/core/hml.c +665 -0
  17. data/ast/src/core/hml.h +11 -0
  18. data/ast/src/core/input.c +458 -0
  19. data/ast/src/core/input.h +118 -0
  20. data/ast/src/core/style.c +101 -0
  21. data/ast/src/core/style.h +41 -0
  22. data/ast/src/core/text.c +784 -0
  23. data/ast/src/core/text.h +93 -0
  24. data/ast/src/core/util.c +140 -0
  25. data/ast/src/core/util.h +48 -0
  26. data/ast/src/hokusai.c +6 -0
  27. data/ast/src/hokusai.h +6 -0
  28. data/ast/test/fixtures/test.ui +13 -0
  29. data/ast/test/greatest.h +1266 -0
  30. data/ast/test/hokusai.c +14 -0
  31. data/ast/test/parser.c +234 -0
  32. data/ast/test/text.c +116 -0
  33. data/ext/extconf.rb +27 -0
  34. data/grammar/Cargo.lock +80 -0
  35. data/grammar/Cargo.toml +26 -0
  36. data/grammar/binding.gyp +20 -0
  37. data/grammar/bindings/node/binding.cc +28 -0
  38. data/grammar/bindings/node/index.js +19 -0
  39. data/grammar/bindings/rust/build.rs +40 -0
  40. data/grammar/bindings/rust/lib.rs +52 -0
  41. data/grammar/corpus/1_document.txt +131 -0
  42. data/grammar/corpus/2_selectors.txt +58 -0
  43. data/grammar/corpus/3_spaces.txt +69 -0
  44. data/grammar/corpus/4_errors.txt +10 -0
  45. data/grammar/corpus/5_macros.txt +175 -0
  46. data/grammar/corpus/6_styles.txt +81 -0
  47. data/grammar/grammar.js +275 -0
  48. data/grammar/package-lock.json +34 -0
  49. data/grammar/package.json +33 -0
  50. data/grammar/src/grammar.json +1269 -0
  51. data/grammar/src/node-types.json +474 -0
  52. data/grammar/src/parser.c +5772 -0
  53. data/grammar/src/scanner.c +258 -0
  54. data/grammar/src/tree_sitter/parser.h +230 -0
  55. data/grammar/src/tree_sitter/scanner.h +12 -0
  56. data/grammar/test.nml +10 -0
  57. data/hokusai.gemspec +19 -0
  58. data/ui/examples/assets/DigitalDisplay.ttf +0 -0
  59. data/ui/examples/assets/OpenSans-Regular.ttf +0 -0
  60. data/ui/examples/assets/addy.png +0 -0
  61. data/ui/examples/assets/baby_sean.png +0 -0
  62. data/ui/examples/assets/football-troll.png +0 -0
  63. data/ui/examples/assets/gear.png +0 -0
  64. data/ui/examples/assets/icecold.ttf +0 -0
  65. data/ui/examples/assets/science-troll.png +0 -0
  66. data/ui/examples/buddy.rb +31 -0
  67. data/ui/examples/clock.rb +58 -0
  68. data/ui/examples/counter.rb +123 -0
  69. data/ui/examples/dynamic.rb +147 -0
  70. data/ui/examples/foobar.rb +236 -0
  71. data/ui/examples/stock.rb +115 -0
  72. data/ui/examples/stock_decider/option.rb +74 -0
  73. data/ui/examples/tic_tac_toe.rb +246 -0
  74. data/ui/lib/lib_hokusai.rb +425 -0
  75. data/ui/spec/hokusai/ast_spec.rb +88 -0
  76. data/ui/spec/hokusai/automation/keys_transcoder_spec.rb +50 -0
  77. data/ui/spec/hokusai/automation/selector_spec.rb +68 -0
  78. data/ui/spec/hokusai/block_spec.rb +126 -0
  79. data/ui/spec/hokusai/directives_spec.rb +327 -0
  80. data/ui/spec/hokusai/e2e/client_spec.rb +58 -0
  81. data/ui/spec/hokusai/e2e/meta_spec.rb +42 -0
  82. data/ui/spec/hokusai/publisher_spec.rb +38 -0
  83. data/ui/spec/hokusai/slots_spec.rb +150 -0
  84. data/ui/spec/hokusai/util/piece_table_spec.rb +90 -0
  85. data/ui/spec/hokusai_spec.rb +0 -0
  86. data/ui/spec/spec_helper.rb +30 -0
  87. data/ui/src/hokusai/ast.rb +446 -0
  88. data/ui/src/hokusai/automation/client.rb +167 -0
  89. data/ui/src/hokusai/automation/constants.rb +98 -0
  90. data/ui/src/hokusai/automation/converters/selector_converter.rb +61 -0
  91. data/ui/src/hokusai/automation/driver.rb +54 -0
  92. data/ui/src/hokusai/automation/driver_command_queue.rb +50 -0
  93. data/ui/src/hokusai/automation/driver_commands/base.rb +79 -0
  94. data/ui/src/hokusai/automation/driver_commands/get_attribute.rb +41 -0
  95. data/ui/src/hokusai/automation/driver_commands/invoke.rb +33 -0
  96. data/ui/src/hokusai/automation/driver_commands/locate.rb +48 -0
  97. data/ui/src/hokusai/automation/driver_commands/trigger_keyboard.rb +94 -0
  98. data/ui/src/hokusai/automation/driver_commands/trigger_mouse.rb +213 -0
  99. data/ui/src/hokusai/automation/keys_transcoder.rb +128 -0
  100. data/ui/src/hokusai/automation/selector.rb +39 -0
  101. data/ui/src/hokusai/automation/server.rb +114 -0
  102. data/ui/src/hokusai/automation.rb +3 -0
  103. data/ui/src/hokusai/backends/raylib/config.rb +47 -0
  104. data/ui/src/hokusai/backends/raylib/font.rb +113 -0
  105. data/ui/src/hokusai/backends/raylib/keys.rb +124 -0
  106. data/ui/src/hokusai/backends/raylib.rb +449 -0
  107. data/ui/src/hokusai/backends/sdl2/Monaco.ttf +0 -0
  108. data/ui/src/hokusai/backends/sdl2/color.rb +12 -0
  109. data/ui/src/hokusai/backends/sdl2/config.rb +31 -0
  110. data/ui/src/hokusai/backends/sdl2/font.rb +127 -0
  111. data/ui/src/hokusai/backends/sdl2/keys.rb +119 -0
  112. data/ui/src/hokusai/backends/sdl2.rb +529 -0
  113. data/ui/src/hokusai/block.rb +237 -0
  114. data/ui/src/hokusai/blocks/button.rb +100 -0
  115. data/ui/src/hokusai/blocks/checkbox.rb +51 -0
  116. data/ui/src/hokusai/blocks/circle.rb +28 -0
  117. data/ui/src/hokusai/blocks/clipped.rb +23 -0
  118. data/ui/src/hokusai/blocks/cursor.rb +49 -0
  119. data/ui/src/hokusai/blocks/dynamic.rb +37 -0
  120. data/ui/src/hokusai/blocks/empty.rb +10 -0
  121. data/ui/src/hokusai/blocks/hblock.rb +35 -0
  122. data/ui/src/hokusai/blocks/image.rb +18 -0
  123. data/ui/src/hokusai/blocks/input.rb +200 -0
  124. data/ui/src/hokusai/blocks/label.rb +39 -0
  125. data/ui/src/hokusai/blocks/panel.rb +126 -0
  126. data/ui/src/hokusai/blocks/rect.rb +24 -0
  127. data/ui/src/hokusai/blocks/scissor_begin.rb +18 -0
  128. data/ui/src/hokusai/blocks/scissor_end.rb +12 -0
  129. data/ui/src/hokusai/blocks/scrollbar.rb +103 -0
  130. data/ui/src/hokusai/blocks/selectable.rb +77 -0
  131. data/ui/src/hokusai/blocks/svg.rb +20 -0
  132. data/ui/src/hokusai/blocks/text.rb +214 -0
  133. data/ui/src/hokusai/blocks/titlebar/osx.rb +145 -0
  134. data/ui/src/hokusai/blocks/toggle.rb +55 -0
  135. data/ui/src/hokusai/blocks/vblock.rb +35 -0
  136. data/ui/src/hokusai/commands/base.rb +22 -0
  137. data/ui/src/hokusai/commands/circle.rb +47 -0
  138. data/ui/src/hokusai/commands/image.rb +45 -0
  139. data/ui/src/hokusai/commands/rect.rb +158 -0
  140. data/ui/src/hokusai/commands/scissor.rb +22 -0
  141. data/ui/src/hokusai/commands/text.rb +92 -0
  142. data/ui/src/hokusai/commands.rb +87 -0
  143. data/ui/src/hokusai/diff.rb +124 -0
  144. data/ui/src/hokusai/error.rb +3 -0
  145. data/ui/src/hokusai/event.rb +54 -0
  146. data/ui/src/hokusai/events/keyboard.rb +84 -0
  147. data/ui/src/hokusai/events/mouse.rb +172 -0
  148. data/ui/src/hokusai/font.rb +280 -0
  149. data/ui/src/hokusai/meta.rb +152 -0
  150. data/ui/src/hokusai/mounting/loop_entry.rb +230 -0
  151. data/ui/src/hokusai/mounting/mount_entry.rb +74 -0
  152. data/ui/src/hokusai/mounting/update_entry.rb +101 -0
  153. data/ui/src/hokusai/node.rb +98 -0
  154. data/ui/src/hokusai/node_mounter.rb +102 -0
  155. data/ui/src/hokusai/painter.rb +214 -0
  156. data/ui/src/hokusai/publisher.rb +32 -0
  157. data/ui/src/hokusai/style.rb +72 -0
  158. data/ui/src/hokusai/types.rb +266 -0
  159. data/ui/src/hokusai/util/clamping_iterator.rb +202 -0
  160. data/ui/src/hokusai/util/piece_table.rb +111 -0
  161. data/ui/src/hokusai/util/selection.rb +145 -0
  162. data/ui/src/hokusai.rb +120 -0
  163. data/ui/vendor/.gitkeep +0 -0
  164. data/vendor/.gitkeep +0 -0
  165. data/xmake.lua +192 -0
  166. metadata +222 -0
@@ -0,0 +1,61 @@
1
+ require_relative "../selector"
2
+
3
+ module Hokusai::Automation
4
+ module Converters
5
+ module SelectorConverter
6
+ def self.parse_selectors(selector)
7
+ final = []
8
+ scanner = StringScanner.new(selector)
9
+
10
+ while !scanner.eos?
11
+ if node = scan_node(scanner)
12
+ id = scan_id(scanner)
13
+ classes = scan_classes(scanner)
14
+ final << Selector.new(node, id, classes)
15
+
16
+ scan_space(scanner)
17
+ elsif id = scan_id(scanner)
18
+ classes = scan_classes(scanner)
19
+ final << Selector.new(nil, id, classes)
20
+
21
+ scan_space(scanner)
22
+ elsif classes = scan_classes(scanner)
23
+ final << Selector.new(nil, nil, classes)
24
+
25
+ scan_space(scanner)
26
+ else
27
+ scanner.terminate
28
+
29
+ if scanner.rest.empty?
30
+ scanner.terminate
31
+ else
32
+ raise Automation::Error.new("Error Scanning: Improperly formatted selector: #{scanner.rest}")
33
+ end
34
+ end
35
+ end
36
+
37
+ final
38
+ end
39
+
40
+ private
41
+
42
+ def self.scan_id(scanner)
43
+ scanner.scan(/\#([A-Za-z0-9-_]+)/)
44
+ scanner[1]
45
+ end
46
+
47
+ def self.scan_classes(scanner)
48
+ scanner.scan(/((\.[A-Za-z0-9-_]+)+)/)
49
+ scanner[1]&.[](1..-1)&.split(".")
50
+ end
51
+
52
+ def self.scan_node(scanner)
53
+ scanner.scan(/[A-Za-z0-9-_]+/)
54
+ end
55
+
56
+ def self.scan_space(scanner)
57
+ scanner.scan(/\s*/)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,54 @@
1
+ require_relative "./driver_commands/base"
2
+ require_relative "./driver_commands/get_attribute"
3
+ require_relative "./driver_commands/invoke"
4
+ require_relative "./driver_commands/locate"
5
+ require_relative "./driver_commands/trigger_keyboard"
6
+ require_relative "./driver_commands/trigger_mouse"
7
+ require_relative "./driver_command_queue"
8
+
9
+ module Hokusai
10
+ module Automation
11
+ class Driver
12
+ attr_reader :server, :queue, :results
13
+
14
+ def initialize
15
+ @queue = DriverCommandQueue.new
16
+ @results = {}
17
+ @server = Hokusai::Automation::Server
18
+ end
19
+
20
+ def serve(*args)
21
+ @server.start(*args, driver: self)
22
+ end
23
+
24
+ def stop
25
+ @server.stop
26
+ end
27
+
28
+ def complete
29
+ queue.completed(results)
30
+ end
31
+
32
+ # Adds a driver command to the queue to be executed
33
+ #
34
+ # Commands process one-by-one on each iteration of the
35
+ # UI loop.
36
+ #
37
+ # When a command is finished, its result will be populated in `#results`
38
+ def execute(command)
39
+ queue.commands << command
40
+ end
41
+
42
+ # Process a command with the given UI state
43
+ #
44
+ # Results will added to the results hash and picked up by the current server request
45
+ #
46
+ # * `blocks` is a tuple containing a block and its parent
47
+ # * `canvas` is the current canvas being painted
48
+ # * `input` is the application input state for this loop iteration
49
+ def process(blocks, canvas, input)
50
+ queue.process(blocks, canvas, input)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,50 @@
1
+ module Hokusai::Automation
2
+ # A queue of `DriverCommand`
3
+ #
4
+ # The queue is processed async on each iteration of the event loop
5
+ class DriverCommandQueue
6
+ attr_accessor :commands
7
+
8
+ def initialize
9
+ @commands = []
10
+ end
11
+
12
+ def completed(results)
13
+ if command = commands[0]
14
+ # command was added in the middle of a render cycle, don't complete it.
15
+ return if command.waiting?
16
+
17
+ if value = command.on_complete
18
+ case value
19
+ when ::Hokusai::Automation::Error
20
+ results[command.request_id] = [command, value]
21
+ else
22
+ results[command.request_id] = [command, value]
23
+ end
24
+ end
25
+
26
+ if command.done?
27
+
28
+ commands.shift
29
+ end
30
+ end
31
+ end
32
+
33
+ # Processes any availabe commands in the queue
34
+ #
35
+ # Returns a Tuple containing the command and it's wrapped return value
36
+ def process(blocks, canvas, input)
37
+ return nil if commands.empty?
38
+
39
+ command = commands[0]
40
+
41
+ # wait for the start of the render loop
42
+ #
43
+ # if there is no parent, execute the command
44
+ return if !blocks[1].nil? && command.waiting?
45
+
46
+ command.pending! if command.waiting?
47
+ command.execute(blocks, canvas, input)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,79 @@
1
+ module Hokusai::Automation
2
+ module DriverCommands
3
+ class Base
4
+ attr_accessor :request_id, :status, :last_parent
5
+ attr_reader :state
6
+
7
+ [:waiting, :pending, :done].each do |key|
8
+ define_method("#{key}?") do
9
+ status == key
10
+ end
11
+
12
+ define_method("#{key}!") do
13
+ self.status = key
14
+ end
15
+ end
16
+
17
+ def initialize(hash)
18
+ @state = hash
19
+ @last_parent = nil
20
+ end
21
+
22
+ def status
23
+ @status ||= :wait
24
+ end
25
+
26
+ def request_id
27
+ @request_id ||= SecureRandom.uuid
28
+ end
29
+
30
+ def on_complete(&block)
31
+ raise NotImplementedError.new("Must implement #{self.class}#on_complete")
32
+ end
33
+
34
+ def execute(blocks, canvas, input)
35
+ raise NotImplementedError.new("Must implement #{self.class}#execute")
36
+ end
37
+
38
+ def matches_block(block)
39
+ return false unless block.node.portal
40
+
41
+ if location == block.node.portal.uuid.to_s
42
+
43
+ return true
44
+ end
45
+
46
+ false
47
+ end
48
+
49
+ def matches_blocks(blocks)
50
+ if matches_block(blocks[0]) || (last_parent == blocks[1] && !last_parent.nil?)
51
+ self.last_parent = blocks[0]
52
+
53
+ return true
54
+ end
55
+
56
+ false
57
+ end
58
+
59
+
60
+ def mouse_center(canvas, input)
61
+ x = canvas.x + (canvas.width / 2)
62
+ y = canvas.y + (canvas.height / 2)
63
+
64
+ mouse_move(x, y, input)
65
+ end
66
+
67
+ def mouse_move(x, y, input)
68
+ LibHokusai.hoku_input_set_mouse_position(input, vec2(x, y))
69
+ end
70
+
71
+ private
72
+
73
+ # Returns an HmlVec2 from {x,y}
74
+ def vec2(x, y)
75
+ LibHokusai::HmlVec2.create(x, y)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,41 @@
1
+ module Hokusai::Automation
2
+ module DriverCommands
3
+ class GetAttribute < Base
4
+ attr_accessor :value
5
+
6
+ def initialize(state)
7
+ @value = nil
8
+
9
+ super
10
+ end
11
+
12
+ def location
13
+ state[:uuid]
14
+ end
15
+
16
+ def attribute_name
17
+ state[:attribute_name]
18
+ end
19
+
20
+ def on_complete
21
+ done!
22
+
23
+ if value.nil?
24
+ return ::Hokusai::Automation::Error.new("Attribute #{attribute_name} not found")
25
+ end
26
+
27
+ return value
28
+ end
29
+
30
+ def execute(blocks, canvas, input)
31
+ return unless matches_block(blocks[0])
32
+
33
+ Log.debug { "Props: #{blocks[0].node.meta.props}".colorize(:yellow) }
34
+
35
+ attribute = blocks[0].node.meta.props[attribute_name.to_sym]
36
+
37
+ self.value = attribute
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,33 @@
1
+ module Hokusai::Automation
2
+ module DriverCommands
3
+ class Invoke < Base
4
+ attr_accessor :value
5
+
6
+ def location
7
+ state[:uuid]
8
+ end
9
+
10
+ def method
11
+ state[:method]
12
+ end
13
+
14
+ def initialize(hash)
15
+ @value = nil
16
+
17
+ super
18
+ end
19
+
20
+ def on_complete
21
+ return value if done?
22
+ end
23
+
24
+ def execute(block, canvas, input)
25
+ return unless matches_block(blocks[0])
26
+
27
+ self.value = blocks[0].public_send(method)
28
+
29
+ done!
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,48 @@
1
+ require_relative "../converters/selector_converter"
2
+
3
+ module Hokusai::Automation
4
+ module DriverCommands
5
+ class Locate < Base
6
+ attr_reader :matches
7
+
8
+ def initialize(hash)
9
+ @matches = []
10
+ @selectors = nil
11
+
12
+ super
13
+ end
14
+
15
+ def on_complete
16
+ return if waiting?
17
+
18
+ done!
19
+
20
+ return ::Hokusai::Automation::Error.new("No matches found") if matches.empty?
21
+
22
+ matches.last
23
+ end
24
+
25
+ def selectors
26
+ @selectors ||= Converters::SelectorConverter.parse_selectors(state[:selector])
27
+ end
28
+
29
+ def execute(blocks, canvas, input)
30
+ if selector = selectors.shift
31
+ if selector.matches(blocks[0])
32
+ Log.debug {"Location match! #{selector}".colorize(:light_magenta)}
33
+
34
+ portal = blocks[0].node.portal
35
+
36
+ Log.debug { "uuid: #{portal.uuid.to_s}".colorize(:light_magenta) }
37
+
38
+ matches << portal.uuid.to_s
39
+
40
+ selectors.unshift(selector) if selectors.empty?
41
+ else
42
+ selectors.unshift(selector)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,94 @@
1
+ module Hokusai::Automation
2
+ module DriverCommands
3
+ class TriggerKeyboard < Base
4
+ attr_reader :exception
5
+
6
+ def initialize(state)
7
+ @exception = nil
8
+
9
+ super
10
+ end
11
+
12
+ def location
13
+ state[:uuid]
14
+ end
15
+
16
+ def keys
17
+ @keys ||= KeysTranscoder.decode(state[:keys])
18
+ end
19
+
20
+ def on_complete
21
+ if keys.empty?
22
+ done!
23
+ end
24
+
25
+ return exception || true
26
+ end
27
+
28
+ def execute(blocks, canvas, input)
29
+ return unless matches_block(blocks[0])
30
+
31
+ Log.info { "Trigger keypress on #{blocks[0].class}".colorize(:cyan) }
32
+
33
+ decode_key = keys.shift
34
+
35
+ mouse_center(canvas, input)
36
+ state = LibHokusai::HmlInputMouseButton.create(clicked: true)
37
+ LibHokusai.hoku_input_mouse_set_button(input, state, 0)
38
+
39
+ begin
40
+ key_results = to_hml_keygroup(decode_key)
41
+
42
+ LibHokusai.hoku_input_keyboard_start(input)
43
+
44
+ key_results.each do |key|
45
+ Log.info { "populating #{key}"}
46
+
47
+ LibHokusai.hoku_input_keyboard_set_key(input, key, true)
48
+ end
49
+
50
+ LibHokusai.hoku_input_keyboard_stop(input)
51
+ rescue Automation::Error => ex
52
+ keys.clear
53
+ self.exeception = ex
54
+
55
+ done!
56
+ end
57
+ end
58
+
59
+ # Transforms a DecodedKey to an array of `LibHokusai::HmlInputKey`
60
+ def to_hml_keygroup(decode_key)
61
+ key_group = []
62
+
63
+ case decode_key
64
+ when Array
65
+ decode_key.each do |key|
66
+ if hml_key = CODE_TO_HML_KEY[key]
67
+ key_group << hml_key
68
+ else
69
+ raise Automation::Exception.new("Error translating key to HmlInput: #{key} not found")
70
+ end
71
+ end
72
+ else
73
+ if hml_key CODE_TO_HML_KEY[decode_key]
74
+ key_group << hml_key
75
+ else
76
+ raise Automation::Exception.new("Error translating key to HmlInput: #{key} not found")
77
+ end
78
+ end
79
+
80
+ key_group
81
+ end
82
+
83
+ def to_hml_keys
84
+ hml_keys = []
85
+
86
+ keys.each do |decode_key|
87
+ hml_keys << to_hml_keygroup(decode_key)
88
+ end
89
+
90
+ hml_keys
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,213 @@
1
+ module Hokusai::Automation
2
+ module DriverCommands
3
+ module MouseMethods
4
+ def trigger_mouse(input, **args)
5
+ state = LibHokusai::HmlInputMouseButton.create(**args)
6
+
7
+ LibHokusai.hoku_input_mouse_set_button(input, state, button)
8
+ end
9
+ end
10
+
11
+ class TriggerMouseBase < Base
12
+ include MouseMethods
13
+
14
+ attr_accessor :value
15
+
16
+ def initialize(hash)
17
+ @value = false
18
+
19
+ super
20
+ end
21
+
22
+ def location
23
+ state[:uuid]
24
+ end
25
+
26
+ def button
27
+ state[:button]
28
+ end
29
+
30
+ def on_complete
31
+ return value if done?
32
+
33
+ return Automation::Error.new("Could not locate block")
34
+ end
35
+ end
36
+
37
+ class TriggerMouseDown < TriggerMouseBase
38
+ def execute(blocks, canvas, input)
39
+ if matches_blocks(blocks)
40
+
41
+ mouse_center(canvas, input)
42
+ trigger_mouse(input, down: true)
43
+
44
+ self.value = true
45
+
46
+ done!
47
+ end
48
+ end
49
+ end
50
+
51
+ class TriggerMouseUp < TriggerMouseBase
52
+ def execute(blocks, canvas, input)
53
+ if matches_blocks(blocks)
54
+
55
+ mouse_center(canvas, input)
56
+ trigger_mouse(input, up: true)
57
+
58
+ self.value = true
59
+
60
+ done!
61
+ end
62
+ end
63
+ end
64
+
65
+ class TriggerMouseClick < TriggerMouseBase
66
+ def execute(blocks, canvas, input)
67
+ if matches_blocks(blocks)
68
+
69
+ mouse_center(canvas, input)
70
+ trigger_mouse(input, clicked: true)
71
+
72
+ self.value = true
73
+
74
+ done!
75
+ end
76
+ end
77
+ end
78
+
79
+ class TriggerMouseRelease < TriggerMouseBase
80
+ def execute(blocks, canvas, input)
81
+ if matches_blocks(blocks)
82
+
83
+ mouse_center(canvas, input)
84
+ trigger_mouse(input, released: true)
85
+
86
+ self.value = true
87
+
88
+ done!
89
+ end
90
+ end
91
+ end
92
+
93
+ class TriggerMouseHover < Base
94
+ def location
95
+ state[:uuid]
96
+ end
97
+
98
+ def on_complete
99
+ return true if done?
100
+
101
+ return Automation::Error.new("Could not locate block")
102
+ end
103
+
104
+ def execute(blocks, canvas, input)
105
+ if matches_block(blocks[0])
106
+ mouse_center(canvas, input)
107
+
108
+ done!
109
+ end
110
+ end
111
+ end
112
+
113
+ class TriggerMouseMove < Base
114
+ def x
115
+ state[:x]
116
+ end
117
+
118
+ def y
119
+ state[:y]
120
+ end
121
+
122
+ def on_complete
123
+ return true
124
+ end
125
+
126
+ def execute(blocks, canvas, input)
127
+ mouse_move(x, y, input) unless done?
128
+
129
+ done!
130
+ end
131
+ end
132
+
133
+ class TriggerMouseDrag < Base
134
+ include MouseMethods
135
+
136
+ attr_accessor :dragging, :cursory_y, :button
137
+
138
+ def initialize(hash)
139
+ @dragging = false
140
+ @cursory_y = 0.0
141
+ @button = 0
142
+
143
+ super
144
+ end
145
+
146
+ def location
147
+ state[:uuid]
148
+ end
149
+
150
+ def x
151
+ state[:x]
152
+ end
153
+
154
+ def y
155
+ state[:y]
156
+ end
157
+
158
+ def on_complete
159
+ return false if dragging
160
+
161
+ true
162
+ end
163
+
164
+ def execute(blocks, canvas, input)
165
+ if matches_block(blocks[0])
166
+ local_x = x || canvas.x + (canvas.width / 2.0)
167
+ local_y = y || canvas.y + (canvas.height / 2.0)
168
+
169
+ if cursor_y < local_y && dragging
170
+ trigger_mouse(input, down: true)
171
+ mouse_move(local_x, cursor_y, input)
172
+
173
+ self.cursor_y += 2.0
174
+ elsif !dragging
175
+ trigger_mouse(input, clicked: true)
176
+
177
+ self.dragging = true
178
+ else
179
+ self.dragging = false
180
+
181
+ done!
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ class TriggerMouseWheel < Base
188
+ def location
189
+ state[:uuid]
190
+ end
191
+
192
+ def scroll_amount
193
+ state[:scroll_amount]
194
+ end
195
+
196
+ def on_complete
197
+ return true if done?
198
+
199
+ return Automation::Error.new("Could not locate block")
200
+ end
201
+
202
+ def execute(blocks, canvas, input)
203
+ if matches_block(blocks[0])
204
+ mouse_center(canvas, input)
205
+ LibHokusai.hoku_input_mouse_set_scroll(input, scroll_amount)
206
+
207
+
208
+ done!
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end