hokusai-zero 0.2.6 → 0.2.7

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -1
  3. data/Gemfile.lock +0 -2
  4. data/README.md +1 -1
  5. data/ast/src/core/ast.c +3 -11
  6. data/ast/src/core/hml.c +212 -40
  7. data/ast/src/core/hml.h +1 -0
  8. data/ast/src/core/input.h +0 -1
  9. data/ast/src/core/log.c +87 -0
  10. data/ast/src/core/log.h +41 -0
  11. data/ast/src/core/util.c +23 -23
  12. data/ast/src/core/util.h +7 -7
  13. data/ast/test/parser.c +1 -0
  14. data/ext/extconf.rb +6 -6
  15. data/hokusai.gemspec +1 -2
  16. data/ui/examples/drag.rb +154 -0
  17. data/ui/examples/embedded.rb +58 -0
  18. data/ui/examples/forum/file.rb +1 -1
  19. data/ui/examples/forum/post.rb +0 -1
  20. data/ui/examples/forum.rb +7 -7
  21. data/ui/examples/game.rb +143 -0
  22. data/ui/examples/keyboard.rb +47 -0
  23. data/ui/examples/overlay.rb +233 -0
  24. data/ui/examples/provider.rb +56 -0
  25. data/ui/examples/shader/test.rb +155 -0
  26. data/ui/examples/shader.rb +100 -0
  27. data/ui/examples/spreadsheet.rb +12 -11
  28. data/ui/examples/wiki.rb +82 -0
  29. data/ui/lib/lib_hokusai.rb +43 -24
  30. data/ui/spec/hokusai/e2e/keyboard_spec.rb +52 -0
  31. data/ui/spec/spec_helper.rb +1 -1
  32. data/ui/src/hokusai/assets/arrow-down-line.png +0 -0
  33. data/ui/src/hokusai/assets/arrow-down-wide-line.png +0 -0
  34. data/ui/src/hokusai/assets/icons/outline/arrow-big-up.svg +19 -0
  35. data/ui/src/hokusai/assets/icons/outline/backspace.svg +20 -0
  36. data/ui/src/hokusai/automation/driver_commands/base.rb +2 -8
  37. data/ui/src/hokusai/automation/driver_commands/trigger_keyboard.rb +3 -6
  38. data/ui/src/hokusai/automation/driver_commands/trigger_mouse.rb +12 -5
  39. data/ui/src/hokusai/automation/server.rb +2 -3
  40. data/ui/src/hokusai/backends/raylib/config.rb +2 -1
  41. data/ui/src/hokusai/backends/raylib/font.rb +24 -3
  42. data/ui/src/hokusai/backends/raylib.rb +167 -36
  43. data/ui/src/hokusai/backends/sdl2/config.rb +9 -6
  44. data/ui/src/hokusai/backends/sdl2/font.rb +3 -1
  45. data/ui/src/hokusai/backends/sdl2.rb +188 -93
  46. data/ui/src/hokusai/blocks/color_picker.rb +1080 -0
  47. data/ui/src/hokusai/blocks/input.rb +2 -2
  48. data/ui/src/hokusai/blocks/keyboard.rb +249 -0
  49. data/ui/src/hokusai/blocks/shader_begin.rb +22 -0
  50. data/ui/src/hokusai/blocks/shader_end.rb +12 -0
  51. data/ui/src/hokusai/blocks/slider.rb +139 -0
  52. data/ui/src/hokusai/blocks/texture.rb +23 -0
  53. data/ui/src/hokusai/commands/rect.rb +12 -3
  54. data/ui/src/hokusai/commands/shader.rb +33 -0
  55. data/ui/src/hokusai/commands/texture.rb +26 -0
  56. data/ui/src/hokusai/commands.rb +22 -0
  57. data/ui/src/hokusai/event.rb +2 -1
  58. data/ui/src/hokusai/events/keyboard.rb +11 -18
  59. data/ui/src/hokusai/events/mouse.rb +10 -8
  60. data/ui/src/hokusai/events/touch.rb +62 -0
  61. data/ui/src/hokusai/meta.rb +9 -4
  62. data/ui/src/hokusai/mounting/loop_entry.rb +1 -1
  63. data/ui/src/hokusai/mounting/update_entry.rb +7 -6
  64. data/ui/src/hokusai/painter.rb +31 -8
  65. data/ui/src/hokusai/types/display.rb +151 -0
  66. data/ui/src/hokusai/types/keyboard.rb +168 -0
  67. data/ui/src/hokusai/types/mouse.rb +36 -0
  68. data/ui/src/hokusai/types/primitives.rb +56 -0
  69. data/ui/src/hokusai/types/touch.rb +181 -0
  70. data/ui/src/hokusai/types.rb +20 -244
  71. data/ui/src/hokusai/util/wrap_stream.rb +193 -0
  72. data/ui/src/hokusai.rb +61 -35
  73. data/xmake.lua +2 -1
  74. metadata +34 -22
  75. data/ui/src/hokusai/assets/chevron-down.svg +0 -1
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Hokusai
2
4
  class MouseEvent < Event
3
5
  extend Forwardable
@@ -67,7 +69,7 @@ module Hokusai
67
69
  protected
68
70
 
69
71
  def hovered(canvas)
70
- LibHokusai.hoku_input_is_hovered(input.raw, canvas.to_hoku_rect)
72
+ input.hovered?(canvas)
71
73
  end
72
74
  end
73
75
 
@@ -85,19 +87,19 @@ module Hokusai
85
87
  name "click"
86
88
 
87
89
  def capture(block, canvas)
88
- if left[:clicked] && clicked(canvas)
90
+ if left.clicked && clicked(canvas)
89
91
  block.node.meta.focus
90
92
 
91
93
  if matches(block)
92
94
  captures << block
93
95
  end
94
- elsif left[:clicked]
96
+ elsif left.clicked
95
97
  block.node.meta.blur
96
98
  end
97
99
  end
98
100
 
99
101
  def clicked(canvas)
100
- LibHokusai.hoku_input_is_clicked(input.raw, canvas.to_hoku_rect)
102
+ left.clicked && input.hovered?(canvas)
101
103
  end
102
104
  end
103
105
 
@@ -105,7 +107,7 @@ module Hokusai
105
107
  name "mouseup"
106
108
 
107
109
  def capture(block, _)
108
- if left[:up] && matches(block)
110
+ if left.up && matches(block)
109
111
  captures << block
110
112
  end
111
113
  end
@@ -115,7 +117,7 @@ module Hokusai
115
117
  name "mousedown"
116
118
 
117
119
  def capture(block, _)
118
- if left[:down] && matches(block)
120
+ if left.down && matches(block)
119
121
  captures << block
120
122
  end
121
123
  end
@@ -168,13 +170,13 @@ module Hokusai
168
170
  def capture(block, canvas)
169
171
  captures << block if matches(block)
170
172
 
171
- if left[:clicked] && !clicked(canvas)
173
+ if left.clicked && !clicked(canvas)
172
174
  block.node.meta.blur
173
175
  end
174
176
  end
175
177
 
176
178
  def clicked(canvas)
177
- LibHokusai.hoku_input_is_clicked(input.raw, canvas.to_hoku_rect)
179
+ left.clicked && input.hovered?(canvas)
178
180
  end
179
181
  end
180
182
  end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hokusai
4
+ class TouchEvent < Event
5
+ extend Forwardable
6
+
7
+ def_delegators :@touch, :tapped?, :swiped?, :longtapped?, :longtapping?, :touching?,
8
+ :duration, :direction, :distance, :angle, :position, :last_position,
9
+ :touch_len, :touch_count, :timer
10
+
11
+ attr_reader :input
12
+
13
+ def initialize(input, state)
14
+ @input = input
15
+ @state = state
16
+ @touch = input.touch
17
+ end
18
+
19
+ def hovered(canvas)
20
+ input.hovered?(canvas)
21
+ end
22
+
23
+ def to_json
24
+ {
25
+ keypress: {
26
+ hold: hold,
27
+ hold_duration: hold_duration.to_s,
28
+ }
29
+ }.to_json
30
+ end
31
+ end
32
+
33
+ class TapHoldEvent < TouchEvent
34
+ name "taphold"
35
+
36
+ def capture(block, canvas)
37
+ if matches(block) && longtapped? && hovered(canvas)
38
+ captures << block
39
+ end
40
+ end
41
+ end
42
+
43
+ class PinchEvent < TouchEvent
44
+ name "pinch"
45
+
46
+ def capture(block, canvas)
47
+ if false && matches(block)
48
+ captures << block
49
+ end
50
+ end
51
+ end
52
+
53
+ class SwipeEvent < TouchEvent
54
+ name "swipe"
55
+
56
+ def capture(block, canvas)
57
+ if swiped? && matches(block)
58
+ captures << block
59
+ end
60
+ end
61
+ end
62
+ end
@@ -118,10 +118,15 @@ module Hokusai
118
118
  child.update
119
119
  end
120
120
  end
121
-
122
- def has_ast?(ast, index)
123
- if portal = children![index]&.node&.portal&.portal
124
- return portal.ast.object_id == ast.object_id
121
+ def has_ast?(ast, index, elsy = false)
122
+ if elsy
123
+ if portal = children![index]&.node&.portal
124
+ return portal.ast.object_id == ast.object_id
125
+ end
126
+ else
127
+ if portal = children![index]&.node&.portal&.portal
128
+ return portal.ast.object_id == ast.object_id
129
+ end
125
130
  end
126
131
 
127
132
  false
@@ -65,7 +65,7 @@ module Hokusai
65
65
 
66
66
  portal = Node.new(ast)
67
67
  node = child_block_class.compile(ast.type, portal)
68
- child_block = child_block_class.new(node: node)
68
+ child_block = child_block_class.new(node: node, providers: mount_providers)
69
69
  child_block.node.add_styles(target.class)
70
70
  child_block.node.add_props_from_block(target, context: ctx)
71
71
  child_block.node.meta.set_prop(ast.loop.var.to_sym, value)
@@ -19,8 +19,8 @@ module Hokusai
19
19
  portal.ast.children.each_with_index do |child, index|
20
20
  next unless child.has_if_condition?
21
21
 
22
- child_present = ->(child) do
23
- meta.has_ast?(child, index)
22
+ child_present = ->(child, elsy) do
23
+ meta.has_ast?(child, index, elsy)
24
24
  end
25
25
 
26
26
  if child.if.args.size > 0
@@ -33,11 +33,11 @@ module Hokusai
33
33
 
34
34
  if !!visible
35
35
  if child.else_condition_active?
36
- meta.child_delete(index) if child_present.call(child)
36
+ meta.child_delete(index) if child_present.call(child, false)
37
37
  child.else_active = 0
38
38
  end
39
39
 
40
- unless child_present.call(child)
40
+ unless child_present.call(child, true)
41
41
  portal = Node.new(child, Node.new(child))
42
42
  node = child_block_klass.compile("root", portal)
43
43
  node.add_styles(target.class)
@@ -52,8 +52,9 @@ module Hokusai
52
52
  child_block = NodeMounter.new(node, child_block_klass, [stack], previous_providers: providers).mount(context: context, providers: providers)
53
53
 
54
54
  UpdateEntry.new(child_block, block, target).register(context: context, providers: providers)
55
-
55
+ pp [meta.has_ast?(child, index, false), "shouldn't be here?"]
56
56
  meta.children!.insert(index, child_block)
57
+ pp ["children", meta.children!.size, meta.children!.map(&:class)]
57
58
 
58
59
  child_block.public_send(:before_updated) if child_block.respond_to?(:before_updated)
59
60
  child_block.update
@@ -61,7 +62,7 @@ module Hokusai
61
62
  end
62
63
  elsif !visible
63
64
  if !child.has_else_condition? || (child.has_else_condition? && !child.else_condition_active?)
64
- if (child_present.call(child))
65
+ if (child_present.call(child, true))
65
66
  meta.child_delete(index)
66
67
  end
67
68
  end
@@ -45,6 +45,16 @@ module Hokusai
45
45
  keyup: KeyUpEvent.new(input, state),
46
46
  keypress: KeyPressEvent.new(input, state)
47
47
  }
48
+
49
+ add_touch_events(events, input, state) unless input.touch.nil?
50
+ end
51
+
52
+ def add_touch_events(events, input, state)
53
+ events.merge!({
54
+ taphold: TapHoldEvent.new(input, state),
55
+ pinch: PinchEvent.new(input, state),
56
+ swipe: SwipeEvent.new(input, state),
57
+ })
48
58
  end
49
59
 
50
60
  def on_before_render(&block)
@@ -86,7 +96,7 @@ module Hokusai
86
96
  root_entry = PainterEntry.new(root, canvas.x, canvas.y, canvas.width, canvas.height)
87
97
  groups << [root_entry, measure(root_children, canvas)]
88
98
 
89
- mouse_y = input.mouse.pos[:y]
99
+ mouse_y = input.mouse.pos.y
90
100
  can_capture = mouse_y >= (canvas.y || 0.0) && mouse_y <= (canvas.y || 0.0) + canvas.height
91
101
 
92
102
  hovered = false
@@ -100,7 +110,6 @@ module Hokusai
100
110
  while group = group_children.shift
101
111
  z = group.block.node.meta.get_prop(:z)&.to_i || 0
102
112
  ztarget = group.block.node.meta.get_prop(:ztarget)
103
- entry = PainterEntry.new(group.block, group.x, group.y, group.w, group.h)
104
113
 
105
114
  if (zindex_counter > 0 || z > 0)
106
115
  case ztarget
@@ -108,12 +117,17 @@ module Hokusai
108
117
  entry = PainterEntry.new(group.block, zroot_x || 0.0, zroot_y || 0.0, zroot_w, zroot_h).freeze
109
118
  when ZTARGET_PARENT
110
119
  entry = PainterEntry.new(group.block, group_parent.x || 0.0, group_parent.y || 0.0, group_parent.w, group_parent.h).freeze
120
+ else
121
+ entry = PainterEntry.new(group.block, group.x, group.y, group.w, group.h).freeze
111
122
  end
123
+ else
124
+ entry = PainterEntry.new(group.block, group.x, group.y, group.w, group.h).freeze
112
125
  end
113
126
 
127
+
114
128
  canvas.reset(entry.x, entry.y, entry.w, entry.h)
115
129
 
116
- before_render&.call([group.block, group.parent], canvas, input.raw)
130
+ before_render&.call([group.block, group.parent], canvas, input)
117
131
 
118
132
  if capture
119
133
  capture_events(group.block, canvas, hovered: hovered)
@@ -170,6 +184,12 @@ module Hokusai
170
184
  events[:mouseout].bubble
171
185
  events[:mousedown].bubble
172
186
  events[:mouseup].bubble
187
+
188
+ unless input.touch.nil?
189
+ events[:taphold].bubble
190
+ events[:pinch].bubble
191
+ events[:swipe].bubble
192
+ end
173
193
  end
174
194
 
175
195
  after_render&.call
@@ -247,10 +267,7 @@ module Hokusai
247
267
  return
248
268
  end
249
269
 
250
- rect = canvas.to_hoku_rect
251
- block_is_hovered = LibHokusai.hoku_input_is_hovered(input.raw, rect)
252
-
253
- if block_is_hovered
270
+ if input.hovered?(canvas)
254
271
  events[:hover].capture(block, canvas)
255
272
  events[:click].capture(block, canvas)
256
273
  events[:wheel].capture(block, canvas)
@@ -261,10 +278,16 @@ module Hokusai
261
278
  end
262
279
  events[:mousemove].capture(block, canvas)
263
280
 
264
- if block_is_hovered || block.node.meta.focused
281
+ if input.hovered?(canvas) || block.node.meta.focused || input.keyboard_override
265
282
  events[:keyup].capture(block, canvas)
266
283
  events[:keypress].capture(block, canvas)
267
284
  end
285
+
286
+ unless input.touch.nil?
287
+ events[:taphold].capture(block, canvas)
288
+ events[:pinch].capture(block, canvas)
289
+ events[:swipe].capture(block, canvas)
290
+ end
268
291
  end
269
292
  end
270
293
  end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hokusai
4
+ Outline = Struct.new(:top, :right, :bottom, :left) do
5
+ def self.default
6
+ new(0.0, 0.0, 0.0, 0.0)
7
+ end
8
+
9
+ def hash
10
+ [self.class, top, right, bottom, left].hash
11
+ end
12
+
13
+ def self.convert(value)
14
+ case value
15
+ when String
16
+ if value =~ /,/
17
+ convert(value.split(",").map(&:to_f))
18
+ else
19
+ convert(value.to_f)
20
+ end
21
+ when Float
22
+ new(value, value, value, value)
23
+ when Array
24
+ new(value[0] || 0.0, value[1] || 0.0, value[2] || 0.0, value[3] || 0.0)
25
+ when Outline
26
+ value
27
+ end
28
+ end
29
+
30
+ def present?
31
+ top > 0.0 || right > 0.0 || bottom > 0.0 || left > 0.0
32
+ end
33
+
34
+ def uniform?
35
+ top == right && top == bottom && top == left
36
+ end
37
+ end
38
+
39
+ class Padding
40
+ attr_reader :top, :left, :right, :bottom
41
+ def initialize(top, right, bottom, left)
42
+ @top = top
43
+ @left = left
44
+ @right = right
45
+ @bottom = bottom
46
+ end
47
+
48
+ alias_method :t, :top
49
+ alias_method :l, :left
50
+ alias_method :r, :right
51
+ alias_method :b, :bottom
52
+
53
+ def width
54
+ right + left
55
+ end
56
+
57
+ def height
58
+ top + bottom
59
+ end
60
+
61
+ def self.convert(value)
62
+ case value
63
+ when String
64
+ if value =~ /,/
65
+ convert(value.split(",").map(&:to_f))
66
+ else
67
+ convert(value.to_i)
68
+ end
69
+ when Integer
70
+ new(value, value, value, value)
71
+ when Array
72
+ new(value[0], value[1], value[2], value[3])
73
+ when Padding
74
+ value
75
+ else
76
+ raise Hokusai::Error.new("Unsupported conversion type #{value.class} for Hokusai::Padding")
77
+ end
78
+ end
79
+
80
+ def hash
81
+ [self.class, top, right, bottom, left].hash
82
+ end
83
+ end
84
+
85
+ class Canvas
86
+ attr_accessor :width, :height, :x, :y, :vertical, :reverse
87
+ def initialize(width, height, x = 0.0, y = 0.0, vertical = true, reverse = false)
88
+ @width = width
89
+ @height = height
90
+ @x = x
91
+ @y = y
92
+ @vertical = vertical
93
+ @reverse = reverse
94
+ end
95
+
96
+ def reset(x, y, width, height, vertical: true, reverse: false)
97
+ self.x = x
98
+ self.y = y
99
+ self.width = width
100
+ self.height = height
101
+ self.vertical = vertical
102
+ self.reverse = reverse
103
+ end
104
+
105
+ def to_bounds
106
+ Hokusai::Rect.new(x, y, width, height)
107
+ end
108
+
109
+ def hovered?(input)
110
+ input.hovered?(self)
111
+ end
112
+
113
+ def reverse?
114
+ reverse
115
+ end
116
+ end
117
+
118
+ # Color = Struct.new(:red, :green, :blue, :alpha) do
119
+ class Color
120
+ attr_reader :red, :green, :blue, :alpha
121
+ def initialize(red, green, blue, alpha = 255)
122
+ @red = red.freeze
123
+ @green = green.freeze
124
+ @blue = blue.freeze
125
+ @alpha = alpha.freeze
126
+ end
127
+
128
+ alias_method :r, :red
129
+ alias_method :b, :blue
130
+ alias_method :g, :green
131
+ alias_method :a, :alpha
132
+
133
+ def self.convert(value)
134
+ case value
135
+ when String
136
+ value = value.split(",").map(&:to_i)
137
+ when Array
138
+ when Color
139
+ return value
140
+ else
141
+ raise Hokusai::Error.new("Unsupported conversion type #{value.class} for Hokusai::Color")
142
+ end
143
+
144
+ new(value[0], value[1], value[2], value[3] || 255)
145
+ end
146
+
147
+ def hash
148
+ [self.class, r, g, b, a].hash
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hokusai
4
+ KEY_CODES = {
5
+ null: 0, apostrophe: 39, comma: 44, minus: 45, period: 46,
6
+ slash: 47, zero: 48, one: 49, two: 50, three: 51, four: 52,
7
+ five: 53, six: 54, seven: 55, eight: 56, nine: 57, semicolon: 59,
8
+ equal: 61, a: 65, b: 66, c: 67, d: 68, e: 69, f: 70, g: 71, h: 72,
9
+ i: 73, j: 74, k: 75, l: 76, m: 77, n: 78, o: 79, p: 80, q: 81, r: 82,
10
+ s: 83, t: 84, u: 85, v: 86, w: 87, x: 88, y: 89, z: 90, left_bracket: 91,
11
+ backslash: 92, right_bracket: 93, grave: 96, space: 32, escape: 256,
12
+ enter: 257, tab: 258, backspace: 259, insert: 260, delete: 261, right: 262,
13
+ left: 263, down: 264, up: 265, page_up: 266, page_down: 267, home: 268, end: 269,
14
+ caps_lock: 280, scroll_lock: 281, num_lock: 282, print_screen: 283, pause: 284,
15
+ f1: 290, f2: 291, f3: 292, f4: 293, f5: 294, f6: 295, f7: 296, f8: 297,
16
+ f9: 298, f10: 299, f11: 300, f12: 301, left_shift: 340, left_control: 341,
17
+ left_alt: 342, left_super: 343, right_shift: 344, right_control: 345, right_alt: 346,
18
+ right_super: 347, kb_menu: 348, kp_0: 320, kp_1: 321, kp_2: 322, kp_3: 323,
19
+ kp_4: 324, kp_5: 325, kp_6: 326, kp_7: 327, kp_8: 328, kp_9: 329, kp_decimal: 330,
20
+ kp_divide: 331, kp_multiply: 332, kp_subtract: 333, kp_add: 334, kp_enter: 335,
21
+ kp_equal: 336, back: 4, menu: 5, volume_up: 24, volume_down: 25
22
+ }
23
+
24
+ class Keyboard
25
+ attr_accessor :shift, :control, :super, :alt
26
+ attr_reader :keys, :pressed, :released
27
+
28
+ def initialize
29
+ @shift = false
30
+ @control = false
31
+ @super = false
32
+ @alt = false
33
+
34
+ @keys = {}
35
+ @pressed = []
36
+ @released = []
37
+
38
+ # populate the key states
39
+ KEY_CODES.each do |symbol, code|
40
+ @keys[symbol] = { code: code, symbol: symbol, up: false, down: false, pressed: false, released: false }
41
+ end
42
+ end
43
+
44
+ def code
45
+ pressed[0]&.[](:code)
46
+ end
47
+
48
+ def char
49
+ pressed[0]&.[](:char)
50
+ end
51
+
52
+ def ctrl
53
+ @control
54
+ end
55
+
56
+ def reset
57
+ @pressed.clear
58
+ @released.clear
59
+
60
+ @shift = false
61
+ @control = false
62
+ @super = false
63
+ @alt = false
64
+ end
65
+
66
+
67
+ def key_is_letter?(symbol)
68
+ symbol == :a || symbol == :b || symbol == :c || symbol == :d ||
69
+ symbol == :e || symbol == :f || symbol == :g || symbol == :h ||
70
+ symbol == :i || symbol == :j || symbol == :k || symbol == :l ||
71
+ symbol == :m || symbol == :n || symbol == :o || symbol == :p ||
72
+ symbol == :q || symbol == :r || symbol == :s || symbol == :t ||
73
+ symbol == :u || symbol == :v || symbol == :w || symbol == :x ||
74
+ symbol == :y || symbol == :z
75
+ end
76
+
77
+ def char_code_from_key(key, shift)
78
+ code = keys[key][:code]
79
+
80
+ if !shift && key_is_letter?(key)
81
+ code += 32
82
+ elsif shift && key == :apostrophe
83
+ code = 34
84
+ elsif shift && key == :comma
85
+ code = 60
86
+ elsif shift && key == :minus
87
+ code = 95
88
+ elsif shift && key == :period
89
+ code = 62
90
+ elsif shift && key == :slash
91
+ code = 63
92
+ elsif shift && key == :zero
93
+ code = 41
94
+ elsif shift && key == :one
95
+ code = 33
96
+ elsif shift && key == :two
97
+ code = 64
98
+ elsif shift && key == :three
99
+ code = 35
100
+ elsif shift && key == :four
101
+ code = 36
102
+ elsif shift && key == :five
103
+ code = 37
104
+ elsif shift && key == :six
105
+ code = 94
106
+ elsif shift && key == :seven
107
+ code = 38
108
+ elsif shift && key == :eight
109
+ code = 42
110
+ elsif shift && key == :nine
111
+ code = 40
112
+ elsif shift && key == :semicolon
113
+ code = 58
114
+ elsif shift && key == :equal
115
+ code = 43
116
+ elsif shift && key == :left_bracket
117
+ code = 123
118
+ elsif shift && key == :backslash
119
+ code = 124
120
+ elsif shift && key == :right_bracket
121
+ code = 125
122
+ elsif shift && key == :grave
123
+ code = 126
124
+ end
125
+
126
+ return code if code <= 256
127
+ end
128
+
129
+ def set(key, down)
130
+ if down
131
+ case key
132
+ when :left_shift, :right_shift
133
+ @shift = true
134
+ when :left_control, :right_control
135
+ @control = true
136
+ when :left_super, :right_super
137
+ @super = true
138
+ when :left_alt, :right_alt
139
+ @alt = true
140
+ end
141
+ end
142
+
143
+ if down && keys[key][:up]
144
+ keys[key][:pressed] = true
145
+ keys[key][:released]= false
146
+
147
+ nkey = keys[key].dup
148
+ nkey.merge!({ char: char_code_from_key(key, shift)&.chr })
149
+
150
+ pressed << nkey
151
+ elsif !down && keys[key][:down]
152
+ keys[key][:pressed] = false
153
+ keys[key][:released] = true
154
+
155
+ nkey = keys[key].dup
156
+ nkey.merge!({ char: char_code_from_key(key, shift)&.chr })
157
+
158
+ released << nkey
159
+ else
160
+ keys[key][:pressed] = false
161
+ keys[key][:released] = false
162
+ end
163
+
164
+ keys[key][:down] = down
165
+ keys[key][:up] = !down
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hokusai
4
+ class MouseButton
5
+ attr_accessor :up, :down, :clicked, :released
6
+
7
+ def initialize
8
+ @up = false
9
+ @down = false
10
+ @clicked = false
11
+ @released = false
12
+ end
13
+ end
14
+
15
+ class Mouse
16
+ attr_reader :pos, :delta, :left, :right, :middle, :scroll
17
+ attr_accessor :scroll_delta
18
+
19
+ def initialize
20
+ @pos = Vec2.new(0.0, 0.0)
21
+ @delta = Vec2.new(0.0, 0.0)
22
+ @scroll = 0.0
23
+ @scroll_delta = 0.0
24
+ @left = MouseButton.new
25
+ @middle = MouseButton.new
26
+ @right = MouseButton.new
27
+ end
28
+
29
+ def scroll=(val)
30
+ last = scroll
31
+ new_y = (last >= val) ? last - val : val - last
32
+ self.scroll_delta = new_y
33
+ @scroll = val
34
+ end
35
+ end
36
+ end