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
@@ -16,8 +16,7 @@ module Hokusai::Backends
16
16
  yield(config)
17
17
  end
18
18
 
19
- block = app.mount
20
- backend.run(block)
19
+ backend.run(app)
21
20
  end
22
21
 
23
22
  def self.cursors
@@ -30,6 +29,17 @@ module Hokusai::Backends
30
29
  }
31
30
  end
32
31
 
32
+ def hml_vec2(x, y)
33
+ if @hml_vec2.nil?
34
+ @hml_vec2 = LibHokusai::HmlVec2.create(x, y)
35
+ else
36
+ @hml_vec2[:x] = x
37
+ @hml_vec2[:y] = y
38
+ end
39
+
40
+ @hml_vec2
41
+ end
42
+
33
43
  def self.stopped
34
44
  @stopped ||= false
35
45
  end
@@ -56,7 +66,19 @@ module Hokusai::Backends
56
66
  yield @config
57
67
  end
58
68
 
59
- def run(block)
69
+ def get_size(window)
70
+ w = FFI::MemoryPointer.new :int
71
+ h = FFI::MemoryPointer.new :int
72
+
73
+ SDL.GL_GetDrawableSize(window, w, h)
74
+
75
+ res = { width: w.read_int, height: h.read_int }
76
+ w.free
77
+ h.free
78
+ res
79
+ end
80
+
81
+ def run(app)
60
82
  resize = true
61
83
  self.render_width = config.width
62
84
  self.render_height = config.height
@@ -80,6 +102,7 @@ module Hokusai::Backends
80
102
  image_libpath: "#{SDL_PATH}/libSDL2_image.so"
81
103
  )
82
104
  end
105
+
83
106
  SDL.Init(config.init_flags)
84
107
  SDL.TTF_Init
85
108
 
@@ -87,46 +110,77 @@ module Hokusai::Backends
87
110
  SDL.SetWindowPosition(window, SDL::WINDOWPOS_CENTERED_MASK, SDL::WINDOWPOS_CENTERED_MASK)
88
111
  renderer = SDL.CreateRenderer(window, -1, SDL::RENDERER_TARGETTEXTURE | SDL::RENDERER_ACCELERATED)
89
112
 
113
+ size = get_size(window)
114
+ SDL.RenderSetScale(renderer, size[:width] / render_width, size[:height] / render_height);
115
+
90
116
  Hokusai.fonts.register "default", SDLBackend::Font.from("#{__dir__}/sdl2/Monaco.ttf", 121)
91
117
  Hokusai.fonts.activate "default"
92
118
  config.after_load_cb&.call
93
119
 
94
120
  register_command_handlers(renderer, window)
121
+ block = app.mount
95
122
  # MemoryProfiler.start if ENV["PROFILE"]
96
123
 
97
- ptr = FFI::MemoryPointer.new :pointer
98
- LibHokusai.hoku_input_init(ptr)
99
- raw = LibHokusai::HmlInput.new(ptr.get_pointer(0))
100
- input = Hokusai::Input.new(raw)
124
+ input = Hokusai::Input.new
125
+
126
+ if config.touch
127
+ input.support_touch!
128
+ end
129
+
101
130
  canvas = Hokusai::Canvas.new(render_width.to_f, render_height.to_f)
102
131
  event = SDL::Event.new
103
132
 
104
133
  loop do
105
- SDL.WaitEvent(event)
106
- break if event[:common][:type] == SDL::QUIT || self.class.stopped
107
- if process_input(input, event)
108
- # since we are using wait event, we need to process the render twice
109
- # once to capture all events, and once after updating block state.
110
- SDL.SetRenderDrawBlendMode(renderer, SDL::BLENDMODE_NONE)
111
- SDL.SetRenderDrawColor(renderer, config.background[:r], config.background[:g], config.background[:b], config.background[:a])
112
- SDL.RenderClear(renderer)
113
- canvas.reset(nil, nil, render_width.to_f, render_height.to_f)
114
- painter = Hokusai::Painter.new(block, input)
115
- painter.render(canvas, resize)
116
- block.update
117
- SDL.RenderPresent(renderer)
118
-
119
- SDL.SetRenderDrawBlendMode(renderer, SDL::BLENDMODE_NONE)
120
- SDL.SetRenderDrawColor(renderer, config.background[:r], config.background[:g], config.background[:b], config.background[:a])
121
- SDL.RenderClear(renderer)
122
- canvas.reset(nil, nil, render_width.to_f, render_height.to_f)
123
- painter = Hokusai::Painter.new(block, input)
124
- painter.render(canvas, resize, capture: false)
125
- SDL.RenderPresent(renderer)
134
+ if SDL.PollEvent(event)
135
+ self.class.stopped = true if event[:common][:type] == SDL::QUIT || self.class.stopped
136
+
137
+ process_input(input, event)
138
+ if config.touch
139
+ if input.touch.touching?
140
+ token = input.touch.token
141
+
142
+ input.mouse.pos.x = token[:x]
143
+ input.mouse.pos.y = token[:y]
144
+ end
145
+
146
+ # translate taps to clicks
147
+ if input.touch.tapped?
148
+ input.mouse.left.clicked = true
149
+ input.mouse.left.down = true
150
+ input.mouse.left.released = false
151
+ input.mouse.left.up = false
152
+ else
153
+ input.mouse.left.clicked = true
154
+ input.mouse.left.down = true
155
+ input.mouse.left.released = false
156
+ input.mouse.left.up = false
157
+ end
158
+ end
126
159
  end
160
+
161
+ break if self.class.stopped
162
+ # since we are using wait event, we need to process the render twice
163
+ # once to capture all events, and once after updating block state.
164
+ SDL.SetRenderDrawBlendMode(renderer, SDL::BLENDMODE_BLEND)
165
+ SDL.SetRenderDrawColor(renderer, config.background[:r], config.background[:g], config.background[:b], config.background[:a])
166
+ SDL.RenderClear(renderer)
167
+ canvas.reset(0.0, 0.0, render_width.to_f, render_height.to_f)
168
+ painter = Hokusai::Painter.new(block, input)
169
+ painter.render(canvas, resize)
170
+
171
+ SDL.RenderPresent(renderer)
172
+ block.update
173
+
174
+ # SDL.SetRenderDrawBlendMode(renderer, SDL::BLENDMODE_NONE)
175
+ # SDL.SetRenderDrawColor(renderer, config.background[:r], config.background[:g], config.background[:b], config.background[:a])
176
+ # SDL.RenderClear(renderer)
177
+ # canvas.reset(nil, nil, render_width.to_f, render_height.to_f)
178
+ # painter = Hokusai::Painter.new(block, input)
179
+ # painter.render(canvas, resize, capture: false)
180
+ # SDL.RenderPresent(renderer)
181
+ SDL.Delay(10)
127
182
  end
128
183
 
129
- LibHokusai.hoku_input_free(input.raw)
130
184
  if ENV["PROFILE"]
131
185
  # report = MemoryProfiler.stop
132
186
  # report.pretty_print
@@ -157,52 +211,76 @@ module Hokusai::Backends
157
211
  end
158
212
 
159
213
  def reset_keys(input)
160
- LibHokusai.hoku_input_keyboard_start(input.raw)
161
- Modifiers.each do |(sdlk, hkey)|
162
- LibHokusai.hoku_input_keyboard_set_key(input.raw, hkey, false)
163
- end
214
+ if !input.keyboard_override
215
+ input.keyboard.reset
164
216
 
165
- Keys.values.each do |hkey|
166
- LibHokusai.hoku_input_keyboard_set_key(input.raw, hkey, false)
167
- end
217
+ Modifiers.each do |(sdlk, hkey)|
218
+ input.keyboard.set(hkey, false)
219
+ end
168
220
 
169
- LibHokusai.hoku_input_keyboard_stop(input.raw)
221
+ Keys.values.each do |hkey|
222
+ input.keyboard.set(hkey, false)
223
+ end
224
+ end
170
225
  end
171
226
 
172
227
  def process_input(input, event)
173
228
  reset_keys(input)
174
229
 
230
+ t = event[:common][:type]
231
+ if config.touch && t != SDL::FINGERDOWN && t != SDL::WINDOWEVENT && t != SDL::FINGERUP && t != SDL::FINGERMOTION && t != SDL::MOUSEMOTION && t != SDL::POLLSENTINEL
232
+ input.touch.clear
233
+ end
234
+
175
235
  case event[:common][:type]
236
+ when SDL::FINGERDOWN
237
+ x = event[:tfinger][:x] * render_width
238
+ y = event[:tfinger][:y] * render_height
239
+
240
+ input.touch.record(0, x, y)
241
+ return true
242
+ when SDL::FINGERUP
243
+ input.touch.clear
244
+ return true
245
+ when SDL::FINGERMOTION
246
+ x = event[:tfinger][:x] * render_width
247
+ y = event[:tfinger][:y] * render_height
248
+
249
+ input.touch.record(0, x, y)
250
+ return true
176
251
  when SDL::KEYDOWN
177
- modifier = event[:key][:keysym][:mod]
178
- code = event[:key][:keysym][:sym]
179
- hkey = Keys[code]
180
-
181
- LibHokusai.hoku_input_keyboard_start(input.raw)
182
- Modifiers.each do |(sdlk, hkey)|
183
- if modifier & sdlk == sdlk
184
- LibHokusai.hoku_input_keyboard_set_key(input.raw, hkey, true)
252
+ if !input.keyboard_override
253
+ modifier = event[:key][:keysym][:mod]
254
+ code = event[:key][:keysym][:sym]
255
+ hkey = Keys[code]
256
+
257
+ input.keyboard.reset
258
+
259
+ Modifiers.each do |(sdlk, hkey)|
260
+ if modifier & sdlk == sdlk
261
+ input.keyboard.set(hkey, true)
262
+ end
185
263
  end
186
- end
187
264
 
188
- LibHokusai.hoku_input_keyboard_set_key(input.raw, hkey, true) unless hkey.nil?
189
- LibHokusai.hoku_input_keyboard_stop(input.raw)
265
+ input.keyboard.set(hkey, true) unless hkey.nil?
266
+ end
190
267
 
191
268
  return true
192
269
  when SDL::KEYUP
193
- modifier = event[:key][:keysym][:mod]
194
- code = event[:key][:keysym][:sym]
195
- hkey = Keys[code]
196
-
197
- LibHokusai.hoku_input_keyboard_start(input.raw)
198
- Modifiers.each do |(sdlk, hkey)|
199
- if modifier & sdlk == sdlk
200
- LibHokusai.hoku_input_keyboard_set_key(input.raw, hkey, false)
270
+ if !input.keyboard_override
271
+ modifier = event[:key][:keysym][:mod]
272
+ code = event[:key][:keysym][:sym]
273
+ hkey = Keys[code]
274
+ input.keyboard.reset
275
+
276
+ Modifiers.each do |(sdlk, hkey)|
277
+ if modifier & sdlk == sdlk
278
+ input.keyboard.set(hkey, false)
279
+ end
201
280
  end
202
- end
203
281
 
204
- LibHokusai.hoku_input_keyboard_set_key(input.raw, hkey, false) unless hkey.nil?
205
- LibHokusai.hoku_input_keyboard_stop(input.raw)
282
+ input.keyboard.set(hkey, false) unless hkey.nil?
283
+ end
206
284
  return true
207
285
  when SDL::WINDOWEVENT
208
286
  if event[:window][:event] == SDL::WINDOWEVENT_RESIZED
@@ -223,54 +301,65 @@ module Hokusai::Backends
223
301
 
224
302
  return true
225
303
  when SDL::MOUSEMOTION
226
- if input.raw[:mouse][:delta][:y] > 0
227
- # LibHokusai.hoku_input_mouse_set_scroll(input.raw, 0.0)
228
- input.raw[:mouse][:delta][:y] = 0.0
229
- input.raw[:mouse][:scroll_delta] = 0.0
230
- input.raw[:mouse][:scroll] = event[:motion][:y]
304
+ if input.mouse.delta.y > 0
305
+ input.mouse.delta.y = 0.0
306
+ input.mouse.scroll_delta = 0.0
307
+ input.mouse.scroll = event[:motion][:y]
231
308
  end
232
309
 
233
- # pp ["set mouse", Time.now.strftime("%H:%M:%S %L")]
234
- hoku_mouse_pos = LibHokusai::HmlVec2.create(event[:motion][:x], event[:motion][:y])
235
- LibHokusai.hoku_input_set_mouse_position(input.raw, hoku_mouse_pos)
310
+ input.mouse.pos.x = event[:motion][:x]
311
+ input.mouse.pos.y = event[:motion][:y]
236
312
 
237
313
  # clear any click events
238
314
  [[:left, 0], [:right, 2], [:middle, 1]].each do |(btn, i)|
239
- button = input.raw[:mouse][btn]
240
- button[:clicked] = false
241
- LibHokusai.hoku_input_mouse_set_button(input.raw, button, i)
315
+ input.mouse.send(btn).clicked = false
242
316
  end
243
317
 
244
318
  return true
245
319
  when SDL::MOUSEWHEEL
246
- LibHokusai.hoku_input_mouse_set_scroll(input.raw, event[:wheel][:preciseY])
247
- input.raw[:mouse][:delta][:y] = event[:wheel][:preciseY]
320
+ input.mouse.scroll = event[:wheel][:preciseY]
321
+ input.mouse.delta.y = event[:wheel][:preciseY]
248
322
 
249
323
  # clear any click events
250
324
  [[:left, 0], [:right, 2], [:middle, 1]].each do |(btn, i)|
251
- button = input.raw[:mouse][btn]
252
- button[:clicked] = false
253
- LibHokusai.hoku_input_mouse_set_button(input.raw, button, i)
325
+ input.mouse.send(btn).clicked = false
254
326
  end
327
+
255
328
  return true
256
329
  when SDL::MOUSEBUTTONDOWN
257
330
  clicked = event[:button][:clicks] > 0
258
- button = mouse_button(down: true, clicked: clicked)
259
-
260
- # LibHokusai.hoku_input_mouse_set_scroll(input.raw, 0.0)
261
- # input.raw[:mouse][:delta][:y] = 0.0
331
+ btn = {
332
+ 0 => :left,
333
+ 1 => :middle,
334
+ 2 => :right
335
+ }[event[:button][:which]]
336
+
337
+ input.mouse.send(btn).clicked = clicked
338
+ input.mouse.send(btn).down = true
339
+ input.mouse.send(btn).up = false
340
+ input.mouse.scroll = 0.0
341
+ input.mouse.delta.y = 0.0
262
342
 
263
- LibHokusai.hoku_input_mouse_set_button(input.raw, button, event[:button][:which])
264
343
  return true
265
344
  when SDL::MOUSEBUTTONUP
266
- button = mouse_button(up: true)
267
- #
268
- # LibHokusai.hoku_input_mouse_set_scroll(input.raw, 0.0)
269
- # input.raw[:mouse][:delta][:y] = 0.0
270
-
271
- LibHokusai.hoku_input_mouse_set_button(input.raw, button, event[:button][:which])
345
+ btn = {
346
+ 0 => :left,
347
+ 1 => :middle,
348
+ 2 => :right
349
+ }[event[:button][:which]]
350
+
351
+ input.mouse.send(btn).up = true
352
+ input.mouse.send(btn).down = false
353
+ input.mouse.scroll = 0.0
354
+ input.mouse.delta.y = 0.0
272
355
  return true
273
356
  when SDL::TEXTINPUT
357
+
358
+ return true
359
+ when SDL::TEXTEDITING
360
+ # start = event[:edit][:start]
361
+ # len = event[:edit][:length]
362
+ # text = event[:edit][:text]
274
363
  return false
275
364
  else
276
365
  false
@@ -410,16 +499,21 @@ module Hokusai::Backends
410
499
  self.class.images[command.source]
411
500
  else
412
501
  file = File.read(command.source)
413
-
414
- rw = SDL.RWFromConstMem(file, file.size)
415
- surface_ptr = SDL.IMG_Load_RW(rw, 1)
416
- if surface_ptr.null?
502
+ SDL.SetHint(SDL::HINT_RENDER_SCALE_QUALITY, "0");
503
+ texture = SDL.IMG_LoadTexture(renderer, command.source)
504
+ if texture.null?
417
505
  raise Hokusai::Error.new("Can't load Image: #{SDL.GetError.read_string}")
418
506
  end
419
507
 
420
- texture = SDL.CreateTextureFromSurface(renderer, surface_ptr)
508
+ # rw = SDL.RWFromConstMem(file, file.size)
509
+ # surface_ptr = SDL.IMG_LoadSVG_RW(rw)
510
+ # if surface_ptr.null?
511
+ # raise Hokusai::Error.new("Can't load Image: #{SDL.GetError.read_string}")
512
+ # end
513
+
514
+ # texture = SDL.CreateTextureFromSurface(renderer, surface_ptr)
421
515
  self.class.images[command.source] = texture
422
- SDL.FreeSurface(surface_ptr)
516
+ # SDL.FreeSurface(surface_ptr)
423
517
  texture
424
518
  end
425
519
  end
@@ -431,6 +525,7 @@ module Hokusai::Backends
431
525
 
432
526
  Hokusai::Commands::Rect.on_draw do |command|
433
527
  next unless inside_scissor(command.x, command.y, command.height)
528
+ next if command.color.a == 0
434
529
  # draw background first
435
530
  x, y, w, h = [command.x, command.y, command.width, command.height]
436
531
 
@@ -506,7 +601,6 @@ module Hokusai::Backends
506
601
  rounding = command.rounding
507
602
 
508
603
  if command.rounding > 0
509
- pp command.color
510
604
  SDL.roundedBoxRGBA(renderer, x, y, x + w, y + h, (command.rounding).ceil.to_i, command.color.r, command.color.g, command.color.b, command.color.a)
511
605
  else
512
606
  rect = SDL::Rect.new
@@ -515,6 +609,7 @@ module Hokusai::Backends
515
609
  rect[:w] = w
516
610
  rect[:h] = h
517
611
 
612
+ SDL.SetRenderDrawBlendMode(renderer, SDL::BLENDMODE_BLEND)
518
613
  SDL.SetRenderDrawColor(renderer, command.color.r, command.color.g, command.color.b, command.color.a)
519
614
  SDL.RenderFillRect(renderer, rect)
520
615
  end