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
@@ -0,0 +1,205 @@
1
+ class Hokusai::Blocks::DropDownItem < Hokusai::Block
2
+ style <<~EOF
3
+ [style]
4
+ cursorStyle {
5
+ cursor: "pointer";
6
+ }
7
+ EOF
8
+
9
+ template <<~EOF
10
+ [template]
11
+ text {
12
+ @hover="hover_handler"
13
+ @mouseout="mouseout_handler"
14
+ ...cursorStyle
15
+ :content="option"
16
+ :color="color"
17
+ :size="size"
18
+ @click="emit_option"
19
+ @height_updated="update_height"
20
+ }
21
+ EOF
22
+
23
+ uses(text: Hokusai::Blocks::Text)
24
+
25
+ computed! :index
26
+ computed! :option
27
+ computed! :size
28
+ computed! :color
29
+
30
+ attr_accessor :hovered
31
+
32
+ def hover_handler(event)
33
+ self.hovered = true
34
+ end
35
+
36
+ def mouseout_handler(event)
37
+ self.hovered = false
38
+ end
39
+
40
+ def update_height(height)
41
+ node.meta.set_prop(:height, height)
42
+
43
+ emit("height", index, height)
44
+ end
45
+
46
+ def emit_option(event)
47
+ emit("option", index)
48
+ end
49
+
50
+ def render(canvas)
51
+ if hovered
52
+ draw do
53
+ rect(canvas.x, canvas.y, canvas.width, canvas.height) do |command|
54
+ command.color = Hokusai::Color.new(255, 255, 255, 20)
55
+ end
56
+ end
57
+ end
58
+
59
+ yield canvas
60
+ end
61
+ end
62
+
63
+ class Hokusai::Blocks::Dropdown < Hokusai::Block
64
+ style <<~EOF
65
+ [style]
66
+ panelStyle {
67
+ z: 1;
68
+ }
69
+ rootStyle {
70
+ height: 70.0;
71
+ color: rgb(122, 118, 135);
72
+ }
73
+
74
+ cursorStyle {
75
+ cursor: "pointer";
76
+ }
77
+ EOF
78
+
79
+ template <<~EOF
80
+ [template]
81
+ vblock {
82
+ @hover="dropdown_hover"
83
+ @mouseout="dropdown_mouseout"
84
+ @click="dropdown_toggle"
85
+ :background="background"
86
+ :height="size_with_padding"
87
+ :outline="outline"
88
+ :outline_color="outline_color"
89
+ }
90
+ hblock
91
+ label {
92
+ ...cursorStyle
93
+ :content="dropdown_option_selected"
94
+ :size="size"
95
+ :color="text_color"
96
+ }
97
+ image {
98
+ padding="5.0,10.0,5.0,5.0"
99
+ :source="dropdown_icon"
100
+ :height="size"
101
+ :width="size"
102
+ }
103
+ [if="dropdown_is_toggled"]
104
+ panel#first {
105
+ ...panelStyle
106
+ :height="panel_height"
107
+ :background="background"
108
+ }
109
+ [for="option in options"]
110
+ dropdown_item {
111
+ :color="text_color"
112
+ :size="size"
113
+ :height="option_height(index)"
114
+ :option="option_content(option)"
115
+ :key="dropdown_key(option, index)"
116
+ :index="index"
117
+ @option="option_emit_selected"
118
+ @height="option_update_height"
119
+ }
120
+ EOF
121
+
122
+ uses(
123
+ vblock: Hokusai::Blocks::Vblock,
124
+ hblock: Hokusai::Blocks::Hblock,
125
+ label: Hokusai::Blocks::Text,
126
+ panel: Hokusai::Blocks::Panel,
127
+ image: Hokusai::Blocks::Image,
128
+ dropdown_item: Hokusai::Blocks::DropDownItem
129
+ )
130
+
131
+ computed! :options
132
+ computed :option_callback, default: ->(option) { option }
133
+ computed :size, default: 25, convert: proc(&:to_i)
134
+ computed :padding, default: Hokusai::Padding.new(5.0, 5.0, 5.0, 5.0), convert: Hokusai::Padding
135
+ computed :background, default: Hokusai::Color.new(67, 64, 92), convert: Hokusai::Color
136
+ computed :outline, default: Hokusai::Outline.new(0.0, 0.0, 1.0, 0.0), convert: Hokusai::Outline
137
+ computed :outline_color, default: Hokusai::Color.new(122, 118, 135), convert: Hokusai::Color
138
+ computed :text_color, default: Hokusai::Color.new(255, 255, 255), convert: Hokusai::Color
139
+ computed :panel_width, default: 200.0, convert: proc(&:to_f)
140
+ computed :panel_height, default: 300.0, convert: proc(&:to_f)
141
+ computed :icon, default: "#{ASSETS_FOLDER}/arrow-drop-down-line.png"
142
+
143
+ attr_accessor :selected, :dropdown_is_toggled, :hovered
144
+ attr_reader :heights
145
+
146
+ def dropdown_icon
147
+ icon
148
+ end
149
+
150
+ def dropdown_hover(event)
151
+ self.hovered = true
152
+ end
153
+
154
+ def dropdown_mouseout(event)
155
+ self.hovered = false
156
+ end
157
+
158
+ def size_with_padding
159
+ size + padding.top + padding.bottom
160
+ end
161
+
162
+ def dropdown_key(option, index)
163
+ "option-#{option_callback.call(option)}-#{index}"
164
+ end
165
+
166
+ def dropdown_toggle(event)
167
+ self.dropdown_is_toggled = !dropdown_is_toggled
168
+ end
169
+
170
+ def dropdown_option_selected
171
+ option_callback.call(selected)
172
+ end
173
+
174
+ def option_height(index)
175
+ heights[index]
176
+ end
177
+
178
+ def option_update_height(index, height)
179
+ heights[index] = height
180
+ end
181
+
182
+ def option_content(option)
183
+ option_callback.call(option)
184
+ end
185
+
186
+ def after_updated
187
+ node.meta.set_prop(:height, size * 2)
188
+ end
189
+
190
+ def option_emit_selected(index)
191
+ emit("selected", options[index])
192
+
193
+ self.selected = options[index]
194
+ self.dropdown_is_toggled = false
195
+ end
196
+
197
+ def initialize(**args)
198
+ super
199
+
200
+ @hovered = false
201
+ @heights = {}
202
+ @dropdown_is_toggled = false
203
+ @selected = options.first
204
+ end
205
+ end
@@ -15,12 +15,12 @@ class Hokusai::Blocks::Hblock < Hokusai::Block
15
15
  canvas.vertical = false
16
16
  canvas.reverse = reverse
17
17
 
18
- if background.nil?
18
+ if background.nil? && outline.nil?
19
19
  yield canvas
20
20
  else
21
21
  draw do
22
22
  rect(canvas.x, canvas.y, canvas.width, canvas.height) do |command|
23
- command.color = background
23
+ command.color = background if background
24
24
  command.outline = outline if outline
25
25
  command.outline_color = outline_color if outline_color
26
26
  command.round = rounding.to_f if rounding
@@ -1,3 +1,5 @@
1
+ require "pathname"
2
+
1
3
  class Hokusai::Blocks::Image < Hokusai::Block
2
4
  template <<~EOF
3
5
  [template]
@@ -7,10 +9,13 @@ class Hokusai::Blocks::Image < Hokusai::Block
7
9
  computed! :source
8
10
  computed :width, default: nil
9
11
  computed :height, default: nil
12
+ computed :padding, default: Hokusai::Padding.new(0.0, 0.0, 0.0, 0.0), convert: Hokusai::Padding
10
13
 
11
14
  def render(canvas)
15
+ src = Pathname.new(source).absolute? ? source : "#{File.dirname(caller[-1].split(":")[0])}/#{source}"
16
+
12
17
  draw do
13
- image(source, canvas.x, canvas.y, width&.to_f || canvas.width, height&.to_f || canvas.height)
18
+ image(src, canvas.x + padding.left, canvas.y + padding.top, (width&.to_f || canvas.width) - padding.right, (height&.to_f || canvas.height) - padding.bottom)
14
19
  end
15
20
 
16
21
  yield canvas
@@ -45,6 +45,19 @@ class Hokusai::Blocks::Input < Hokusai::Block
45
45
  @start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
46
46
  @buffer_offset = 0
47
47
  @offset = 0
48
+ @changed = false
49
+ end
50
+
51
+ def after_updated
52
+ if @changed && !growable
53
+ @table = ::Hokusai::Util::PieceTable.new(initial)
54
+ @buffer = ""
55
+ @buffer_count = 0
56
+ @start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
57
+ @buffer_offset = 0
58
+ @offset = 0
59
+ @changed = false
60
+ end
48
61
  end
49
62
 
50
63
  def update_height(value)
@@ -74,6 +87,7 @@ class Hokusai::Blocks::Input < Hokusai::Block
74
87
  end
75
88
 
76
89
  def dynamic_keypress_handle(event)
90
+ return unless node.meta.focused
77
91
  case event
78
92
  when proc(&:ctrl), proc(&:super)
79
93
  if event.char == "z"
@@ -116,6 +130,7 @@ class Hokusai::Blocks::Input < Hokusai::Block
116
130
  flush
117
131
 
118
132
  emit("change", table.to_s)
133
+ @changed = true
119
134
 
120
135
  self.table = ::Hokusai::Util::PieceTable.new("")
121
136
  self.buffer_offset = 0
@@ -142,6 +157,8 @@ class Hokusai::Blocks::Input < Hokusai::Block
142
157
  self.buffer += event.char
143
158
  end
144
159
  end
160
+
161
+ emit("modified")
145
162
  end
146
163
 
147
164
  def flush
@@ -6,6 +6,7 @@ class Hokusai::Blocks::Label < Hokusai::Block
6
6
  EOF
7
7
 
8
8
  computed! :content
9
+ computed :font, default: nil
9
10
  computed :size, default: 12
10
11
  computed :color, default: [33,33,33], convert: Hokusai::Color
11
12
  computed :padding, default: [5.0, 5.0, 5.0, 5.0], convert: Hokusai::Padding
@@ -21,8 +22,9 @@ class Hokusai::Blocks::Label < Hokusai::Block
21
22
 
22
23
  def render(canvas)
23
24
  if @last_content != content
24
- width, _ = Hokusai.fonts.active.measure(content.to_s, size.to_i)
25
-
25
+ width, height = Hokusai.fonts.active.measure(content.to_s, size.to_i)
26
+ node.meta.set_prop(:width, width + padding.right + padding.left)
27
+ node.meta.set_prop(:height, height + padding.top + padding.bottom)
26
28
  emit("width_updated", width + padding.right + padding.left)
27
29
 
28
30
  @last_content = content
@@ -33,6 +35,7 @@ class Hokusai::Blocks::Label < Hokusai::Block
33
35
  command.color = color
34
36
  command.size = size
35
37
  command.padding = padding
38
+ command.font = font unless font.nil?
36
39
  end
37
40
  end
38
41
  end
@@ -0,0 +1,62 @@
1
+ class Hokusai::Blocks::Modal < Hokusai::Block
2
+ style <<~EOF
3
+ [style]
4
+ closeButtonStyle {
5
+ width: 40;
6
+ height: 40;
7
+ cursor: "pointer";
8
+ padding: padding(10.0, 10.0, 10.0, 0.0)
9
+ }
10
+ EOF
11
+
12
+ template <<~EOF
13
+ [template]
14
+ hblock
15
+ empty
16
+ empty
17
+ image {
18
+ :source="close_icon"
19
+ ...closeButtonStyle
20
+ @click="emit_close"
21
+
22
+ }
23
+ hblock
24
+ empty
25
+ slot
26
+ empty
27
+ hblock
28
+ empty
29
+ EOF
30
+
31
+ uses(
32
+ vblock: Hokusai::Blocks::Vblock,
33
+ hblock: Hokusai::Blocks::Hblock,
34
+ empty: Hokusai::Blocks::Empty,
35
+ image: Hokusai::Blocks::Image
36
+ )
37
+
38
+ computed :active, default: false
39
+ computed :background, default: [0, 0, 0, 200], convert: Hokusai::Color
40
+ computed :close_icon, default: "#{ASSETS_FOLDER}/close-large-line.png"
41
+
42
+ def emit_close(event)
43
+ emit("close")
44
+ end
45
+
46
+ def on_mounted
47
+ node.meta.set_prop(:z, 1)
48
+ node.meta.set_prop(:ztarget, "root")
49
+ end
50
+
51
+ def render(canvas)
52
+ return unless active
53
+
54
+ draw do
55
+ rect(canvas.x, canvas.y, canvas.width, canvas.height) do |command|
56
+ command.color = background
57
+ end
58
+ end
59
+
60
+ yield canvas
61
+ end
62
+ end
@@ -62,8 +62,8 @@ class Hokusai::Blocks::Panel < Hokusai::Block
62
62
  if y = top
63
63
  if new_scroll_y < y
64
64
  self.scroll_goto_y = y
65
- elsif new_scroll_y > panel_height
66
- self.scroll_goto_y = panel_height
65
+ elsif new_scroll_y - top >= panel_height
66
+ self.scroll_goto_y = panel_height if scroll_percent != 1.0
67
67
  else
68
68
  self.scroll_goto_y = new_scroll_y
69
69
  end
@@ -50,8 +50,6 @@ class Hokusai::Blocks::Scrollbar < Hokusai::Block
50
50
  else
51
51
  self.scrolling = false
52
52
  end
53
-
54
- # event.stop
55
53
  end
56
54
 
57
55
  def scroll_top_height
@@ -15,13 +15,15 @@ class Hokusai::Blocks::Text < Hokusai::Block
15
15
  uses(empty: Hokusai::Blocks::Empty)
16
16
 
17
17
  computed! :content
18
+ computed :cursor, default: nil
19
+ computed :font, default: nil
18
20
  computed :size, default: 16, convert: proc(&:to_i)
19
21
  computed :line_height, default: 5, convert: proc(&:to_f)
20
22
  computed :color, default: [33,33,33], convert: Hokusai::Color
21
23
  computed :selection_color, default: [233,233,233], convert: Hokusai::Color
22
24
  computed :padding, default: [5.0, 5.0, 5.0, 5.0], convert: Hokusai::Padding
23
25
  computed :cursor_offset, default: nil
24
- computed :markdown, default: false
26
+ computed :markdown, default: false, convert: ->(val) { val == "true" || val == true }
25
27
 
26
28
  inject :selection
27
29
  inject :panel_top
@@ -65,7 +67,6 @@ class Hokusai::Blocks::Text < Hokusai::Block
65
67
 
66
68
  draw_with do |commands|
67
69
  iterator.on_draw do |text, x, y, group|
68
-
69
70
  if selector = selection
70
71
  if cursor_offset&.zero? && !selector.started
71
72
  selector.cursor = [x, y + offset_y, 0.0, size.to_f]
@@ -86,6 +87,7 @@ class Hokusai::Blocks::Text < Hokusai::Block
86
87
  commands.text(text, x, y) do |command|
87
88
  command.color = color
88
89
  command.size = size
90
+ command.font = font unless font.nil?
89
91
 
90
92
  if group.respond_to?(:bold?)
91
93
 
@@ -169,7 +171,7 @@ class Hokusai::Blocks::Text < Hokusai::Block
169
171
  end
170
172
  end
171
173
 
172
- if link_hovered
174
+ if link_hovered || cursor == "pointer"
173
175
  Hokusai.set_mouse_cursor(:pointer)
174
176
  elsif hovered
175
177
  Hokusai.set_mouse_cursor(:ibeam)
@@ -186,7 +188,8 @@ class Hokusai::Blocks::Text < Hokusai::Block
186
188
 
187
189
  def clamp(text, width)
188
190
  if markdown
189
- Hokusai.fonts.active.clamp_markdown(text, size.to_i, width - size.to_f - padding.right)
191
+ clamping = Hokusai.fonts.active.clamp_markdown(text, size.to_i, width - size.to_f - padding.right)
192
+ clamping
190
193
  else
191
194
  Hokusai.fonts.active.clamp(text, size.to_i, width - size.to_f, padding.right)
192
195
  end
@@ -203,10 +206,13 @@ class Hokusai::Blocks::Text < Hokusai::Block
203
206
 
204
207
  height = internal_render(last_clamping, canvas)
205
208
  self.last_content = last_content
206
- emit("height_updated", height + padding.bottom) unless last_height == height + padding.bottom
209
+
210
+ new_height = height + padding.bottom + padding.top
211
+ new_height -= size if markdown
207
212
 
208
- self.last_height = height + padding.bottom + padding.top
213
+ emit("height_updated", new_height) unless last_height == new_height
209
214
 
215
+ self.last_height = new_height
210
216
 
211
217
  yield canvas
212
218
  end
@@ -32,12 +32,12 @@ module Hokusai::Blocks::Titlebar
32
32
  EOF
33
33
 
34
34
  computed :rounding, default: 0.0, convert: proc(&:to_f)
35
- computed :outline, default: [0.0, 0.0, 0.0, 0.0], convert: Hokusai::Outline
36
- computed :outline_color, default: [0,0,0,0], convert: Hokusai::Color
35
+ computed :outline, default: nil
36
+ computed :outline_color, default: nil
37
37
  computed :unhovered_color, default: DEFAULT, convert: Hokusai::Color
38
38
  computed :radius, default: 6.0, convert: proc(&:to_f)
39
- computed :background, default: nil, convert: Hokusai::Color
40
- computed :background_drag, default: nil, convert: Hokusai::Color
39
+ computed :background, default: nil
40
+ computed :background_drag, default: nil
41
41
 
42
42
 
43
43
  uses(
@@ -0,0 +1,33 @@
1
+ class Hokusai::Blocks::Variable < Hokusai::Block
2
+ template <<~EOF
3
+ [template]
4
+ empty
5
+ EOF
6
+
7
+ uses(empty: Hokusai::Blocks::Empty)
8
+
9
+ computed! :script
10
+
11
+ def after_updated
12
+ if @last_height != children[0].node.meta.get_prop(:height)
13
+ @last_height = children[0].node.meta.get_prop(:height)
14
+
15
+ node.meta.set_prop(:height, @last_height)
16
+ emit("height_updated", @last_height)
17
+ end
18
+ end
19
+
20
+ def on_mounted
21
+ klass = eval(script)
22
+
23
+ raise Hokusai::Error.new("Class #{klass} is not a Hokusai::Block") unless klass.ancestors.include?(Hokusai::Block)
24
+
25
+ node.meta.set_child(0, klass.mount)
26
+ end
27
+
28
+ def render(canvas)
29
+ if Hokusai.can_render(canvas)
30
+ yield canvas
31
+ end
32
+ end
33
+ end
@@ -15,7 +15,7 @@ class Hokusai::Blocks::Vblock < Hokusai::Block
15
15
  canvas.vertical = true
16
16
  canvas.reverse = reverse
17
17
 
18
- if background.nil?
18
+ if background.nil? && outline.nil?
19
19
  yield canvas
20
20
  else
21
21
  draw do
@@ -26,10 +26,10 @@ module Hokusai
26
26
  def trim_canvas(canvas)
27
27
  x, y, w, h = background_boundary
28
28
 
29
- canvas.x = x + padding.left
30
- canvas.y = y + padding.top
31
- canvas.width = w - (padding.left + padding.right)
32
- canvas.height = h - (padding.top + padding.bottom)
29
+ canvas.x = x + padding.left + outline.left
30
+ canvas.y = y + padding.top + outline.top
31
+ canvas.width = w - (padding.left + padding.right + outline.left + outline.right)
32
+ canvas.height = h - (padding.top + padding.bottom + outline.top + outline.bottom)
33
33
 
34
34
  canvas
35
35
  end
@@ -6,82 +6,99 @@ require_relative "./commands/scissor"
6
6
  require_relative "./commands/text"
7
7
 
8
8
  module Hokusai
9
+ # A proxy class for invoking various UI commands
10
+ #
11
+ # Invocations of commands are immediately sent to the backend
12
+ # for drawing
13
+ #
14
+ # Used as part of the drawing api for Hokusai::Block
9
15
  class Commands
10
16
  attr_reader :queue
11
17
 
12
18
  def initialize
13
- # @queue = []
19
+ @queue = []
14
20
  end
15
21
 
16
- # def hash
17
- # [self.class, *@queue.map(&:hash)].hash
18
- # end
19
-
22
+ # Draw a rectangle
23
+ #
24
+ # @param [Float] the x coordinate
25
+ # @param [Float] the y coordinate
26
+ # @param [Float] the width of the rectangle
27
+ # @param [Float] height of the rectangle
20
28
  def rect(x, y, w, h)
21
29
  command = Commands::Rect.new(x, y, w, h)
30
+
22
31
  yield(command)
23
32
 
24
- command.draw
25
- # add(command)
33
+ queue << command
34
+ # command.draw
26
35
  end
27
36
 
37
+ # Draw a circle
38
+ #
39
+ # @param [Float] x coordinate
40
+ # @param [Float] y coordinate
41
+ # @param [Float] radius of the circle
28
42
  def circle(x, y, radius)
29
43
  command = Commands::Circle.new(x, y, radius)
44
+
30
45
  yield(command)
31
46
 
32
- command.draw
33
- # add(command)
47
+
48
+ queue << command
49
+ # command.draw
34
50
  end
35
51
 
52
+ # Draws an SVG
53
+ #
54
+ # @param [String] location of the svg
55
+ # @param [Float] x coord
56
+ # @param [Float] y coord
57
+ # @param [Float] width of the svg
58
+ # @param [Float] height of the svg
36
59
  def svg(source, x, y, w, h)
37
60
  command = Commands::SVG.new(source, x, y, w, h)
61
+
38
62
  yield(command)
39
63
 
40
- # add(command)
64
+ queue << command
41
65
  end
42
66
 
43
67
  # Invokes an image command
44
68
  # from a filename, at position {x,y} with `w`x`h` dimensions
45
69
  def image(source, x, y, w, h)
46
- Commands::Image.new(source, x, y, w, h).draw
47
- # add(Commands::Image.new(source, x, y, w, h))
70
+ queue << Commands::Image.new(source, x, y, w, h)
48
71
  end
49
72
 
50
73
  # Invokes a scissor begin command
51
74
  # at position {x,y} with `w`x`h` dimensions
52
75
  def scissor_begin(x, y, w, h)
53
- Commands::ScissorBegin.new(x, y, w, h).draw
54
- # add(Commands::ScissorBegin.new(x, y, w, h))
76
+ queue << Commands::ScissorBegin.new(x, y, w, h)
55
77
  end
56
78
 
57
79
  # Invokes a scissor stop command
58
80
  def scissor_end
59
- Commands::ScissorEnd.new.draw
60
- # add(Commands::ScissorEnd.new)
81
+ queue << Commands::ScissorEnd.new
61
82
  end
62
83
 
84
+ # Draws text
85
+ #
86
+ # @param [String] the text content
87
+ # @param [Float] x coord
88
+ # @param [Float] y coord
63
89
  def text(content, x, y)
64
90
  command = Commands::Text.new(content, x, y)
65
91
  yield command
66
92
 
67
- command.draw
68
- # add(command)
93
+ queue << command
69
94
  end
70
95
 
71
- def each
72
- queue.each do |cmd|
73
- yield(cmd)
74
- end
96
+ def execute
97
+ queue.each(&:draw)
75
98
  end
76
99
 
77
100
  def clear!
78
- # @queue = []
79
- end
80
-
81
- def add(command)
82
- # @queue << command
83
-
84
- self
101
+ queue.clear
85
102
  end
86
103
  end
87
104
  end