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.
- checksums.yaml +4 -4
- data/Gemfile +3 -1
- data/Gemfile.lock +4 -0
- data/README.md +2 -0
- data/ast/src/core/hml.c +9 -9
- data/ast/src/core/text.c +1 -3
- data/ast/test/text.c +3 -3
- data/docs.sh +29 -0
- data/ext/extconf.rb +50 -14
- data/grammar/corpus/1_document.txt +24 -0
- data/grammar/corpus/6_styles.txt +23 -0
- data/grammar/grammar.js +4 -4
- data/grammar/src/grammar.json +19 -19
- data/grammar/src/parser.c +1904 -1956
- data/grammar/test.nml +10 -8
- data/hokusai.gemspec +2 -1
- data/ui/examples/assets/Delius-Regular.ttf +0 -0
- data/ui/examples/assets/DoHyeon.ttf +0 -0
- data/ui/examples/assets/Inter-Regular.ttf +0 -0
- data/ui/examples/assets/ernest.gif +0 -0
- data/ui/examples/assets/icons/audio-x-generic.png +0 -0
- data/ui/examples/assets/icons/image-x-generic.png +0 -0
- data/ui/examples/assets/icons/media-playback-pause.png +0 -0
- data/ui/examples/assets/icons/media-playback-start.png +0 -0
- data/ui/examples/assets/icons/media-playback-stop.png +0 -0
- data/ui/examples/assets/icons/package-x-generic.png +0 -0
- data/ui/examples/assets/icons/text-x-generic.png +0 -0
- data/ui/examples/assets/icons/video-x-generic.png +0 -0
- data/ui/examples/buddy.rb +16 -14
- data/ui/examples/clock.rb +38 -36
- data/ui/examples/counter.rb +100 -98
- data/ui/examples/dynamic.rb +115 -113
- data/ui/examples/foobar.rb +189 -187
- data/ui/examples/forum/file.rb +54 -0
- data/ui/examples/forum/music.rb +76 -0
- data/ui/examples/forum/post.rb +146 -0
- data/ui/examples/forum.rb +198 -0
- data/ui/examples/spreadsheet/csv.rb +261 -0
- data/ui/examples/spreadsheet.rb +138 -0
- data/ui/examples/stock.rb +86 -92
- data/ui/examples/stock_decider/option.rb +1 -1
- data/ui/examples/tic_tac_toe.rb +193 -191
- data/ui/lib/lib_hokusai.rb +0 -1
- data/ui/src/hokusai/ast.rb +42 -43
- data/ui/src/hokusai/backends/raylib/font.rb +1 -2
- data/ui/src/hokusai/backends/raylib.rb +16 -7
- data/ui/src/hokusai/backends/sdl2/font.rb +13 -9
- data/ui/src/hokusai/backends/sdl2.rb +5 -5
- data/ui/src/hokusai/block.rb +7 -0
- data/ui/src/hokusai/blocks/hblock.rb +2 -2
- data/ui/src/hokusai/blocks/image.rb +5 -1
- data/ui/src/hokusai/blocks/input.rb +17 -0
- data/ui/src/hokusai/blocks/label.rb +5 -2
- data/ui/src/hokusai/blocks/text.rb +10 -5
- data/ui/src/hokusai/blocks/titlebar/osx.rb +4 -4
- data/ui/src/hokusai/blocks/variable.rb +33 -0
- data/ui/src/hokusai/blocks/vblock.rb +1 -1
- data/ui/src/hokusai/commands/rect.rb +4 -4
- data/ui/src/hokusai/commands.rb +33 -31
- data/ui/src/hokusai/diff.rb +11 -0
- data/ui/src/hokusai/event.rb +19 -5
- data/ui/src/hokusai/events/mouse.rb +9 -1
- data/ui/src/hokusai/font.rb +60 -0
- data/ui/src/hokusai/meta.rb +10 -16
- data/ui/src/hokusai/node.rb +1 -1
- data/ui/src/hokusai/painter.rb +1 -2
- data/ui/src/hokusai/util/clamping_iterator.rb +5 -6
- data/ui/src/hokusai.rb +36 -4
- 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
|