hokusai-zero 0.1.3 → 0.1.4

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/Gemfile.lock +4 -0
  4. data/README.md +2 -0
  5. data/ast/src/core/hml.c +9 -9
  6. data/ast/src/core/text.c +1 -3
  7. data/ast/test/text.c +3 -3
  8. data/docs.sh +29 -0
  9. data/ext/extconf.rb +50 -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 +2 -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 +0 -1
  44. data/ui/src/hokusai/ast.rb +42 -43
  45. data/ui/src/hokusai/backends/raylib/font.rb +1 -2
  46. data/ui/src/hokusai/backends/raylib.rb +16 -7
  47. data/ui/src/hokusai/backends/sdl2/font.rb +13 -9
  48. data/ui/src/hokusai/backends/sdl2.rb +5 -5
  49. data/ui/src/hokusai/block.rb +7 -0
  50. data/ui/src/hokusai/blocks/hblock.rb +2 -2
  51. data/ui/src/hokusai/blocks/image.rb +5 -1
  52. data/ui/src/hokusai/blocks/input.rb +17 -0
  53. data/ui/src/hokusai/blocks/label.rb +5 -2
  54. data/ui/src/hokusai/blocks/text.rb +10 -5
  55. data/ui/src/hokusai/blocks/titlebar/osx.rb +4 -4
  56. data/ui/src/hokusai/blocks/variable.rb +33 -0
  57. data/ui/src/hokusai/blocks/vblock.rb +1 -1
  58. data/ui/src/hokusai/commands/rect.rb +4 -4
  59. data/ui/src/hokusai/commands.rb +33 -31
  60. data/ui/src/hokusai/diff.rb +11 -0
  61. data/ui/src/hokusai/event.rb +19 -5
  62. data/ui/src/hokusai/events/mouse.rb +9 -1
  63. data/ui/src/hokusai/font.rb +60 -0
  64. data/ui/src/hokusai/meta.rb +10 -16
  65. data/ui/src/hokusai/node.rb +1 -1
  66. data/ui/src/hokusai/painter.rb +1 -2
  67. data/ui/src/hokusai/util/clamping_iterator.rb +5 -6
  68. data/ui/src/hokusai.rb +36 -4
  69. metadata +37 -3
@@ -0,0 +1,198 @@
1
+ require_relative "../src/hokusai"
2
+ require_relative "../src/hokusai/backends/raylib"
3
+ require_relative "../src/hokusai/backends/sdl2"
4
+
5
+ require "ostruct"
6
+ require_relative "./forum/post"
7
+ require_relative "./forum/file"
8
+ require_relative "./forum/music"
9
+
10
+ module Demos
11
+ module Forum
12
+ class App < Hokusai::Block
13
+ style <<~EOF
14
+ [style]
15
+ app {
16
+ outline: outline(1.0, 1.0, 1.0, 1.0);
17
+ outline_color: rgb(64, 70, 101);
18
+ background: rgb(39, 43, 62);
19
+ rounding: 0.02;
20
+ }
21
+
22
+ appTitle {
23
+ content: "Skettinet v3";
24
+ font: "dohyeon";
25
+ color: rgb(255, 255, 255);
26
+ size: 20;
27
+ cursor: "pointer";
28
+ padding: padding(7.0, 0.0, 7.0, 20.0);
29
+ }
30
+
31
+ recentsLabel {
32
+ content: "Recent Uploads";
33
+ font: "dohyeon";
34
+ size: 30;
35
+ color: rgb(255, 255, 255);
36
+ }
37
+
38
+ appTitleContainer {
39
+ height: 100;
40
+ }
41
+
42
+ titlebar {
43
+ height: 36;
44
+ outline: outline(0.0, 0.0, 2.0, 0.0);
45
+ outline_color: rgb(49, 55, 78);
46
+ background_drag: rgb(49, 55, 78);
47
+ cursor: "pointer";
48
+ }
49
+
50
+ panelStyle {
51
+ scroll_color: rgb(85, 92, 120);
52
+ scroll_background: rgb(39, 43, 62);
53
+ }
54
+
55
+ ernestImage {
56
+ height: 80;
57
+ width: 30;
58
+ source: "assets/ernest.gif";
59
+ }
60
+ EOF
61
+
62
+ template <<~EOF
63
+ [template]
64
+ vblock {
65
+ ...app
66
+ }
67
+ titlebar {
68
+ ...titlebar
69
+ }
70
+ label {
71
+ ...appTitle
72
+ }
73
+ panel#app { ...panelStyle }
74
+ vblock { :height="50.0" }
75
+ hblock { :height="forum_height" }
76
+ hblock { :width="margin_width" }
77
+ vblock { :width="panel_width" }
78
+ [for="post in posts"]
79
+ post {
80
+ @height_updated="update_forum_height"
81
+ :width="panel_width"
82
+ :index="index"
83
+ :key="index"
84
+ :post="post"
85
+ }
86
+ vblock.recents
87
+ hblock.header { width="100" }
88
+ image { ...ernestImage }
89
+ vblock { width="20" }
90
+ vblock { width="300" }
91
+ text { ...recentsLabel }
92
+ music { height="50" }
93
+ [for="item in files"]
94
+ file { height="30" :item="item" :key="index" :index="index" }
95
+
96
+ EOF
97
+
98
+ uses(
99
+ vblock: Hokusai::Blocks::Vblock,
100
+ hblock: Hokusai::Blocks::Hblock,
101
+ post: Forum::PostBlock,
102
+ file: Forum::FileBlock,
103
+ music: Forum::MusicBlock,
104
+ panel: Hokusai::Blocks::Panel,
105
+ dynamic: Hokusai::Blocks::Dynamic,
106
+ text: Hokusai::Blocks::Text,
107
+ label: Hokusai::Blocks::Label,
108
+ titlebar: Hokusai::Blocks::Titlebar::OSX,
109
+ image: Hokusai::Blocks::Image
110
+ )
111
+
112
+ def update_forum_height(height, index)
113
+ @indicies ||= {}
114
+ @indicies[index] = height
115
+ end
116
+
117
+ def forum_height
118
+ @indicies&.values&.sum || 0.0
119
+ end
120
+
121
+ def on_resize(canvas)
122
+ if canvas.width <= 800
123
+ @panel_width = canvas.width - 50
124
+ @margin_width = 25.0
125
+ else
126
+ @panel_width = 900
127
+ @margin_width = (canvas.width - 800) / 2
128
+ end
129
+ end
130
+
131
+ def margin_width
132
+ @margin_width || 0.0
133
+ end
134
+
135
+ def panel_width
136
+ @panel_width || 800
137
+ end
138
+
139
+ def files
140
+ @files ||= (1..10).to_a.map do |i|
141
+ file = OpenStruct.new
142
+ file.type = [:video, :audio, :app, nil, :image].sample
143
+ file.name = ["hello.mp3", "thing.png", "what.mp4", "yeah"].sample
144
+ file
145
+ end
146
+ end
147
+
148
+ def posts
149
+ @posts ||= (1..10).to_a.map do |i|
150
+ post = OpenStruct.new
151
+ post.author_image = ["#{__dir__}/assets/baby_sean.png", "#{__dir__}/assets/addy.png"].sample
152
+ post.author_name = "Baby Sean"
153
+ post.title = ["Hello World", "My neon jeans", "How to eat a sandwich without killing yourself"].sample
154
+ post.date = "January 4th @ 10.00 am"
155
+ post.body = <<~EOF
156
+ Lorem markdownum vigor concutiens iter frondes, [non spes
157
+ parente](http://www.et.com/mirantiesse) isque, in defunctum concrescere ultima!
158
+ Corpus nepotis tristique isti forsitan respicit o invenit, cur ope in sit
159
+ [eat](http://stringebat.io/). At equus *ullam sua efflant* ludat, silvas
160
+ Achilles, nata aere, modo [Amazone pectore](http://minustantum.com/).
161
+
162
+ Mea tolerare [iussi plumbo](http://perpetiarcorpora.net/pertimuit): ad otia,
163
+ requiris procis, ne illa rore glaebam, velis. Vero creatum Perseus dextrum at
164
+ sterilem telum amensque aliis sermone et pyram meruisse Titania furiosior
165
+ laterum fuit, fata. Qua exstitit aberat sunt dea nequeam concentu raptae Phrygia
166
+ relictis ferebat hoc fuit videtur reddita spectare ignotissima *amorem fugit
167
+ crines*. Oscula Tectaphon.
168
+ EOF
169
+
170
+ post
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ Hokusai::Backends::RaylibBackend.run(Demos::Forum::App) do |config|
178
+ config.after_load do
179
+ font = Hokusai::Backends::RaylibBackend::Font.from("#{__dir__}/assets/Inter-Regular.ttf")
180
+ Hokusai.fonts.register "inter", font
181
+ Hokusai.fonts.activate "inter"
182
+
183
+ font = Hokusai::Backends::RaylibBackend::Font.from_ext("#{__dir__}/assets/Delius-Regular.ttf", 160)
184
+ Hokusai.fonts.register "dohyeon", font
185
+ end
186
+
187
+ config.fps = 40
188
+ config.width = 800
189
+ config.height = 500
190
+ config.title = "Counter application"
191
+
192
+ # config.window_config_flags = SDL::WINDOW_RESIZABLE | SDL::WINDOW_BORDERLESS
193
+
194
+ config.config_flags = Raylib::FLAG_WINDOW_RESIZABLE | Raylib::FLAG_VSYNC_HINT | Raylib::FLAG_WINDOW_TRANSPARENT
195
+ config.window_state_flags = Raylib::FLAG_WINDOW_RESIZABLE | Raylib::FLAG_WINDOW_UNDECORATED | Raylib::FLAG_WINDOW_TRANSPARENT
196
+ config.background = Raylib::BLANK
197
+ end
198
+
@@ -0,0 +1,261 @@
1
+ module Demos
2
+ module Spreadsheet
3
+ class Cell < Hokusai::Block
4
+ style <<~EOF
5
+ [style]
6
+ cellStyle {
7
+ outline: outline(0.0, 1.0, 0.0, 0.0);
8
+ outline_color: rgb(49, 55, 78);
9
+ }
10
+
11
+ cellInputStyle {
12
+ padding: padding(5.0, 5.0, 5.0, 5.0);
13
+ size: 20;
14
+ text_color: rgb(244, 244, 244);
15
+ }
16
+ EOF
17
+
18
+ template <<~EOF
19
+ [template]
20
+ vblock { ...cellStyle :background="cell_background" }
21
+ input {
22
+ ...cellInputStyle
23
+ @modified="emit_modified"
24
+ @change="emit_changed_cell"
25
+ @height_updated="update_height"
26
+ :initial="cell_content"
27
+ }
28
+ EOF
29
+
30
+ computed :cell, default: nil
31
+ computed! :row_index
32
+ computed! :index
33
+
34
+ uses(
35
+ vblock: Hokusai::Blocks::Vblock,
36
+ text: Hokusai::Blocks::Text,
37
+ input: Hokusai::Blocks::Input
38
+ )
39
+
40
+ def cell_content
41
+ cell.nil? ? "" : cell
42
+ end
43
+
44
+ def cell_background
45
+ node.meta.focused ? Hokusai::Color.new(27, 31, 50,255) : nil
46
+ end
47
+
48
+ def emit_modified
49
+ emit("cell_modified", index)
50
+ end
51
+
52
+ def emit_changed_cell(value)
53
+ if value =~ /^=/
54
+ value = value.gsub('=', '')
55
+ positions = value.split("-")
56
+
57
+ emit("cell_forumla", index, *positions)
58
+ else
59
+ emit("cell_updated", index, value)
60
+ end
61
+ end
62
+
63
+ def update_height(height)
64
+ @height = height
65
+ node.meta.set_prop(:height, height)
66
+
67
+ emit("height_updated", height, index)
68
+ end
69
+
70
+ def height
71
+ @height || 0.0
72
+ end
73
+ end
74
+
75
+ class Row < Hokusai::Block
76
+ style <<~EOF
77
+ [style]
78
+ rowStyle {
79
+ outline: outline(0.0, 0.0, 1.0, 0.0);
80
+ outline_color: rgb(49, 55, 78);
81
+ }
82
+ EOF
83
+
84
+ template <<~EOF
85
+ [template]
86
+ hblock { ...rowStyle }
87
+ [for="cell in row"]
88
+ cell {
89
+ @cell_forumla="emit_formula"
90
+ @cell_modified="emit_modified_cell"
91
+ @cell_updated="emit_changed_cell"
92
+ @height_updated="update_height"
93
+ :cell="cell"
94
+ :height="max_height"
95
+ :index="index"
96
+ :key="cell_key(index)"
97
+ }
98
+
99
+ EOF
100
+
101
+ computed! :row
102
+ computed! :index
103
+
104
+ uses(
105
+ hblock: Hokusai::Blocks::Hblock,
106
+ cell: Spreadsheet::Cell
107
+ )
108
+
109
+ def emit_formula(target, cell_1, cell_2)
110
+ emit("cell_formula", index, target, cell_1, cell_2)
111
+ end
112
+
113
+ def emit_modified_cell(cell_index)
114
+ emit("cell_modified", index, cell_index)
115
+ end
116
+
117
+ def emit_changed_cell(cell_index, value)
118
+ emit("cell_updated", index, cell_index, value)
119
+ end
120
+
121
+ def max_height
122
+ @heights ||= {}
123
+ @heights.values.max || 30.0
124
+ end
125
+
126
+ def update_height(height, idx)
127
+ @heights ||= {}
128
+ @heights[idx] = height
129
+
130
+ node.meta.set_prop(:height, max_height)
131
+ end
132
+
133
+ def cell_key(index)
134
+ "cell-#{index}"
135
+ end
136
+ end
137
+
138
+ class CSV < Hokusai::Block
139
+ style <<~EOF
140
+ [style]
141
+ csvTitle {
142
+ color: rgb(233, 233, 233);
143
+ height: 40.0;
144
+ }
145
+
146
+ panelStyle {
147
+ outline: outline(1.0, 1.0, 1.0, 1.0);
148
+ outline_color: rgb(49, 55, 78);
149
+ }
150
+
151
+ headerStyle {
152
+ color: rgb(233, 233, 233);
153
+ size: 14;
154
+ padding: padding(7.0, 4.0, 7.0, 4.0);
155
+ }
156
+ outliner {
157
+ outline: outline(0.0, 1.0, 1.0, 1.0);
158
+ outline_color: rgb(49, 55, 78);
159
+ }
160
+ EOF
161
+
162
+ template <<~EOF
163
+ [template]
164
+ hblock { ...csvTitle }
165
+ [for="header in headers"]
166
+ hblock { ...outliner :key="row_header(index)" }
167
+ label { ...headerStyle :content="get_header(index)" }
168
+ panel { ...panelStyle }
169
+ [for="row in rows"]
170
+ row {
171
+ @cell_formula="formula"
172
+ @cell_modified="change_cell"
173
+ @cell_updated="update_cell"
174
+ :row="row"
175
+ :index="index"
176
+ :key="row_key(index)"
177
+ }
178
+ EOF
179
+
180
+ uses(
181
+ hblock: Hokusai::Blocks::Hblock,
182
+ panel: Hokusai::Blocks::Panel,
183
+ row: Spreadsheet::Row,
184
+ label: Hokusai::Blocks::Label
185
+ )
186
+
187
+ computed! :csv
188
+
189
+ def change_cell(rowi, celli)
190
+ emit("modified")
191
+ end
192
+
193
+ def get_header(index)
194
+ headers[index] || ""
195
+ end
196
+
197
+ def formula(row_index, target, pos1, pos2)
198
+ memo = 0
199
+
200
+ srow, scol = pos1.split(":")
201
+ erow, ecol = pos2.split(":")
202
+
203
+ (srow.to_i..erow.to_i).each do |idx|
204
+ memo += csv[idx][scol.to_i].to_i
205
+ end
206
+
207
+ csv[row_index + 1][target] = memo
208
+ end
209
+
210
+ def update_cell(row_index, cell_index, value)
211
+ if csv[row_index + 1].nil?
212
+ csv[row_index + 1] = empty_row
213
+ end
214
+
215
+ csv[row_index + 1][cell_index] = value
216
+
217
+ emit("update", csv)
218
+ end
219
+
220
+ def rows
221
+ (1..row_count).map do |rindex|
222
+ row = csv[rindex] || Array.new(column_count, nil)
223
+
224
+ (0..column_count).map do |cindex|
225
+ row[cindex] || ""
226
+ end
227
+ end
228
+ end
229
+
230
+ def empty_row
231
+ Array.new(headers.size - 1, nil)
232
+ end
233
+
234
+ def column_count
235
+ csv.to_a.map(&:size).max
236
+ end
237
+
238
+ def row_count
239
+ csv.to_a.size
240
+ end
241
+
242
+ def headers
243
+ csv.to_a[0]
244
+ end
245
+
246
+ def headers
247
+ (0..column_count).map do |cindex|
248
+ csv[0][cindex] || nil
249
+ end
250
+ end
251
+
252
+ def row_header(index)
253
+ "header-#{index}"
254
+ end
255
+
256
+ def row_key(index)
257
+ "row-#{index}"
258
+ end
259
+ end
260
+ end
261
+ end
@@ -0,0 +1,138 @@
1
+ require_relative "../src/hokusai"
2
+ require_relative "../src/hokusai/backends/raylib"
3
+ require_relative "../src/hokusai/backends/sdl2"
4
+
5
+ require_relative "./spreadsheet/csv"
6
+ require "csv"
7
+
8
+ require "ostruct"
9
+
10
+ module Demos
11
+ module Spreadsheet
12
+ class App < Hokusai::Block
13
+ style <<~EOF
14
+ [style]
15
+ app {
16
+ outline: outline(1.0, 1.0, 1.0, 1.0);
17
+ outline_color: rgb(64, 70, 101);
18
+ background: rgb(39, 43, 62);
19
+ rounding: 0.02;
20
+ }
21
+
22
+ titlebar {
23
+ height: 36;
24
+ outline: outline(0.0, 0.0, 2.0, 0.0);
25
+ outline_color: rgb(49, 55, 78);
26
+ background_drag: rgb(49, 55, 78);
27
+ cursor: "pointer";
28
+ }
29
+
30
+ appTitle {
31
+ content: "Spreadsheet Demo";
32
+ font: "dohyeon";
33
+ color: rgb(255, 255, 255);
34
+ size: 20;
35
+ cursor: "pointer";
36
+ padding: padding(7.0, 0.0, 7.0, 20.0);
37
+ }
38
+ EOF
39
+
40
+ template <<~EOF
41
+ [template]
42
+ vblock { ...app }
43
+ titlebar { ...titlebar }
44
+ label { ...appTitle }
45
+ label { ...appTitle size="14" content="somecsv.csv" }
46
+ label { ...appTitle size="14" :content="status" }
47
+ [if="has_spreadsheet"]
48
+ csv { @modified="set_status" :csv="spreadsheet" @keypress="handle_keypress" }
49
+ EOF
50
+
51
+ uses(
52
+ vblock: Hokusai::Blocks::Vblock,
53
+ hblock: Hokusai::Blocks::Hblock,
54
+ panel: Hokusai::Blocks::Panel,
55
+ text: Hokusai::Blocks::Text,
56
+ label: Hokusai::Blocks::Label,
57
+ titlebar: Hokusai::Blocks::Titlebar::OSX,
58
+ image: Hokusai::Blocks::Image,
59
+ csv: Spreadsheet::CSV
60
+ )
61
+
62
+ attr_reader :spreadsheet
63
+
64
+ def initialize(**args)
65
+ super
66
+ @status = :unchanged
67
+ end
68
+
69
+ def set_status
70
+ @status = :changed
71
+ end
72
+
73
+ def handle_keypress(event)
74
+ case event
75
+ when proc(&:ctrl), proc(&:super)
76
+ if event.char == "s"
77
+ save
78
+ end
79
+ end
80
+ end
81
+
82
+ def save
83
+ File.open("somecsv.csv", "wb") do |io|
84
+ io << spreadsheet.to_a.map(&:to_csv).join("")
85
+ end
86
+ @status = :saved
87
+ end
88
+
89
+ def status
90
+ case @status
91
+ when :changed
92
+ "(Modified)"
93
+ when :saved
94
+ "(Saved)"
95
+ else
96
+ "(Not Modified)"
97
+ end
98
+ end
99
+
100
+ def has_spreadsheet
101
+ !@spreadsheet.nil?
102
+ end
103
+
104
+ def on_mounted
105
+ if File.exist?("somecsv.csv")
106
+ @spreadsheet = ::CSV.read("somecsv.csv", headers: false)
107
+ else
108
+ @spreadsheet = ::CSV.parse(<<~EOF, headers: false)
109
+ Name,Department,Salary
110
+ Bob,Engineering,1000
111
+ Jane,Sales,2000
112
+ John,Management,5000
113
+ EOF
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ Hokusai::Backends::RaylibBackend.run(Demos::Spreadsheet::App) do |config|
121
+ config.after_load do
122
+ font = Hokusai::Backends::RaylibBackend::Font.from("#{__dir__}/assets/Inter-Regular.ttf")
123
+ Hokusai.fonts.register "inter", font
124
+ Hokusai.fonts.activate "inter"
125
+
126
+ font = Hokusai::Backends::RaylibBackend::Font.from_ext("#{__dir__}/assets/Delius-Regular.ttf", 160)
127
+ Hokusai.fonts.register "dohyeon", font
128
+ end
129
+
130
+ config.fps = 60
131
+ config.width = 800
132
+ config.height = 500
133
+ config.title = "Spreadsheet application"
134
+
135
+ config.config_flags = Raylib::FLAG_WINDOW_RESIZABLE | Raylib::FLAG_VSYNC_HINT | Raylib::FLAG_WINDOW_TRANSPARENT
136
+ config.window_state_flags = Raylib::FLAG_WINDOW_RESIZABLE | Raylib::FLAG_WINDOW_UNDECORATED | Raylib::FLAG_WINDOW_TRANSPARENT
137
+ config.background = Raylib::BLANK
138
+ end