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.
Files changed (166) hide show
  1. checksums.yaml +7 -0
  2. data/Dockerfile +26 -0
  3. data/Gemfile +15 -0
  4. data/Gemfile.lock +91 -0
  5. data/LICENSE +21 -0
  6. data/README.md +28 -0
  7. data/ast/genheader +3 -0
  8. data/ast/include/hashmap.c +1151 -0
  9. data/ast/include/hashmap.c.license +20 -0
  10. data/ast/include/hashmap.h +54 -0
  11. data/ast/src/core/ast.c +448 -0
  12. data/ast/src/core/ast.h +259 -0
  13. data/ast/src/core/common.h +24 -0
  14. data/ast/src/core/component.c +85 -0
  15. data/ast/src/core/component.h +35 -0
  16. data/ast/src/core/hml.c +665 -0
  17. data/ast/src/core/hml.h +11 -0
  18. data/ast/src/core/input.c +458 -0
  19. data/ast/src/core/input.h +118 -0
  20. data/ast/src/core/style.c +101 -0
  21. data/ast/src/core/style.h +41 -0
  22. data/ast/src/core/text.c +784 -0
  23. data/ast/src/core/text.h +93 -0
  24. data/ast/src/core/util.c +140 -0
  25. data/ast/src/core/util.h +48 -0
  26. data/ast/src/hokusai.c +6 -0
  27. data/ast/src/hokusai.h +6 -0
  28. data/ast/test/fixtures/test.ui +13 -0
  29. data/ast/test/greatest.h +1266 -0
  30. data/ast/test/hokusai.c +14 -0
  31. data/ast/test/parser.c +234 -0
  32. data/ast/test/text.c +116 -0
  33. data/ext/extconf.rb +27 -0
  34. data/grammar/Cargo.lock +80 -0
  35. data/grammar/Cargo.toml +26 -0
  36. data/grammar/binding.gyp +20 -0
  37. data/grammar/bindings/node/binding.cc +28 -0
  38. data/grammar/bindings/node/index.js +19 -0
  39. data/grammar/bindings/rust/build.rs +40 -0
  40. data/grammar/bindings/rust/lib.rs +52 -0
  41. data/grammar/corpus/1_document.txt +131 -0
  42. data/grammar/corpus/2_selectors.txt +58 -0
  43. data/grammar/corpus/3_spaces.txt +69 -0
  44. data/grammar/corpus/4_errors.txt +10 -0
  45. data/grammar/corpus/5_macros.txt +175 -0
  46. data/grammar/corpus/6_styles.txt +81 -0
  47. data/grammar/grammar.js +275 -0
  48. data/grammar/package-lock.json +34 -0
  49. data/grammar/package.json +33 -0
  50. data/grammar/src/grammar.json +1269 -0
  51. data/grammar/src/node-types.json +474 -0
  52. data/grammar/src/parser.c +5772 -0
  53. data/grammar/src/scanner.c +258 -0
  54. data/grammar/src/tree_sitter/parser.h +230 -0
  55. data/grammar/src/tree_sitter/scanner.h +12 -0
  56. data/grammar/test.nml +10 -0
  57. data/hokusai.gemspec +19 -0
  58. data/ui/examples/assets/DigitalDisplay.ttf +0 -0
  59. data/ui/examples/assets/OpenSans-Regular.ttf +0 -0
  60. data/ui/examples/assets/addy.png +0 -0
  61. data/ui/examples/assets/baby_sean.png +0 -0
  62. data/ui/examples/assets/football-troll.png +0 -0
  63. data/ui/examples/assets/gear.png +0 -0
  64. data/ui/examples/assets/icecold.ttf +0 -0
  65. data/ui/examples/assets/science-troll.png +0 -0
  66. data/ui/examples/buddy.rb +31 -0
  67. data/ui/examples/clock.rb +58 -0
  68. data/ui/examples/counter.rb +123 -0
  69. data/ui/examples/dynamic.rb +147 -0
  70. data/ui/examples/foobar.rb +236 -0
  71. data/ui/examples/stock.rb +115 -0
  72. data/ui/examples/stock_decider/option.rb +74 -0
  73. data/ui/examples/tic_tac_toe.rb +246 -0
  74. data/ui/lib/lib_hokusai.rb +425 -0
  75. data/ui/spec/hokusai/ast_spec.rb +88 -0
  76. data/ui/spec/hokusai/automation/keys_transcoder_spec.rb +50 -0
  77. data/ui/spec/hokusai/automation/selector_spec.rb +68 -0
  78. data/ui/spec/hokusai/block_spec.rb +126 -0
  79. data/ui/spec/hokusai/directives_spec.rb +327 -0
  80. data/ui/spec/hokusai/e2e/client_spec.rb +58 -0
  81. data/ui/spec/hokusai/e2e/meta_spec.rb +42 -0
  82. data/ui/spec/hokusai/publisher_spec.rb +38 -0
  83. data/ui/spec/hokusai/slots_spec.rb +150 -0
  84. data/ui/spec/hokusai/util/piece_table_spec.rb +90 -0
  85. data/ui/spec/hokusai_spec.rb +0 -0
  86. data/ui/spec/spec_helper.rb +30 -0
  87. data/ui/src/hokusai/ast.rb +446 -0
  88. data/ui/src/hokusai/automation/client.rb +167 -0
  89. data/ui/src/hokusai/automation/constants.rb +98 -0
  90. data/ui/src/hokusai/automation/converters/selector_converter.rb +61 -0
  91. data/ui/src/hokusai/automation/driver.rb +54 -0
  92. data/ui/src/hokusai/automation/driver_command_queue.rb +50 -0
  93. data/ui/src/hokusai/automation/driver_commands/base.rb +79 -0
  94. data/ui/src/hokusai/automation/driver_commands/get_attribute.rb +41 -0
  95. data/ui/src/hokusai/automation/driver_commands/invoke.rb +33 -0
  96. data/ui/src/hokusai/automation/driver_commands/locate.rb +48 -0
  97. data/ui/src/hokusai/automation/driver_commands/trigger_keyboard.rb +94 -0
  98. data/ui/src/hokusai/automation/driver_commands/trigger_mouse.rb +213 -0
  99. data/ui/src/hokusai/automation/keys_transcoder.rb +128 -0
  100. data/ui/src/hokusai/automation/selector.rb +39 -0
  101. data/ui/src/hokusai/automation/server.rb +114 -0
  102. data/ui/src/hokusai/automation.rb +3 -0
  103. data/ui/src/hokusai/backends/raylib/config.rb +47 -0
  104. data/ui/src/hokusai/backends/raylib/font.rb +113 -0
  105. data/ui/src/hokusai/backends/raylib/keys.rb +124 -0
  106. data/ui/src/hokusai/backends/raylib.rb +449 -0
  107. data/ui/src/hokusai/backends/sdl2/Monaco.ttf +0 -0
  108. data/ui/src/hokusai/backends/sdl2/color.rb +12 -0
  109. data/ui/src/hokusai/backends/sdl2/config.rb +31 -0
  110. data/ui/src/hokusai/backends/sdl2/font.rb +127 -0
  111. data/ui/src/hokusai/backends/sdl2/keys.rb +119 -0
  112. data/ui/src/hokusai/backends/sdl2.rb +529 -0
  113. data/ui/src/hokusai/block.rb +237 -0
  114. data/ui/src/hokusai/blocks/button.rb +100 -0
  115. data/ui/src/hokusai/blocks/checkbox.rb +51 -0
  116. data/ui/src/hokusai/blocks/circle.rb +28 -0
  117. data/ui/src/hokusai/blocks/clipped.rb +23 -0
  118. data/ui/src/hokusai/blocks/cursor.rb +49 -0
  119. data/ui/src/hokusai/blocks/dynamic.rb +37 -0
  120. data/ui/src/hokusai/blocks/empty.rb +10 -0
  121. data/ui/src/hokusai/blocks/hblock.rb +35 -0
  122. data/ui/src/hokusai/blocks/image.rb +18 -0
  123. data/ui/src/hokusai/blocks/input.rb +200 -0
  124. data/ui/src/hokusai/blocks/label.rb +39 -0
  125. data/ui/src/hokusai/blocks/panel.rb +126 -0
  126. data/ui/src/hokusai/blocks/rect.rb +24 -0
  127. data/ui/src/hokusai/blocks/scissor_begin.rb +18 -0
  128. data/ui/src/hokusai/blocks/scissor_end.rb +12 -0
  129. data/ui/src/hokusai/blocks/scrollbar.rb +103 -0
  130. data/ui/src/hokusai/blocks/selectable.rb +77 -0
  131. data/ui/src/hokusai/blocks/svg.rb +20 -0
  132. data/ui/src/hokusai/blocks/text.rb +214 -0
  133. data/ui/src/hokusai/blocks/titlebar/osx.rb +145 -0
  134. data/ui/src/hokusai/blocks/toggle.rb +55 -0
  135. data/ui/src/hokusai/blocks/vblock.rb +35 -0
  136. data/ui/src/hokusai/commands/base.rb +22 -0
  137. data/ui/src/hokusai/commands/circle.rb +47 -0
  138. data/ui/src/hokusai/commands/image.rb +45 -0
  139. data/ui/src/hokusai/commands/rect.rb +158 -0
  140. data/ui/src/hokusai/commands/scissor.rb +22 -0
  141. data/ui/src/hokusai/commands/text.rb +92 -0
  142. data/ui/src/hokusai/commands.rb +87 -0
  143. data/ui/src/hokusai/diff.rb +124 -0
  144. data/ui/src/hokusai/error.rb +3 -0
  145. data/ui/src/hokusai/event.rb +54 -0
  146. data/ui/src/hokusai/events/keyboard.rb +84 -0
  147. data/ui/src/hokusai/events/mouse.rb +172 -0
  148. data/ui/src/hokusai/font.rb +280 -0
  149. data/ui/src/hokusai/meta.rb +152 -0
  150. data/ui/src/hokusai/mounting/loop_entry.rb +230 -0
  151. data/ui/src/hokusai/mounting/mount_entry.rb +74 -0
  152. data/ui/src/hokusai/mounting/update_entry.rb +101 -0
  153. data/ui/src/hokusai/node.rb +98 -0
  154. data/ui/src/hokusai/node_mounter.rb +102 -0
  155. data/ui/src/hokusai/painter.rb +214 -0
  156. data/ui/src/hokusai/publisher.rb +32 -0
  157. data/ui/src/hokusai/style.rb +72 -0
  158. data/ui/src/hokusai/types.rb +266 -0
  159. data/ui/src/hokusai/util/clamping_iterator.rb +202 -0
  160. data/ui/src/hokusai/util/piece_table.rb +111 -0
  161. data/ui/src/hokusai/util/selection.rb +145 -0
  162. data/ui/src/hokusai.rb +120 -0
  163. data/ui/vendor/.gitkeep +0 -0
  164. data/vendor/.gitkeep +0 -0
  165. data/xmake.lua +192 -0
  166. metadata +222 -0
@@ -0,0 +1,237 @@
1
+ require_relative "./publisher"
2
+ require "stringio"
3
+ require "forwardable"
4
+
5
+ module Hokusai
6
+ module Blocks; end
7
+ class Block
8
+ attr_reader :node
9
+ attr_reader :publisher
10
+ attr_reader :provides
11
+
12
+ def self.provide(name, value = nil, &block)
13
+ if block_given?
14
+ provides[name] = block
15
+ else
16
+ if value.is_a?(Symbol)
17
+ provides[name] = value
18
+ else
19
+ provides[name] = ->{value}
20
+ end
21
+ end
22
+ end
23
+
24
+ def self.provides
25
+ @provides ||= {}
26
+ end
27
+
28
+ # Sets the template for this block
29
+ #
30
+ # @param [String] template to set
31
+ def self.template(template)
32
+ @template = template
33
+ @uses ||= {}
34
+ end
35
+
36
+ def self.style(template)
37
+ case template
38
+ when String
39
+ @styles = Hokusai::Style.parse(template)
40
+ when Hokusai::Style
41
+ @styles = template
42
+ end
43
+ end
44
+
45
+ # Sets the template for this block
46
+ # Uses a file
47
+ #
48
+ # @param [String] the filename to use
49
+ def self.template_from_file(path)
50
+ @template = File.read(path)
51
+ end
52
+
53
+ # Fetches the template for this block
54
+ #
55
+ # @return [String] the template
56
+ def self.template_get
57
+ @template || (raise Hokusai::Error.new("Must define template for #{self}"))
58
+ end
59
+
60
+ def self.styles_get
61
+ @styles || {}
62
+ end
63
+
64
+ def self.uses(**args)
65
+ args.each do |key, value|
66
+ raise Hokusai::Error.new("#{key} value must be a Block, got #{value}") unless value.is_a?(Block.class)
67
+
68
+ @uses[key.to_s.downcase] = value
69
+ end
70
+ end
71
+
72
+ def self.use(type)
73
+ if block_klass = @uses[type]
74
+ block_klass
75
+ else
76
+ raise Hokusai::Error.new("Type #{type} is not used on #{self}")
77
+ end
78
+ end
79
+
80
+ def self.computed(name, **args)
81
+ define_method(name) do
82
+ prop = node.meta.get_prop(name.to_sym)#props[name.to_sym]
83
+
84
+ if prop.nil?
85
+ prop = args[:default]
86
+ end
87
+
88
+ if prop.nil?
89
+ return
90
+ end
91
+
92
+ case args[:convert]
93
+ when Proc
94
+ args[:convert].call(prop)
95
+ when NilClass
96
+ prop
97
+ else
98
+ if args[:convert].respond_to?(:convert)
99
+ args[:convert].convert(prop)
100
+ else
101
+ raise Hokusai::Error.new("Prop converter #{args[:convert]} requires a convert method `.convert(value) => #{args[:convert]}`")
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ def self.computed!(name)
108
+ define_method(name.to_sym) do
109
+ return node.meta.get_prop(name.to_sym) || (raise Hokusai::Error.new("Missing prop: #{name} on #{self.class}"))
110
+ end
111
+ end
112
+
113
+ def self.inject(name, aliased = name)
114
+ define_method(aliased) do
115
+ if provider = Node.provides[node.uuid]&.[](name)
116
+ provider.call
117
+ end
118
+ end
119
+ end
120
+
121
+ def self.inject!(name, aliased)
122
+ define_method(aliased) do
123
+ if provider = Node.provides[node.uuid]&.[](name)
124
+ return provider.call
125
+ end
126
+
127
+ raise Hokusai::Error.new("No provision for #{name}")
128
+ end
129
+ end
130
+
131
+ def self.compile(name = "root", parent_node = nil)
132
+ Node.parse(template_get, name, parent_node)
133
+ end
134
+
135
+ def self.mount(name = "root", parent_node = nil)
136
+ compile(name, parent_node).mount(self)
137
+ end
138
+
139
+ def initialize(**args)
140
+ raise Hokusai::Error.new("Must supply node argument to #{self.class}.new") unless args[:node]
141
+
142
+ @node = args[:node]
143
+ end
144
+
145
+ def children?
146
+ node.meta.children?
147
+ end
148
+
149
+ def children
150
+ node.meta.children!
151
+ end
152
+
153
+ def update
154
+ node.meta.children?&.each do |child|
155
+ child.before_updated if child.respond_to?(:before_updated)
156
+ end
157
+
158
+ node.meta.update(self)
159
+
160
+ node.meta.children?&.each do |child|
161
+ child.after_updated if child.respond_to?(:after_updated)
162
+ end
163
+ end
164
+
165
+ def emit(name, *args, **kwargs)
166
+ if portal = node.portal
167
+ if event = portal.event(name)
168
+ node.meta.publisher.notify(event.value.method, *args, **kwargs)
169
+ end
170
+ end
171
+ end
172
+
173
+ def draw(&block)
174
+ instance_eval(&block)
175
+ # node.meta.commands.each(&:draw)
176
+ # node.meta.commands.clear!
177
+ end
178
+
179
+ 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)
182
+ end
183
+
184
+ super
185
+ end
186
+
187
+ def draw_with
188
+ yield Hokusai::Meta.commands
189
+
190
+ # node.meta.commands.each(&:draw)
191
+ # node.meta.commands.clear!
192
+ end
193
+
194
+ def render(canvas)
195
+ yield(canvas)
196
+ end
197
+
198
+ def on_resize(canvas); end
199
+
200
+ def dump(level = 1, show_props: false)
201
+ io = ""
202
+ io << "#{self.class}"
203
+ io << " if " if node.ast.has_if_condition?
204
+ io << "(#{node.type})"
205
+
206
+ if portal = node.portal
207
+ io << ".#{portal.ast.classes.join(".")}"
208
+ end
209
+
210
+ io << "\n"
211
+
212
+ if node.meta.props!.values.size > 0 && show_props
213
+ io << "#{" " * level * 2}{\n"
214
+ node.meta.props!.each do |key, value|
215
+ io << "#{" " * level * 3}#{key} = #{value}\n"
216
+ end
217
+
218
+ unless node.portal.nil?
219
+ node.portal.ast.events.each do |_, event|
220
+ io << "#{" " * level * 3}@#{event.name} = #{event.value.method} #{!!node.portal.ast.event(event.name)}\n"
221
+ end
222
+ end
223
+ io << "#{" " * level * 2}}\n"
224
+ end
225
+
226
+ if children.nil?
227
+ io << "#{" " * level * 2}(no children)\n"
228
+ else
229
+ child_dump = children?&.map {|child| child.dump(level + 1, show_props: show_props) }
230
+ io << "#{" " * level * 2}#{child_dump.join("#{" " * level * 2}") }\n"
231
+ end
232
+
233
+ io
234
+ end
235
+ end
236
+ end
237
+
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hokusai::Blocks::Button < Hokusai::Block
4
+ template <<~EOF
5
+ [template]
6
+ rect {
7
+ @click="emit_click"
8
+ @hover="set_hovered"
9
+ @mouseout="unset_hovered"
10
+ :color="background_color"
11
+ :height="button_height"
12
+ :width="button_width"
13
+ :rounding="rounding"
14
+ :outline="outline"
15
+ :outline_color="outline_color"
16
+ }
17
+ label {
18
+ :padding="padding"
19
+ :color="color"
20
+ @width_updated="update_width"
21
+ :content="content"
22
+ :size="size"
23
+ }
24
+ EOF
25
+
26
+ uses(label: Hokusai::Blocks::Label, rect: Hokusai::Blocks::Rect)
27
+
28
+ DEFAULT_BACKGROUND = [39, 95, 206]
29
+ DEFAULT_CLICKED_BACKGROUND = [24, 52, 109]
30
+ DEFAULT_HOVERED_BACKGROUND = [242, 52, 109]
31
+
32
+ computed :padding, default: [5.0, 15.0, 5.0, 15.0], convert: Hokusai::Padding
33
+ computed :size, default: 24
34
+ computed :rounding, default: 0.5
35
+ computed :content, default: ""
36
+ computed :outline, default: 0.0, convert: Hokusai::Outline
37
+ computed :outline_color, default: nil, convert: Hokusai::Color
38
+ computed :background, default: DEFAULT_BACKGROUND, convert: Hokusai::Color
39
+ computed :hovered_background, default: DEFAULT_HOVERED_BACKGROUND, convert: Hokusai::Color
40
+ computed :clicked_background, default: DEFAULT_CLICKED_BACKGROUND, convert: Hokusai::Color
41
+ computed :color, default: [215, 213, 226], convert: Hokusai::Color
42
+
43
+ attr_accessor :button_width
44
+
45
+ def emit_click(event)
46
+ @clicked = true
47
+
48
+ event.stop
49
+
50
+ emit("clicked", event)
51
+ end
52
+
53
+ def update_width(value)
54
+ self.button_width = value + (outline.right)
55
+ end
56
+
57
+ def set_hovered(event)
58
+ @hovered = true
59
+ @clicked = event.left.down
60
+
61
+ Hokusai.set_mouse_cursor(:pointer)
62
+ end
63
+
64
+ def unset_hovered(_)
65
+ @clicked = false
66
+
67
+ if @hovered
68
+ Hokusai.set_mouse_cursor(:default)
69
+ end
70
+
71
+ @hovered = false
72
+ end
73
+
74
+ def button_height
75
+ size + padding.top + padding.bottom
76
+ end
77
+
78
+ def after_updated
79
+ node.meta.props[:height] = button_height
80
+ end
81
+
82
+ def background_color
83
+ @hovered ? (@clicked ? clicked_background : hovered_background) : background
84
+ end
85
+
86
+ def render(canvas)
87
+ canvas.height = button_height
88
+ canvas.width = button_width
89
+
90
+ yield canvas
91
+ end
92
+
93
+ def initialize(**args)
94
+ @button_width = 0.0
95
+ @hovered = false
96
+ @clicked = false
97
+
98
+ super(**args)
99
+ end
100
+ end
@@ -0,0 +1,51 @@
1
+ class Hokusai::Blocks::Checkbox < Hokusai::Block
2
+ template <<~EOF
3
+ [template]
4
+ rect#checkbox {
5
+ @click="check"
6
+ :width="size"
7
+ :height="size"
8
+ :color="color"
9
+ }
10
+ [if="checked"]
11
+ circle { :radius="circle_size" :color="circle_color" }
12
+ EOF
13
+
14
+ uses(
15
+ rect: Hokusai::Blocks::Rect,
16
+ circle: Hokusai::Blocks::Circle,
17
+ empty: Hokusai::Blocks::Empty
18
+ )
19
+
20
+ DEFAULT_COLOR = [184,201,219]
21
+ DEFAULT_CIRCLE_COLOR = [44, 113, 183]
22
+
23
+ computed :color, default: DEFAULT_COLOR, convert: Hokusai::Color
24
+ computed :circle_color, default: DEFAULT_CIRCLE_COLOR, convert: Hokusai::Color
25
+ computed :size, default: 25.0
26
+
27
+ attr_accessor :checked
28
+
29
+ def circle_size
30
+ (size.to_f * 0.35)
31
+ end
32
+
33
+ def check(event)
34
+ self.checked = !checked
35
+
36
+ emit("check", checked)
37
+ end
38
+
39
+ def initialize(**args)
40
+ @checked = false
41
+
42
+ super(**args)
43
+ end
44
+
45
+ def render(canvas)
46
+ canvas.width = size.to_f
47
+ canvas.height = size.to_f
48
+
49
+ yield canvas
50
+ end
51
+ end
@@ -0,0 +1,28 @@
1
+ class Hokusai::Blocks::Circle < Hokusai::Block
2
+ template <<~EOF
3
+ [template]
4
+ virtual
5
+ EOF
6
+
7
+ computed :radius, default: 10.0, convert: proc(&:to_f)
8
+ computed :color, default: [255,255,255], convert: Hokusai::Color
9
+ computed :outline, default: nil
10
+ computed :outline_color, default: [0,0,0,0], convert: Hokusai::Color
11
+
12
+ def render(canvas)
13
+ x = canvas.x + (canvas.width / 2)
14
+ y = canvas.y + canvas.height / 2
15
+
16
+ draw do
17
+ circle(x, y, radius) do |command|
18
+ command.color = color
19
+ if outline
20
+ command.outline = outline
21
+ command.outline_color = outline_color
22
+ end
23
+ end
24
+ end
25
+
26
+ yield canvas
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ class Hokusai::Blocks::Clipped < Hokusai::Block
2
+ style <<-EOF
3
+ [style]
4
+ scissorStyle {
5
+ height: 0.0;
6
+ width: 0.0;
7
+ }
8
+ EOF
9
+
10
+ template <<-EOF
11
+ [template]
12
+ scissorbegin { :offset="offset" }
13
+ slot
14
+ scissorend { ...scissorStyle }
15
+ EOF
16
+
17
+ uses(
18
+ scissorbegin: Hokusai::Blocks::ScissorBegin,
19
+ scissorend: Hokusai::Blocks::ScissorEnd,
20
+ )
21
+
22
+ computed :offset, default: 0.0
23
+ end
@@ -0,0 +1,49 @@
1
+ class Hokusai::Blocks::Cursor < Hokusai::Block
2
+ template <<~EOF
3
+ [template]
4
+ virtual
5
+ EOF
6
+
7
+ DEFAULT_COLOR = [255,0,0,244]
8
+
9
+ computed :x, default: 0.0
10
+ computed :y, default: 0.0
11
+ computed :show, default: false
12
+ computed :speed, default: 0.1
13
+ computed :cursor_width, default: 2.0
14
+ computed :cursor_height, default: 0.0
15
+ computed :color, default: DEFAULT_COLOR, convert: Hokusai::Color
16
+
17
+ def initialize(**args)
18
+ @active = false
19
+ @iteration = 0
20
+
21
+ super(**args)
22
+ end
23
+
24
+ def before_updated
25
+ frames = speed * 30
26
+
27
+ @active = @iteration < frames
28
+
29
+ if @iteration >= 30
30
+ @iteration = 0
31
+ else
32
+ @iteration += 1
33
+ end
34
+ end
35
+
36
+ def render(canvas)
37
+ if show
38
+ draw do
39
+ if @active
40
+ rect(x, y, cursor_width, cursor_height) do |command|
41
+ command.color = color
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ yield canvas
48
+ end
49
+ end
@@ -0,0 +1,37 @@
1
+ class Hokusai::Blocks::Dynamic < Hokusai::Block
2
+ template <<~EOF
3
+ [template]
4
+ slot
5
+ EOF
6
+
7
+ computed :reverse, default: false
8
+
9
+ def before_updated
10
+ width, height = compute_size
11
+
12
+ emit("size_updated", width, height)
13
+ end
14
+
15
+ def on_mounted
16
+ compute_size
17
+ end
18
+
19
+ def compute_size
20
+ h = 0.0
21
+ w = 0.0
22
+
23
+ children.each do |block|
24
+ h += block.node.meta.get_prop?(:height)&.to_f || 0.0
25
+ w += block.node.meta.get_prop?(:width)&.to_f || 0.0
26
+ end
27
+
28
+ [w, h]
29
+ end
30
+
31
+ def render(canvas)
32
+ canvas.vertical = true
33
+ canvas.reverse = (reverse == true || reverse == "true")
34
+
35
+ yield canvas
36
+ end
37
+ end
@@ -0,0 +1,10 @@
1
+ class Hokusai::Blocks::Empty < Hokusai::Block
2
+ template <<~EOF
3
+ [template]
4
+ virtual
5
+ EOF
6
+
7
+ def render(canvas)
8
+ yield canvas
9
+ end
10
+ end
@@ -0,0 +1,35 @@
1
+ class Hokusai::Blocks::Hblock < Hokusai::Block
2
+ template <<~EOF
3
+ [template]
4
+ slot
5
+ EOF
6
+
7
+ computed :padding, default: 0, convert: Hokusai::Padding
8
+ computed :background, default: nil, convert: Hokusai::Color
9
+ computed :rounding, default: 0.0
10
+ computed :outline, default: Hokusai::Outline.default, convert: Hokusai::Outline
11
+ computed :outline_color, default: nil, convert: Hokusai::Color
12
+ computed :reverse, default: false
13
+
14
+ def render(canvas)
15
+ canvas.vertical = false
16
+ canvas.reverse = reverse
17
+
18
+ if background.nil?
19
+ yield canvas
20
+ else
21
+ draw do
22
+ rect(canvas.x, canvas.y, canvas.width, canvas.height) do |command|
23
+ command.color = background
24
+ command.outline = outline if outline
25
+ command.outline_color = outline_color if outline_color
26
+ command.round = rounding.to_f if rounding
27
+ command.padding = padding
28
+ canvas = command.trim_canvas(canvas)
29
+ end
30
+ end
31
+
32
+ yield canvas
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,18 @@
1
+ class Hokusai::Blocks::Image < Hokusai::Block
2
+ template <<~EOF
3
+ [template]
4
+ virtual
5
+ EOF
6
+
7
+ computed! :source
8
+ computed :width, default: nil
9
+ computed :height, default: nil
10
+
11
+ def render(canvas)
12
+ draw do
13
+ image(source, canvas.x, canvas.y, width&.to_f || canvas.width, height&.to_f || canvas.height)
14
+ end
15
+
16
+ yield canvas
17
+ end
18
+ end