hokusai-zero 0.2.6.pre.android → 0.2.6.pre.pinephone2

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -1
  3. data/Gemfile.lock +0 -2
  4. data/ast/src/core/input.c +135 -0
  5. data/ast/src/core/input.h +32 -0
  6. data/ast/test/hokusai.c +2 -0
  7. data/ast/test/input.c +44 -0
  8. data/hokusai.gemspec +1 -2
  9. data/ui/examples/drag.rb +154 -0
  10. data/ui/examples/embedded.rb +58 -0
  11. data/ui/examples/game.rb +143 -0
  12. data/ui/examples/overlay.rb +233 -0
  13. data/ui/examples/provider.rb +56 -0
  14. data/ui/examples/shader/test.rb +145 -0
  15. data/ui/examples/shader.rb +100 -0
  16. data/ui/examples/wiki.rb +82 -0
  17. data/ui/lib/lib_hokusai.rb +20 -1
  18. data/ui/spec/spec_helper.rb +1 -1
  19. data/ui/src/hokusai/assets/arrow-down-line.png +0 -0
  20. data/ui/src/hokusai/assets/arrow-down-wide-line.png +0 -0
  21. data/ui/src/hokusai/automation/server.rb +2 -3
  22. data/ui/src/hokusai/backends/embedded/config.rb +48 -0
  23. data/ui/src/hokusai/backends/embedded/font.rb +112 -0
  24. data/ui/src/hokusai/backends/embedded/keys.rb +124 -0
  25. data/ui/src/hokusai/backends/embedded.rb +540 -0
  26. data/ui/src/hokusai/backends/raylib.rb +80 -5
  27. data/ui/src/hokusai/blocks/color_picker.rb +1080 -0
  28. data/ui/src/hokusai/blocks/shader_begin.rb +22 -0
  29. data/ui/src/hokusai/blocks/shader_end.rb +12 -0
  30. data/ui/src/hokusai/blocks/texture.rb +23 -0
  31. data/ui/src/hokusai/commands/rect.rb +10 -1
  32. data/ui/src/hokusai/commands/shader.rb +33 -0
  33. data/ui/src/hokusai/commands/texture.rb +26 -0
  34. data/ui/src/hokusai/commands.rb +22 -0
  35. data/ui/src/hokusai/event.rb +2 -1
  36. data/ui/src/hokusai/events/touch.rb +66 -0
  37. data/ui/src/hokusai/painter.rb +22 -0
  38. data/ui/src/hokusai/types.rb +89 -0
  39. data/ui/src/hokusai.rb +4 -9
  40. data/xmake.lua +1 -1
  41. metadata +25 -22
  42. data/ui/src/hokusai/assets/chevron-down.svg +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce738bae9af93e8117b6a962e52d140c69ca8dacac118b7830819a8e4d1db585
4
- data.tar.gz: 0a0cbb5d8f6fb7a35dbcb619e17d06f5d05788c226480b11d546b3e9de7c8813
3
+ metadata.gz: e6b346169398fdc8ace4e949627b34928b44230de71c120dc1b7ec2e3cb377c5
4
+ data.tar.gz: 444a5c3581cc74ca1537f2682cd0a1fd3859164f92a773af738a3fea434d579f
5
5
  SHA512:
6
- metadata.gz: 1752951b5745a54239c07c9cb3a0b9569105a0011531174a6bfced4b9062466054b098029a72b7562b3f73a89378e422cd13983ff432b0130bcc1a8bce622e6e
7
- data.tar.gz: cc55da6b2f736f4f637a50115ad294247da5eb5c73fb74785ba2eec790c8476b9aae1d0b97822a65152f27ac924a32fd3a58192594e97b5af9f1bb7479f8db94
6
+ metadata.gz: a9e491ff21f1ed5532ae4b265c2084f3599a1c242f68cd14974d9ccd2f0b9cc8d39897ff38795183460641aea0b62984fcf3cdcaea1432bc076b0bf4844e12c7
7
+ data.tar.gz: 80a602eff3310633a24f4edc99b7191d2d367a1a826e0f591ac4bece88119088551566cf82779f138f757c5fcd8c651efae8be1188b0c77c2131725aa016de87
data/Gemfile CHANGED
@@ -3,7 +3,6 @@ source "https://www.rubygems.org"
3
3
  gem "ffi", github: "ffi/ffi", submodules: true
4
4
 
5
5
  group :development, :test do
6
- gem "concurrent-ruby", require: "concurrent"
7
6
  gem "memory_profiler", require: false
8
7
  gem "mini_portile2", "~> 2.0.0"
9
8
  gem "raylib-bindings"
data/Gemfile.lock CHANGED
@@ -8,7 +8,6 @@ GIT
8
8
  GEM
9
9
  remote: https://www.rubygems.org/
10
10
  specs:
11
- concurrent-ruby (1.3.5)
12
11
  daemons (1.4.1)
13
12
  diff-lcs (1.6.1)
14
13
  domain_name (0.6.20240107)
@@ -77,7 +76,6 @@ PLATFORMS
77
76
  x86_64-linux
78
77
 
79
78
  DEPENDENCIES
80
- concurrent-ruby
81
79
  ffi!
82
80
  memory_profiler
83
81
  mini_portile2 (~> 2.0.0)
data/ast/src/core/input.c CHANGED
@@ -4,6 +4,134 @@
4
4
  #include "input.h"
5
5
  #include <stdio.h>
6
6
 
7
+ #define NANO_TO_MILLISECONDS 1000000
8
+
9
+ int hoku_input_touch_init(hoku_input_touch** embedded, int max_touch_positions)
10
+ {
11
+ hoku_input_touch* out = malloc(sizeof(hoku_input_touch));
12
+ if (!out) return -1;
13
+
14
+ out->last_touch_positions = malloc(sizeof(hoku_dvec2*) * max_touch_positions);
15
+ if (out->last_touch_positions == NULL) return -1;
16
+
17
+ out->touch_positions = malloc(sizeof(hoku_dvec2*) * max_touch_positions);
18
+ if (out->touch_positions == NULL) return -1;
19
+
20
+ for (int i=0; i < max_touch_positions; i++)
21
+ {
22
+ out->last_touch_positions[i] = malloc(sizeof(hoku_dvec2));
23
+ if (out->last_touch_positions[i] == NULL) return -1;
24
+ out->last_touch_positions[i]->x = -1.0;
25
+ out->last_touch_positions[i]->y = -1.0;
26
+
27
+
28
+ out->touch_positions[i] = malloc(sizeof(hoku_dvec2));
29
+ if (out->touch_positions[i] == NULL) return -1;
30
+ out->touch_positions[i]->x = -1.0;
31
+ out->touch_positions[i]->y = -1.0;
32
+ }
33
+
34
+ out->touch_len = max_touch_positions;
35
+ out->touch_count = 0;
36
+ out->touching_now = false;
37
+ out->timer = 0;
38
+
39
+ *embedded = out;
40
+ return 0;
41
+ }
42
+
43
+ long hoku_input_touch_duration(hoku_input* input)
44
+ {
45
+ return input->touch->timer * NANO_TO_MILLISECONDS;
46
+ }
47
+
48
+ bool hoku_input_touch_tapped(hoku_input* input)
49
+ {
50
+ if (input->touch->touching_now == false && input->touch->last_touch_positions[0] != NULL) return true;
51
+
52
+ return false;
53
+ }
54
+
55
+ bool hoku_input_touch_swiped(hoku_input* input, float threshold)
56
+ {
57
+ if (input->touch->touching_now == false)
58
+ {
59
+ hoku_dvec2* last = input->touch->last_touch_positions[0];
60
+ hoku_dvec2* now = input->touch->touch_positions[0];
61
+
62
+ if (last->x == -1.0 || last->y == -1.0) return false;
63
+ if (last == NULL || now == NULL) return false;
64
+
65
+ return (abs((int)(now->x - last->x)) >= threshold || abs((int)(now->y - last->y)) >= threshold);
66
+ }
67
+
68
+ return false;
69
+ }
70
+
71
+ bool hoku_input_touch_pinched(hoku_input* input)
72
+ {
73
+ return false;
74
+ }
75
+
76
+ bool hoku_input_touch_longtapped(hoku_input* input, int threshold)
77
+ {
78
+ if (input->touch->touching_now && input->touch->timer > 0l)
79
+ {
80
+ hoku_dvec2* last = input->touch->last_touch_positions[0];
81
+ hoku_dvec2* now = input->touch->touch_positions[0];
82
+
83
+ return (abs((int)(now->x - last->x)) < threshold && abs((int)(now->y - last->y)) < threshold);
84
+ }
85
+
86
+ return false;
87
+ }
88
+
89
+ void hoku_input_clear_touch(hoku_input* input, int index)
90
+ {
91
+ input->touch->touching_now = false;
92
+ input->touch->timer = 0l;
93
+ }
94
+
95
+ int hoku_input_record_touch(hoku_input* input, int index, float x, float y)
96
+ {
97
+ struct timespec start;
98
+ if (clock_gettime(CLOCK_MONOTONIC, &start) == -1) return -1;
99
+
100
+ if (!(input->touch->touching_now))
101
+ {
102
+ input->touch->last_touch_positions[index]->x = input->touch->touch_positions[index]->x;
103
+ input->touch->last_touch_positions[index]->y = input->touch->touch_positions[index]->y;
104
+
105
+ input->touch->timer = start.tv_nsec;
106
+ }
107
+ else
108
+ {
109
+ input->touch->timer = start.tv_nsec - input->touch->timer;
110
+ }
111
+
112
+ input->touch->touch_positions[index]->x = x;
113
+ input->touch->touch_positions[index]->y = y;
114
+ input->touch->touching_now = true;
115
+
116
+ return 0;
117
+ }
118
+
119
+ int hoku_input_attach_touch(hoku_input* input, int max_touch_count)
120
+ {
121
+ hoku_input_touch* touch;
122
+ if (hoku_input_touch_init(&touch, max_touch_count) == -1) return -1;
123
+ input->touch = touch;
124
+
125
+ return 0;
126
+ }
127
+
128
+ void hoku_input_touch_free(hoku_input_touch* embedded)
129
+ {
130
+ free(embedded->touch_positions);
131
+ free(embedded->last_touch_positions);
132
+ free(embedded);
133
+ }
134
+
7
135
  static int hoku_keycodes[HOKU_KEY_MAX] = {
8
136
  0,39,44,45,46,47,48,49,50,51,52,53,54,55,56,57,59,61,65,66,67,68,69,
9
137
  70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,
@@ -273,6 +401,12 @@ void hoku_input_free(hoku_input* input)
273
401
  {
274
402
  hoku_input_keyboard_free(input->keyboard);
275
403
  hoku_input_mouse_free(input->mouse);
404
+
405
+ if (input->touch)
406
+ {
407
+ hoku_input_touch_free(input->touch);
408
+ }
409
+
276
410
  free(input);
277
411
  }
278
412
 
@@ -298,6 +432,7 @@ int hoku_input_init(hoku_input** input)
298
432
  return -1;
299
433
  }
300
434
  init->keyboard = keyboard;
435
+ init->touch = NULL;
301
436
 
302
437
  *input = init;
303
438
  return 0;
data/ast/src/core/input.h CHANGED
@@ -4,6 +4,7 @@
4
4
  #include "common.h"
5
5
  #include <stdbool.h>
6
6
  #include <stdlib.h>
7
+ #include <time.h>
7
8
 
8
9
  typedef struct HmlInputMouseButton
9
10
  {
@@ -87,13 +88,44 @@ typedef struct HmlInputKeyboard
87
88
  bool collecting;
88
89
  } hoku_input_keyboard;
89
90
 
91
+ typedef enum HmlDragDirection {
92
+ HOKU_DRAG_UP,
93
+ HOKU_DRAG_DOWN,
94
+ HOKU_DRAG_LEFT,
95
+ HOKU_DRAG_RIGHT
96
+ } hoku_drag_direction;
97
+
98
+ typedef enum HmlPinchDirection {
99
+ HOKU_PINCH_IN,
100
+ HOKU_PINCH_OUT
101
+ } hoku_pinch_direction;
102
+
103
+ typedef struct HmlInputTouch
104
+ {
105
+ int touch_len;
106
+ int touch_count;
107
+ bool touching_now;
108
+ long timer;
109
+ hoku_dvec2** last_touch_positions;
110
+ hoku_dvec2** touch_positions;
111
+ } hoku_input_touch;
112
+
90
113
  typedef struct HmlInput
91
114
  {
92
115
  hoku_input_keyboard* keyboard;
93
116
  hoku_input_mouse* mouse;
117
+ hoku_input_touch* touch;
94
118
  } hoku_input;
95
119
 
96
120
 
121
+ long hoku_input_touch_duration(hoku_input* input);
122
+ bool hoku_input_touch_tapped(hoku_input* input);
123
+ bool hoku_input_touch_swiped(hoku_input* input, float threshold);
124
+ bool hoku_input_touch_longtapped(hoku_input* input, int threshold);
125
+ void hoku_input_clear_touch(hoku_input* input, int index);
126
+ int hoku_input_record_touch(hoku_input* input, int index, float x, float y);
127
+ int hoku_input_attach_touch(hoku_input* input, int max_touch_count);
128
+
97
129
  int hoku_input_keyboard_init(hoku_input_keyboard** keyboard);
98
130
  int hoku_input_mouse_init(hoku_input_mouse** mouse);
99
131
  int hoku_input_init(hoku_input** input);
data/ast/test/hokusai.c CHANGED
@@ -1,6 +1,7 @@
1
1
  #include "greatest.h"
2
2
  #include "parser.c"
3
3
  #include "text.c"
4
+ #include "input.c"
4
5
 
5
6
  GREATEST_MAIN_DEFS();
6
7
 
@@ -9,6 +10,7 @@ int main(int argc, char** argv) {
9
10
 
10
11
  RUN_SUITE(hoku_parser_suite);
11
12
  RUN_SUITE(hoku_text_suite);
13
+ RUN_SUITE(hoku_input_suite);
12
14
 
13
15
  GREATEST_MAIN_END();
14
16
  }
data/ast/test/input.c ADDED
@@ -0,0 +1,44 @@
1
+ #include "../src/core/input.c"
2
+ #include<unistd.h>
3
+
4
+ TEST test_hoku_input_touch_basic()
5
+ {
6
+ hoku_input* input;
7
+ int ret = hoku_input_init(&input);
8
+ ASSERT_EQ_FMT(ret, 0, "%d");
9
+
10
+ ret = hoku_input_attach_touch(input, 2);
11
+ ASSERT_EQ_FMT(ret, 0, "%d");
12
+
13
+ hoku_input_record_touch(input, 0, 1.0, 2.0);
14
+ hoku_input_clear_touch(input, 0);
15
+
16
+ bool tapped = hoku_input_touch_tapped(input);
17
+ bool swiped = hoku_input_touch_swiped(input, 4);
18
+
19
+ ASSERT_EQ_FMT(1, tapped, "%d");
20
+ ASSERT_EQ_FMT(0, swiped, "%d");
21
+
22
+ hoku_input_record_touch(input, 0, 1.0, 2.0);
23
+ usleep(1000);
24
+ hoku_input_record_touch(input, 0, 3.0, 1.0);
25
+
26
+ bool longtapped = hoku_input_touch_longtapped(input, 4);
27
+
28
+ hoku_input_clear_touch(input, 0);
29
+ swiped = hoku_input_touch_swiped(input, 1.0);
30
+
31
+ ASSERT_EQ_FMT(1, longtapped, "%d");
32
+ ASSERT_EQ_FMT(1, swiped, "%d");
33
+ // ASSERT_EQ_FMT(pinched, 0, "%d");
34
+
35
+ hoku_input_free(input);
36
+
37
+ PASS();
38
+ }
39
+
40
+
41
+ SUITE(hoku_input_suite)
42
+ {
43
+ RUN_TEST(test_hoku_input_touch_basic);
44
+ }
data/hokusai.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'hokusai-zero'
3
- s.version = '0.2.6-android'
3
+ s.version = '0.2.6-pinephone2'
4
4
  s.licenses = ['MIT']
5
5
  s.summary = "A Ruby library for writing GUI applications"
6
6
  s.authors = ["skinnyjames"]
@@ -16,7 +16,6 @@ Gem::Specification.new do |s|
16
16
  s.metadata = { "source_code_uri" => "https://codeberg.org/skinnyjames/hokusai" }
17
17
 
18
18
  s.add_dependency "ffi", "~> 1.16"
19
- s.add_dependency "concurrent-ruby", "~> 1.3.4"
20
19
  s.add_dependency "raylib-bindings", "~> 0.7.9"
21
20
  s.add_dependency "sdl2-bindings", "~> 0.2.3"
22
21
  s.add_dependency "memory_profiler"
@@ -0,0 +1,154 @@
1
+ require_relative "../src/hokusai"
2
+ require_relative "../src/hokusai/backends/raylib"
3
+ require "ostruct"
4
+
5
+ class Item < Hokusai::Block
6
+ style <<~EOF
7
+ [style]
8
+ circleStyle {
9
+ cursor: "pointer";
10
+ }
11
+ EOF
12
+ template <<~EOF
13
+ [template]
14
+ empty {
15
+ ...circleStyle
16
+ :color="color"
17
+ @mousedown="start_drag"
18
+ @mouseup="release_drag"
19
+ @mousemove="emit_drag"
20
+ }
21
+ EOF
22
+
23
+ uses(empty: Hokusai::Blocks::Empty)
24
+
25
+ computed :index
26
+ computed! :pos
27
+ computed! :color
28
+
29
+ attr_accessor :dragging
30
+
31
+ def initialize(**props)
32
+ @dragging = false
33
+
34
+ super
35
+ end
36
+
37
+ def contains(p)
38
+ (((p.x - pos[0]) * (p.x - pos[0]) + (p.y - pos[1]) * (p.y - pos[1])) <= 40 * 40)
39
+ end
40
+
41
+ def start_drag(event)
42
+ if event.left.down && contains(event.pos)
43
+
44
+ self.dragging = true
45
+ node.meta.set_prop(:z, 2)
46
+ node.meta.set_prop(:position, "absolute")
47
+ end
48
+ end
49
+
50
+ def release_drag(event)
51
+ if dragging
52
+ emit("done", index)
53
+ self.dragging = false
54
+
55
+ node.meta.set_prop(:z, nil)
56
+ node.meta.set_prop(:position, nil)
57
+ end
58
+ end
59
+
60
+ def emit_drag(event)
61
+ if dragging && event.left.down
62
+ emit("drag", index, [event.pos.x, event.pos.y])
63
+ elsif dragging
64
+ emit("done", index)
65
+
66
+ self.dragging = false
67
+ node.meta.set_prop(:z, nil)
68
+ node.meta.set_prop(:position, nil)
69
+ end
70
+ end
71
+
72
+ def render(canvas)
73
+ canvas.x = canvas.x + (canvas.width / 2)
74
+ canvas.y = canvas.y + canvas.height / 2
75
+
76
+ circle(pos[0], pos[1], 40) do |command|
77
+ command.color = color
78
+ end
79
+
80
+ yield canvas
81
+ end
82
+ end
83
+
84
+
85
+ class Drag < Hokusai::Block
86
+ template <<~EOF
87
+ [template]
88
+ vblock { background="233,233,233" }
89
+ [for="thing in items"]
90
+ item {
91
+ :z="z(index)"
92
+ :key="key(index, thing)"
93
+ :index="index"
94
+ @drag="update_position"
95
+ @done="update_drag_state"
96
+ :pos="pos(thing)"
97
+ :color="color(thing)"
98
+ }
99
+ EOF
100
+
101
+ uses(
102
+ vblock: Hokusai::Blocks::Vblock,
103
+ item: Item
104
+ )
105
+
106
+ attr_reader :items
107
+
108
+ def z(index)
109
+ items[index].dragging ? 2 : nil
110
+ end
111
+
112
+ def update_drag_state(index)
113
+ items[index].dragging = false
114
+ end
115
+
116
+ def key(index, thing)
117
+ "key-#{index}"
118
+ end
119
+
120
+ def pos(thing)
121
+ thing.position
122
+ end
123
+
124
+ def color(thing)
125
+ thing.color
126
+ end
127
+
128
+ def update_position(index, pos)
129
+ items[index].dragging = true
130
+ items[index].position = pos
131
+ end
132
+
133
+ def initialize(**args)
134
+ @items = [[0, 10, [222,222,0]], [100, 100, [0,222,222]], [300, 300, [0, 222, 0]]].map do |list|
135
+ item = OpenStruct.new
136
+ item.position = [list[0], list[1]]
137
+ item.color = Hokusai::Color.convert(list[2])
138
+ item.dragging = false
139
+ item
140
+ end
141
+
142
+ pp items
143
+
144
+ super
145
+ end
146
+ end
147
+
148
+ Hokusai::Backends::RaylibBackend.run(Drag) do |config|
149
+ config.after_load do
150
+ font = Hokusai::Backends::RaylibBackend::Font.from("#{__dir__}/assets/Inter-Regular.ttf")
151
+ Hokusai.fonts.register "inter", font
152
+ Hokusai.fonts.activate "inter"
153
+ end
154
+ end
@@ -0,0 +1,58 @@
1
+ require_relative "../src/hokusai"
2
+ require_relative "../src/hokusai/backends/embedded"
3
+
4
+ class App < Hokusai::Block
5
+ template <<~EOF
6
+ [template]
7
+ button {
8
+ @clicked="clear_text"
9
+ height="30"
10
+ content="clear"
11
+ }
12
+ panel {
13
+ @swipe="handle_swipe"
14
+ @taphold="handle_taphold"
15
+ @pinch="handle_pinch"
16
+ }
17
+ text {
18
+ :content="text"
19
+ :size="15"
20
+ }
21
+ EOF
22
+
23
+ uses(
24
+ button: Hokusai::Blocks::Button,
25
+ panel: Hokusai::Blocks::Panel,
26
+ text: Hokusai::Blocks::Text
27
+ )
28
+
29
+ attr_accessor :text
30
+
31
+ def initialize(**args)
32
+ @text = ""
33
+
34
+ super
35
+ end
36
+
37
+ def clear_text(event)
38
+ self.text = ""
39
+ end
40
+
41
+ def handle_pinch(event)
42
+ self.text += "Pinch: #{event.pinch_direction} - #{event.pinch_pos.x}x#{event.pinch_pos.y} (#{event.pinch_angle})\n\n"
43
+ end
44
+
45
+ def handle_swipe(event)
46
+ self.text += "Swipe: #{event.drag_direction} - #{event.drag_pos.x}x#{event.drag_pos.y} (#{event.drag_angle})\n\n"
47
+ end
48
+
49
+ def handle_taphold(event)
50
+ self.text += "Taphold #{event.hold_duration}\n\n"
51
+ end
52
+ end
53
+
54
+ Hokusai::Backends::EmbeddedBackend.run(App) do |config|
55
+ config.after_load do
56
+ Hokusai.maximize_window
57
+ end
58
+ end
@@ -0,0 +1,143 @@
1
+ require_relative "../src/hokusai"
2
+ require_relative "../src/hokusai/backends/raylib"
3
+ require 'ostruct'
4
+
5
+ TILES = [
6
+ ["Power Supply", 500],
7
+ ["Power Distribution", 400],
8
+ ["Farm", 100],
9
+ ["Medicine Production", 50],
10
+ ["Science Research", 400],
11
+ ["Lumberyard", 200],
12
+ ["Art Gallery", 20],
13
+ ["School", 100],
14
+ ["Commercial transportation", 300],
15
+ ["Mechanical Automation", 700],
16
+ ["Tailor shop", 50],
17
+ ["Housing Construction", 200],
18
+ ["Commerical Building Construction", 300],
19
+ ["Restaraunt", 50],
20
+ ["Furniture manufacturing", 200],
21
+ ["Cotton mill", 200],
22
+ ["Metals processing", 400],
23
+ ["Forestry center", 400],
24
+ ["Bar", 50],
25
+ ["Healthcare", 100]
26
+ ]
27
+
28
+
29
+ class Game < Hokusai::Block
30
+ style <<-EOF
31
+ [style]
32
+ bg {
33
+ color: rgb(173, 207, 224);
34
+ width: 100;
35
+ height: 100;
36
+ outline: outline(1.0, 1.0, 1.0, 1.0);
37
+ outline_color: rgb(0, 0, 0);
38
+ }
39
+ board {
40
+ height: 500;
41
+ width: 500;
42
+ }
43
+ height {
44
+ height: 100;
45
+ }
46
+ textPadding {
47
+ padding: padding(10.0, 5.0, 10.0, 10.0);
48
+ }
49
+ EOF
50
+ template <<~EOF
51
+ [template]
52
+ vblock { ...board }
53
+ hblock
54
+ [for="tile in top"]
55
+ rect { :key="top_key(tile)" ...bg }
56
+ text { :content="tile" ...textPadding}
57
+ [for="i in middle"]
58
+ hblock {...height :key="get(i)"}
59
+ rect {...bg}
60
+ text { :key="get(i)" :content="get(i)" ...textPadding }
61
+ empty
62
+ empty
63
+ empty
64
+ rect {...bg }
65
+ text { :key="get_next(i)" :content="get_next(i)" ...textPadding}
66
+ hblock
67
+ [for="tile in bottom"]
68
+ rect { ...bg :key="bottom_key(tile)" }
69
+ text { :key="tile" :content="tile" ...textPadding }
70
+ EOF
71
+
72
+ uses(
73
+ hblock: Hokusai::Blocks::Hblock,
74
+ vblock: Hokusai::Blocks::Vblock,
75
+ text: Hokusai::Blocks::Text,
76
+ empty: Hokusai::Blocks::Empty,
77
+ rect: Hokusai::Blocks::Rect
78
+ )
79
+
80
+ attr_reader :tiles
81
+
82
+ def get(i)
83
+ tiles[i[0]].title
84
+ end
85
+
86
+ def get_next(i)
87
+ tiles[i[1]].title
88
+ end
89
+
90
+ def middle
91
+ (5..10).each_slice(2).to_a
92
+ end
93
+
94
+ def bottom_key(t)
95
+ "bottom-#{t}"
96
+ end
97
+
98
+ def top_key(t)
99
+ "top-#{t}"
100
+ end
101
+
102
+ def top
103
+ tiles.take(5).map(&:title)
104
+ end
105
+
106
+ def bottom
107
+ a = tiles[-5, 5].map(&:title)
108
+ a
109
+ end
110
+
111
+ def after_updated
112
+ @tiles = TILES.map do |(label, cost)|
113
+ os = OpenStruct.new
114
+ os.title = label
115
+ os.cost = cost
116
+ os
117
+ end
118
+ end
119
+
120
+ def initialize(**args)
121
+ @tiles = TILES.map do |(label, cost)|
122
+ os = OpenStruct.new
123
+ os.title = label
124
+ os.cost = cost
125
+ os
126
+ end
127
+
128
+ super
129
+ end
130
+ end
131
+
132
+
133
+ Hokusai::Backends::RaylibBackend.run(Game) do |config|
134
+ config.width = 500
135
+ config.height = 500
136
+
137
+ config.after_load do
138
+ font = Hokusai::Backends::RaylibBackend::Font.from_ext("#{__dir__}/assets/OpenSans-Regular.ttf", 160)
139
+ Hokusai.fonts.register "opensans", font
140
+ Hokusai.fonts.activate "opensans"
141
+ end
142
+ end
143
+