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.
- checksums.yaml +7 -0
- data/Dockerfile +26 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +91 -0
- data/LICENSE +21 -0
- data/README.md +28 -0
- data/ast/genheader +3 -0
- data/ast/include/hashmap.c +1151 -0
- data/ast/include/hashmap.c.license +20 -0
- data/ast/include/hashmap.h +54 -0
- data/ast/src/core/ast.c +448 -0
- data/ast/src/core/ast.h +259 -0
- data/ast/src/core/common.h +24 -0
- data/ast/src/core/component.c +85 -0
- data/ast/src/core/component.h +35 -0
- data/ast/src/core/hml.c +665 -0
- data/ast/src/core/hml.h +11 -0
- data/ast/src/core/input.c +458 -0
- data/ast/src/core/input.h +118 -0
- data/ast/src/core/style.c +101 -0
- data/ast/src/core/style.h +41 -0
- data/ast/src/core/text.c +784 -0
- data/ast/src/core/text.h +93 -0
- data/ast/src/core/util.c +140 -0
- data/ast/src/core/util.h +48 -0
- data/ast/src/hokusai.c +6 -0
- data/ast/src/hokusai.h +6 -0
- data/ast/test/fixtures/test.ui +13 -0
- data/ast/test/greatest.h +1266 -0
- data/ast/test/hokusai.c +14 -0
- data/ast/test/parser.c +234 -0
- data/ast/test/text.c +116 -0
- data/ext/extconf.rb +27 -0
- data/grammar/Cargo.lock +80 -0
- data/grammar/Cargo.toml +26 -0
- data/grammar/binding.gyp +20 -0
- data/grammar/bindings/node/binding.cc +28 -0
- data/grammar/bindings/node/index.js +19 -0
- data/grammar/bindings/rust/build.rs +40 -0
- data/grammar/bindings/rust/lib.rs +52 -0
- data/grammar/corpus/1_document.txt +131 -0
- data/grammar/corpus/2_selectors.txt +58 -0
- data/grammar/corpus/3_spaces.txt +69 -0
- data/grammar/corpus/4_errors.txt +10 -0
- data/grammar/corpus/5_macros.txt +175 -0
- data/grammar/corpus/6_styles.txt +81 -0
- data/grammar/grammar.js +275 -0
- data/grammar/package-lock.json +34 -0
- data/grammar/package.json +33 -0
- data/grammar/src/grammar.json +1269 -0
- data/grammar/src/node-types.json +474 -0
- data/grammar/src/parser.c +5772 -0
- data/grammar/src/scanner.c +258 -0
- data/grammar/src/tree_sitter/parser.h +230 -0
- data/grammar/src/tree_sitter/scanner.h +12 -0
- data/grammar/test.nml +10 -0
- data/hokusai.gemspec +19 -0
- data/ui/examples/assets/DigitalDisplay.ttf +0 -0
- data/ui/examples/assets/OpenSans-Regular.ttf +0 -0
- data/ui/examples/assets/addy.png +0 -0
- data/ui/examples/assets/baby_sean.png +0 -0
- data/ui/examples/assets/football-troll.png +0 -0
- data/ui/examples/assets/gear.png +0 -0
- data/ui/examples/assets/icecold.ttf +0 -0
- data/ui/examples/assets/science-troll.png +0 -0
- data/ui/examples/buddy.rb +31 -0
- data/ui/examples/clock.rb +58 -0
- data/ui/examples/counter.rb +123 -0
- data/ui/examples/dynamic.rb +147 -0
- data/ui/examples/foobar.rb +236 -0
- data/ui/examples/stock.rb +115 -0
- data/ui/examples/stock_decider/option.rb +74 -0
- data/ui/examples/tic_tac_toe.rb +246 -0
- data/ui/lib/lib_hokusai.rb +425 -0
- data/ui/spec/hokusai/ast_spec.rb +88 -0
- data/ui/spec/hokusai/automation/keys_transcoder_spec.rb +50 -0
- data/ui/spec/hokusai/automation/selector_spec.rb +68 -0
- data/ui/spec/hokusai/block_spec.rb +126 -0
- data/ui/spec/hokusai/directives_spec.rb +327 -0
- data/ui/spec/hokusai/e2e/client_spec.rb +58 -0
- data/ui/spec/hokusai/e2e/meta_spec.rb +42 -0
- data/ui/spec/hokusai/publisher_spec.rb +38 -0
- data/ui/spec/hokusai/slots_spec.rb +150 -0
- data/ui/spec/hokusai/util/piece_table_spec.rb +90 -0
- data/ui/spec/hokusai_spec.rb +0 -0
- data/ui/spec/spec_helper.rb +30 -0
- data/ui/src/hokusai/ast.rb +446 -0
- data/ui/src/hokusai/automation/client.rb +167 -0
- data/ui/src/hokusai/automation/constants.rb +98 -0
- data/ui/src/hokusai/automation/converters/selector_converter.rb +61 -0
- data/ui/src/hokusai/automation/driver.rb +54 -0
- data/ui/src/hokusai/automation/driver_command_queue.rb +50 -0
- data/ui/src/hokusai/automation/driver_commands/base.rb +79 -0
- data/ui/src/hokusai/automation/driver_commands/get_attribute.rb +41 -0
- data/ui/src/hokusai/automation/driver_commands/invoke.rb +33 -0
- data/ui/src/hokusai/automation/driver_commands/locate.rb +48 -0
- data/ui/src/hokusai/automation/driver_commands/trigger_keyboard.rb +94 -0
- data/ui/src/hokusai/automation/driver_commands/trigger_mouse.rb +213 -0
- data/ui/src/hokusai/automation/keys_transcoder.rb +128 -0
- data/ui/src/hokusai/automation/selector.rb +39 -0
- data/ui/src/hokusai/automation/server.rb +114 -0
- data/ui/src/hokusai/automation.rb +3 -0
- data/ui/src/hokusai/backends/raylib/config.rb +47 -0
- data/ui/src/hokusai/backends/raylib/font.rb +113 -0
- data/ui/src/hokusai/backends/raylib/keys.rb +124 -0
- data/ui/src/hokusai/backends/raylib.rb +449 -0
- data/ui/src/hokusai/backends/sdl2/Monaco.ttf +0 -0
- data/ui/src/hokusai/backends/sdl2/color.rb +12 -0
- data/ui/src/hokusai/backends/sdl2/config.rb +31 -0
- data/ui/src/hokusai/backends/sdl2/font.rb +127 -0
- data/ui/src/hokusai/backends/sdl2/keys.rb +119 -0
- data/ui/src/hokusai/backends/sdl2.rb +529 -0
- data/ui/src/hokusai/block.rb +237 -0
- data/ui/src/hokusai/blocks/button.rb +100 -0
- data/ui/src/hokusai/blocks/checkbox.rb +51 -0
- data/ui/src/hokusai/blocks/circle.rb +28 -0
- data/ui/src/hokusai/blocks/clipped.rb +23 -0
- data/ui/src/hokusai/blocks/cursor.rb +49 -0
- data/ui/src/hokusai/blocks/dynamic.rb +37 -0
- data/ui/src/hokusai/blocks/empty.rb +10 -0
- data/ui/src/hokusai/blocks/hblock.rb +35 -0
- data/ui/src/hokusai/blocks/image.rb +18 -0
- data/ui/src/hokusai/blocks/input.rb +200 -0
- data/ui/src/hokusai/blocks/label.rb +39 -0
- data/ui/src/hokusai/blocks/panel.rb +126 -0
- data/ui/src/hokusai/blocks/rect.rb +24 -0
- data/ui/src/hokusai/blocks/scissor_begin.rb +18 -0
- data/ui/src/hokusai/blocks/scissor_end.rb +12 -0
- data/ui/src/hokusai/blocks/scrollbar.rb +103 -0
- data/ui/src/hokusai/blocks/selectable.rb +77 -0
- data/ui/src/hokusai/blocks/svg.rb +20 -0
- data/ui/src/hokusai/blocks/text.rb +214 -0
- data/ui/src/hokusai/blocks/titlebar/osx.rb +145 -0
- data/ui/src/hokusai/blocks/toggle.rb +55 -0
- data/ui/src/hokusai/blocks/vblock.rb +35 -0
- data/ui/src/hokusai/commands/base.rb +22 -0
- data/ui/src/hokusai/commands/circle.rb +47 -0
- data/ui/src/hokusai/commands/image.rb +45 -0
- data/ui/src/hokusai/commands/rect.rb +158 -0
- data/ui/src/hokusai/commands/scissor.rb +22 -0
- data/ui/src/hokusai/commands/text.rb +92 -0
- data/ui/src/hokusai/commands.rb +87 -0
- data/ui/src/hokusai/diff.rb +124 -0
- data/ui/src/hokusai/error.rb +3 -0
- data/ui/src/hokusai/event.rb +54 -0
- data/ui/src/hokusai/events/keyboard.rb +84 -0
- data/ui/src/hokusai/events/mouse.rb +172 -0
- data/ui/src/hokusai/font.rb +280 -0
- data/ui/src/hokusai/meta.rb +152 -0
- data/ui/src/hokusai/mounting/loop_entry.rb +230 -0
- data/ui/src/hokusai/mounting/mount_entry.rb +74 -0
- data/ui/src/hokusai/mounting/update_entry.rb +101 -0
- data/ui/src/hokusai/node.rb +98 -0
- data/ui/src/hokusai/node_mounter.rb +102 -0
- data/ui/src/hokusai/painter.rb +214 -0
- data/ui/src/hokusai/publisher.rb +32 -0
- data/ui/src/hokusai/style.rb +72 -0
- data/ui/src/hokusai/types.rb +266 -0
- data/ui/src/hokusai/util/clamping_iterator.rb +202 -0
- data/ui/src/hokusai/util/piece_table.rb +111 -0
- data/ui/src/hokusai/util/selection.rb +145 -0
- data/ui/src/hokusai.rb +120 -0
- data/ui/vendor/.gitkeep +0 -0
- data/vendor/.gitkeep +0 -0
- data/xmake.lua +192 -0
- metadata +222 -0
@@ -0,0 +1,214 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./event"
|
4
|
+
|
5
|
+
module Hokusai
|
6
|
+
class PainterEntry
|
7
|
+
attr_reader :block, :parent, :x, :y, :w, :h
|
8
|
+
def initialize(block, x, y, w, h)
|
9
|
+
@block = block
|
10
|
+
@x = x
|
11
|
+
@y = y
|
12
|
+
@w = w
|
13
|
+
@h = h
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class CursorState
|
18
|
+
attr_accessor :set
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@set = false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Painter
|
26
|
+
attr_reader :root, :input, :before_render, :after_render,
|
27
|
+
:events
|
28
|
+
|
29
|
+
def initialize(root, input)
|
30
|
+
state = CursorState.new
|
31
|
+
|
32
|
+
@root = root
|
33
|
+
@input = input
|
34
|
+
@events = {
|
35
|
+
hover: HoverEvent.new(input, state),
|
36
|
+
wheel: WheelEvent.new(input, state),
|
37
|
+
click: ClickEvent.new(input, state),
|
38
|
+
mousemove: MouseMoveEvent.new(input, state),
|
39
|
+
mouseout: MouseOutEvent.new(input, state),
|
40
|
+
mouseup: MouseUpEvent.new(input, state),
|
41
|
+
mousedown: MouseDownEvent.new(input, state),
|
42
|
+
keyup: KeyUpEvent.new(input, state),
|
43
|
+
keypress: KeyPressEvent.new(input, state)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def on_before_render(&block)
|
48
|
+
@before_render = block
|
49
|
+
end
|
50
|
+
|
51
|
+
def on_after_render(&block)
|
52
|
+
@after_render = block
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Array(Commands::Base)] the command list
|
56
|
+
def render(canvas, resize = false, capture: true)
|
57
|
+
return if root.children.empty?
|
58
|
+
|
59
|
+
@root.on_resize(canvas) if resize
|
60
|
+
|
61
|
+
before_render&.call([root, nil], canvas, input)
|
62
|
+
|
63
|
+
root_children = (canvas.reverse? ? root.children?&.reverse.dup : root.children?&.dup) || []
|
64
|
+
groups = []
|
65
|
+
groups << [root, measure(root_children, canvas)]
|
66
|
+
|
67
|
+
mouse_y = input.mouse.pos[:y]
|
68
|
+
can_capture = mouse_y >= (canvas.y || 0.0) && mouse_y <= (canvas.y || 0.0) + canvas.height
|
69
|
+
|
70
|
+
hovered = false
|
71
|
+
|
72
|
+
while payload = groups.pop
|
73
|
+
group_parent, group_children = payload
|
74
|
+
|
75
|
+
while group = group_children.shift
|
76
|
+
canvas.reset(group.x, group.y, group.w, group.h)
|
77
|
+
|
78
|
+
before_render&.call([group.block, group.parent], canvas, input.raw)
|
79
|
+
|
80
|
+
if capture && can_capture
|
81
|
+
capture_events(group.block, canvas, hovered: hovered)
|
82
|
+
end
|
83
|
+
|
84
|
+
if resize
|
85
|
+
group.block.on_resize(canvas)
|
86
|
+
end
|
87
|
+
|
88
|
+
breaked = false
|
89
|
+
|
90
|
+
group.block.render(canvas) do |local_canvas|
|
91
|
+
local_children = (local_canvas.reverse? ? group.block.children?&.reverse : group.block.children?)
|
92
|
+
|
93
|
+
unless local_children.nil?
|
94
|
+
groups << [group_parent, group_children]
|
95
|
+
groups << [group.block, measure(local_children, local_canvas)]
|
96
|
+
breaked = true
|
97
|
+
else
|
98
|
+
breaked = false
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
break if breaked
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
if capture
|
107
|
+
events[:hover].bubble
|
108
|
+
events[:wheel].bubble
|
109
|
+
events[:click].bubble
|
110
|
+
events[:keyup].bubble
|
111
|
+
events[:keypress].bubble
|
112
|
+
events[:mousemove].bubble
|
113
|
+
events[:mouseout].bubble
|
114
|
+
events[:mousedown].bubble
|
115
|
+
events[:mouseup].bubble
|
116
|
+
end
|
117
|
+
|
118
|
+
after_render&.call
|
119
|
+
end
|
120
|
+
|
121
|
+
def measure(children, canvas)
|
122
|
+
x = canvas.x || 0.0
|
123
|
+
y = canvas.y || 0.0
|
124
|
+
width = canvas.width
|
125
|
+
height = canvas.height
|
126
|
+
vertical = canvas.vertical
|
127
|
+
|
128
|
+
count = 0
|
129
|
+
wcount = 0
|
130
|
+
hcount = 0
|
131
|
+
wsum = 0.0
|
132
|
+
hsum = 0.0
|
133
|
+
|
134
|
+
children.each do |block|
|
135
|
+
# children.each do |block|
|
136
|
+
h = block.node.meta.get_prop?(:height)&.to_f
|
137
|
+
w = block.node.meta.get_prop?(:width)&.to_f
|
138
|
+
|
139
|
+
if w
|
140
|
+
wsum += w
|
141
|
+
wcount = wcount.succ
|
142
|
+
end
|
143
|
+
|
144
|
+
if h
|
145
|
+
hsum += h
|
146
|
+
hcount = hcount.succ
|
147
|
+
end
|
148
|
+
|
149
|
+
count = count.succ
|
150
|
+
end
|
151
|
+
|
152
|
+
neww = width
|
153
|
+
newh = height
|
154
|
+
|
155
|
+
if vertical
|
156
|
+
c = (count - hcount)
|
157
|
+
newh = (newh - hsum) / (c.zero? ? 1 : c)
|
158
|
+
else
|
159
|
+
c = (count - wcount)
|
160
|
+
neww = (neww - wsum) / (c.zero? ? 1 : c)
|
161
|
+
end
|
162
|
+
|
163
|
+
entries = []
|
164
|
+
|
165
|
+
children.each do |block|
|
166
|
+
# nw, nh = ntuple
|
167
|
+
w = block.node.meta.get_prop?(:width)&.to_f || neww
|
168
|
+
h = block.node.meta.get_prop?(:height)&.to_f || newh
|
169
|
+
|
170
|
+
# local_canvas = Hokusai::Canvas.new(w, h, x, y)
|
171
|
+
# block.node.meta.props[:height] ||= h
|
172
|
+
# block.node.meta.props[:width] ||= w
|
173
|
+
|
174
|
+
entries << PainterEntry.new(block, x, y, w, h).freeze
|
175
|
+
|
176
|
+
if vertical
|
177
|
+
y += h
|
178
|
+
else
|
179
|
+
x += w
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
entries
|
184
|
+
end
|
185
|
+
|
186
|
+
def capture_events(block, canvas, hovered: false)
|
187
|
+
if block.node.portal.nil?
|
188
|
+
return
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
rect = canvas.to_hoku_rect
|
193
|
+
block_is_hovered = LibHokusai.hoku_input_is_hovered(input.raw, rect)
|
194
|
+
|
195
|
+
if block_is_hovered
|
196
|
+
events[:hover].capture(block, canvas)
|
197
|
+
events[:click].capture(block, canvas)
|
198
|
+
events[:wheel].capture(block, canvas)
|
199
|
+
events[:mousedown].capture(block, canvas)
|
200
|
+
events[:mouseup].capture(block, canvas)
|
201
|
+
else
|
202
|
+
events[:mouseout].capture(block, canvas)
|
203
|
+
end
|
204
|
+
|
205
|
+
events[:mousemove].capture(block, canvas)
|
206
|
+
|
207
|
+
if block_is_hovered || block.node.meta.focused
|
208
|
+
events[:keyup].capture(block, canvas)
|
209
|
+
events[:keypress].capture(block, canvas)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Hokusai
|
2
|
+
# An event emitter
|
3
|
+
class Publisher
|
4
|
+
attr_reader :listeners
|
5
|
+
|
6
|
+
def initialize(listeners = [])
|
7
|
+
@listeners = listeners
|
8
|
+
end
|
9
|
+
|
10
|
+
# Adds a listener that subscribes
|
11
|
+
# to events emitted
|
12
|
+
# by this publisher
|
13
|
+
#
|
14
|
+
# @param [Hokusai::Block] listener
|
15
|
+
def add(listener)
|
16
|
+
listeners << listener
|
17
|
+
end
|
18
|
+
|
19
|
+
# emits `event` with `**args`
|
20
|
+
# to all subscribers
|
21
|
+
# @see
|
22
|
+
# @param [String] name the event name
|
23
|
+
# @param [**args] the args to emit
|
24
|
+
def notify(name, *args, **kwargs)
|
25
|
+
listeners.each do |listener|
|
26
|
+
raise Hokusai::Error.new("No target `##{name}` on #{listener.class}") unless listener.respond_to?(name)
|
27
|
+
|
28
|
+
listener.public_send(name, *args, **kwargs)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Hokusai
|
2
|
+
class Style
|
3
|
+
attr_reader :raw
|
4
|
+
|
5
|
+
def self.parse(template)
|
6
|
+
raw = LibHokusai.parse_style(template)
|
7
|
+
new(parse_styles(raw))
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.parse_styles(raw)
|
11
|
+
styles = {}
|
12
|
+
|
13
|
+
until raw.null?
|
14
|
+
styles[raw[:name]] = parse_attributes(raw[:attributes])
|
15
|
+
|
16
|
+
raw = raw[:next]
|
17
|
+
end
|
18
|
+
|
19
|
+
styles
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.parse_attributes(raw)
|
23
|
+
attributes = {}
|
24
|
+
|
25
|
+
until raw.null?
|
26
|
+
case raw[:type]
|
27
|
+
when :style_int
|
28
|
+
value = raw[:value].to_i
|
29
|
+
when :style_bool
|
30
|
+
value = (raw[:value] == "true")
|
31
|
+
when :style_float
|
32
|
+
value = raw[:value].to_f
|
33
|
+
when :style_string
|
34
|
+
value = raw[:value]
|
35
|
+
when :style_func
|
36
|
+
value = parse_function(raw[:function_name], raw[:value])
|
37
|
+
end
|
38
|
+
|
39
|
+
attributes[raw[:name]] = value
|
40
|
+
|
41
|
+
raw = raw[:next]
|
42
|
+
end
|
43
|
+
|
44
|
+
attributes
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.parse_function(name, value)
|
48
|
+
case name
|
49
|
+
when "rgb"
|
50
|
+
Color.convert(value)
|
51
|
+
when "outline"
|
52
|
+
Outline.convert(value)
|
53
|
+
when "padding"
|
54
|
+
Padding.convert(value)
|
55
|
+
else
|
56
|
+
raise Hokusai::Error.new("Unknown style function #{name}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize(elements)
|
61
|
+
@elements = elements
|
62
|
+
end
|
63
|
+
|
64
|
+
def [](element_name)
|
65
|
+
@elements[element_name]
|
66
|
+
end
|
67
|
+
|
68
|
+
def keys
|
69
|
+
@elements.keys
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hokusai
|
4
|
+
# Rect = Struct.new(:x, :y, :width, :height) do
|
5
|
+
class Rect
|
6
|
+
attr_accessor :x, :y, :width, :height
|
7
|
+
|
8
|
+
def initialize(x, y, width, height)
|
9
|
+
@x = x
|
10
|
+
@y = y
|
11
|
+
@width = width
|
12
|
+
@height = height
|
13
|
+
end
|
14
|
+
def to_hoku_rect
|
15
|
+
@hoku_rect ||= LibHokusai::HmlRect.create(x, y, width, height)
|
16
|
+
end
|
17
|
+
|
18
|
+
def includes_y?(y)
|
19
|
+
LibHokusai.hoku_rect_includes_y(to_hoku_rect, y)
|
20
|
+
end
|
21
|
+
|
22
|
+
def includes_x?(x)
|
23
|
+
LibHokusai.hoku_rect_includes_x(to_hoku_rect, x)
|
24
|
+
end
|
25
|
+
|
26
|
+
def move_x_left(times = 1)
|
27
|
+
LibHokusai.hoku_rect_x_left(to_hoku_rect, times)
|
28
|
+
end
|
29
|
+
|
30
|
+
def move_x_right(times = 1)
|
31
|
+
LibHokusai.hoku_rect_x_right(to_hoku_rect, times)
|
32
|
+
end
|
33
|
+
|
34
|
+
def move_y_up(times = 1)
|
35
|
+
LibHokusai.hoku_rect_y_up(to_hoku_rect, times)
|
36
|
+
end
|
37
|
+
|
38
|
+
def move_y_down(times = 1)
|
39
|
+
LibHokusai.hoku_rect_y_down(to_hoku_rect, times)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.from_hoku_rect(rect)
|
43
|
+
self.x = rect[:x]
|
44
|
+
self.y = rect[:y]
|
45
|
+
self.width = rect[:w]
|
46
|
+
self.height = rect[:h]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Outline = Struct.new(:top, :right, :bottom, :left) do
|
51
|
+
def self.default
|
52
|
+
new(0.0, 0.0, 0.0, 0.0)
|
53
|
+
end
|
54
|
+
|
55
|
+
def hash
|
56
|
+
[self.class, top, right, bottom, left].hash
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.convert(value)
|
60
|
+
case value
|
61
|
+
when String
|
62
|
+
if value =~ /,/
|
63
|
+
convert(value.split(",").map(&:to_f))
|
64
|
+
else
|
65
|
+
convert(value.to_f)
|
66
|
+
end
|
67
|
+
when Float
|
68
|
+
new(value, value, value, value)
|
69
|
+
when Array
|
70
|
+
new(value[0] || 0.0, value[1] || 0.0, value[2] || 0.0, value[3] || 0.0)
|
71
|
+
when Outline
|
72
|
+
value
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def present?
|
77
|
+
top > 0.0 || right > 0.0 || bottom > 0.0 || left > 0.0
|
78
|
+
end
|
79
|
+
|
80
|
+
def uniform?
|
81
|
+
top == right && top == bottom && top == left
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class Padding
|
86
|
+
attr_reader :top, :left, :right, :bottom
|
87
|
+
def initialize(top, right, bottom, left)
|
88
|
+
@top = top
|
89
|
+
@left = left
|
90
|
+
@right = right
|
91
|
+
@bottom = bottom
|
92
|
+
end
|
93
|
+
|
94
|
+
alias_method :t, :top
|
95
|
+
alias_method :l, :left
|
96
|
+
alias_method :r, :right
|
97
|
+
alias_method :b, :bottom
|
98
|
+
|
99
|
+
def self.convert(value)
|
100
|
+
case value
|
101
|
+
when String
|
102
|
+
if value =~ /,/
|
103
|
+
convert(value.split(",").map(&:to_f))
|
104
|
+
else
|
105
|
+
convert(value.to_i)
|
106
|
+
end
|
107
|
+
when Integer
|
108
|
+
new(value, value, value, value)
|
109
|
+
when Array
|
110
|
+
new(value[0], value[1], value[2], value[3])
|
111
|
+
when Padding
|
112
|
+
value
|
113
|
+
else
|
114
|
+
raise Hokusai::Error.new("Unsupported conversion type #{value.class} for Hokusai::Padding")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def hash
|
119
|
+
[self.class, top, right, bottom, left].hash
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class Canvas
|
124
|
+
attr_accessor :width, :height, :x, :y, :vertical, :reverse
|
125
|
+
def initialize(width, height, x = 0.0, y = 0.0, vertical = true, reverse = false)
|
126
|
+
@width = width
|
127
|
+
@height = height
|
128
|
+
@x = x
|
129
|
+
@y = y
|
130
|
+
@vertical = vertical
|
131
|
+
@reverse = reverse
|
132
|
+
end
|
133
|
+
|
134
|
+
def reset(x, y, width, height, vertical: true, reverse: false)
|
135
|
+
self.x = x
|
136
|
+
self.y = y
|
137
|
+
self.width = width
|
138
|
+
self.height = height
|
139
|
+
self.vertical = vertical
|
140
|
+
self.reverse = reverse
|
141
|
+
end
|
142
|
+
|
143
|
+
def to_bounds
|
144
|
+
Hokusai::Rect.new(x, y, width, height)
|
145
|
+
end
|
146
|
+
|
147
|
+
def reverse?
|
148
|
+
reverse
|
149
|
+
end
|
150
|
+
|
151
|
+
def to_hoku_rect
|
152
|
+
LibHokusai::HmlRect.create(x, y, width, height)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Color = Struct.new(:red, :green, :blue, :alpha) do
|
157
|
+
class Color
|
158
|
+
attr_reader :red, :green, :blue, :alpha
|
159
|
+
def initialize(red, green, blue, alpha = 255)
|
160
|
+
@red = red.freeze
|
161
|
+
@green = green.freeze
|
162
|
+
@blue = blue.freeze
|
163
|
+
@alpha = alpha.freeze
|
164
|
+
end
|
165
|
+
|
166
|
+
alias_method :r, :red
|
167
|
+
alias_method :b, :blue
|
168
|
+
alias_method :g, :green
|
169
|
+
alias_method :a, :alpha
|
170
|
+
|
171
|
+
def self.convert(value)
|
172
|
+
case value
|
173
|
+
when String
|
174
|
+
value = value.split(",").map(&:to_i)
|
175
|
+
when Array
|
176
|
+
when Color
|
177
|
+
return value
|
178
|
+
else
|
179
|
+
raise Hokusai::Error.new("Unsupported conversion type #{value.class} for Hokusai::Color")
|
180
|
+
end
|
181
|
+
|
182
|
+
new(value[0], value[1], value[2], value[3] || 255)
|
183
|
+
end
|
184
|
+
|
185
|
+
def hash
|
186
|
+
[self.class, r, g, b, a].hash
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
class Keyboard
|
191
|
+
attr_reader :raw
|
192
|
+
|
193
|
+
[
|
194
|
+
:shift, :super, :ctrl,
|
195
|
+
:alt, :pressed, :pressed_len, :released,
|
196
|
+
:released_len
|
197
|
+
].each do |name|
|
198
|
+
define_method(name) do
|
199
|
+
raw[name]
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def keyboard_key
|
204
|
+
pressed.read_array_of_type(TYPE_UINT8, :read_uint8, pressed_len).first
|
205
|
+
end
|
206
|
+
|
207
|
+
def key
|
208
|
+
keyboard_key[:key][:key]
|
209
|
+
end
|
210
|
+
|
211
|
+
def initialize(raw)
|
212
|
+
@raw = raw
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
class Mouse
|
217
|
+
attr_reader :raw
|
218
|
+
|
219
|
+
def initialize(raw)
|
220
|
+
@raw = raw
|
221
|
+
end
|
222
|
+
|
223
|
+
[
|
224
|
+
:pos, :delta, :scroll,
|
225
|
+
:scroll_delta, :selection,
|
226
|
+
:selection_type, :left,
|
227
|
+
:middle, :right
|
228
|
+
].each do |name|
|
229
|
+
define_method(name) do
|
230
|
+
# instance_variable_set("@#{name}", raw[name]) if instance_variable_get("@#{name}").nil?
|
231
|
+
#
|
232
|
+
# instance_variable_get("@#{name}")
|
233
|
+
|
234
|
+
raw[name]
|
235
|
+
end
|
236
|
+
|
237
|
+
define_method("#{name}=") do |val|
|
238
|
+
raw[name] = val
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
class Input
|
244
|
+
attr_reader :raw
|
245
|
+
|
246
|
+
def hash
|
247
|
+
[self.class, mouse.pos.x, mouse.pos.y, mouse.scroll, mouse.left.clicked, mouse.left.down, mouse.left.up].hash
|
248
|
+
end
|
249
|
+
|
250
|
+
def initialize(raw)
|
251
|
+
@raw = raw
|
252
|
+
end
|
253
|
+
|
254
|
+
def keyboard
|
255
|
+
Keyboard.new(@raw[:keyboard])
|
256
|
+
end
|
257
|
+
|
258
|
+
def mouse
|
259
|
+
@mouse ||= Mouse.new(@raw[:mouse])
|
260
|
+
end
|
261
|
+
|
262
|
+
def hovered?(canvas)
|
263
|
+
LibHokusai.hoku_input_is_hovered(raw, canvas.to_hoku_rect)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|