hokusai-zero 0.1.3 → 0.1.5

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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/Gemfile.lock +4 -0
  4. data/README.md +33 -83
  5. data/ast/src/core/hml.c +9 -9
  6. data/ast/src/core/text.c +21 -3
  7. data/ast/test/text.c +3 -3
  8. data/docs.sh +29 -0
  9. data/ext/extconf.rb +69 -14
  10. data/grammar/corpus/1_document.txt +24 -0
  11. data/grammar/corpus/6_styles.txt +23 -0
  12. data/grammar/grammar.js +4 -4
  13. data/grammar/src/grammar.json +19 -19
  14. data/grammar/src/parser.c +1904 -1956
  15. data/grammar/test.nml +10 -8
  16. data/hokusai.gemspec +3 -1
  17. data/ui/examples/assets/Delius-Regular.ttf +0 -0
  18. data/ui/examples/assets/DoHyeon.ttf +0 -0
  19. data/ui/examples/assets/Inter-Regular.ttf +0 -0
  20. data/ui/examples/assets/ernest.gif +0 -0
  21. data/ui/examples/assets/icons/audio-x-generic.png +0 -0
  22. data/ui/examples/assets/icons/image-x-generic.png +0 -0
  23. data/ui/examples/assets/icons/media-playback-pause.png +0 -0
  24. data/ui/examples/assets/icons/media-playback-start.png +0 -0
  25. data/ui/examples/assets/icons/media-playback-stop.png +0 -0
  26. data/ui/examples/assets/icons/package-x-generic.png +0 -0
  27. data/ui/examples/assets/icons/text-x-generic.png +0 -0
  28. data/ui/examples/assets/icons/video-x-generic.png +0 -0
  29. data/ui/examples/buddy.rb +16 -14
  30. data/ui/examples/clock.rb +38 -36
  31. data/ui/examples/counter.rb +100 -98
  32. data/ui/examples/dynamic.rb +115 -113
  33. data/ui/examples/foobar.rb +189 -187
  34. data/ui/examples/forum/file.rb +54 -0
  35. data/ui/examples/forum/music.rb +76 -0
  36. data/ui/examples/forum/post.rb +146 -0
  37. data/ui/examples/forum.rb +198 -0
  38. data/ui/examples/spreadsheet/csv.rb +261 -0
  39. data/ui/examples/spreadsheet.rb +138 -0
  40. data/ui/examples/stock.rb +86 -92
  41. data/ui/examples/stock_decider/option.rb +1 -1
  42. data/ui/examples/tic_tac_toe.rb +193 -191
  43. data/ui/lib/lib_hokusai.rb +2 -1
  44. data/ui/src/hokusai/assets/arrow-drop-down-line.png +0 -0
  45. data/ui/src/hokusai/assets/chevron-down.svg +1 -0
  46. data/ui/src/hokusai/assets/close-large-line.png +0 -0
  47. data/ui/src/hokusai/ast.rb +42 -43
  48. data/ui/src/hokusai/backends/raylib/font.rb +1 -2
  49. data/ui/src/hokusai/backends/raylib.rb +29 -17
  50. data/ui/src/hokusai/backends/sdl2/font.rb +13 -9
  51. data/ui/src/hokusai/backends/sdl2.rb +32 -5
  52. data/ui/src/hokusai/block.rb +14 -7
  53. data/ui/src/hokusai/blocks/dropdown.rb +205 -0
  54. data/ui/src/hokusai/blocks/hblock.rb +2 -2
  55. data/ui/src/hokusai/blocks/image.rb +6 -1
  56. data/ui/src/hokusai/blocks/input.rb +17 -0
  57. data/ui/src/hokusai/blocks/label.rb +5 -2
  58. data/ui/src/hokusai/blocks/modal.rb +62 -0
  59. data/ui/src/hokusai/blocks/panel.rb +2 -2
  60. data/ui/src/hokusai/blocks/scrollbar.rb +0 -2
  61. data/ui/src/hokusai/blocks/text.rb +12 -6
  62. data/ui/src/hokusai/blocks/titlebar/osx.rb +4 -4
  63. data/ui/src/hokusai/blocks/variable.rb +33 -0
  64. data/ui/src/hokusai/blocks/vblock.rb +1 -1
  65. data/ui/src/hokusai/commands/rect.rb +4 -4
  66. data/ui/src/hokusai/commands.rb +46 -29
  67. data/ui/src/hokusai/diff.rb +11 -0
  68. data/ui/src/hokusai/event.rb +19 -5
  69. data/ui/src/hokusai/events/mouse.rb +9 -1
  70. data/ui/src/hokusai/font.rb +60 -0
  71. data/ui/src/hokusai/meta.rb +11 -24
  72. data/ui/src/hokusai/node.rb +1 -1
  73. data/ui/src/hokusai/painter.rb +66 -8
  74. data/ui/src/hokusai/util/clamping_iterator.rb +5 -6
  75. data/ui/src/hokusai.rb +53 -4
  76. metadata +56 -3
@@ -25,15 +25,21 @@ module Hokusai
25
25
  end
26
26
 
27
27
  # The loop variable
28
+ #
28
29
  # eg [for="item in list"]
29
30
  # the var is `item`
31
+ #
32
+ # @return [String]
30
33
  def var
31
34
  @name ||= raw[:name].freeze
32
35
  end
33
36
 
34
37
  # The loop method
38
+ #
35
39
  # eg [for="item in list"]
36
40
  # the method is `list`
41
+ #
42
+ # @return [String]
37
43
  def method
38
44
  @list_name ||= raw[:list_name].freeze
39
45
  end
@@ -49,6 +55,7 @@ module Hokusai
49
55
  end
50
56
 
51
57
  # Name of the func
58
+ #
52
59
  # eg @target="run_this(one,two)"
53
60
  # the name is `run_this`
54
61
  #
@@ -58,6 +65,7 @@ module Hokusai
58
65
  end
59
66
 
60
67
  # Args of the func
68
+ #
61
69
  # eg @target="run_this(one, two)"
62
70
  # the args are [one, two]
63
71
  #
@@ -74,6 +82,7 @@ module Hokusai
74
82
  class Event
75
83
  attr_reader :raw
76
84
 
85
+ # @param [LibHokusai::Event] raw event
77
86
  def initialize(raw)
78
87
  @raw = raw
79
88
  end
@@ -93,6 +102,7 @@ module Hokusai
93
102
  end
94
103
  end
95
104
 
105
+ # A node representing an ast prop
96
106
  class Prop
97
107
  attr_reader :raw
98
108
 
@@ -100,14 +110,17 @@ module Hokusai
100
110
  @raw = raw
101
111
  end
102
112
 
113
+ # @return [Bool] is this prop computed?
103
114
  def computed?
104
115
  raw[:computed]
105
116
  end
106
117
 
118
+ # @return [String] the props name
107
119
  def name
108
120
  @name ||= raw[:name].freeze
109
121
  end
110
122
 
123
+ # @return [Ast::Func] the props value
111
124
  def value
112
125
  @call ||= raw[:call]
113
126
 
@@ -166,60 +179,74 @@ module Hokusai
166
179
  end
167
180
  end
168
181
 
182
+ # Marks this ast as dirty
183
+ # @return [Void]
169
184
  def dirty!
170
185
  @dirty = true
171
186
  end
172
187
 
188
+ # Is this ast dirty?
189
+ # @return [Bool]
173
190
  def dirty?
174
191
  @dirty
175
192
  end
176
193
 
194
+ # @return [Bool] is this node a slot?
177
195
  def slot?
178
196
  type == "slot"
179
197
  end
180
198
 
199
+ # @return [Bool] is this node virtual?
181
200
  def virtual?
182
201
  type == "virtual"
183
202
  end
184
203
 
204
+ # @return [Bool] does this node belong to a loop?
185
205
  def loop?
186
206
  @loop_condition = !raw[:loop].null? if @loop_condition.nil?
187
207
 
188
208
  @loop_condition
189
209
  end
190
210
 
211
+ # @return [Bool] does this node have an if condition?
191
212
  def has_if_condition?
192
213
  @if_condition = !raw[:cond].null? if @if_condition.nil?
193
214
 
194
215
  @if_condition
195
216
  end
196
217
 
218
+ # @return [Bool] does this node have an else condition?
197
219
  def has_else_condition?
198
220
  @else_condition = !raw[:else_relations].null? if @else_condition.nil?
199
221
 
200
222
  @else_condition
201
223
  end
202
224
 
225
+ # @return [Bool] is the else condition on this node currently active?
203
226
  def else_condition_active?
204
227
  has_else_condition? && @else_active == 1
205
228
  end
206
229
 
230
+ # @param [Bool] else condition is active or not
207
231
  def else_active=(val)
208
232
  @else_active = val
209
233
  end
210
234
 
235
+ # @return [Hokusai::Ast?] the ast of the else condition
211
236
  def else_ast
212
237
  return nil unless has_else_condition?
213
238
 
214
239
  Ast.new(raw[:else_relations][:next_child])
215
240
  end
216
241
 
242
+ # @return [Ast::Loop?] the loop that the ast belongs to
217
243
  def loop
218
244
  return nil unless loop?
219
245
 
220
246
  @loop ||= Loop.new(raw[:loop])
221
247
  end
222
248
 
249
+ # @return [Ast::Func?] the if condition of this ast
223
250
  def if
224
251
  @cond ||= raw[:cond]
225
252
 
@@ -232,14 +259,17 @@ module Hokusai
232
259
  @func ||= Func.new(@call)
233
260
  end
234
261
 
262
+ # @return [String] the node type
235
263
  def type
236
264
  @type ||= raw[:type].nil? ? "(null)" : raw[:type]
237
265
  end
238
266
 
267
+ # @return [String] the node id
239
268
  def id
240
269
  @id ||= raw[:id].nil? ? "(null)" : raw[:id]
241
270
  end
242
271
 
272
+ # @return [Array<String>] the list of classes for this node
243
273
  def classes
244
274
  return @classes unless @classes.nil?
245
275
 
@@ -251,6 +281,7 @@ module Hokusai
251
281
  @classes
252
282
  end
253
283
 
284
+ # @return [Array<Hokusai::Ast>] all the children of this node
254
285
  def children
255
286
  return @children unless @children.nil?
256
287
 
@@ -262,6 +293,7 @@ module Hokusai
262
293
  @children
263
294
  end
264
295
 
296
+ # @return [Array<Hokusai::Ast>] all the siblings of this node
265
297
  def siblings
266
298
  return @siblings unless @siblings.nil?
267
299
 
@@ -277,6 +309,7 @@ module Hokusai
277
309
  @siblings
278
310
  end
279
311
 
312
+ # @return [Array<Hokusai::Ast>] the children of the else condition for this node
280
313
  def else_children
281
314
  children = []
282
315
 
@@ -290,6 +323,7 @@ module Hokusai
290
323
  children
291
324
  end
292
325
 
326
+ # @return [Array<Ast::Prop>] all the props of this node
293
327
  def props
294
328
  return @props unless @props.nil?
295
329
 
@@ -302,6 +336,7 @@ module Hokusai
302
336
  @props
303
337
  end
304
338
 
339
+ # @return [Array<Ast::Event>] all the events of this node
305
340
  def events
306
341
  return @events unless @events.nil?
307
342
 
@@ -382,60 +417,24 @@ module Hokusai
382
417
  i.free
383
418
  end
384
419
 
420
+ # Fetches a prop by name
421
+ #
422
+ # @param [String] name of the prop
423
+ # @return [Ast::Prop?] the prop or nil
385
424
  def prop(name)
386
425
  props[name]
387
426
  end
388
427
 
389
- # Search for a prop by name
390
- #
391
- # @param [String] name the name of the prop to find
392
- # @return [Hokusai::Ast::Prop?] the prop if found
393
- # def prop(name)
394
- # prop_ptr = FFI::MemoryPointer.new :pointer
395
- # code = LibHokusai.hoku_ast_prop_init(prop_ptr, name)
428
+ # Fetches an event by name
396
429
  #
397
- # raise Hokusai::Error.new("Failed to allocate prop") unless code.zero?
398
- #
399
- # prop_ptr2 = prop_ptr.get_pointer(0)
400
- # prop = LibHokusai::HmlAstProp.new(prop_ptr2)
401
- # response = LibHokusai.hoku_ast_get_prop(raw, prop)
402
- # return nil if response.null?
403
- #
404
- # Prop.new(response)
405
- # ensure
406
- # prop_ptr.free
407
- # end
408
-
430
+ # @param [String] the name of the event
431
+ # @return [Ast::Event?] the event or nil
409
432
  def event(name)
410
433
  events[name]
411
434
  end
412
435
 
413
- # Search for an event by name
414
- #
415
- # @param [String] name the name of the prop to find
416
- # @return [Prop?] the prop if found
417
- # def event(name)
418
- # event_ptr = FFI::MemoryPointer.new :pointer
419
- # code = LibHokusai.hoku_ast_prop_init(event_ptr, name)
420
- #
421
- # raise Hokusai::Error.new("Failed to allocate prop") unless code.zero?
422
- #
423
- # event_ptr2 = event_ptr.get_pointer(0)
424
- # event = LibHokusai::HmlAstEvent.new(event_ptr2)
425
- # response = LibHokusai.hoku_ast_get_event(raw, event)
426
- # event_ptr.free
427
- #
428
- # return nil if response.null?
429
- #
430
- # Event.new(response)
431
- # ensure
432
- # event_ptr.free
433
- # end
434
-
435
436
  def destroy
436
- puts "before destroy"
437
437
  LibHokusai.hoku_ast_free(raw)
438
- puts "after destroy"
439
438
  end
440
439
 
441
440
  # dumps this ast to STDOUT
@@ -20,7 +20,7 @@ module Hokusai
20
20
  OnWidthCb = Proc.new do |char, ffi_pointer|
21
21
  data = DataForCb.new ffi_pointer
22
22
 
23
- Raylib.MeasureTextEx(data[:raw], "#{char.chr}", data[:size], data[:spacing]).x + data[:spacing]
23
+ Raylib.MeasureTextEx(data[:raw], "#{char.chr}", data[:size], data[:spacing]).x + 1.565#@ data[:spacing]
24
24
  end
25
25
 
26
26
  class Font < Hokusai::Font
@@ -83,7 +83,6 @@ module Hokusai
83
83
  raw.baseSize
84
84
  end
85
85
 
86
-
87
86
  def clamp_markdown(text, size, width, initial_offset = 0.0)
88
87
  clamping_pointer = FFI::MemoryPointer.new :pointer
89
88
  RaylibBackend::DataForCb.create(size, spacing, raw) do |ptr|
@@ -5,7 +5,18 @@ require 'memory_profiler'
5
5
 
6
6
  module Hokusai::Backends
7
7
  class RaylibBackend
8
- RAYLIB_PATH = ENV["RAYLIB_PATH"] || "#{__dir__}/../../../../vendor/lib"
8
+
9
+ RAYLIB_PATH = ENV["RAYLIB_PATH"] || begin
10
+ path = "#{__dir__}/../../../../vendor/lib"
11
+ case RbConfig::CONFIG['host_os']
12
+ when /darwin/
13
+ "#{path}/libraylib.dylib"
14
+ when /mswin|msys|mingw/
15
+ "#{path}/libraylib.dll"
16
+ when /linux/
17
+ "#{path}/libraylib.so"
18
+ end
19
+ end
9
20
 
10
21
  attr_reader :config
11
22
 
@@ -37,8 +48,8 @@ module Hokusai::Backends
37
48
  yield(config)
38
49
  end
39
50
 
40
- def vec2(x, y)
41
- if @raylib_vec2.nil?
51
+ def vec2(x, y, fresh = false)
52
+ if @raylib_vec2.nil? || fresh
42
53
  @raylib_vec2 = Raylib::Vector2.new
43
54
  end
44
55
  @raylib_vec2[:x] = x
@@ -137,14 +148,7 @@ module Hokusai::Backends
137
148
  def run(block)
138
149
  self.class.reset
139
150
 
140
- case RbConfig::CONFIG['host_os']
141
- when /darwin/
142
- Raylib.load_lib("#{RAYLIB_PATH}/libraylib.dylib")
143
- when /mswin|msys|mingw/
144
- Raylib.load_lib("#{RAYLIB_PATH}/libraylib.dll")
145
- when /linux/
146
- Raylib.load_lib("#{RAYLIB_PATH}/libraylib.so")
147
- end
151
+ Raylib.load_lib(RAYLIB_PATH)
148
152
 
149
153
  resize = false
150
154
  initial = true
@@ -201,7 +205,9 @@ module Hokusai::Backends
201
205
  height = last_height
202
206
 
203
207
  process_input(input)
208
+ block.public_send(:before_updated) if block.respond_to?(:before_updated)
204
209
  block.update
210
+ block.public_send(:after_updated) if block.respond_to?(:after_updated)
205
211
 
206
212
  canvas.reset(nil, nil, width.to_f, height.to_f)
207
213
 
@@ -327,7 +333,6 @@ module Hokusai::Backends
327
333
  end
328
334
 
329
335
  Hokusai::Commands::SVG.on_draw do |command|
330
- command = command.as(Hokusai::Commands::SVG)
331
336
  texture = begin
332
337
  if self.class.images[command.source]
333
338
  self.class.images[command.source]
@@ -368,7 +373,12 @@ module Hokusai::Backends
368
373
  Hokusai::Commands::Text.on_draw do |command|
369
374
  next unless inside_scissor(command.x, command.y, command.size)
370
375
 
376
+ active_name = Hokusai.fonts.active_font_name
371
377
  font = Hokusai.fonts.active
378
+
379
+ Hokusai.fonts.activate command.font.nil? ? active_name : command.font
380
+ font = Hokusai.fonts.active
381
+
372
382
  c = color(command.color)
373
383
  x = command.x + command.padding.l
374
384
  y = command.y + command.padding.t
@@ -380,6 +390,8 @@ module Hokusai::Backends
380
390
  else
381
391
  Raylib.DrawText(command.content, x, y, command.size, c)
382
392
  end
393
+
394
+ Hokusai.fonts.activate active_name
383
395
  end
384
396
 
385
397
  Hokusai::Commands::Rect.on_draw do |command|
@@ -407,26 +419,26 @@ module Hokusai::Backends
407
419
 
408
420
  # now draw the outlines
409
421
  if command.outline_uniform? && command.rounding > 0.0 && outline_color.a > 0
410
- Raylib.DrawRectangleRoundedLines(outline_rect, command.rounding, 50, command.outline.top, outline_color)
422
+ Raylib.DrawRectangleRoundedLinesEx(outline_rect, command.rounding, 50, command.outline.top + 1, outline_color)
411
423
  elsif command.outline_uniform? && !(command.rounding <= 0.0) && outline_color.a > 0
412
424
  Raylib.DrawRectangleLinesEx(outline_rect, command.outline.top, outline_color)
413
425
  elsif !command.outline_uniform?
414
426
  ox, oy, ow, oh = command.background_boundary
415
427
 
416
428
  if command.outline.top > 0.0
417
- Raylib.DrawLineEx(vec2(ox, oy), vec2(ox + ow, oy), command.outline.top, outline_color)
429
+ Raylib.DrawLineEx(vec2(ox, oy, true), vec2(ox + ow, oy, true), command.outline.top, outline_color)
418
430
  end
419
431
 
420
432
  if command.outline.left > 0.0
421
- Raylib.DrawLineEx(vec2(ox, oy), vec2(ox, oy + oh), command.outline.left, outline_color)
433
+ Raylib.DrawLineEx(vec2(ox, oy, true), vec2(ox, oy + oh, true), command.outline.left, outline_color)
422
434
  end
423
435
 
424
436
  if command.outline.right > 0.0
425
- Raylib.DrawLineEx(vec2(ox + ow, oy), vec2(ox + ow, oy + oh), command.outline.right, outline_color)
437
+ Raylib.DrawLineEx(vec2(ox + ow, oy, true), vec2(ox + ow, oy + oh, true), command.outline.right, outline_color)
426
438
  end
427
439
 
428
440
  if command.outline.bottom > 0.0
429
- Raylib.DrawLineEx(vec2(ox, oy + oh), vec2(ox + ow, oy + oh), command.outline.bottom, outline_color)
441
+ Raylib.DrawLineEx(vec2(ox, oy + oh, true), vec2(ox + ow, oy + oh, true), command.outline.bottom, outline_color)
430
442
  end
431
443
  end
432
444
  else
@@ -80,7 +80,6 @@ module Hokusai::Backends
80
80
 
81
81
  def clamp_markdown(text, size, width, initial_offset = 0.0)
82
82
  self.size = size
83
-
84
83
  clamping_pointer = FFI::MemoryPointer.new :pointer
85
84
 
86
85
  ret = LibHokusai.hoku_text_md_clamp(clamping_pointer, text, width, initial_offset, raw, SDLBackend::OnWidthCb)
@@ -105,18 +104,23 @@ module Hokusai::Backends
105
104
  end
106
105
 
107
106
  def measure(text, size = 15)
108
- w = FFI::MemoryPointer.new :int
109
- h = FFI::MemoryPointer.new :int
107
+ begin
108
+ self.size = size
109
+ w = FFI::MemoryPointer.new :int
110
+ h = FFI::MemoryPointer.new :int
110
111
 
111
- SDL.TTF_SizeText(raw, text, w, h)
112
+ SDL.TTF_SizeText(raw, text, w, h)
112
113
 
113
- width = w.read_int
114
- height = h.read_int
114
+ width = w.read_int
115
+ height = h.read_int
115
116
 
116
- w.free
117
- h.free
117
+ w.free
118
+ h.free
118
119
 
119
- [width, height]
120
+ [width, height]
121
+ ensure
122
+ self.size = height
123
+ end
120
124
  end
121
125
 
122
126
  def size=(val)
@@ -57,7 +57,7 @@ module Hokusai::Backends
57
57
  end
58
58
 
59
59
  def run(block)
60
- resize = false
60
+ resize = true
61
61
  self.render_width = config.width
62
62
  self.render_height = config.height
63
63
 
@@ -89,7 +89,7 @@ module Hokusai::Backends
89
89
 
90
90
  Hokusai.fonts.register "default", SDLBackend::Font.from("#{__dir__}/sdl2/Monaco.ttf", 121)
91
91
  Hokusai.fonts.activate "default"
92
- config.after_load&.call
92
+ config.after_load_cb&.call
93
93
 
94
94
  register_command_handlers(renderer, window)
95
95
  # MemoryProfiler.start if ENV["PROFILE"]
@@ -107,7 +107,7 @@ module Hokusai::Backends
107
107
  if process_input(input, event)
108
108
  # since we are using wait event, we need to process the render twice
109
109
  # once to capture all events, and once after updating block state.
110
- SDL.SetRenderDrawBlendMode(renderer, SDL::BLENDMODE_BLEND)
110
+ SDL.SetRenderDrawBlendMode(renderer, SDL::BLENDMODE_NONE)
111
111
  SDL.SetRenderDrawColor(renderer, config.background[:r], config.background[:g], config.background[:b], config.background[:a])
112
112
  SDL.RenderClear(renderer)
113
113
  canvas.reset(nil, nil, render_width.to_f, render_height.to_f)
@@ -116,7 +116,7 @@ module Hokusai::Backends
116
116
  block.update
117
117
  SDL.RenderPresent(renderer)
118
118
 
119
- SDL.SetRenderDrawBlendMode(renderer, SDL::BLENDMODE_BLEND)
119
+ SDL.SetRenderDrawBlendMode(renderer, SDL::BLENDMODE_NONE)
120
120
  SDL.SetRenderDrawColor(renderer, config.background[:r], config.background[:g], config.background[:b], config.background[:a])
121
121
  SDL.RenderClear(renderer)
122
122
  canvas.reset(nil, nil, render_width.to_f, render_height.to_f)
@@ -402,9 +402,35 @@ module Hokusai::Backends
402
402
  SDL.RenderCopy(renderer, texture, nil, rect)
403
403
  end
404
404
 
405
- Hokusai::Commands::Rect.on_draw do |command|
405
+ Hokusai::Commands::SVG.on_draw do |command|
406
406
  next unless inside_scissor(command.x, command.y, command.height)
407
407
 
408
+ texture = begin
409
+ if self.class.images[command.source]
410
+ self.class.images[command.source]
411
+ else
412
+ 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?
417
+ raise Hokusai::Error.new("Can't load Image: #{SDL.GetError.read_string}")
418
+ end
419
+
420
+ texture = SDL.CreateTextureFromSurface(renderer, surface_ptr)
421
+ self.class.images[command.source] = texture
422
+ SDL.FreeSurface(surface_ptr)
423
+ texture
424
+ end
425
+ end
426
+
427
+ SDL.SetTextureColorMod(texture, command.color.r, command.color.g, command.color.b)
428
+ rect = sdl_rect(command.x, command.y, command.width, command.height)
429
+ SDL.RenderCopy(renderer, texture, nil, rect)
430
+ end
431
+
432
+ Hokusai::Commands::Rect.on_draw do |command|
433
+ next unless inside_scissor(command.x, command.y, command.height)
408
434
  # draw background first
409
435
  x, y, w, h = [command.x, command.y, command.width, command.height]
410
436
 
@@ -480,6 +506,7 @@ module Hokusai::Backends
480
506
  rounding = command.rounding
481
507
 
482
508
  if command.rounding > 0
509
+ pp command.color
483
510
  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)
484
511
  else
485
512
  rect = SDL::Rect.new
@@ -4,6 +4,11 @@ require "forwardable"
4
4
 
5
5
  module Hokusai
6
6
  module Blocks; end
7
+ # A UI Component
8
+ #
9
+ # Blocks are reusable and can be mounted in other blocks via templates
10
+ #
11
+ # Blocks have `props`` and emit `events`
7
12
  class Block
8
13
  attr_reader :node
9
14
  attr_reader :publisher
@@ -61,6 +66,8 @@ module Hokusai
61
66
  @styles || {}
62
67
  end
63
68
 
69
+ # Defines blocks that this block uses in it's template
70
+ # Keys map to template node names, values map to a `Hokusai::Block`
64
71
  def self.uses(**args)
65
72
  args.each do |key, value|
66
73
  raise Hokusai::Error.new("#{key} value must be a Block, got #{value}") unless value.is_a?(Block.class)
@@ -172,23 +179,23 @@ module Hokusai
172
179
 
173
180
  def draw(&block)
174
181
  instance_eval(&block)
175
- # node.meta.commands.each(&:draw)
176
- # node.meta.commands.clear!
177
182
  end
178
183
 
179
184
  def method_missing(name, *args,**kwargs, &block)
180
- if Hokusai::Meta.commands.respond_to?(name)
181
- return Hokusai::Meta.commands.send(name, *args, **kwargs, &block)
185
+ if node.meta.commands.respond_to?(name)
186
+ return node.meta.commands.send(name, *args, **kwargs, &block)
182
187
  end
183
188
 
184
189
  super
185
190
  end
186
191
 
187
192
  def draw_with
188
- yield Hokusai::Meta.commands
193
+ yield node.meta.commands
194
+ end
189
195
 
190
- # node.meta.commands.each(&:draw)
191
- # node.meta.commands.clear!
196
+ def execute_draw
197
+ node.meta.commands.execute
198
+ node.meta.commands.clear!
192
199
  end
193
200
 
194
201
  def render(canvas)